我有一个名为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时都可以正常工作。我还编写了一个C ++ DLL(让我们称之为mywrapper.dll),它使用tccdvc.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正在被成功读取和映射。 Process Monitor显示的内容没有任何提示,说明在使用C#时它失败的原因,而不是在使用C ++时。
有什么想法吗? 谢谢!
答案 0 :(得分:1)
我有几点建议:
(关于最后一句话:我绝不是C ++专家,实际上这是我迄今为止唯一的项目。这当然值得更多细节,但我从来不知道也没有知识找到问题的根源,但它得到修复,因为我只需要它。感谢您指出任何错误/更好的解释。)
以下是适用于我的问题的一些解决方案:
How to use a C callback from C#? 如果你想查看我的所有代码,只有.DLL链接。
此外,还有一些在这个领域对我有帮助的工具:
愿力量与你同在: - )
答案 1 :(得分:0)
因此,从C ++应用程序调用时,您的C代码可以正常工作,但是当从.NET二进制文件调用时,相同的代码会失败,而LoadLibrary
中的代码失败...
这只是一种预感,所以我不确定是否描述了你的情况,但LoadLibrary
有一些复杂的标准来解析相对DLL名称的路径,这可能因某些参数而异。我不知道他们都是我的头脑。可能是.NET二进制文件的EXE清单中的某些内容阻止它根据这些规则查找DLL。您可以尝试调整PATH
环境变量或使用绝对路径加载DLL。 (您可以使用GetModuleFileName
等来查找自己代码的绝对路径...)