在本篇文章中,我們將討論下面的問題:
·使用C#創建一個簡單的COM對象(使用COM的Interop特性)。
·從VC++客戶端軟件中訪問COM。客戶端軟件使用了TypeLibrary(.TLB文件)。
為了簡單和方便開發人員使用、測試起見,我們使用了SQLSERVER數據庫軟件的缺省安裝中的Northwind數據庫。
·修改COM對象中SQLServer的名字,與SQLServer連接。
·我們已經創建了連接數據庫用的分別為scott、tiger的用戶名和口令,我們可以使用它或者其他現有的用戶名和口令。
第一部分:用C#創建簡單的COM對象
COM對象是ClassLibrary類,它生成DLL文件。要在VS開發環境中創建一個簡單的COM對象,我們可以依次選擇“文件”->;“新創建”->;“工程”->;“VisualC#工程”->;“類庫”,然後創建一個名字為Database_COMObject的工程。
需要注意的是:在COM中調用VC#對象需要下面的條件:
·類必須是public性質。
·特性、方法和事件必須是public性質的。
·特性和方法必須在類接口中定義。
·事件必須在事件接口中定義。
不是在這些接口中定義的public性質的類成員不能被COM訪問,但它們可以被其他的.NET Framework對象訪問。要讓COM能夠訪問特性和方法,我們必須在類接口中定義它們,使它們具有DispId屬性,並在類中實現這些特性和方法。這些成員定義時的順序也就是它們在COM中順序。要讓COM訪問類中的事件,必須在事件接口中定義這些事件,並賦予它們DispId屬性。事件接口不應當由類完成,類只實現類接口(它可以實現不止一個接口,但第一個接口是缺省接口),應當在缺省接口中實現需要讓COM訪問的方法和特性,方法和特性必須被標識為public性質,並符合在類接口中的定義。需要讓COM訪問的事件也在缺省的類接口中完成,它們也必須被標識為public性質,並符合事件接口中的定義。
在接口名字之前,每個接口需要一個GUID特性。要生成變個唯一的Guid,需要運行guidgen.exe工具軟件,並選擇“注冊表格式” 下面是一個類界面:
[Guid(";694C1820-04B6-4988-928F-FD858B95C880";)] public interface DBCOM_Interface { [DispId(1)] void Init(string userid , string password); [DispId(2)] bool ExecuteSelectCommand(string selCommand); [DispId(3)] bool NextRow(); [DispId(4)] void ExecuteNonSelectCommand(string insCommand); [DispId(5)] string GetColumnData(int pos); }
COM事件接口:
// 事件接口Database_COMObjectEvents [Guid(";47C976E0-C208-4740-AC42-41212D3C34F0";), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface DBCOM_Events { }
下面是實際的類定義:
[Guid(";9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E";), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(DBCOM_Events))] public class DBCOM_Class : DBCOM_Interface {
需要注意的是,在類的前面,需要設置下面的特性:
ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(DBCOM_Events))]
ClassInterfaceType.None表示沒有為該類生成類接口,如果沒有明確地實現接口,類只能通過IDispatch提供後期綁定訪問。用戶希望通過明確地由類實現的接口使外部對象能夠訪問類的功能,這也是推薦的ClassInterfaceAttribute的設置。
ComSourceInterfaces(typeof(DBCOM_Events))]確定許多作為COM事件向外部對象提供的接口。在本文的例子中,我們不對外部對象開放任何事件。
下面是COM對象完整的源代碼:
using System; using System.Runtime.InteropServices; using System.IO; using System.Text; using System.Data.SqlClient; using System.Windows.Forms ; namespace Database_COMObject { [Guid(";694C1820-04B6-4988-928F-FD858B95C880";)] public interface DBCOM_Interface { [DispId(1)] void Init(string userid , string password); [DispId(2)] bool ExecuteSelectCommand(string selCommand); [DispId(3)] bool NextRow(); [DispId(4)] void ExecuteNonSelectCommand(string insCommand); [DispId(5)] string GetColumnData(int pos); } // 事件接口Database_COMObjectEvents [Guid(";47C976E0-C208-4740-AC42-41212D3C34F0";), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface DBCOM_Events { } [Guid(";9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E";), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(DBCOM_Events))] public class DBCOM_Class : DBCOM_Interface { private SqlConnection myConnection = null ; SqlDataReader myReader = null ; public DBCOM_Class() { } public void Init(string userid , string password) { try { string myConnectString = ";user id=";+userid+";;password=";+password+ ";;Database=NorthWind;Server=SKYWALKER;Connect Timeout=30";; myConnection = new SqlConnection(myConnectString); myConnection.Open(); MessageBox.Show(";CONNECTED";); } catch(Exception e) { MessageBox.Show(e.Message); } } public bool ExecuteSelectCommand(string selCommand) { if ( myReader != null ) myReader.Close() ; SqlCommand myCommand = new SqlCommand(selCommand); myCommand.Connection = myConnection; myCommand.ExecuteNonQuery(); myReader = myCommand.ExecuteReader(); return true ; } public bool NextRow() { if ( ! myReader.Read() ) { myReader.Close(); return false ; } return true ; } public string GetColumnData(int pos) { Object obj = myReader.GetValue(pos); if ( obj == null ) return ";"; ; return obj.ToString() ; } public void ExecuteNonSelectCommand(string insCommand) { SqlCommand myCommand = new SqlCommand(insCommand , myConnection); int retRows = myCommand.ExecuteNonQuery(); } } }
在創建COM對象前,我們必須向COM Interop注冊該對象。右擊方案管理器中的工程名字,點擊快捷菜單上的“屬性”選項,然後再點擊“配置”->;“創建”,擴展output小節,將Register for COM Interop選項的值設置為true。這樣,一個COM對象就能夠與可管理性應用程序進行交互。