非托管C++通过C++/CLI包装调用C# DLL
项目中要给其它客户程序提供DLL做为接口,该项目是在.Net4.0平台下开发。终所周知.Net的各个版本之间存在着兼容性的问题,但是为了使用高版本运行平台的新特性,又不得不兼顾其它低版本平台客户程序的调用。为了解决这个问题尝试通过一个C++/CLI DLL对高版本的.Net DLL的接口加了一层包装,对外暴露C风格的接口给客户程序调用。
可支持的客户语言平台:
- VB 6.0
- VC++
- .Net 1.0/.Net 1.1
- .Net 2.0
- .Net 3.5
创建C# .Net4.0的类库
创建一个C#项目:Csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Csharp
{
public class CsharpClass
{
public int DoTesting(int x, int y, string testing, out string error)
{
error = testing + " -> testing is ok.";
return x + y;
}
}
}
创建C++/CLI包装类库
创建项目C++/CLI项目:CsharpWrap

添加对Csharp的引用

CsharpWrap.h
// CsharpWrap.h #pragma once #include <windows.h>
#include <string> using namespace System;
using namespace Csharp;
using namespace std;
using namespace Runtime::InteropServices;
CsharpWrap.cpp
// This is the main DLL file. #include "stdafx.h" #include "CsharpWrap.h" extern "C" _declspec(dllexport) int DoTesting(int x, int y, char* testing, char* error)
{
try
{
CsharpClass ^generator = gcnew CsharpClass();
String^ strTesting = gcnew String(testing);
String^ strError; int sum = generator->DoTesting(x, y,strTesting, strError); if(strError != nullptr)
{
char* cError =
(char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();
memcpy(error,cError,strlen(cError) + );
}
else
{
error = nullptr;
} return sum;
}
catch(exception e)
{
memcpy(error,e.what(),strlen(e.what()) + );
return -;
}
}
项目输出和使用
- Csharp.dll
- CsharpWrap.dll
如果要调用CsharpWrap.dll必须保证Csharp.dll也被调用程序可见(即应该放在进程EXE文件同一目录下)
调用Demo代码
C++
HINSTANCE hInst= LoadLibrary(_T("CsharpWrap.dll"));
if(hInst)
{
pfunc DoTesting = (pfunc)GetProcAddress(hInst,"DoTesting");
if(DoTesting)
{
char error[]= {NULL};
int sum = DoTesting(, , "Hello", error);
//show testing results
char strSum[];
_itoa_s(sum,strSum,);
::MessageBoxA(NULL, error, strSum, MB_OK);
}
else
{
::MessageBoxA(NULL, "Get function fail.", "Fail", MB_OK);
}
//free library
FreeLibrary(hInst);
hInst = nullptr;
}
else
{
::MessageBoxA(NULL, "Load dll fail.", "Fail", MB_OK);
}
C#低版本.Net
导出函数
[DllImport("CsharpWrap.dll")]
static extern int DoTesting(int x, int y, string testing, StringBuilder error);
调用
StringBuilder sb = new StringBuilder();
int sum = DoTesting(, , "Hellow", sb);
MessageBox.Show(sb.ToString(), sum.ToString());
VB6.0
导出函数
Public Declare Function DoTesting Lib "CsharpWrap.dll" (ByVal x As Integer, ByVal y As Integer, ByVal testing As String, ByVal error As String) As Integer
调用
Dim error As String
Dim testing As String
Dim x As Integer
Dim y As Integer
Dim sum As Integer testing = "Hello"
error = String(, vbNullChar)
sum = DoTesting(x, y, testing, error)
常见问题及注意事项
- 平台工具集的问题
如果使用的是VS2010以上的版本编译出来的C++/CLI DLL可能会遇到缺少依赖等运行错误。
如果要支持XP系统工具集尽量用_xp结尾的

平台工具集的依赖DLL,把下面的或其它相应版本的依赖DLL放到目标机器的C:\WINDOWS\SYSTEM32下
- msvcp100.dll
- msvcr100.dll
- msvcp110.dll
- msvcr110.dll
- 字符集的问题,因为.Net默认用的字符集是Unicode,但是客户程序有可能是其它字符集,这样也可能会造成字符串在程序间的兼容问题。
可选择Unicode/Multi-Byte,根据不项目需求选择相应的字符集

代码内对不同字符集进行转换
从char* to 宽字符
wchar_t *GetWC(const char *c)
{
const size_t cSize = strlen(c)+;
wchar_t* wc = new wchar_t[cSize];
MultiByteToWideChar(CP_ACP,,(const char *)c,int(cSize),wc,int(cSize));
return wc;
}
String^ to Char*
char* cError = (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();
- 调用的C++/CLI DLL的时候传入参数的问题
C#调用的时候String参数对应的类型应该是StringBuilder,要注意StringBuilder的容量,默认是256个字符,如果返回的比较多的东西要注意初始化相应大小的容量。
- DLL多层嵌套的问题
如果用LoadLibrary加载DLL失败,可以尝试用LoadLibraryEx,同时保证所依赖的C#DLL放到进程EXE同级目录。
LoadLibraryEx("DLL绝对路径", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
转载请注明出处:http://www.cnblogs.com/keitsi/p/5554110.html
非托管C++通过C++/CLI包装调用C# DLL的更多相关文章
- [.net 面向对象程序设计进阶] (8) 托管与非托管
本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托 ...
- .net 资源释放(托管资源和非托管资源)
1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...
- CLR回收非托管资源
一.非托管资源 在<垃圾回收算法之引用计数算法>.<垃圾回收算法之引用跟踪算法>和<垃圾回收算法之引用跟踪算法>这3篇文章中,我们介绍了垃圾回收的一些基本概念和原理 ...
- C#中的托管与非托管
在.net 编程环境中,系统的资源分为托管资源和非托管资源. 字面理解托管,就是托付个别人管理,要的是结果,具体怎么完成的我并不关心,就像某些'牛逼'的老板“我只要结果”那样. 在.NET FRAME ...
- .net非托管资源的回收
释放未托管的资源有两种方法 1.析构函数 2.实现System.IDisposable接口 一.析构函数 构造函数可以指定必须在创建类的实例时进行的某些操作,在垃圾收集器删除对象时,也可以调用析构函数 ...
- 编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源
建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源. 提供给调用者调用 ...
- C#内存管理之托管堆与非托管堆( reprint )
在 .NET Framework 中,内存中的资源(即所有二进制信息的集合)分为“托管资源”和“非托管资源”.托管资源必须接受 .NET Framework 的 CLR (通用语言运行时)的管理(诸如 ...
- 在 C# 中通过 P/Invoke 调用Win32 DLL
在 C# 中通过 P/Invoke 调用Win32 DLL 发布日期 : 1/13/2005 | 更新日期 : 1/13/2005 Jason Clark 下载本文的代码: NET0307.exe ( ...
- C#调用C++ DLL动态库的两种方式
第一种方式:C++导出函数, c#dllimport 的方式 在很多地方都看到过,如[dllimport "user32.dll"]这种代码,调用windows API,就是通过这 ...
随机推荐
- ASP.NET MVC3 系列教程 – Web Pages 1.0
http://www.cnblogs.com/highend/archive/2011/04/14/aspnet_mvc3_web_pages.html I:Web Pages 1.0中以“_”开头的 ...
- unsupported dynamic reloc R_ARM_REL32 AND hidden symbol '__dso_handle' is not defined
项目里编译codec src\makefiles\android\codec\Makefileline 25 原本用 4.6 不会报错-L/data/android/android-ndk/sourc ...
- 利用red5搭建一个简单的流媒体直播系统
http://blog.sina.com.cn/s/blog_51396f890102exmz.html 一.red5安装.设置. 这个过程就不多说了,参见http://blog.csdn.net/l ...
- hdu 1151 Air Raid(二分图最小路径覆盖)
http://acm.hdu.edu.cn/showproblem.php?pid=1151 Air Raid Time Limit: 1000MS Memory Limit: 10000K To ...
- 需要熟记的git命令
需要熟记的github常用命令 总结一下ubuntu下github常用的命令,设置部分跳过,假设repository的名字叫hello-world: .创建一个新的repository: 先在gith ...
- Global.asax.cs介绍
转载 http://www.cnblogs.com/tech-bird/p/3629585.html ASP.NET的配置文件 Global.asax--全局应用程序文件 Web.config--基 ...
- 关于mysql_fetch_****
今天调试如下代码: mysql_select_db('content',$link);//选择数据库 mysql_query("set names utf8");//设置编码格式 ...
- HTML5学习笔记(一):HTML简介
Web前端涵盖的内容较多且杂,主要由3个部分组成:HTML标记语言.CSS样式语言和JavaScript脚本语言组成,而下面我们将先学习最新的标记语言HTML5. <!DOCTYPE>标记 ...
- C#多线程(上) 分类: C# 线程 2015-03-09 10:35 174人阅读 评论(0) 收藏
一.多线程的相关概念 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源. 而一个进程又是由多个线程所组成的. 什么是线程? 线程是程序中的一个执行 ...
- C#自定义控件的开发:Pin和Connector
C#自定义控件的开发:Pin和Connector 2009-08-03 14:46 wonsoft hi.baidu 我要评论(0) 字号:T | T 本文介绍了如何使用智能设备扩展C#自定义控件. ...