Building COM Objects in C#
Building COM Objects in C#.
Introduction
The topics covered in this article are:
- Creating a simple COM object in C# (use the COM Interop property).
- Accessing the COM from a VC++ client. (I have tested it with VC++6.0 and VC++ .NET). Client uses the TypeLibrary (.TLB?file).
For the sake of simplicity and ease of use for the developers, testing this code, I have used the?Northwinddatabase built into with the default installation of SQL Server database.
- Modify the name of the SQL Server in the COM object to connect to your SQL Server.
- Also, I have created a default user ID and password of?scott / tiger?to connect to the database. Either create this, or use an existing ID / password.
Part I: Creating a simple COM object in C#
COM objects are of the type?ClassLibrary. The COM object generates a DLL file. To create a simple COM object from the VS Development Environment, select ....
Hide???Copy Code New->Project->Visual C# Projects ->Class LibraryCreate a project named?Database_COMObject.
Remember: Exposing the VC# objects to the COM world requires the following ...
- The class must be?public.
- Properties, methods, and events must be?public.
- Properties and methods must be declared on the class interface.
- Events must be declared in the event interface.
Other public members in the class that are not declared in these interfaces will not be visible to COM, but they will be visible to other .NET Framework objects. To expose properties and methods to COM, you must declare them on the class interface and mark them with a?DispId?attribute, and implement them in the class. The order the members are declared in the interface is the order used for the COM?vtable. To expose events from your class, you must declare them on the events interface and mark them with a?DispId?attribute. The class should not implement this interface. The class implements the class interface (it can implement more than one interface, but the first implementation will be the default class interface). Implement the methods and properties exposed to COM here. They must be marked?public?and must match the declarations in the class interface. Also, declare the events raised by the class here. They must be marked?public?and must match the declarations in the events interface.
Every interface needs a GUID property set before the interface name. To generate the unique GUID, use theguidgen.exe?utility and select the?Registry Format.
Here is how the interface class looks like ...
Hide???Copy Code [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); }For COM events ..
Hide???Copy Code // // Events interface Database_COMObjectEvents [Guid("47C976E0-C208-4740-AC42-41212D3C34F0"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface DBCOM_Events { }For the actual class declaration:
Hide???Copy Code [Guid("9E5E5FB2-219D-4ee7-AB27-E4DBED8E123E"),ClassInterface(ClassInterfaceType.None),ComSourceInterfaces(typeof(DBCOM_Events))]public class DBCOM_Class : DBCOM_Interface{Note the following property set before the class:
Hide???Copy Code ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(DBCOM_Events))]The?ClassInterfaceType.None?indicates that no class interface is generated for the class. If no interfaces are implemented explicitly, the class will only provide late bound access through?IDispatch. Users are expected to expose functionality through interfaces that are explicitly implemented by the class. This is the recommended setting for?ClassInterfaceAttribute.
The?ComSourceInterfaces(typeof(DBCOM_Events))]?identifies a list of interfaces that are exposed as COM event sources for the attributed class. For our example, we do not have any events exposed.
Here is the complete COM object source ..
Hide???Shrink????Copy Code 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);}// Events interface 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();}} }Before you build the COM object, we have to register the object for COM Interop. To do this, right click the project name in the Solution Explorer. Click Properties. Click Configuration ->Build. Expand the output section. Set the?Register for COM Interop?to?true.
Indicate that your managed application will expose a COM object (a COM-callable wrapper) that allows a COM object to interact with your managed application.
In order for the COM object to be exposed, your class library assembly must also have a strong name. To create a strong name, use the utility?SN.EXE.
Hide???Copy Code sn -k Database_COM_Key.snkOpen the?AssemblyInfo.cs?and modify the line:
Hide???Copy Code [assembly: AssemblyKeyFile("Database_COM_Key.snk")]Build the object. The build also results into a type library that can be imported into your managed or unmanaged code.
Part II: Creating a Client using Visual C++ to access this COM Object
I have tested the COM object with the VC++ 6.0 and VC++ .NET environment. Create a simple project using the VC++ development environment. Import the type library using the?#import?directive. Create a Smart Pointer to the?Interface.Execute, the exposed functions from the interface. Make sure to add the?CoInitialize()?call when the application loads.
Hide???Copy Code CoInitialize(NULL);Database_COMObject::DBCOM_InterfacePtrp(__uuidof(Database_COMObject::DBCOM_Class)); db_com_ptr = p ; db_com_ptr->Init("scott" , "tiger");This code executes a SQL Command against the?Customers?table and returns the customer information for a given customer ID.
Hide???Copy Code 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 ;License
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found?here
總結
以上是生活随笔為你收集整理的Building COM Objects in C#的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 引用程序集没有强名称解决办法
- 下一篇: A标签使用javascript:伪协议