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

时间:2015-03-05 08:09:49

标签: c# .net windows dll interop

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

IDE:VS Express Desktop 2013 x64

  

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

这是我的互操作班:

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项目最初都以框架形式定位到AnyCPU的框架4.5,一切正常。

我被要求将解决方案降级到目标框架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   86)

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

1 个答案:

答案 0 :(得分:4)

BadImageFormatException很可能是因为尝试加载具有错误" bitness"的可执行文件而导致的。 (例如,在64位进程中加载​​32位DLL)。如果Legacy.dll是32位DLL(它似乎基于您提供的信息),您应该简单地编译Program.exe目标x86。如果您定位AnyCPU,则Program.exe将在64位操作系统上以64位进程执行,如果您要加载32位DLL,则不希望发生这种情况。实际上,在.NET 4.5中,这稍微改变了,因此可执行项目的默认值是使用AnyCPU但是对于#34;更喜欢32位" (/platform:anycpu32bitpreferred)解释了为什么在降级到.NET 4时只遇到问题。

  

这是否真的意味着我的程序即使在64位机器上也会以32位运行?

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

一般情况下,如果您的代码依赖于仅存在32位或64位的DLL,则应避免定位AnyCPU,这通常是您进行互操作时的情况。相反,任何具有32位依赖关系的程序集都应该以{{1​​}}为目标,并且此特定目标应该从依赖关系链一直流向可执行项目。

Project dependencies