首先我們來看看今天的主題和CLR Interop的關系,在我們組裡,interop這個術語包含了四個范疇,即P/Invoke, Reverse P/Invoke, COM Interop和Reverse COM Interop。前二個概念通過動態連接庫(DLL)在native世界和.NET世界中實現互通性;後兩個概念顧名思義,就是和COM打交道了。其中,COM interop是在.NET應用中使用COM組件;Reverse COM Interop指的是在COM應用中使用.NET組件。概念有些繞口令,看官先別急著拋轉,看看下圖。
可能有人會問, COM技術已經歷史悠久了,.NET程序員為什麼需要和它打交道呢?問題的答案就在於”組件”一詞。舉個例子,若干年前一個牛人寫了個程序,擴展性極佳,他用了COM把插件的接口定義的明明白白,而我們想用.NET來做這個插件。。。
為COM寫一個.NET組件,可以參照以下三部曲
1.定義.NET接口,撰寫.NET class
2.部署.NET組件
3.撰寫COM客戶端
第一步驟對經常從事.NET的開發朋友來說非常熟悉,這裡給出例子,不再贅述。
csc /target:library a.cs
第二,要部署.NET組件,這裡包括兩個方面:
regasm a.dll /tlb
1.把類型庫(type library)導出。對於COM應用來說,它只懂得類型庫,是為COM組件遵循的二進制”標准”。/tlb選項告訴regasm,導出類型庫。我們可以用oleview察看tlb的內容,如下圖所示,此前定義的.NET接口和類都在其中。
2.把步驟2中生成的dll放到注冊表中。COM並不懂得諸如GAC的概念,而是通過注冊表來查詢HKEY_CLASSES_ROOT\CLS_ID\00000000-0000-0000-FFFF-000000000004,觀察這個注冊表項,InprocServer32中把COM的動態鏈接庫指向了mscoree.dll,這就是傳說中的墊片(shim),它會負責加載公共語言運行時,並找到真正的.NET組件----a.dll。
有了以上兩步,我們就可以在COM應用中使用.NET組件了。如何撰寫COM組件超出了本文的范疇,有興趣的讀者可以參考代碼中的注釋。
cl client.cs
// client.cs #define _WIN32_COM #include <stdio.h> #include <wtypes.h> #import "a.tlb" no_namespace named_guids raw_interfaces_only // a.tlb是第二步中導出的 int main() { IUnknown *pUnk = NULL; IA *pIA = NULL; HRESULT hresult; // 0. 初始化COM組件 hresult = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hresult)) { printf("ERROR: cannot initialze COM: 0x%x\n", hresult); return -1; } // 1. 獲取IUnknown接口 hresult = CoCreateInstance(CLSID_A, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnk); if (FAILED(hresult)) { printf("ERROR: cannot Get the IUnkown interface: 0x%x\n", hresult); return -1; } // 2. 獲得IA接口 hresult = pUnk->QueryInterface(IID_IA, (void **)&pIA); if (FAILED(hresult)) { printf("ERROR: cannot Convert to IDispatch interface: 0x%x\n", hresult); pUnk->Release(); return -1; } pUnk->Release(); // 3. 調用.NET組件 hresult = pIA->Hello(); if (FAILED(hresult)) { printf("ERROR: Invoke failed: 0x%x\n", hresult); } // 4. 清理 pIA->Release(); CoUninitialize(); return 0; }
By com.microsoft.stbc.devdiv.ndp.interop.dev/mountaintai二世