[英]C# & C++, runtime error when call C++ dll from C#
我為C#編寫了一個C ++包裝器DLL來調用。 DLL已經過測試,並且在我的C ++測試程序中運行良好。
現在與C#集成,我得到了運行時錯誤並崩潰了。 無法使用調試器查看更多詳細信息。
C ++方面只有一個方法:
#ifdef DLLWRAPPERWIN32_EXPORTS
#define DLLWRAPPERWIN32_API __declspec(dllexport)
#else
#define DLLWRAPPERWIN32_API __declspec(dllimport)
#endif
#include "NB_DPSM.h"
extern "C" {
DLLWRAPPERWIN32_API int WriteGenbenchDataWrapper(string fileNameToAnalyze,
string parameterFileName,
string baseNameToSaveData,
string logFileName,
string& message) ;
}
在C#方面,有一個定義,
[DllImport("..\\..\\thirdParty\\cogs\\DLLWrapperWin32.dll")]
public static extern int WriteGenbenchDataWrapper(string fileNameToAnalyze,
string parameterFileName,
string baseNameToSaveData,
string logFileName,
ref string message);
並致電:
string msg = "";
int returnVal = WriteGenbenchDataWrapper(rawDataFileName,
parameterFileName, outputBaseName, logFileName, ref msg);
我想函數的最后一個參數肯定有問題。 string&
C ++中的ref string
應該是C#中的ref string
嗎?
EDIT:
我們真的需要extern "C"
嗎?
EDIT 2:
在我從dll中刪除extern "C
后,我得到了EntryPointNotFoundException。當我使用DLL Export Viewer查看dll時,我發現函數名稱為”int __cdecl WriteGenbenchDataWrapper(class std :: ...“我需要嗎?包括“__cdecl”?
有一堆用PInvoke編組的規則。 供manchaned和unmanaged之間的Marsheling參考
首先關注C#方面。 如果您事先知道消息的合理大小,則可以使用StringBuilder類型並定義該大小,例如。
[DllImport("DLLWrapperWin32.dll")]
public static extern int WriteGenbenchDataWrapper(string fileNameToAnalyze,
string parameterFileName,
string baseNameToSaveData,
string logFileName,
StringBuilder message
int messageLength );
來自姓名消息(和其他帖子)的印象表示您不知道前面的大小,並且您不會將部分消息傳遞給該功能,所以也許
[DllImport("DLLWrapperWin32.dll")]
public static extern int WriteGenbenchDataWrapper(in string fileNameToAnalyze,
in string parameterFileName,
in string baseNameToSaveData,
in string logFileName,
out string message );
現在在C / C ++方面 - 匹配第二個定義
extern "C" // if this is a C++ file to turn off name mangling for this function only
int WriteGenbenchDataWrapper( char * fileNameToAnalyze,
char * parameterFileName,
char * baseNameToSaveData,
char * logFileName,
char ** message ) {
string internalMessage;
SomeFunc( internalMessage ); // these functions won't have extern "C" applied
* message = (char *)::CoTaskMemAlloc(internalMessage.length()+1);
strcpy(* message, internalMessage.c_str());
}
考慮unicode / ansi字符串也很重要,請參考[MarshalAsAttribute(UnmanagedType.LPWSTR)]
對於發布模式,您需要刪除開發路徑設置“.. \\ .. \\ thirdParty \\ cogs”
在您的C ++代碼中:
我總是需要外部的“C”。 如果不這樣做,C ++會破壞函數名稱(需要修改以支持函數重載)。 外部“C”告訴它不要這樣做。
我還將函數聲明為__stdcall。 我相信你可以告訴C#使用哪種類型的調用約定,但我認為__stdcall是默認值。
至於傳遞一個字符串對象,我不確定,我堅持只使用原語進行參數傳遞,所以我會使用const char *並在我的C ++代碼中進行相應的調整。
另外,我盡量避免通過引用傳遞。 相反,如果我需要返回幾個值,我將設置一系列getter來處理這個(const char *作為IntPtr返回)。
在您的C#代碼中:
我使用String作為const char *,int作為int,依此類推。 我相信微軟有一個圖表可以告訴你什么應該分為什么。
處理返回的字符串時,需要將其轉換為ANSI。 這可以通過調用Marshal.PtrToStringAnsi()來完成。
例如:
在我的C ++代碼中:
extern "C" __declspec(dllexport) const char* __stdcall GetCompany(const char *In) {
return MyGetCompany(In); // Calls the real implementation
}
在我的C#代碼中:
[DllImport("TheDLL.dll", EntryPoint = "GetCompany")]
private static extern IntPtr privGetCompany(String In);
// Call this one, not the one above:
public String GetProvince(String In)
{
return Marshal.PtrToStringAnsi(privGetCompany(In));
}
最后要注意的是,如果您在64位計算機上運行,“任何CPU”配置將生成64位C#可執行文件,這將需要64位DLL。 如果您只有32位DLL,則需要添加配置(x86)。
您收到的錯誤消息表明您的C#程序可能正確地找到了DLL和函數,因此名稱修改可能不是問題。 這聽起來像調用約定問題或參數傳遞的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.