为什么我的 C++ 互操作可以在 .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)

这是我的互操作 class :

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 为目标,平台设置为 AnyCPU,一切正常。

我被要求将解决方案降级为目标 Framework 4,幸运的是,在 Interface.dll 中无需修改任何代码,并且与它在 Program.dll 中的使用无关,因此设置变为:

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

从那时起,每次 Inteface.dll 尝试调用 C++ dll 的函数时,我都会收到 BadImageFormatException

我找到了解决方法:如果我将我的调用程序 (Program.exe) 设置为仅针对 x86 CPU,它会再次运行。

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

我只不过是一名高级开发人员,所以我完全不知道这个问题。为什么会这样?是否可以将我的 Program.exe 配置恢复为 AnyCPU ?如果不是,那真的意味着即使在 64 位机器上,我的程序也会 运行 作为 32 位程序吗?

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

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

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

一般来说,如果您的代码依赖于仅以 32 位或 64 位形式存在的 DLL(通常在您进行互操作时就是这种情况),则应避免将 AnyCPU 作为目标。相反,任何具有 32 位依赖项的程序集都应该以 x86 为目标,并且这个特定的目标应该一直沿依赖链向上流动到可执行项目。