2011-04-14 74 views
8

我目前正在嘗試構建與COM組件接口的C++庫(DLL文件),以使其可用於Java。我的想法是,我將構建一個非常小的C++ DLL,其中包含一個圍繞COM組件「包裝」的類,然後使用SWIG將其導出。我很遠通過使用#import語句:用於Java互操作的C++(ATL,MFC或純C++)處理COM事件

#import "ComponentName.dll" 

而且調用CoInitialize()和創建組件的一個實例(通過這是由Visual Studio生成的IComponentNamePtr類)。這適用於所有正常的COM方法調用,這很好。

但是,我無法弄清楚如何讓事件工作。我看到有互補的主要「智能指針」類IComponentNameEventsPtr,但我不能工作了做得到它的工作

我已經試過什麼都下面讓事件工作:

  • Pure C++ —我無法解決如何做到這一點。我嘗試創建一個從IComponentNameEvents類繼承的新類,爲所有抽象函數創建存根,並覆蓋函數,但函數未標記爲虛擬,因此不起作用。
  • MFC —我無法接到電話AfxOleInit正常工作。谷歌搜索告訴我,從DLL調用時調用失敗,因爲它假定OLE已經被初始化。我不太清楚如何解決這個問題。每次我嘗試創建COM組件實例時,我的庫都崩潰了(我假設COM因爲未正確初始化)
  • ATL —我無法弄清楚如何在ATL中執行事件。我可以創建類(通過「簡單ATL」嚮導,然後是「實現接口」嚮導),但無法解決如何使用它。我讀Using IDispEventImpl on MSDN,但無法解決如何使用該howto生成的類。我是否也需要通過ATL使用COM對象(或者我可以使用#import自動生成的類)?我如何「附加」事件監聽器類?
  • 我讀了Event Handling in COM,它使用event_receiver屬性(新的Visual C++統一事件模型的一部分)。最初我無法弄清楚如何將它與使用通過#import語句創建的COM組件相結合。我終於搞定了(並且在頁面上提到了它),我需要在#import語句中使用「embedded_idl」標誌,但是這打破了其他一些東西(我有一堆「期望類型規範接近」錯誤.tlh文件)

有誰知道該怎麼做?最簡單的方法是什麼?我的背景是在C#和PHP中,所以我沒有太多關於在C++中使用COM的經驗。

tldr:在C++ DLL中使用COM事件的最簡單方法是什麼?

回答

1

事實上,我這個我自己工作統一事件模型。從我的經驗得到它的一些筆記工作:

,然後添加一個

typedef struct StructName StructName; 

對於引發錯誤

  • 一旦這樣做了每一個結構,你應該能夠初始化COM並創建你的對象的一個​​實例。醜陋的示例代碼:

    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!"; 
    } 
    

一旦你有你的COM對象,可以活動連接爲每MSDN「事件在COM處理」的文章:

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

一定要解開所有事件在調用CoUninitialize()之前,否則你會得到錯誤。

3

在代碼中實現源接口(使用任何機制,包括使用midl編譯器生成純C代碼)。在外部類型庫(你正在消耗一個)尋找看起來像接口:

[source] interface IOutGoing; 

一旦你實現它,那源的事件(註銷其與Unadvise)在物體上使用Advise註冊它

這裏是展現出典型的用一個片段,假設你去了MIDL方式(與ATL/MFC你必須寫更少的代碼,但知道更多宏/模板)

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

我實際上是在使用統一事件模型自己工作的。當我得到一些空閒時間時,我將不得不在這裏寫一個答案:) – 2011-04-15 12:16:54

+0

我試圖讓自己完成這件事,我不確定IOutGoing應該是什麼,我沒有對COM庫的所有權它不包含看起來像IOutGoing的類型。如何創建我的CSink類? – innova 2015-06-25 07:35:00