日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【译文转帖】用C#写COM组件 Building COM Objects in C#

發布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【译文转帖】用C#写COM组件 Building COM Objects in C# 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說明:

我是一個C#程序員,但是有一次一個需求只能用C/C++去寫,恰好需要讀取的數據存放在DB(SQL CE v3)里面,而我又不會C/C++(關鍵是用OleDB訪問DB,這個實在是繁瑣),所以催生了用C#寫一個COM組件,用C/C++去調用的想法.可謂,很傻很天真.但是也是一種思路,如果MS提供C API的話,問題就簡單多了.可是事實是,MS自己的.NET CF用著C API,給用戶卻暴露著COM API.....OK,言歸正傳.

?

主要內容:

  • 用C#創建一個簡單的COM組件(通過COM Interop)
  • 用VC++寫一個客戶端去訪問COM組件.客戶端用TLB文件.

本著易于使用的目的,我把Northwind導入到了SQLServer,然后測試了我的代碼.(the sake of simplycity這個不知道啥意思,難道是由于出現紙尿布....).

  • 修改COM組件里面的機器名為你的SQL Server的機器名.(2005以上需要 機器名\實例名)
  • 當然我在里面也創建了一個用戶scott密碼是tiger,用來連接數據庫.你可以選擇這個用戶名,或者重新建一個.

Part I: 用C#創建一個簡單的COM組件

COM對象是一種類庫.COM組件將產生DLL文件.在VS環境里面創建COM組件請選擇....

  File->New->Project->VisualC# Projects ->Class Library.

創建一個名為Database_COMObject的類庫工程.

請記住:想要把C#對象當作COM對象需要以下幾點...

  • class必須是public的
  • 屬性,方法和事件必須是public
  • 屬性和方法必須在Interface里面定義
  • 事件必須在事件的接口中

未在接口中定義的成員,而在實現里面是public的成員,對COM是不可見的,但是對其他的.NET程序是可見的.為了把屬性和方法暴露給 COM,你必須在接口中定義他們,并且把他們用DispId屬性標記,在class里面實現(.....).在接口里面定義的成員只是為了使用 vtable(虛函數表).要想暴露事件,你也必須把成員定義在事件接口里面并且標記DispId屬性.類不需要實現此接口(???).類可以實現接口 (一個類可以實現多個接口,只有第一個接口才是默認的接口.).暴露給COM的那些屬性方法其實就在類的實現里面.他們必須被標記為public,而且要符合接口里面的定義.Also, declare the events raised by the class here. They must be marked public and must match the declarations in the events interface. (這兩句不知道具體的含義,代碼里面也沒看出端倪.)

每一個接口都要有一個GUID屬性(我當時上學的時候,把他叫屬性屬性,或者定制屬性,現在也不清楚到底叫什么..).你可以用guidgen.exe來產生一個GUID值.

這個接口就長這個樣子:

?

    [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("694C1820-04B6-4988-928F-FD858B95C880")]
publicinterfaceDBCOM_Interface
{
[DispId(1)]
voidInit(stringuserid , stringpassword);
[DispId(2)]
boolExecuteSelectCommand(stringselCommand);
[DispId(3)]
boolNextRow();
[DispId(4)]
voidExecuteNonSelectCommand(stringinsCommand);
[DispId(5)]
stringGetColumnData(intpos);
}

COM事件:

?

    // // 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{

?

在類的前面標記:

?

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);}// 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();}}
}

?

?

在編譯COM組件之前,需要在COM Interop那里注冊.

打開Solution Explorer->Properties->Configuration->Build->Expand the output section->Register for COM Interop改為True.

(我在VS 2008里面貌似不是這么操作的,工程上面點右鍵->屬性->Build->最下面的Output->Register for COM Interop改為True).

表明,我要把Managed程序導出一個COM對象,并且COM對象可以和我們的托管程序交互.

為了(真正)導出COM對象,程序集還需要強命名,可以用sn.exe生成一個StrongName:

sn -k Database_COM_Key.snk

在AssemblyInfo.cs文件里面修改:

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

編譯這個對象.會產生一個tlb文件,通過這個可以使Managed代碼和Native代碼都能訪問你的COM對象.

Part II : 用VC++創建一個客戶端去訪問這個COM對象

我已經在VC++6.0和VC++.NET下面訪問呢過改COM對象.

創建一個簡單的工程,通過?#import directive導入type library.

?

創建一個只能指針指向接口的實例,執行那些導出函數,確保在程序加載的時候執行CoInitialize().

?

    CoInitialize(NULL);Database_COMObject::DBCOM_InterfacePtr p(__uuidof(Database_COMObject::DBCOM_Class));db_com_ptr = p ;db_com_ptr->Init("scott" , "tiger");

?

下面的代碼通過一個Customer ID去在Customer表中查詢:

?

    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 ;

?

PS:

總算翻譯完了....英語不好,有一些句子不能理解含義,英語好的童鞋推薦直接看e文.

我只能說我很悲劇,當初想法很好,只可惜,.NET CF下面,不支持用C#寫一個COM組件.

我的口頭禪就是:.NET CF除了慢,再沒有其他優點.

轉載于:https://www.cnblogs.com/SuperBrothers/archive/2012/10/29/2744933.html

總結

以上是生活随笔為你收集整理的【译文转帖】用C#写COM组件 Building COM Objects in C#的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。