且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

成功实现C++调用C#写的库(CLR),我的个人心得与总结

更新时间:2022-08-22 11:08:00

一、先说说我的个人心得


我新建了C++ win32动态库工程,准备调用C#类库。


//使用CLR的方式,成功实现C++调用C#类库,注意事项:

//1.

//不要尝试在DllMain或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。

//解决办法:

//注释掉dllmain.cpp文件里的主函数BOOL APIENTRY DllMain

//2.

//本人在实践工程中遇到两个难点:

//(1)CLR/CLI链接器失败,错误LNK2022 - 自定义属性不一致

//(2)软件发布,Windows7 64位纯净版,软件启动时,出现KERNELBASE.dll错误

//问题原因及解决方法:

//.NET版本不匹配,请安装需要的.NET版本,详情见第3点说明

//3.

//visual studio如何修改c++项目的.net framework框架版本

//修改项目文件

//在 Visual Studio 的“解决方案资源管理器”中,打开项目的快捷菜单,然后选择“卸载项目”。

//这将为你的项目卸载项目文件(.vcxproj)。

//在菜单栏上,依次选择“文件”、“打开”、“文件”。 在“打开文件”对话框中,导航到项目文件夹,

//然后打开项目文件(.vcxproj)。在项目文件中,找到目标 Framework 版本的条目。

//例如,如果你的项目设计为使用.NET Framework 4.5,<PropertyGroup Label = "Globals">元素中找到

//请在<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>元素

//如果 <TargetFrameworkVersion> 元素不存在,则新增之,并修改相应版本号。

//4.

//VC++的平台工具集如果是MSVC2015,则.NET框架至少要4.0版本

//VC++的平台工具集如果是MSVC2013,则.NET框架可以是3.5版本

//考虑到纯净版的Windows 7操作系统自带的.NET版本是3.5,所以建议C++工程使用MSVC2013编译;

//因为客户的Win7电脑不一定会有.NET4.0,这样我们自己可以省得每次设备出货时安装.NET4.0框架



二、再来看网上摘录的经验总结


C++编写的程序为非托管代码,C#编写的程序为托管代码。托管代码虽然提供了其他开发平台没有的许多优势,但由于前期系统及历史版本很多使用的是非托管代码编写的程序,所以CLR提供了一些机制,允许在应用程序中同时包含托管和非托管代码。具体说分为以下三种:


1、托管代码能调用DLL中的非托管函数。通过P/Invoke(Platform Invoke)机制调用DLL中的函数,如Kernel32.dll等。


2、托管代码可以使用现有COM组件(服务器)。许多公司都已经实现了大量非托管COM组件。利用来自这些组件的类型库,可创建一个托管程序集来描述COM组件。托管代码可像访问其他任何类型一样访问托管程序集中的类型。


3、非托管代码可以使用托管类型(服务器)。许多现有的非托管代码要求提供COM组件来确保代码正确工作。使用托管代码可以更简单地实现这些组件,避免所有代码都不得不和引用计数和接口打交道。比如C++调用C#开发的dll。


那C++如何调用C#写的库?查了网上的资料,目前知道两种情况,一种是用C++/CLI(通用语言接口),另一种则是使用COM组建。


总结:

1)用C#写任何的类库

2)C++ 中要引用此类库,使用#using引用C#编写的DLL,而不是#include,引用C#的DLL后,还需要添加该DLL的命名空间using namespace MathDLL

3)创建C#对象时要用gcnew ;

4) C++ 编译设置一定设置为:支持公共语言运行时支持(/clr),使用C++/clr语法,采用正确的方式访问托管对象,即:使用帽子“^”,而不是“*”

5) 自身的C++类要用 ref class 定义。


6)#using "..\\TestDLL\\bin\\Debug\\TestDLL.dll"  这是VC++托管代码中调用.net DLL的方法,如果是原生C++代码,不能这么调用,要用COM方式,但是被调用的必须是public static方法。


