[英]Calling C++ DLL from C++ works, but not from C#
我有一個名為tccdvc.dll的DLL,它是此處提供的SDK的一部分:
該DLL是用C ++編寫的,檢查DLL顯示它已與鏈接器版本6.0鏈接,因此我認為它是用VC ++ 6.0編寫的。 該DLL沒有源代碼,只有.lib文件和.h文件。 所有導出的函數都聲明為extern“ C”(因此,無需C ++名稱修飾)並帶有APIENTRY(因此__stdcall)。
我已經在Windows XP SP3(32位)上的Visual Studio 2010中編寫了一個C ++(不是.NET)程序來訪問此tccdvc.dll。 使用提供的.lib文件和使用LoadLibrary / GetProcAddress時,此方法均能正常工作。 我還編寫了一個使用tccdvc.dll的C ++ DLL(我們將其稱為mywrapper.dll),並且又有兩個版本,一個使用.lib文件,另一個使用LoadLibrary / GetProcAddress。 同樣,這很好。 此mywrapper.dll使用__cdecl調用約定。 它包含一個名為InitMyWrapperDLL()的函數,該函數會加載tccdvc.dll。 使用LoadLibrary / GetProcAddress的mywrapper.dll版本具有如下代碼:
typedef int (APIENTRY *TCCPROCTYPE01)();
HMODULE TCCmodule;
TCCPROCTYPE01 Proc_TCC_DVCOpen;
extern "C" __declspec(dllexport) void InitMyWrapperDLL ()
{ TCCmodule = LoadLibrary("tccdvc.dll");
Proc_TCC_DVCOpen = (TCCPROCTYPE01)GetProcAddress(TCCmodule, "TCC_DVCOpen");
...
}
同樣,使用C ++前端,效果很好。 但是,從C#(在同一台計算機上)調用它時,LoadLibrary(“ tccdvc.dll”)調用返回NULL。 在C#中,我正在使用:
[DllImport("mywrapper.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi, ExactSpelling=true, EntryPoint="InitMyWrapperDLL")]
private static extern void InitMyWrapperDLL ();
...
InitMyWrapperDLL();
使用提供的tccdvc.lib文件編譯mywrapper.dll時,它也會失敗,錯誤代碼為0x8007045a(也稱為1114),表示DLL初始化失敗,並且將mywrapper.dll作為DLL的名稱。 事實證明,失敗的原因是tccdvc.dll,該文件通過mywrapper.dll加載。
在C#中使用以下命令也會失敗:
[DllImport("tcc.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi, ExactSpelling=true, EntryPoint="TCC_DVCOpen")]
private static extern Int32 TCC_DVCOpen ();
...
TCC_DVCOpen();
我在聲明中也使用了“不安全”,但這沒有任何區別。 可預測的,因為LoadLibrary()失敗,所以它甚至都沒有到達TCC_DVCOpen()。
為了查明問題,我再次使用了mywrapper.dll的LoadLibrary / GetProcAddress版本,並將以下代碼放入了我的C#程序中:
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary (string lpLibFileName);
[DllImport("kernel32.dll")]
private static extern Int32 GetLastError ();
...
IntPtr hdll1 = LoadLibrary("mywrapper.dll");
IntPtr hdll2 = LoadLibrary("tccdvc.dll");
Int32 errcode = GetLastError();
此后,hdll1具有有效值,但hdll2為0。使用.NET 3.5 Framework時,GetLastError()再次返回0x8007045a,但是使用.NET 4.0時,GetLastError()返回0(ERROR_SUCCESS)。
我使用Sysinternals的Process Monitor來獲取更多信息,並且可以看到正在成功讀取和映射tccdvc.dll。 在使用C#時,Process Monitor顯示的任何內容都沒有給我任何提示,為什么它失敗了,但是在使用C ++時,卻沒有。
有任何想法嗎? 謝謝!
我為您提供一些建議:
(關於最后一句話:我絕對不是C ++專家,實際上這是我到目前為止所做的唯一項目。這當然值得更多的細節,但是我不知道也沒有知識來找到問題的根源,但是它得到了解決,因為我只需要它 ,感謝您指出任何錯誤/更好的解釋。)
這是適用於我的問題的一些解決方案:
如何使用C#中的C回調? 如果您想查看我所有的代碼,則有指向.DLL的鏈接。
另外,在此領域對我有用的一些工具:
願原力與你同在 :-)
所以,你的C代碼工作從C ++應用程序調用的時候,但是從.NET二進制文件,它在失敗時調用相同的代碼失敗LoadLibrary
...
這只是預感,所以我不確定是否描述您的情況,但是LoadLibrary
具有一些復雜的標准來解析相對DLL名稱的路徑,該標准可能會因某些參數而異。 我不了解所有人。 .NET二進制文件的EXE清單中的某些內容可能阻止它根據這些規則查找DLL。 您可以嘗試調整PATH
環境變量或使用絕對路徑加載DLL。 (您可以使用GetModuleFileName
等來找到您自己的代碼的絕對路徑...)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.