从调用C ++工程C ++ DLL,而不是从C#

从调用C ++工程C ++ DLL,而不是从C#

问题描述:

我有一个名为tccdvc.dll DLL是这里提供一个SDK的一部分:

I have a DLL called tccdvc.dll which is part of an SDK available here:

http://www.commell.com.tw/Download/驱动器/工业%20Peripheral /驱动器/ MPX-885 / MPX-885%20SDK 20%(1.2)/SetupCOMMELL%20MPX-885_20100627.rar

DLL是用C ++编写,并检查DLL显示它与连接器6.0版的链接,所以我认为它与VC ++ 6.0编写。该DLL不附带源代码,只有一的.lib文件和.h文件。所有导出函数声明为externC(所以没有C ++名字改编),并与APIENTRY(所以__stdcall)。

The DLL was written in C++ and examining the DLL shows it was linked with linker version 6.0, so I assume it was written with VC++ 6.0. The DLL does not come with source code, only a .lib file and a .h file. All exported functions are declared as extern "C" (so no C++ name mangling) and with APIENTRY (so __stdcall).

我写了一个C ++(而不是.NET)程序在Visual Studio 2010在Windows XP SP3(32位)访问此tccdvc.dll。使用提供的.lib文件,并使用调用LoadLibrary / GetProcAddress的时候既当这工作得很好。我也写一个C ++ DLL(姑且称之为mywrapper.dll),使用tccdvc.dll并再次,在两个版本,一个使用的.lib文件,另一个使用调用LoadLibrary / GetProcAddress的。同样,这工作正常。这mywrapper.dll使用__cdecl调用约定。它包含一个名为InitMyWrapperDLL()函数加载tccdvc.dll。使用调用LoadLibrary / GetProcAddress的该mywrapper.dll的版本有这样的代码:

I have written a C++ (not .NET) program in Visual Studio 2010 on Windows XP SP3 (32-bit) to access this tccdvc.dll. This works fine, both when using the provided .lib file and when using LoadLibrary/GetProcAddress. I have also written a C++ DLL (let's call it mywrapper.dll) that uses tccdvc.dll and, again, in two versions, one using the .lib file, the other using LoadLibrary/GetProcAddress. Again, this works fine. This mywrapper.dll uses the __cdecl calling convention. It contains a function called InitMyWrapperDLL() which loads the tccdvc.dll. The version of mywrapper.dll that uses LoadLibrary/GetProcAddress has code like this:

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#中,我使用的:

Again, using a C++ front-end, this works fine. However, when calling it from C# (on the same machine), the LoadLibrary("tccdvc.dll") call returns NULL. In C#, I am using:

[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加载的

When compiling mywrapper.dll using the provided tccdvc.lib file instead, it fails as well, with error code 0x8007045a (also known as 1114), meaning the DLL initialisation failed, and it gives mywrapper.dll as the name of the DLL. It turns out that the failure is because of tccdvc.dll, which gets loaded through mywrapper.dll.

使用在C#以下的失败,以及:

Using the following in C# fails as well:

[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()。

I have also used "unsafe" in the declaration, but that did not make any difference. Predictable, because LoadLibrary() fails, so it does not even get to TCC_DVCOpen().

要查明问题,我用mywrapper.dll的调用LoadLibrary / GetProcAddress的版本再次,把下面的代码在我的C#程序:

To pinpoint the problem, I used the LoadLibrary/GetProcAddress version of mywrapper.dll again and put the following code in my C# program:

[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框架

After this, hdll1 has a valid value, but hdll2 is 0. When using the .NET 3.5 Framework, GetLastError() returns 0x8007045a again, but when using .NET 4.0, GetLastError() returns 0 (ERROR_SUCCESS).

,GetLastError()返回0x8007045a一遍,但使用.NET 4.0的时候,GetLastError()返回0(ERROR_SUCCESS)。我用进程监视器通过的Sysinternals获得更多的信息和我可以看到tccdvc.dll被读取并绘制成功。没有什么进程监视器显示给我任何暗示,为什么它使用C#时会失败,但使用C时不++。

I used Process Monitor by Sysinternals to get more information and I can see that tccdvc.dll is being read and mapped successfully. Nothing that Process Monitor displays gives me any hint as to why it fails when using C#, but not when using C++.

任何想法?
谢谢

Any ideas? Thanks!

我给你几个建议:


  • 您可以创建一个C ++ / CLI类libary项目,然后在C#项目引用它。

  • 在我的情况下,我发现UnmanagedFunctionPointerAttribute是至关重要的号召,

  • 有一种情况,无论我会做,在调用.DLL从来没有从C#的工作,只有.LIB工作对我来说(这意味着实现我的第一次建议)。故障导致我的'DLL空间并不适合于特定库

(至于最后一句:没有办法,我一个C ++高手,其实那是我没那么远。这当然值得更多细节的唯一项目,但我从来不知道也没有知识,找到问题的根源,但它得到固定的,因为的我只是需要它。>感谢您指出任何错误/更好的解释)

(Regarding last sentence : in no way I am a C++ expert, actually that's the only project I did so far. This certainly deserves more details but I never knew nor had the knowledge to find the source of the problem, but it got fixed because I simply needed it. Thanks for pointing any mistake / better explanations.)

下面是一些适用于我的问题的解决方案:

Here is some of the solution that applied to my problem :

如何使用从C#一个C回调?
,则链接到.DLL,如果你想看到我的代码只问。

How to use a C callback from C#? There is the link to the .DLL, if you want to see all my code just ask.

此外,已帮助我在一些工具此域名:

Also, a few tools that have been helpful to me in this domain :

  • PE Explorer for viewing DLL exports
  • PInvoke Interop Assistant helps in creating PInvoke declarations

愿力量与你同在: - )

May the force be with you :-)