用C#創(chuàng)建COM對象(轉(zhuǎn)自計算機(jī)世界)
2024-07-21 02:24:19
供稿:網(wǎng)友
在本篇文章中,我們將討論下面的問題:
·使用c#創(chuàng)建一個簡單的com對象(使用com的interop特性)。
·從vc++客戶端軟件中訪問com。客戶端軟件使用了typelibrary(.tlb文件)。
為了簡單和方便開發(fā)人員使用、測試起見,我們使用了sqlserver數(shù)據(jù)庫軟件的缺省安裝中的northwind數(shù)據(jù)庫。
·修改com對象中sqlserver的名字,與sqlserver連接。
·我們已經(jīng)創(chuàng)建了連接數(shù)據(jù)庫用的分別為scott、tiger的用戶名和口令,我們可以使用它或者其他現(xiàn)有的用戶名和口令。
第一部分:用c#創(chuàng)建簡單的com對象
com對象是classlibrary類,它生成dll文件。要在vs開發(fā)環(huán)境中創(chuàng)建一個簡單的com對象,我們可以依次選擇“文件”->“新創(chuàng)建”->“工程”->“visualc#工程”->“類庫”,然后創(chuàng)建一個名字為database_comobject的工程。
需要注意的是:在com中調(diào)用vc#對象需要下面的條件:
·類必須是public性質(zhì)。
·特性、方法和事件必須是public性質(zhì)的。
·特性和方法必須在類接口中定義。
·事件必須在事件接口中定義。
不是在這些接口中定義的public性質(zhì)的類成員不能被com訪問,但它們可以被其他的.net framework對象訪問。要讓com能夠訪問特性和方法,我們必須在類接口中定義它們,使它們具有dispid屬性,并在類中實現(xiàn)這些特性和方法。這些成員定義時的順序也就是它們在com中順序。要讓com訪問類中的事件,必須在事件接口中定義這些事件,并賦予它們dispid屬性。事件接口不應(yīng)當(dāng)由類完成,類只實現(xiàn)類接口(它可以實現(xiàn)不止一個接口,但第一個接口是缺省接口),應(yīng)當(dāng)在缺省接口中實現(xiàn)需要讓com訪問的方法和特性,方法和特性必須被標(biāo)識為public性質(zhì),并符合在類接口中的定義。需要讓com訪問的事件也在缺省的類接口中完成,它們也必須被標(biāo)識為public性質(zhì),并符合事件接口中的定義。
在接口名字之前,每個接口需要一個guid特性。要生成變個唯一的guid,需要運(yùn)行g(shù)uidgen.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
{
需要注意的是,在類的前面,需要設(shè)置下面的特性:
classinterface(classinterfacetype.none),
comsourceinterfaces(typeof(dbcom_events))]
classinterfacetype.none表示沒有為該類生成類接口,如果沒有明確地實現(xiàn)接口,類只能通過idispatch提供后期綁定訪問。用戶希望通過明確地由類實現(xiàn)的接口使外部對象能夠訪問類的功能,這也是推薦的classinterfaceattribute的設(shè)置。
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();
}
}
}
在創(chuàng)建com對象前,我們必須向com interop注冊該對象。右擊方案管理器中的工程名字,點擊快捷菜單上的“屬性”選項,然后再點擊“配置”->“創(chuàng)建”,擴(kuò)展output小節(jié),將register for com interop選項的值設(shè)置為true。這樣,一個com對象就能夠與可管理性應(yīng)用程序進(jìn)行交互。
為了使com對象能夠被外部對象調(diào)用,類庫組合必須有一個強(qiáng)名字。創(chuàng)建強(qiáng)名字需要用到sn.exe名字:
sn -k database_com_key.snk
打開assemblyinfo.cs,并修改下面一行的內(nèi)容:
[assembly: assemblykeyfile("database_com_key.snk")]
創(chuàng)建對象。創(chuàng)建對象會生成一個可以被導(dǎo)入到可管理性或非可管理性代碼中的類庫。
第二部分:使用visual c++創(chuàng)建訪問com對象的客戶端軟件
·使用vc++開發(fā)環(huán)境創(chuàng)建一個簡單的工程。
·使用#import directive導(dǎo)入類型庫。
·在界面中創(chuàng)建一個smart pointer,從接口中執(zhí)行com類提供的功能。確保在應(yīng)用程序加載時添加coinitialize()調(diào)用:
coinitialize(null);
database_comobject::dbcom_interfaceptr p(__uuidof(database_comobject::dbcom_class));
db_com_ptr = p ;
db_com_ptr->init("scott" , "tiger");
下面的代碼對customers數(shù)據(jù)庫表執(zhí)行一個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 ;
,歡迎訪問網(wǎng)頁設(shè)計愛好者web開發(fā)。