用C#建立COM對象(轉自電腦世界)
最後更新:2017-02-28
來源:互聯網
上載者:User
建立|對象 在本篇文章中,我們將討論下面的問題:
·使用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對象就能夠與可管理性應用程式進行互動。
為了使COM對象能夠被外部對象調用,類庫組合必須有一個強名字。建立強名字需要用到SN.EXE名字:
sn -k Database_COM_Key.snk
開啟AssemblyInfo.cs,並修改下面一行的內容:
[assembly: AssemblyKeyFile("Database_COM_Key.snk")]
建立對象。建立對象會產生一個可以被匯入到可管理性或非可管理性代碼中的類庫。
第二部分:使用Visual C++建立訪問COM對象的用戶端軟體
·使用VC++開發環境建立一個簡單的工程。
·使用#import directive匯入類型庫。
·在介面中建立一個Smart Pointer,從介面中執行COM類提供的功能。確保在應用程式載入時添加CoInitialize()調用:
CoInitialize(NULL);
Database_COMObject::DBCOM_InterfacePtr p(__uuidof(Database_COMObject::DBCOM_Class));
db_com_ptr = p ;
db_com_ptr->Init("scott" , "tiger");
下面的代碼對Customers資料庫表執行一個SQL命令,返回給定ID的客戶的資訊:
char cmd[1024];
sprintf(cmd , "SELECT COMPANYNAME , CONTACTNAME ,
CONTACTTITLE , ADDRESS FROM CUSTOMERS WHERE CUSTOMERID = '%s'" , m_id );
const char *p ;
bool ret = db_com_ptr->ExecuteSelectCommand(cmd);
if ( ! db_com_ptr->NextRow() ) return ;
_bstr_t mData = db_com_ptr->GetColumnData(3);
p = mData ;
m_address = (CString)p ;