调用C++;来自C++;工作,但不是从C#

调用C++;来自C++;工作,但不是从C#,c#,c++,dll,loadlibrary,C#,C++,Dll,Loadlibrary,我有一个名为tccdvc.DLL的DLL,它是SDK的一部分,可在此处使用: DLL用C++编写,检查DLL显示它与链接器版本6链接,所以假设它是用VC++ 6编写的。DLL没有源代码,只有一个.lib文件和一个.h文件。所有导出函数都被声明为“外部”C(因此没有C++名称的修饰),并用ApItEnter(So.AyStdCalk)。< /P> 我在Visual Studio 2010上在WindowsXP SP3(32位)上编写了一个C++(不.NET)程序来访问这个TCCDVC.DLL。

我有一个名为tccdvc.DLL的DLL,它是SDK的一部分,可在此处使用:

DLL用C++编写,检查DLL显示它与链接器版本6链接,所以假设它是用VC++ 6编写的。DLL没有源代码,只有一个.lib文件和一个.h文件。所有导出函数都被声明为“外部”C(因此没有C++名称的修饰),并用ApItEnter(So.AyStdCalk)。< /P> 我在Visual Studio 2010上在WindowsXP SP3(32位)上编写了一个C++(不.NET)程序来访问这个TCCDVC.DLL。无论是在使用提供的.lib文件还是在使用LoadLibrary/GetProcAddress时,这都可以正常工作。我还编写了一个C++ DLL(我们称之为MyWrasPr.dll),它使用TCCDVC.DLL,并且,在两个版本中,一个使用.LIB文件,另一个使用LooalStudio/GeCopTeLoad。同样,这很好用。此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#程序中添加了以下代码:

在此之后,hdll1具有有效值,但hdll2为0。使用.NET 3.5 Framework时,GetLastError()再次返回0x8007045a,但使用.NET 4.0时,GetLastError()返回0(错误\成功)

我通过Sysinternals使用processmonitor来获取更多信息,我可以看到tccdvc.dll正在被成功读取和映射。进程监视器显示的任何内容都没有提示为什么使用C语言时失败,而不是使用C++时。 有什么想法吗?
谢谢

我有几点建议给你:

  • 您可以创建一个C++/CLI类库项目,然后在C#项目中引用它
  • 在我的例子中,我发现UnmanagedFunctionPointerAttribute对调用至关重要
  • 有一种情况是,无论我做什么,对.DLL的调用从C#开始就不起作用,只有.LIB对我起作用(这意味着实现我的第一个建议)。故障排除使我发现“DLL空间”不适合该特定库

(关于最后一句话:我决不是一个C++专家,实际上这是我迄今为止所做的唯一一个项目。这当然值得更多的细节,但我从来不知道也没有知识来找到问题的根源,但它被固定了,因为我只需要它。谢谢指点任何错误/更好的解释。)< 以下是适用于我的问题的一些解决方案:

有一个指向.DLL的链接,如果你想查看我的所有代码,请询问

此外,还有一些在这一领域对我很有帮助的工具:

  • 用于查看DLL导出
  • 帮助创建PInvoke声明

< P> >强制与你在一起:-(<)/P>< P> >,C代码在C++应用程序调用时起作用,但当从.NET二进制调用时,相同代码失败,在<代码> LoadLibrary < /COD>…< /P>中失败。
这只是一种预感,所以我不确定是否描述了您的情况,但是
LoadLibrary
有一些复杂的标准来解析相对DLL名称的路径,这些路径可能会根据某些参数而变化。我并不是一下子就认识所有的人。可能是.NET二进制文件的EXE清单中的某些内容阻止它根据这些规则查找DLL。您可以尝试调整
PATH
环境变量,或使用绝对路径加载DLL。(您可以使用
GetModuleFileName
等来查找您自己代码的绝对路径…

tccdvc.dll是否有任何其他依赖项可通过Dependes查看?考虑到.net appUsing Dependency Walker可能找不到这些依赖项,它显示了5个直接依赖项:kernel32.dll、user32.dll、advapi32.dll、ole32.dll、oleaut32.dll,它们都存在于系统中。许多级别嵌套在advapi32.dll中,这表明延迟加载依赖项ieshims.dll和wer.dll不存在。但是,根据Process Monitor,它从不尝试加载这些。加载期间,
tccdvc.dll
是否会产生任何额外的线程?如果您没有该dll的源代码,则需要与供应商联系以获得支持。P/调用GetLastError不可靠。你需要使用。
[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();