非托管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,就是通过这 ...
随机推荐
- C语言中 v...printf类函数的用法
C语言的自学渐渐接近尾声,今天学到了标准库中的stdarg.h头,里面关联了stdio.h头里面的一类函数:v...printf函数,里面举的例子看了之后还是不太明白,google了一下依旧不是很懂, ...
- android sensor传感器系统架构初探
http://blog.csdn.net/qianjin0703/article/details/5942579 http://blog.chinaunix.net/uid-28621021-id-3 ...
- 连分数(分数类模板) uva6875
//连分数(分数类模板) uva6875 // 题意:告诉你连分数的定义.求连分数,并逆向表示出来 // 思路:直接上分数类模板.要注意ai可以小于0 #include <iostream> ...
- 内核源码分析之tasklet(基于3.16-rc4)
tasklet是在HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断的基础上实现的(它们是在同一个源文件中实现,由此可见它们的关系密切程度),它的数据结构和软中断比较相似,这篇博文将分析t ...
- Java 从单核到多核的多线程(并发)
JAVA 并发编程 最初计算机是单任务的,然后发展到多任务,接着出现多线程并行,同时计算机也从单cpu进入到多cpu.如下图: 多任务:其实就是利用操作系统时间片轮转使用的原理.操作系统通 ...
- poj 3268 Silver Cow Party(最短路)
Silver Cow Party Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 17017 Accepted: 7767 ...
- CentOS_6.5 64位系统,安装git服务器+客户端
================ git服务器安装 ==================== CentOS安装Git服务器 Centos 6.4 + Git 1.8.2.2 + gitosis## . ...
- Rop 文件上传解决思路
由于服务请求报文是一个文本,无法直接传送二进制的文件内容,因此必须采用某种转换机制将二进制的文件内容转换为字符串.Rop 采用如下的方式对上传文件进行编码:<fileType>@<B ...
- 转载 JQuery中attr属性和JQuery.data()学习
转载原地址: http://www.cnblogs.com/yeminglong/p/5405745.html 用html直接data-key来存放,key必须全部小写. <div data-m ...
- ActiveMQ学习笔记(一) JMS概要
(一)什么是JMS jms即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送 ...