COM和.NET的互操作
◆ 鹿傳明
.NET Framework的產生已經有兩年多的時間了,有不少公司開始采用.NET開發應用軟件。但是很多公司在多年的項目應用中,開發了很多COM、DCOM組件,現在采用.NET開發組件,使這些組件成為了遺留代碼。由于在開發COM組件時投入了大量的人力、財力,如何在.NET環境下重用這些COM組件就顯得更有意義,本文將介紹使這些COM組件“起死回生”的方法。
.NET支持運行時通過COM、COM+、本地WinAPI調用與未管制代碼的雙向互操作性,BCL為此提供了一套類和屬性,包括受管制對象生存期的精確控制等。要實現互操作性,必須首先引入.NET Framework的 System.Runtime.InteropServices命名空間。C#的語法為:
using System.Runtime.InteropServices;
而VB.NET的語法為:
import System.Runtime.InteropServices
.NET訪問API
.NET允許C#訪問未管制的DLL的函數。如要調用Windows User32.dll的MessageBox函數:
int MessageBox(HWND hwnd,LPCTSTR lpText, LPCTSTR lpCaption,UINT uType)
可以聲明一個具有DLLImport屬性的static extern方法:
using System.Runtime.InteropServices;
[DllImport(“user32.dll”)]
static ertern int MessageBox(int hwnd,string text,string caption,int type);
然后在代碼里面直接調用就可以了。這里要注意在調用返回字符串的API中使用StringBuilder對象。
.NET訪問COM組件
從.NET調用COM組件比較容易,只要使用tlbimp.exe產生COM的裝配形式的WarpClass,然后在.NET項目中調用即可。
注意COM的類型信息通過Type Library文件描述,.NET裝配件是自描述的。Tlbimp的作用是從COM組件及其類型信息中產生自描述的裝配件。由于VB是進行COM組件開發最簡單的語言,所以我們以一個簡單的VB COM組件來說明。
1.編寫VB組件
VB組件原碼(文件名CoAccount.cls)如下:
Private m_Balance As Integer
’組件的私有成員變量
Public Sub Deposit(sum As Integer)
’存錢的方法
m_Balance = m_Balance + sum
End Sub
Public Property Get Balance() As Integer
’屬性Balance訪問成員變量m_Balance
Balance = m_Balance
End Property
將上述代碼編譯生成CoAccount.dll。
2. 產生.NET可訪問的包裝類(assembly),使用TlbImp.exe產生.NET裝配件。
TlbImp /out:NetAccount.dll CoAccount.dll
3.在.NET代碼中訪問
.NET代碼只需引用CoAccount.dll,就可以像訪問.NET的裝配件一樣訪問COM組件。
將.NET組件轉化為COM組件
因為.NET裝配件開發效率較高,先在.NET環境下開發裝配件,然后轉化為COM組件,由VB、ASP等調用,可以加快開發進度。下面我們用一個例子簡單闡述一下整個過程。步驟如下:
1.定義接口
COM是通過拋出接口讓外部應用調用的,每個接口、組件都有一個GUID,在.NET中開發COM組件也不例外。
[Guid(“18E2BCAF-F4B5-4031-8F84-FCFB1DC04877”)] //接口GUID
public interface IAccount
//定義接口IAccount
{ [DispId(1)]
//每個方法或屬性都具有DISPID屬性,是為了讓VBScript等腳本語言調用
void deposit(int num);
//方法,實現存錢的功能
[DispId(2)]
int Balance
//屬性,查看當前的賬戶余額,只讀。請注意.NET下屬性的定義方法
{ get; }
}
2.實現接口的派生類
[Guid(“9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E”), //組件的GUID
ClassInterface(ClassInterfaceType.None)]
//指明組件的調用方式,支持后期綁定
public class NetAccount:IAccount
//實現接口派生類,注意派生類要實現接口的所有方法。
{ private int balance;
//組件的私有成員變量(在.NET中稱為域(FIELD))
public NetAccount()
//構造函數,初始化成員變量
{ balance=10; }
public void deposit(int num)
//實現存錢方法。
{ balance+=num; }
public int Balance
//實現Balance屬性,通過它訪問成員變量
{ get
{ return balance; }
}
}
3.將.NET私有裝配件轉化成公有裝配件
.NET下對裝配件的調用,實際上是拷貝到調用應用程序的本地目錄,稱為私有裝配件。要轉化為COM組件,首先要轉化為公有裝配件,也就是放到GAC里。
(1) 創建強名字
為了使COM對象能夠被外部對象調用,類庫組合必須有一個強名字。創建強名字需要用到SN.EXE,語法為:sn -k account.snk, 然后將強名字拷貝到debug目錄下。打開AssemblyInfo.cs,并修改下面一行的內容:
[assembly: AssemblyKeyFile(@“account.snk”)]
(2) 將裝配件轉入GAC
編譯項目文件產生NetAccount.dll文件,使用GacUtil.exe裝入GAC:
gacutil -i NetAccount.dll
(3) 注冊裝配件
在注冊表里面注冊裝配件,允許COM組件的客戶調用,也可以生成注冊表文件,以備將來調用。
RegAsm NETAccount.Dll
執行上述語句,則裝配件可以被腳本語言調用。
(4) 導出類型庫
為了可以在VB里面使用組件,必須使用tlbexp.Exe導出COM類型庫。
Tlbexp /out:NetAccount.tlb NetAccount.dll
經過上面的工作,就將一個.NET裝配件轉化為COM組件。需要注意的是:在COM中調用.NET對象需要具備以下條件:
● 類必須是public性質;
● 特性、方法和事件必須是public性質的;
● 特性和方法必須在類接口中定義;
● 事件必須在事件接口中定義。
(計算機世界報 第43期 C17、C18)
|