DllImport - 尝试加载格式不正确的程序

8
我希望我的C#应用程序能够有条件地运行本地方法。在运行时决定是运行dll的x86版本还是x64版本。 这个问题解释了如何在编译时选择32位或64位,但这并没有帮助。我想在运行时做出决策。
我目前正在执行以下操作:
[SuppressUnmanagedCodeSecurity]
internal static class MiniDumpMethods
{
    [DllImport("dbghelp.dll",
        EntryPoint = "MiniDumpWriteDump",
        CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Unicode,
        ExactSpelling = true,
        SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MiniDumpWriteDump(
        IntPtr hProcess,
        uint processId,
        SafeHandle hFile,
        MINIDUMP_TYPE dumpType,
        IntPtr expParam,
        IntPtr userStreamParam,
        IntPtr callbackParam);

[DllImport("dbghelpx86.dll",
EntryPoint = "MiniDumpWriteDump",
CallingConvention = CallingConvention.StdCall,
CharSet = CharSet.Unicode,
ExactSpelling = true,
SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MiniDumpWriteDumpX86(
        IntPtr hProcess,
        uint processId,
        SafeHandle hFile,
        MINIDUMP_TYPE dumpType,
        IntPtr expParam,
        IntPtr userStreamParam,
        IntPtr callbackParam);
}

但是当我尝试调用x86方法时,出现错误:
Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
   at <exeName>.MiniDumpMethods.MiniDumpWriteDumpX86(IntPtr hProcess, UInt32 processId, SafeHandle hFile, MINIDUMP_TYPE dumpType, IntPtr expParam, IntPtr userStreamParam, IntPtr callbackParam)

有什么办法可以有条件地加载x86或x64版本的dll吗?

(注意:dbghelpx86.dll是我重命名的dbghelp.dll的x86版本)

谢谢


1
一个进程可以是32位或64位。你只能将32位DLL加载到32位进程中,同样的,64位也是如此。 - Jonathon Reinhart
根据什么条件? - LVBen
编译器指令的方法(在链接的答案中)是正确的方法。不需要运行时检查,只需导入所需的即可。 - Baldrick
@JonathonReinhart 真的吗?我认为在技术上应该是可行的,让一个64位进程加载32位DLL。 - Zain Rizvi
@Zain 绝对不行。当任务切换到您的进程时,操作系统会将CPU置于正确的模式下,CPU只能运行适合其所在模式的代码类型。您不能在64位进程下运行32位DLL。 - Jonathon Reinhart
1个回答

13
您的程序将是32位或64位。在64位程序中无法执行32位代码,在32位程序中也无法执行64位代码。如果尝试执行,将会收到运行时异常!因此,您不能拥有一个同时执行x86和x64代码的程序。根据您想要做什么,您有3个选项。
选项1:使用“Any CPU”,然后您的程序可以在32位平台上以32位形式运行,在64位平台上以64位形式运行。在这种情况下,您可以使用以下代码确定使用哪个DLL,并且只需要1个程序集来处理32位和64位平台,它将使用正确的dll:
使用Environment.Is64BitProcess
if (Environment.Is64BitProcess)
{
   //call MiniDumpWriteDump
}
else
{
   //call MiniDumpWriteDumpX86
}

选项2: 如果你想使用“预处理器”条件来实现这一点,那么你需要编译两个不同的程序集。你需要编译一个32位程序集,以在32位平台上运行,并使用32位DLL,而你需要编译一个单独的64位程序集,在64位平台上运行。
选项3: 使用IPC(进程间通信)。你将拥有一个连接到32位程序的64位程序。64位程序可以运行64位DLL函数,但当你需要运行32位DLL函数时,你需要向32位程序发送包含所需信息的消息,然后32位程序可以发送带有任何要返回的信息的响应。

1
好的回答,但请注意它只适用于.NET 4.0及以上框架。 - G-Man
1
这个方法可以运行,但它是一个运行时检查,这意味着你仍然需要导入两个版本。这是不必要的,并且会在应用程序代码中添加选择逻辑,使其变得混乱。更好的方法是让编译器根据标志为您选择正确的版本。 - Baldrick
@Zain,你还没有回答这个问题:“基于什么条件?” - LVBen
@LVBen 我确实这样做了,但是后来有人编辑了问题,只是说“我想在运行时做出决定”,这是一个有效的总结。 这是实际条件:我希望我的二进制文件能够对给定进程进行内存转储。 根据正在转储内存的进程是否为32位或64位,它将选择从x86或x64版本的dbghelp.dll运行MiniDumpWriteDump方法。 - Zain Rizvi
@Jonathon那不是真的! - LVBen
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接