COM对象与VC++客户端交互指南

在本文中,将探讨如何创建一个简单的COM对象,并使用VC++客户端访问该对象以实现数据库操作。将使用C#来创建COM对象,并使用VC++6.0或VC++.NET环境来创建客户端。

第一部分:创建简单的COM对象

COM对象通常是一个类库(ClassLibrary),生成DLL文件。要在Visual Studio开发环境中创建一个简单的COM对象,选择“文件”->“新建”->“项目”->“Visual C#项目”->“类库”。创建一个名为Database_COMObject的项目。

为了将C#对象暴露给COM世界,需要满足以下条件:

  • 类必须是public的。
  • 属性、方法和事件必须是public的。
  • 属性和方法必须在类接口上声明。
  • 事件必须在事件接口上声明。
  • 其他public成员如果不是在这些接口上声明的,对COM不可见,但对其他.NET Framework对象可见。

为了将属性和方法暴露给COM,必须在类接口上声明它们,并使用DispId属性标记它们,并在类中实现它们。事件必须在事件接口上声明,并使用DispId属性标记。类不应实现这个接口。类实现类接口(它可以实现多个接口,但第一个实现将是默认的类接口)。在这里实现暴露给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事件:

[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); } [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; private 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互操作注册对象。要这样做,请在解决方案资源管理器中右键单击项目名称。单击属性。单击配置->构建。展开输出部分。将“注册为COM互操作”设置为true。这表明托管应用程序将公开一个COM对象(一个COM可调用包装器),允许COM对象与托管应用程序交互。

为了使COM对象被公开,类库程序集还必须具有强名称。要创建强名称,请使用SN.EXE工具。

sn -k Database_COM_Key.snk

打开AssemblyInfo.cs并修改该行:

[assembly: AssemblyKeyFile("Database_COM_Key.snk")]

构建对象。构建还会产生一个类型库,可以导入到托管或非托管代码中。

第二部分:使用Visual C++创建客户端以访问此COM对象

已经在VC++ 6.0和VC++ .NET环境中测试了COM对象。使用VC++开发环境创建一个简单的项目。使用#import指令导入类型库。创建一个智能指针到Interface.Execute,这是接口公开的函数。确保在应用程序加载时添加CoInitialize()调用。

以下是客户端代码示例:

CoInitialize(NULL); Database_COMObject::DBCOM_InterfacePtr db_com_ptr(__uuidof(Database_COMObject::DBCOM_Class)); db_com_ptr->Init("scott", "tiger"); 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;
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485