JAVIS 编译
在本篇文章中,我们将讨论下面的
问题:
·使用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 Sy