BCB6 调用C# DLL

最近项目涉及第三方接口调用。第三方是用C#实现的WCF服务。而我们的程序是使用的BCB6开发。因此,打算将与WCF的通讯包含在C#的类库中,给BCB6调用。BCB6 是无法直接调用C#的DLL,但可以通过C#编写一个COM组件,然后BCB调用这个COM组件来调用。

  1. 用C#编写COM

    大体步骤是

    1. 新建一个类库项目

BCB6 调用C# DLL

 

  1. 设置Assemblyinfo.cs

    BCB6 调用C# DLL

  2. 设置项目属性

    BCB6 调用C# DLL

  3. 编写代码

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.InteropServices;//1添加Rumtime.InteropServices程序集引用

using System.Windows.Forms;//2为了演示,所以加入了forms引用

 

namespace ComImpTest

{

[Guid("3CD116D4-18A1-4504-921B-57C053BAD618")]//3主菜单->工具->创建GUID产生

publicinterfaceIComInterface//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")]

publicclassComImp :IComInterface//6编写一个实现接口的类

{

publicvoid Hello(string name)

{

Console.WriteLine("你好"+name);

MessageBox.Show("你好"+name,"C# dll 弹出界面");

}

 

publicint Add(int x,int y)

{

return x + y;

}

 

publicstring COMINFO

{

get

{

return"com测试";

}

}

}

}

  1. 编译得到DLL 和 TLB

    BCB6 调用C# DLL

  1. BCB编写调用
    1. 首先BCB的开发环境中需要安装.NET FrameWork ,这里都是用的.NET FrameWork 4.0,安装之后,

      在如图的目录会得到RegAsm.exe(一定要用安装后得到的RegAsm 从其他地方复制的RegASM可能存在版本不兼容),

      这个在注册COM的时候要用到。

      BCB6 调用C# DLL

    2. 建立一个BCB控制台工程
    3. 吧RegAsm.exe(我们是为了注册方便),前面编译得到的 ComImpTest.tlb 、ComImpTest.dll 复制到BCB工程的EXE

      输出目录。(这也不是必须的,本质上COM只要能注册,然后BCB功能能找到TLB创建代理类即可)

      BCB6 调用C# DLL

    4. 用管理员启动命令行,注册ComImpTest.dll

      BCB6 调用C# DLL

       

      其本质是吧这个COM类注册到了注册表中。向系统进行了发布。

    5. 用BCB 产生代理类

      打开BCB 工程,选择主菜单 projectàimport type library

      BCB6 调用C# DLL

       

      BCB6 调用C# DLL

       

      BCB6 调用C# DLL

       

      得到代理类

      BCB6 调用C# DLL

      包含这个头文件,我们就可以调用了。

       

      但是这里不知道是BCB的bug,还是兼容性的问题,BCB产生的ComImp代理类的GUID是错误的。

      BCB6 调用C# DLL

      正确的GUID 应该是编写C#dll 时产生的Guid

[Guid("1A8EB38C-E732-49B2-A897-B40FFD744E3D")]

 

我们只需要替换这个Guid即可,如果不这么做,调用时HRESULT会返回找不到实现接口。

 

BCB6 调用C# DLL

 

 

 

  1. BCB 调用COM的代码
    1. 在控制台工程中,加入代理类的头文件 ComImpTest_tlb.h
    2. 代码如下

//---------------------------------------------------------------------------

#pragmahdrstop

#include<iostream>

#include<vcl.h>//注意,iostream要在 vcl.h前面定义,否则cout<<AnsiString报错

#include"Comimptest_tlb.h"

usingnamespace 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方法,在bcbWidestring对应 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;

}

 

 

BCB6 调用C# DLL

 

BCB6 调用C# DLL

 

4 用vc调用COM

用VC调用C#的COM 就没有这么多事情。下面是VC调用的代码,

将ComImpTest.tlb 和 ComImpTest.dll 拷贝到 VC工程的debug目录下。然后用import指令(BCB 无法用import识别,估计是不兼容)

BCB6 调用C# DLL
// 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;
}


//---------------------------------------------------------------------------
BCB6 调用C# DLL

 

相关文章: