一.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 版權聲明:本文爲博主原創文章,轉載請附上博文連接!