最近項目涉及第三方接口調用。第三方是用C#實現的WCF服務。而咱們的程序是使用的BCB6開發。所以,打算將與WCF的通信包含在C#的類庫中,給BCB6調用。BCB6 是沒法直接調用C#的DLL,但能夠經過C#編寫一個COM組件,而後BCB調用這個COM組件來調用。ios
大致步驟是c#
using System; ide using System.Collections.Generic; 函數 using System.Linq; 工具 using System.Text; 測試 using System.Runtime.InteropServices; //1添加Rumtime.InteropServices 程序集引用ui using System.Windows.Forms; //2爲了演示,因此加入了forms引用spa
namespace ComImpTest 命令行 { debug [Guid("3CD116D4-18A1-4504-921B-57C053BAD618")] //3主菜單->工具->建立GUID產生 public interface IComInterface //4必須先定義接口 { [DispId(1)] //5每個函數或者屬性都須要指定DispID void Hello(string name); [DispId(2)] int Add(int x,int y); [DispId(3)] string COMINFO{get;}
}
[Guid("1A8EB38C-E732-49B2-A897-B40FFD744E3D")] public class ComImp : IComInterface //6編寫一個實現接口的類 { public void Hello(string name) { Console.WriteLine("你好"+name); MessageBox.Show("你好"+name,"C# dll 彈出界面"); }
public int Add(int x, int y) { return x + y; }
public string COMINFO { get { return "com 測試"; } } } } |
在如圖的目錄會獲得RegAsm.exe(必定要用安裝後獲得的RegAsm 從其餘地方複製的RegASM可能存在版本不兼容),
這個在註冊COM的時候要用到。
輸出目錄。(這也不是必須的,本質上COM只要能註冊,而後BCB功能能找到TLB建立代理類便可)
其本質是吧這個COM類註冊到了註冊表中。向系統進行了發佈。
打開BCB 工程,選擇主菜單 projectàimport type library
獲得代理類
包含這個頭文件,咱們就能夠調用了。
可是這裏不知道是BCB的bug,仍是兼容性的問題,BCB產生的ComImp代理類的GUID是錯誤的。
正確的GUID 應該是編寫C#dll 時產生的Guid
[Guid("1A8EB38C-E732-49B2-A897-B40FFD744E3D")] |
咱們只須要替換這個Guid便可,若是不這麼作,調用時HRESULT會返回找不到實現接口。
//--------------------------------------------------------------------------- #pragma hdrstop #include <iostream> #include <vcl.h> //注意,iostream要在 vcl.h 前面定義,不然cout<<AnsiString 報錯 #include "Comimptest_tlb.h" using namespace std; //---------------------------------------------------------------------------
#pragma argsused int main(int argc, char* argv[]) { HRESULT hr; //初始化COM CoInitialize ( NULL ); //建立智能指針命名空間在頭文件Comimptest_tlb.h中能夠查找到 //接口智能指針的定義也能查找到 Comimptest_tlb::IComInterfacePtr ptr;
//建立實例,ComImp 的聲明,也能在頭文件中查找到。 hr = ptr.CreateInstance(__uuidof (Comimptest_tlb::ComImp));
if(hr == S_OK) { //調用ADD方法 cout << ptr->Add (1, 2)<<endl; //調用Hello方法,在bcb中Widestring 對應 c#的 string WideString name = "Zakk wylde 和奧茲"; ptr->Hello(name.c_bstr()); //調用COMINFO屬性,這裏COM進行了名字改變,這些函數均可以在頭文件中查到原型定義。 BSTR outp = NULL; ptr->get_COMINFO(&outp); //由於是寬字符,因此要轉換爲AnsiString進行輸出 cout<<AnsiString(outp)<<endl; }
CoUninitialize (); system("pause"); return 0; } |
4 用vc調用COM
用VC調用C#的COM 就沒有這麼多事情。下面是VC調用的代碼,
將ComImpTest.tlb 和 ComImpTest.dll 拷貝到 VC工程的debug目錄下。而後用import指令(BCB 沒法用import識別,估計是不兼容)
// testCOM3.cpp : 定義控制檯應用程序的入口點。 // #include "stdafx.h" #include <iostream> #include <Windows.h> using namespace std; #import "../debug/ComImpTest.tlb" int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr; //初始化COM CoInitialize ( NULL ); //建立智能指針 ComImpTest::IComInterfacePtr ptr; //建立實例 hr = ptr.CreateInstance(__uuidof (ComImpTest::ComImp)); if(hr == S_OK) { cout << ptr->Add (1,2)<<endl; ptr->Hello(L"VC++ 調用"); cout<<ptr->COMINFO<<endl; } CoUninitialize (); system("pause"); return 0; } //---------------------------------------------------------------------------