为什么我的 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
为目标,并且这个特定的目标应该一直沿依赖链向上流动到可执行项目。