您的位置:首页 > 编程语言 > C语言/C++

C++ 调用C#工程的 dll , 互相调用方法

2018-01-10 15:18 609 查看
很多时候在项目中需要通过C++调用C#的dll,或者反过来条用。

首先明白一个前提:C#是托管型代码。C++是非托管型代码。

托管型代码的对象在托管堆上分配内存,创建的对象由虚拟机托管。(C#


       非托管型代码对象有实际的内存地址,创建的对象必须自己来管理和释放。(C++)

两者详细区别阅读我的另一篇:托管代码和非托管代码的介绍,以及在这区别下的混合调试方法

1、C#调用C++的dll.

在C#工程中的引用项中直接将要使用的C++dll引用进来即可。 然后创建对象或者调用接口。



2、C++调用C#的dll.

C++调用C#dll,目前我知道的有两种方式

(1)com方式调用。

这种调用方式就是将dll转换成类com组件的方式调用。

直接看方法:C++ 调用C#dll不是直接调用dll, 而是调用一个转变后的文件:.tlb文件的支持

tlb文件:com类型库文件,它包含接口相关信息。在需要使用对应com类的模块里,通过"#import xxx.tlb"来调用。

eg: 在C++代码中使用: #import "../../out/debug/TGPDFSignLib.tlb"

这个.tlb文件会对应的生成tgpdfsignlib.tli 和 tgpdfsignlib.tlh两个文件。 

在VC下#import "TGPDFSignLib.tlb" no_namespace;编译后产生TGPDFSignLib.tlh和TGPDFSignLib.tli两个文件,不生成namespace,如果没有no_namespace,则生成的内容都在namespaceTGPDFSignLib中。如果dll中含有tlb资源,则也可以使用#import
"xxx.dll"来生成tlh和tli文件。一般的c++ dll不能使用#import "xxx.dll"。

那么tlh、tli文件是什么?

tlh、tli文件是vc++编译器解析tlb文件生成的标准c++文件。因为tlb并不是C++标准的东西,有必要把它们翻译成标准的C++类型,使得C++开发者可以使用。tlh相当于类型申明(头文件),tli相当于定义实现(CPP文件,inline)。

当写到这里时所有的调用已经完成,你已经可以通过这种方法调用C#dll了。

但是有一个问题,我们需要通过.tlb文件调用,那么.tlb文件从哪来的呢???

生成.tlb文件一般有2种方法:

1)     在工程编译时同步互操作注册生成文件。

在vs中C#项目,选择项目属性,打开属性配置页,生成页中选择为com互操作注册复选框,在编译时会同时生成。

eg:vs2013中



2)  在命令框中注册dll生成。

直接将regasm.exe文件拷贝到dll目录方便。

打开cmd,选择管理员权限运行。cd到dll所在目录, 输入命令:

regasmTGPDFSignLib.dll /tlb

运行,注册成功,即可生成.tlb文件。

注: 请注意版本的对应,也就是你不能用.net2.0的regasm.exe去注册.ne t4.0的dll.如果这样或报错:RegAsm error: Failed to load 'XXXXX.dll' because it is not a valid.Net assembly。

每个版本都有一个对应的regasm.exe,2.0就用2.0的注册,4.0用4.0的注册。

(2)虚拟化方式调用(clr)

创建一个C#工程,得到一个dll.

eg:  这样的一个简单工程,
namespace MathDLL

{

   public class DDD

    {

       public int demoAdd(int x, int y)

       {

           int sum;

           sum = x + y;

           return sum;

       } 

}

}

那么在C++工程中可以直接引用:

#include "stdafx.h"
#using "../MathDLL/bin/Debug/MathDLL.dll"   //引用dll
using namespace MathDLL;   //使用dll的命名空间
int _tmain(intargc, _TCHAR* argv[])
{
    int sum, x, y;
    x = 10;
    y = 22;
    DDD ^a = gcnew DDD();  //创建对象
    sum = a->demoAdd(x, y);  //调用方法
    sum = x + y;
    printf("计算结果:%d", sum);
       return 0;
}
如此即可完成调用;这种方式不需要中间文件。

该方法需要设置公共语言运行支持属性,否则无法识别:



说明:以下几点需要记住且明确

1、         使用#using引用C#
DLL,而不是#include;

2、         别忘了using namespace MathDLL;

3、         使用C++/clr语法,采用正确的访问托管对象,即:使用'^',而不是星号'*'。

在vs中^显示为:



4、         使用gcnew创建对象。

注:gcnew关键字

C++/CLI中使用gcnew关键字表示在托管堆上分配内存,并且为了与以前的指针区分,用^来替换*,就语义上来说他们的区别大致如下:
1.     gcnew返回的是一个句柄(Handle),而new返回的是实际的内存地址. 
2.     gcnew创建的对象由虚拟机托管,而new创建的对象必须自己来管理和释放.
从程序员的角度来说,管它是句柄还是什么其他的东西,总跑不掉是对某块内存地址的引用,实际上我们都可以理解成指针.

该方法:如果dll和应用程序不在同一目录则调用失败,运行报错。

       比如,ie浏览器调用C++控件,然后控件中调用C#dll,
dll显然和ie.exe不在同一目录。

       原因以及实现方法还在研究中…….

       如果有人遇到过相同的问题,解决了的,欢迎留言一下分享一下解决方法,不胜感激。

如果有人遇到过相同的问题,解决了的,欢迎留言一下分享一下解决方法,不胜感激。

如果有人遇到过相同的问题,解决了的,欢迎留言一下分享一下解决方法,不胜感激。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: