用C#创建COM对象

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

⽤C#创建COM对象
在本篇⽂章中,我们将讨论下⾯的问题:
·使⽤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 ;。

相关文档
最新文档