关于c#:为什么我的C ++ interop适用于.Net 4.5但不适用于4

Why does my C++ interop works on .Net 4.5 but not on 4

在我的项目中,我必须使用第三方C++DLL(不COM)。我开发了一个接口C dll,它被我的主程序使用。这是设置:

IDE:vs Express桌面2013 x64

Legacy.dll (C++) Interface.dll (C# .Net4.5 AnyCPU) Program.exe (C#
.Net4.5 AnyCPU)

这是我的interop类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public static class Legacy
{
    // Establish a connection with a protocol channel
    // extern"C" long WINAPI LegacyConnect(unsigned long ProtocolID, unsigned long Flags, unsigned long *pChannelID)
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyConnect(Int32 ProtocolId, Int32 Flags, ref Int32 pChannelId);

    // Terminate a connection with a protocol channel
    // extern"C" long WINAPI LegacyDisconnect(unsigned long ChannelID)
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyDisconnect(Int32 ChannelId);

    // General I/O control functions for reading and writing protocol configuration parameters (e.g. initialization, baud rates, programming voltages, etc.)
    // extern"C" long WINAPI LegacyIoctl(unsigned long ChannelID, unsigned long IoctlID, void *pInput, void *pOutput)
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyIoctl(Int32 ChannelID, Int32 IoctlId, byte[] pInput, Int32 pOutput);
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyIoctl(Int32 ChannelID, Int32 IoctlId, ref SCONFIG_LIST pInput, Int32 pOutput);
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyIoctl(Int32 ChannelID, Int32 IoctlId, ref SCONFIG_HWTYPE_BAUDRATE pInput, Int32 pOutput);
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyIoctl(Int32 ChannelID, Int32 IoctlId, IntPtr pInput, Int32 pOutput);
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyIoctl(Int32 ChannelID, Int32 IoctlId, ref int pInput, Int32 pOutput);

    // Read message(s) from a protocol channel
    // extern"C" long WINAPI LegacyReadMsgs(unsigned long ChannelID, Legacy_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout)
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyReadMsgs(Int32 ChannelID, ref Legacy_MSG pMsg, ref Int32 pNumMsgs, Int32 TimeOut);

    // Write message(s) to a protocol channel
    // extern"C" long WINAPI LegacyWriteMsgs(unsigned long ChannelID, Legacy_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout)
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyWriteMsgs(Int32 ChannelID, ref Legacy_MSG pMsg, ref Int32 pNumMsgs, Int32 TimeOut);
    [DllImport("Legacy.dll")]
    public static extern LegacyErrCodes LegacyWriteMsgs(Int32 ChannelID, IntPtr pMsg, ref Int32 pNumMsgs, Int32 TimeOut);
}

两个.NET项目最初都以框架4.5为目标,将platform设置为anycpu,一切工作正常。

我被要求将解决方案降级到目标框架4,幸运的是,在interface.dll中不需要修改任何代码,也不需要相对于在program.dll中的使用进行任何修改,因此安装程序变为:

Legacy.dll (C++) Interface.dll (C# .Net4 AnyCPU) Program.exe (C# .Net4
AnyCPU)

从那时起,每当我的IngField.dll试图调用C++ DLL的函数时,我就得到了一个BaDimaGrimeExtExchange。

我找到了一种解决方法:如果我将调用程序(program.exe)设置为仅针对x86 CPU,它将再次工作。

Legacy.dll (C++) Interface.dll (C# .Net4 AnyCPU) Program.exe (C# .Net4
x86)

我只是一个高级开发人员,所以我对这个问题完全迷路了。为什么会这样?它是一种将program.exe配置恢复到anycpu的方法吗?如果不是,这是否真的意味着我的程序将以32位的方式运行,即使是在64位的机器上?


BadImageFormatException很可能是由于试图加载具有错误"位"的可执行文件(例如,在64位进程中加载32位dll)造成的。如果Legacy.dll是一个32位的dll(它似乎基于您提供的信息),您应该简单地编译Program.exex86为目标。如果以AnyCPU为目标,那么Program.exe将在64位操作系统上以64位进程执行,如果加载32位dll,则不希望发生这种情况。实际上,在.NET 4.5中,这一点略有更改,因此可执行项目的默认值是使用AnyCPU,但"首选32位"(/platform:anycpu32bitpreferred,这解释了为什么Y只有降级到.NET 4时才会遇到此问题。

does that really mean my program will run as a 32 bits one even on a 64 bits machine ?

是的,您的程序加载一个32位的旧DLL,并且必须在32位进程中执行,即使是在64位操作系统上。只有获得64位版本的旧DLL,程序才能在64位进程中执行。

一般来说,如果您的代码依赖于一个仅以32位或64位形式存在的dll,那么应该避免以AnyCPU为目标,这通常是在执行互操作时发生的。相反,任何表示32位依赖项的程序集都应该以x86为目标,而这个特定的目标应该一直沿着依赖链流向可执行项目。

Project dependencies