在COM應用中使用.NET組件


上一博中,我們用Visual Studio.NET組件(託管組件)變成了COM服務器。本博繼續這個話題,看看如何使用.NET工具包來完成相應的功能。

首先我們來看看今天的主題和CLR Interop的關係,在我們組裏,interop這個術語包含了四個範疇,即P/Invoke, Reverse P/Invoke, COM InteropReverse COM Interop。前二個概念通過動態連接庫(DLL)native世界和.NET世界中實現互通性;後兩個概念顧名思義,就是和COM打交道了。其中,COM interop是在.NET應用中使用COM組件;Reverse COM Interop指的是在COM應用中使用.NET組件。概念有些繞口令,看官先別急着拋轉,看看下圖。

f0.jpg

可能有人會問, 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接口和類都在其中。

f2.JPG

 

2.       把步驟2中生成的dll放到註冊表中。COM並不懂得諸如GAC的概念,而是通過註冊表來查詢HKEY_CLASSES_ROOT/CLS_ID/00000000-0000-0000-FFFF-000000000004,觀察這個註冊表項,InprocServer32中把COM的動態鏈接庫指向了mscoree.dll,這就是傳說中的墊片(shim),它會負責加載公共語言運行時,並找到真正的.NET組件----a.dll

 f1.jpg

有了以上兩步,我們就可以在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;

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章