用C#建立COM物件 (轉)

worldblog發表於2007-12-13
用C#建立COM物件 (轉)[@more@]

用建立COM


作者:天極論壇

在本篇文章中,我們將討論下面的問題:
  ·使用C#建立一個簡單的COM物件(使用COM的Interop特性)。
  ·從VC++客戶端中訪問COM。客戶端軟體使用了TypeLibrary(.TLB)。
  為了簡單和方便開發人員使用、測試起見,我們使用了SERVER軟體的預設中的Northwind資料庫。
  ·修改COM物件中SQLServer的名字,與SQLServer連線。
  ·我們已經建立了連線資料庫用的分別為tt、tiger的名和口令,我們可以使用它或者其他現有的使用者名稱和口令。

  第一部分:用C#建立簡單的COM物件
  COM物件是Claibrary類,它生成DLL檔案。要在VS開發環境中建立一個簡單的COM物件,我們可以依次選擇“檔案”->;“新建立”->;“工程”->;“VisualC#工程”->;“類庫”,然後建立一個名字為Database_COM的工程。

  需要注意的是:在COM中VC#物件需要下面的條件:
  ·類必須是public性質。
  ·特性、方法和事件必須是public性質的。
  ·特性和方法必須在類介面中定義。
  ·事件必須在事件介面中定義。

  不是在這些介面中定義的public性質的類成員不能被COM訪問,但它們可以被其他的 物件訪問。要讓COM能夠訪問特性和方法,我們必須在類介面中定義它們,使它們具有DispId屬性,並在類中實現這些特性和方法。這些成員定義時的順序也就是它們在COM中順序。要讓COM訪問類中的事件,必須在事件介面中定義這些事件,並賦予它們DispId屬性。事件介面不應當由類完成,類只實現類介面(它可以實現不止一個介面,但第一個介面是預設介面),應當在預設介面中實現需要讓COM訪問的方法和特性,方法和特性必須被標識為public性質,並符合在類介面中的定義。需要讓COM訪問的事件也在預設的類介面中完成,它們也必須被標識為public性質,並符合事件介面中的定義。
  在介面名字之前,每個介面需要一個GUID特性。要生成變個唯一的Guid,需要執行guidgen.exe工具軟體,並選擇“登錄檔格式” 下面是一個類介面:

[Guid(";694C1820-04B6-4988-928F-FD858B95C880";)]
public interface COM_Interface
{
[DispId(1)]
void Init(string userid , string pass);
[DispId(2)]
bool ExecuteCommand(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),
ComInterfaces(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..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物件前,我們必須向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 ;
注: 轉載自中文技術網

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992716/,如需轉載,請註明出處,否則將追究法律責任。

相關文章