项目中要给其它客户程序提供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. ndk文件操作问题及小结

    最近在做文件传输,发现在android下用f系列的C库函数去读取文件文件大小会受到2G大小的约束,查阅了很久,最后只能去看google的libc源码,发现了以下几个问题: 1.bionic的libc是 ...

  2. 杂谈:HTML 5页面可视性API

    译文来源:http://www.ido321.com/1126.html 原文:HTML5 Page Visibility API 译文:HTML 5的页面可视性API 译者:dwqs 在早期,浏览器 ...

  3. bzoj 3884 上帝与集合的正确用法(递归,欧拉函数)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3884 [题意] 求2^2^2… mod p [思路] 设p=2^k * q+(1/0) ...

  4. Spark系列(七)Master中的资源调度

    资源调度 说明: Application的调度算法有两种,分别为spreadOutApps和非spreadOutApps spreadOutApps 在spark-submit脚本中,可以指定要多少个 ...

  5. Hibernate配置文件——hibernate.cfg.xml

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuratio ...

  6. DataSnap与FireDAC三层

    相交资料: http://blog.csdn.net/shuaihj/article/details/6129131http://www.cnblogs.com/hnxxcxg/p/4007876.h ...

  7. Gradle – Spring 4 MVC Hello World Example – Annotation

    In this tutorial, we will take the previous Gradle + Spring MVC XML example, rewrite it to support @ ...

  8. java封装对象转json字符串

    /** * Copyright (c) 2011-2015, James Zhan 詹波 (jfinal@126.com). * * Licensed under the Apache License ...

  9. EasyUI datagrid添加右键菜单项

    js代码 //动态加载数据表格 function InitData() { $('#grid').datagrid({ url: '/Home/Query?r=' + Math.random(), / ...

  10. c# 递归算法

    c# 递归算法 2009-03-13 09:44 6950人阅读 评论(8) 收藏 举报 算法c#funn2c 1)1.1.2.3.5.8.......用递归算法求第30位数的值? 首先我们可以发现从 ...