标签:
项目中要给其它客户程序提供DLL做为接口,该项目是在.Net4.0平台下开发。终所周知.Net的各个版本之间存在着兼容性的问题,但是为了使用高版本运行平台的新特性,又不得不兼顾其它低版本平台客户程序的调用。为了解决这个问题尝试通过一个C++/CLI DLL对高版本的.Net DLL的接口加了一层包装,对外暴露C风格的接口给客户程序调用。
可支持的客户语言平台:
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; } } }
// CsharpWrap.h #pragma once #include <windows.h> #include <string> using namespace System; using namespace Csharp; using namespace std; using namespace Runtime::InteropServices;
// 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) + 1); } else { error = nullptr; } return sum; } catch(exception e) { memcpy(error,e.what(),strlen(e.what()) + 1); return -1; } }
如果要调用CsharpWrap.dll必须保证Csharp.dll也被调用程序可见(即应该放在进程EXE文件同一目录下)
HINSTANCE hInst= LoadLibrary(_T("CsharpWrap.dll")); if(hInst) { pfunc DoTesting = (pfunc)GetProcAddress(hInst,"DoTesting"); if(DoTesting) { char error[100]= {NULL}; int sum = DoTesting(1, 2, "Hello", error); //show testing results char strSum[8]; _itoa_s(sum,strSum,16); ::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); }
导出函数
[DllImport("CsharpWrap.dll")]
static extern int DoTesting(int x, int y, string testing, StringBuilder error);
调用
StringBuilder sb = new StringBuilder(200); int sum = DoTesting(1, 2, "Hellow", sb); MessageBox.Show(sb.ToString(), sum.ToString());
导出函数
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(60000, vbNullChar) sum = DoTesting(x, y, testing, error)
如果使用的是VS2010以上的版本编译出来的C++/CLI DLL可能会遇到缺少依赖等运行错误。
可选择Unicode/Multi-Byte,根据不项目需求选择相应的字符集
代码内对不同字符集进行转换
从char* to 宽字符
wchar_t *GetWC(const char *c) { const size_t cSize = strlen(c)+1; wchar_t* wc = new wchar_t[cSize]; MultiByteToWideChar(CP_ACP,0,(const char *)c,int(cSize),wc,int(cSize)); return wc; }
String^ to Char*
char* cError = (char*)(Marshal::StringToHGlobalAnsi(strError)).ToPointer();
C#调用的时候String参数对应的类型应该是StringBuilder,要注意StringBuilder的容量,默认是256个字符,如果返回的比较多的东西要注意初始化相应大小的容量。
如果用LoadLibrary加载DLL失败,可以尝试用LoadLibraryEx,同时保证所依赖的C#DLL放到进程EXE同级目录。
LoadLibraryEx("DLL绝对路径", NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
标签:
原文地址:http://www.cnblogs.com/keitsi/p/5554110.html