最近项目涉及第三方接口调用。第三方是用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; } //---------------------------------------------------------------------------