7)CSDN赵4老师的建议是:


不要做A语言代码修改为B语言代码的无用功。

也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。

只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。

即可很方便地让A、B两种语言之间协调工作。

比如:

A将请求数据写到文件a.txt,写完后改名为aa.txt

B发现aa.txt存在时,读取其内容,调用相应功能,将结果写到文件b.txt,写完后删除aa.txt,再将b.txt改名为bb.txt

A发现bb.txt存在时,读取其内容,读完后删除bb.txt

以上A可以替换为任何一种开发语言或开发环境,B可以替换为任何一种与A不同的开发语言或开发环境。

除非A或B不支持判断文件是否存在、文件读写和文件更名。

但是谁又能举出不支持判断文件是否存在、文件读写和文件更名的开发语言或开发环境呢?

可以将临时文件放在RamDisk上提高效率减少磨损磁盘。

数据的结构很复杂的话,文本文件的格式问题可参考json或xml


共享临时文本文件这种进程之间的通讯方法相比其它方法的优点有很多,下面仅列出我现在能想到的:

·进程之间松耦合

·进程可在同一台机器上,也可跨机,跨操作系统,跨硬件平台,甚至跨国。

·方便调试和监视,只需让第三方或人工查看该临时文本文件即可。

·方便在线开关服务,只需删除或创建该临时文本文件即可。

·方便实现分布式和负载均衡。

·方便队列化提供服务,而且几乎不可能发生队列满的情况(除非硬盘空间满)

·……

“跨语言、跨机,跨操作系统,跨硬件平台,跨国,跨*.*的”苦海无边,

回头是“使用共享纯文本文件进行信息交流”的岸!



三、转载网上文章《N种方法使用C++调用C#.NET库》


常规方法1:COM

使用C#把托管类注册成COM,用regasm.exe注册output assembly,然后用C++像调用COM一样调用assembly里面的type。

优点:编写代码简单,调用方便

缺点:需要注册output,发布不够简单

参考:http://www.codeproject.com/KB/cs/ManagedCOM.aspx


常规方法2:CLR

C#常规编写类,生产assembly,C++使用CLR编译既可直接引用托管类。

优点:编写代码简单,调用方便

缺点:需要了解C++ CLR语法(既不像C++,又不像C#,总之很奇怪)

参考:http://www.codeproject.com/KB/mcpp/cppcliintro01.aspx


http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx


常规方法3:API

C#常规编写类,生产assembly,C++使用SDK提供的CLR非托管接口(CLRCreateInstance)进行调用。

优点:传统C#编程,传统C++编程

缺点:要求.Net Framework 4.0以上版本

参考:http://nport.codeplex.com/SourceControl/changeset/view/45681#903468


http://msdn.microsoft.com/en-us/library/dd537633.aspx


变通方法:

1. 使用C#/VB包装现有托管类,注册成Windows服务,暴露SOAP web service。VC2005可以使用非托管代码添加引用Web service。

2. 使用C#/VB包装现有托管类,注册成Windows服务。C++利用Windows message和服务通讯。

3. 使用C#/VB包装现有托管类,注册成Windows服务。C++利用Windows共享内存和服务通讯。

其实利用双进程通讯的方法,可以演变出各种各样调用的思路。聪明的你可以充分发挥想象力,写出自己独有的调用模式。



---


参考文献:


https://www.cnblogs.com/bylikai/p/4695317.html CLR


https://www.cnblogs.com/huangmianwu/p/6145044.html COM


https://blog.csdn.net/shq886258963/article/details/59057797 两种都有


https://blog.csdn.net/sudazf/article/details/52160514 这个好


从C++到C++/CLI 科普


https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-4.0/ms172271(v=vs.100)


https://docs.microsoft.com/en-us/previous-versions/ms235289(v=vs.140)


https://docs.microsoft.com/zh-cn/cpp/dotnet/initialization-of-mixed-assemblies?view=vs-2019