Pregunta

Fondo

La aplicación que estoy trabajando con tiene varias DLL COM.

Una de las DLL COM tiene un objeto único mundial, que almacena punteros a interfaces COM en otros archivos DLL. Debido a que es un objeto único mundial, he empleado la inicialización perezosa idioma, ya que es posible que la interfaz estoy tratando de obtener un puntero a un archivo DLL existe en el cual aún no se ha cargado.

( Side-nota: Esto es especialmente importante cuando se registra un solo archivo DLL, como los objetos globales serán construidos dentro del proceso regsvr32, y no quiero que la DLL para tratar de obtener una interfaz a otro DLL durante este proceso.)

Por ejemplo, mi método de inicialización perezosa podría hacer algo como esto:

CComPtr<IMyOtherObject>&
CGlobalSingleton::
GetMyOtherObject()
{
    // SNIP: Other code removed for clarity...

    if (! m_pMyOtherObject)
    {
        hr = pUnknown->QueryInterface(IID_IMyOtherObject,
            (void**) &m_pMyOtherObject);
    }

    return m_pMyOtherObject;
}

NOTA:. m_pMyOtherObject es una variable miembro del tipo de CComPtr

La inicialización perezosa puede no ser relevante para mi problema aquí, pero estoy incluyendo que esté completa.

Problema

Lo que he notado es que en algunas circunstancias, consigo aserciones fallen cuando mi aplicación se cierra. Sin embargo, si cambio de código para llamar QueryInterface() todos tiempo que necesito para acceder IID_IMyOtherOBject (en lugar de almacenarla como una variable miembro) esto evita que las afirmaciones.

Esto me parece ser un problema de duración de los objetos COM. Mi hipótesis es que porque soy un puntero storing COM, es necesario que haya algún tipo de sincronización entre la destrucción de la interfaz COM que estoy señalando, y mi propio puntero a él.

Mi comprensión de la clase CComPtr (que estoy utilizando) es que se quita una gran cantidad de los dolores de cabeza de tratar con los problemas de toda la vida (es decir, llamando AddRef() y Release()). Pero no parece estar funcionando en mi caso.

¿Alguien puede escoger lo que puedo estar haciendo mal?

¿Fue útil?

Solución

En lugar de implementar su propio producto único global, buscar en el uso de la IGlobalInterfaceTable interfaz en lugar. Es un producto único que es proporcionada por el sistema operativo a nivel de proceso. Cualquiera de sus archivos DLL puede poner sus objetos COM en la tabla, y los otros archivos DLL seguir para recuperar cuando sea necesario. Todo lo que se necesita para poner en práctica de su parte es una manera para que los archivos DLL para el intercambio de galletas DWORD de la mesa entre sí.

Otros consejos

Usted está devolviendo una referencia al puntero inteligente que no podría estar aumentando el número de referencias. Lo siento, me gustaría comprobar pero es tarde aquí. Esa es mi corazonada y que se adapte a lo que usted está describiendo -. Mirar en constructores de copia de CComPtr

Espero que ayude,

K

Una puñalada salvaje en la oscuridad: ¿Es posible que CGlobalSingleton podría quedar destruida después CoUninitialize() se llama, bajo ninguna circunstancia? Si lo fuera, y por lo tanto también m_pMyOtherObject fue destruida después de desinicialización COM, sería otra manera de causar la violación de acceso que Igor mencionado.

Sospecho que el problema está en su comprensión de la semántica copia / asignación de la clase CComPtr; No estoy particularmente familiarizado con CComPtr, pero en mi experiencia punteros inteligentes tienden a no funcionar de la manera que puede ser que ellos esperan. En primer lugar debe leer la documentación de CComPtr y asegúrese de entender cómo funciona (no estaría de más que mirar el código fuente, tampoco). También podría intentar poner algunos puntos de interrupción en el AddRef () y Release () miembros de CComPtr para ver lo que sucede durante y después de la llamada a GetMyOtherObject (), sobre todo si está almacenando temporalmente el valor de retorno y se sale del ámbito.

Suena como m_pMyOtherObject está todavía vivo cuando apaga su aplicación. Además de copiar cuestiones constructor m_pMyOtherObject debe ser un CComPtr o CGlobalSingleton debe llamar al método m_pMyOtherObject de Release a la destrucción.

Editado por claridad.

Editar Sólo hizo una prueba rápida y no tuve ningún problema usando una función que devuelve una referencia a CComPtr. Mientras que esto es un poco inusual que no causa ningún problema de recuento de referencia.

quería ampliar pesar de lo que suceda si m_pMyOtherObject no es un puntero inteligente. En este escenario nunca va a ser liberado. Te voy a enseñar por qué:

  1. Se llama a QueryInterface en algunos puntero. Se llamará AddRef en ese objeto.
  2. devuelven CComPtr y CComPtr y puntero de interfaz o desnudo. Esto es en gran medida irrelevante. No hay operaciones de recuento ref tienen lugar (a menos que se asigna el valor devuelto a otro CComPtr, que AddRef ella. Sin embargo, desde que se CComPtr equilibrarlo con una llamada a la versión no importa).
  3. ¿Qué se termina con 1 o bien es llamada a AddRef y 0 para liberar o 2 llamadas a AddRef y de 1 a lanzamiento. En otras palabras, son desequilibradas y usted tiene una fuga de referencia.

Para evitar esto es necesario estructurar su programa como este:

class CGlobalSingleton{

CComPtr<IMyOtherObject> m_spMyOtherObject;

IMyOtherObject* GetMyOtherObject()
{
    // SNIP: Other code removed for clarity...

    if (! m_spMyOtherObject)
    {
        //pUnknown gets AddRef'ed, but that's OK, m_spMyOtherObject will call release when CGlobalSingleton goes out of scope
        hr = pUnknown->QueryInterface(IID_IMyOtherObject,
            (void**) &m_spMyOtherObject);
    }

    return m_pMyOtherObject;
}
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top