项目中要给其它客户程序提供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 -;
}
}
  • 项目输出和使用

  1. Csharp.dll
  2. 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下

      1. msvcp100.dll
      2. msvcr100.dll
      3. msvcp110.dll
      4. 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的更多相关文章

  1. [.net 面向对象程序设计进阶] (8) 托管与非托管

    本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托 ...

  2. .net 资源释放(托管资源和非托管资源)

    1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...

  3. CLR回收非托管资源

    一.非托管资源 在<垃圾回收算法之引用计数算法>.<垃圾回收算法之引用跟踪算法>和<垃圾回收算法之引用跟踪算法>这3篇文章中,我们介绍了垃圾回收的一些基本概念和原理 ...

  4. C#中的托管与非托管

    在.net 编程环境中,系统的资源分为托管资源和非托管资源. 字面理解托管,就是托付个别人管理,要的是结果,具体怎么完成的我并不关心,就像某些'牛逼'的老板“我只要结果”那样. 在.NET FRAME ...

  5. .net非托管资源的回收

    释放未托管的资源有两种方法 1.析构函数 2.实现System.IDisposable接口 一.析构函数 构造函数可以指定必须在创建类的实例时进行的某些操作,在垃圾收集器删除对象时,也可以调用析构函数 ...

  6. 编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源

    建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源. 提供给调用者调用 ...

  7. C#内存管理之托管堆与非托管堆( reprint )

    在 .NET Framework 中,内存中的资源(即所有二进制信息的集合)分为“托管资源”和“非托管资源”.托管资源必须接受 .NET Framework 的 CLR (通用语言运行时)的管理(诸如 ...

  8. 在 C# 中通过 P/Invoke 调用Win32 DLL

    在 C# 中通过 P/Invoke 调用Win32 DLL 发布日期 : 1/13/2005 | 更新日期 : 1/13/2005 Jason Clark 下载本文的代码: NET0307.exe ( ...

  9. C#调用C++ DLL动态库的两种方式

    第一种方式:C++导出函数, c#dllimport 的方式 在很多地方都看到过,如[dllimport "user32.dll"]这种代码,调用windows API,就是通过这 ...

随机推荐

  1. [Hive - LanguageManual] DML: Load, Insert, Update, Delete

    LanguageManual DML Hive Data Manipulation Language Hive Data Manipulation Language Loading files int ...

  2. HDU-4750 Count The Pairs 最小生成树,并查集

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4750 题意:Q个询问t,求在一个无向图上有多少对点(i,j)满足 i 到 j 的所有路径上的最长边的最 ...

  3. mysql的登录密码带特殊符号登录不进去的问题

    eg : mysqldump -u root -p)P:9 ${dbname} > $dataPath$filename 当我将数据库的数据每天进行自动导出时,需要带上密码,但 ) 是一个特殊符 ...

  4. hadoop streaming 编程

    概况 Hadoop Streaming 是一个工具, 代替编写Java的实现类,而利用可执行程序来完成map-reduce过程.一个最简单的程序 $HADOOP_HOME/bin/hadoop jar ...

  5. Spring SimpleJdbcTemplate Querying examples

    Here are few examples to show how to use SimpleJdbcTemplate query() methods to query or extract data ...

  6. jquery easyui中的dialog拖动超出浏览器问题解决办法

    juqery easyui当鼠标点着拖动超出浏览器后,就回不来了,拉不下的问题: //控制dialog超出浏览器回到原来的地方 var default_left; var default_top;// ...

  7. [HDU 4089]Activation[概率DP]

    题意: 有n个人排队等着在官网上激活游戏.Tomato排在第m个. 对于队列中的第一个人.有以下情况: 1.激活失败,留在队列中等待下一次激活(概率为p1) 2.失去连接,出队列,然后排在队列的最后( ...

  8. Codeforces Round #352 (Div. 2) D. Robin Hood (二分答案)

    题目链接:http://codeforces.com/contest/672/problem/D 有n个人,k个操作,每个人有a[i]个物品,每次操作把最富的人那里拿一个物品给最穷的人,问你最后贫富差 ...

  9. CFileDialog的用法

    CFileDialog 在MSDN中的函数原形 CFileDialog::CFileDialog( BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL, L ...

  10. hibernate和mybatis

    本来是个菜鸟程序员,现在大学还没毕业. 最近一直在想一个问题,到底是hibernate好还是mybatis好.我总觉得 hibernate好用之极,在大学里做过的小项目都是用的hibernate,只要 ...