一.string类型不兼容
这个算是最多见也是最初级的问题了,为了方便跨语言接口调用,若是数据量不是特别大的话,咱们能够在封装DLL时选择json串来做为方法的引入参数和返回值,但因为C++的string类型(实际上是STL)内存分配器兼容性很滑稽,基本上跨平台调用就必定会出现异常。因此要避免在动态库接口中传递STL容器。html
解决方案:
比较常规的方法是使用char *进行指针传递,但同时有会存在一个问题,就是返回这个指针以后,调用层还能不能收的到,为了保证这块内存不随着调用方法结束而释放,咱们能够采起全局变量等方法。ios
extern "C"
{
char res[255];
__declspec(dllexport) const char * __stdcall change_str(const char* s)
{
string ss = s;
strcpy_s(res, ("change_str::" + ss).c_str());
return res;
}
}
二.x86和x64引发的内存异常json
解决方案:
修改配置函数
三.__stdcall和__cdecl
__stdcall和__cdecl是两种函数名字修饰。__stdcall和__cdecl函数参数都是从可向左入栈的,而且由调用者完成入栈操做。对于__stdcall方式被调用者自身在函数返回前清空堆栈;而__cdecl则由调用者维护内存堆栈,因此调用者函数生成的汇编代码比前一种方式长。工具
__stdcall方式:_FuncName@sizeofParametersspa
例如:int __stdcall test(int a,double b)编译以后完整的函数名为_test@12.net
__cdecl方式:_FuncName指针
例如:int __stdcall test(int a,double b)编译以后完整的函数名为_testhtm
使用VS进行dll开发若是不加修饰符的话,默认是采起__cdecl的方式,__cdecl虽然约定的函数只能被C/C++调用。但其余语言也是能够调用的,如delphi。可是C#或者VB的默认方式是__stdcall,因此直接不能直接经过 Public Declare Function add Lib的方式调用。不然会报错:blog
调用致使堆栈不对称。缘由多是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。
解决方案:
有人说能够经过[DllImport("Dll.dll")]改成[DllImport("Dll.dll", CallingConvention=CallingConvention.Cdecl)]也就是换成Cdecl方式能够解决
Imports System.Runtime.InteropServices
<DllImport("tset.dll", CallingConvention = CallingConvention.Cdecl)> Private Shared Function add(ByVal a As Integer, ByVal b As Integer) As Integer
End Function
并且DllImport看起来也比Declare要高大上。
https://cloud.tencent.com/info/06698cf1621639b6be6d87fe705a9795.html
可是不知道是否是个人VB版本问题,提示找不到CallingConvention这个属性,很尴尬。
同时,为了提升DLL的扩展性,仍是建议使用_stdcall方式来封装:
extern "C"
{
__declspec(dllexport) int __stdcall add(int a, int b)
{
return a + b;
}
}
四.找不到方法的入口点&C++调用GetProcAddress获取函数指针异常
解决方案:
1.使用工具(例如dependency)查看封装的DLL是否存在相应的接口
2.若是没有的话,封装DLL时能够导入def文件
EXPORTS下面的名与C++接口对应
LIBRARY "Test"
EXPORTS
add @1
change_str @2
print_creater @3
#include "stdafx.h"
extern "C"
{
char res[255];
__declspec(dllexport) int __stdcall add(int a, int b)
{
return a + b;
}
__declspec(dllexport) const char * __stdcall change_str(const char* s)
{
string ss = s;
strcpy_s(res, ("change_str::" + ss).c_str());
return res;
}
__declspec(dllexport) const char * __stdcall print_creater()
{
strcpy_s(res, "nine_sun666");
return res;
}
}
在项目属性中导入模块定义文件便可
VB代码:
Module Module1
Public Declare Function add Lib "test.dll" (ByVal a As Integer, ByVal b As Integer) As Integer
Public Declare Function print_creater Lib "test.dll" () As String
Public Declare Function change_str Lib "test.dll" (ByVal s As String) As String
Sub Main(ByVal args As String())
Console.WriteLine("Hello World!")
Console.WriteLine(add(10, 20))
Console.WriteLine(print_creater())
Console.WriteLine(change_str("6666666"))
End Sub
End Module
调用成功!
五.C++调用约定声明冲突
解决方案:
仍是因为默认的导入修饰符为__cdecl形成的,因此在C++调用层定义类型也要加上__stdcall
pSubtract1 add = pSubtract1(GetProcAddress(hDLL, "add"));
#include "stdafx.h" #include<iostream> using namespace std; int main() { HMODULE hDLL = LoadLibrary(_T("test.dll")); //加载dll文件 if (hDLL != NULL) { typedef int (__stdcall *pSubtract1)(int a, int b); pSubtract1 add = pSubtract1(GetProcAddress(hDLL, "add")); typedef const char * (__stdcall *pSubtract2)(); pSubtract2 print_creater = pSubtract2(GetProcAddress(hDLL, "print_creater")); typedef const char * (__stdcall *pSubtract3)(const char * a); pSubtract3 change_str = pSubtract3(GetProcAddress(hDLL, "change_str")); cout << add(10, 20) << endl; cout << print_creater() << endl; cout << change_str("hello word") << endl; FreeLibrary(hDLL); } else { std::cout << "Cannot Find " << "testdll" << std::endl; } system("pause"); return 0; } --------------------- 做者:九日王朝 来源:CSDN 原文:https://blog.csdn.net/sm9sun/article/details/84986875 版权声明:本文为博主原创文章,转载请附上博文连接!