2011-04-14 25 views
8

Actualmente estoy tratando de compilar una biblioteca C++ (archivo DLL) que interactúe con un componente COM para que pueda utilizarse en Java. La idea era que construiría una pequeña DLL de C++ con una clase que "se enrolla" alrededor del componente COM, y luego la exportaría usando SWIG. Tengo bastante lejos utilizando una instrucción import:Manejo de eventos COM en C++ (ATL, MFC o C++ puro) para la interoperabilidad de Java

#import "ComponentName.dll" 

y llamar a CoInitialize() y la creación de una instancia del componente (a través de la clase IComponentNamePtr que fue generado por Visual Studio). Esto funcionó para todas las llamadas a métodos COM normales, lo cual fue bueno.

Sin embargo, no puedo encontrar la forma de que los eventos funcionen. Veo que hay una IComponentNameEventsPtr que complementa la clase principal "puntero inteligente", pero no podía trabajar en lo que hay que hacer para que funcione

He intentado todo lo siguiente para obtener los eventos de trabajo:

  • Pure C++ — No pude encontrar la manera de hacerlo. Traté de crear una nueva clase que heredó de la clase IComponentNameEvents, haciendo stubs para todas las funciones abstractas y anulando las funciones, excepto que las funciones no están marcadas como virtuales, por lo que no funcionó.
  • MFC — No pude obtener la llamada a AfxOleInit funcionando correctamente. Google me dijo que la llamada falla cuando se llama desde una DLL, ya que supone que OLE ya se ha inicializado. No estaba muy seguro de cómo solucionar esto. Mi biblioteca se bloqueó cada vez que traté de crear una instancia del componente COM (supongo que porque COM no se inicializó correctamente)
  • ATL — No pude averiguar cómo hacer los eventos en ATL. Pude crear la clase (a través del asistente "ATL simple", luego el asistente "Implementar interfaz") pero no pude encontrar la forma de usarlo. Leí Using IDispEventImpl on MSDN pero no pude entender cómo usar la clase producida por ese howto. ¿Necesito usar el objeto COM a través de ATL también (o puedo usar las clases autorizadas de #import)? ¿Cómo "adjunto" la clase de escucha de eventos?
  • Leo Event Handling in COM que usa el atributo event_receiver (parte del nuevo modelo de evento unificado de Visual C++). Originalmente no pude averiguar cómo combinar eso con el uso del componente COM creado a través de la instrucción # import. Finalmente funcioné (¡y se mencionó en la página!) Que necesito usar el indicador "embedded_idl" en la declaración # import, pero eso rompió otras cosas (obtuve un montón de errores "esperando una especificación de tipo cerca" en el archivo .tlh)

¿Alguien sabe cómo hacer esto? ¿Cuál es el enfoque más fácil de tomar? Mi experiencia está en C# y PHP, así que no tengo mucha experiencia con el uso de COM en C++.

tldr: ¿Cuál es la forma más fácil de usar eventos COM en una DLL de C++?

Respuesta

1

realidad tiene este yo mismo trabajando ing el modelo de evento unificado. Algunas notas de mi experiencia en conseguir que funcione:

Y a continuación, añadir un

typedef struct StructName StructName; 

Para cada estructura que genera un error

  • Una vez hecho esto, usted debe ser capaz de inicializar COM y crea una instancia de tu objeto. Feo código de ejemplo:

    IComponentName blah; 
    HRESULT hr = CoInitialize(NULL); 
    if (FAILED(hr)) 
    { 
        MessageBox(NULL, "Failed to initialize COM", "Hi!", 0); 
        throw "Failed to initialize COM"; 
    } 
    
    try 
    { 
        hr = blah.CreateInstance("Something.Something"); 
        if (FAILED(hr)) 
        { 
         CoUninitialize(); 
         MessageBox(NULL, "Failed to initialize the COM library!!", "Hi!", 0); 
         throw "Failed to initialize the COM library"; 
        } 
    } 
    catch (...) 
    { 
        MessageBox(NULL, "Exception occured when initialising library!", "Error", 0); 
        CoUninitialize(); 
        throw "Exception occured when initialising library!"; 
    } 
    

Una vez que tenga su objeto COM, puede conectar los eventos según el "Manejo de Eventos en el COM" MSDN artículo:

__hook(&IComponentNameEvents::OnWhatever, blah, &EventHandlerClass::OnWhatever); 

Asegúrese de desenganchar todos los eventos antes de llamar a CoUninitialize(), de lo contrario, obtendrá errores.

3

Implemente la interfaz de origen en su código (utilizando cualquier mecanismo, incluso quizás generando código C simple utilizando el compilador midl).En su librería de tipos externa (la que usted está consumiendo) Busque la interfaz que se parece a:

[source] interface IOutGoing; 

Una vez que la implementó, se registra utilizando Advise en el objeto de que las fuentes de los eventos (anular el registro con Unadvise)

Aquí hay un fragmento que muestra un uso típico, suponiendo que se tiró de MIDL (con ATL/MFC que tendría que escribir menos código, sino conocer más macros/templates)

class CSink : public IOutGoing 
{ 
public: 
    // IUnknown 
    ULONG __stdcall AddRef(); 
    ULONG __stdcall Release(); 
    HRESULT __stdcall QueryInterface(REFIID riid, void** ppv); 

    // IOutGoing 
    HRESULT __stdcall GotMessage(int Message); 

    CSink() : m_cRef(0) { } 
    ~CSink() { } 

private: 
    long m_cRef; 
}; 


IUnknown* pUnknown; 
CoCreateInstance(CLSID_XXXXXXXXX, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown); 

IConnectionPointContainer* pConnectionPointContainer; 
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer); 

hr = pConnectionPointContainer->FindConnectionPoint(IID_IOutGoing, &pConnectionPoint); 

// Instantiate the sink object. 
CSink* mySink = new CSink; 

// Give the connectable object a pointer to the sink. 
DWORD dwCookie; 
pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie); 
+0

De hecho, esto funcionaba usando el Modelo de eventos unificado. Tendré que escribir una respuesta aquí cuando tenga algo de tiempo libre :) –

+0

Estoy tratando de hacer esto yo mismo y no estoy seguro de qué se supone que sea IOutGoing, no tengo propiedad sobre la biblioteca COM y no contiene un tipo que parece ser como IOutGoing. ¿Cómo puedo crear mi clase CSink? – innova

Cuestiones relacionadas