8

I want my C# application to conditionally run a native method. Deciding at run time whether to run either the x86 or the x64 version of the dll.

This question explains how to choose 32 bit or 64 bit at compile time, but that does not help. I want to make the decision at runtime.

I'm currently doing the following:

[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);
}

But when I try to call the x86 method I get the error:

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)

Any idea how I can conditionally load either the x86 or the x64 version of the dll?

(Note: dbghelpx86.dll is the x86 version of dbghelp.dll that I renamed)

Thanks

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Zain Rizvi
  • 23,586
  • 22
  • 91
  • 133
  • 1
    A process is either 32-bit or 64-bit. You can only load 32-bit DLLs into a 32-bit process, and likewise for 64-bit. – Jonathon Reinhart Jun 19 '14 at 02:07
  • Based on what condition? – LVBen Jun 19 '14 at 02:13
  • The approach of compiler directives (in the linked answer) is the way to go. No runtime checks needed, only import the one you need. – Baldrick Jun 19 '14 at 02:16
  • @JonathonReinhart Really? I would have thought it should be technically doable to have a 64 bit process load a 32 bit DLL – Zain Rizvi Jun 19 '14 at 18:52
  • @Zain Absolutely not. The OS puts the CPU in the correct mode when task-switching to your process, and the CPU can only run the type of code appropriate for the mode it is in. You cannot run a 32-bit DLL under a 64-bit process. – Jonathon Reinhart Jun 19 '14 at 21:04

1 Answers1

13

Your program will be either 32-bit or 64-bit. It is not possible to execute 32-bit code in an 64-bit program, and it is not possible to execute 64-bit code in a 32-bit program. You will get a run-time exception if you try! Thus, you cannot have 1 program which executes both x86 and x64 code. You have 3 options depending on what you would like to do.

Option 1: (Original answer)

Use "Any CPU", and then your program can run as 32-bit on a 32-bit platform and 64-bit on a 64-bit platform. In that case, you can use this code to determine which DLL to use and you would only need 1 assembly to be able to handle both 32-bit and 64-bit platforms and it will use the correct dll:

use Environment.Is64BitProcess

if (Environment.Is64BitProcess)
{
   //call MiniDumpWriteDump
}
else
{
   //call MiniDumpWriteDumpX86
}

Option 2:

If you want to use "preprocessor" conditions to do this, then you would compile 2 different assemblies. You would compile a 32-bit assembly to be run on 32-bit platforms which uses the 32-bit DLL, and you would compile a separate 64-bit assembly to run in 64-bit platforms.

Option 3:

Use IPC(Inter-process-communications). You would have 1 64-bit program which "connects" to a 32-bit program. The 64-bit program can run the 64-bit DLL function, but when you need to run the 32-bit DLL function, you would have to send a message to the 32-bit program with the information needed to run it, and then the 32-bit program could send a response with any information that you want back.

LVBen
  • 2,041
  • 13
  • 27
  • 1
    Good answer however please note that it would only work with the .NET 4.0 and up framework – G-Man Jun 19 '14 at 02:13
  • 1
    This will work, but it is a runtime check, which means you still have to import both versions. This is unnecessary, and clutters up your application code with selection logic. Much better to let the compiler choose the right one for you based on a flag. – Baldrick Jun 19 '14 at 02:24
  • This won't work, because you will still be trying to import the incorrect DLL (as you have to import both), which will fail. – Jonathon Reinhart Jun 19 '14 at 21:05
  • Thanks but that's not what my question was about. I've updated the question accordingly – Zain Rizvi Jun 19 '14 at 21:53
  • @Zain, You still haven't answered the question: "Based on what condition?" – LVBen Jun 20 '14 at 05:47
  • @LVBen I did but someone edited the question later to just say "I want to make the decision at runtime" which is a valid summation. Here's the actual condition: I want my binary to take a memory dump of a given process. Based on whether or not the process it's taking a memory dump of is 32 or 64 bit it'll choose to run the MiniDumpwriteDump method from the x86 or x64 version of dbghelp.dll. – Zain Rizvi Jun 20 '14 at 18:01
  • @Jonathon That is not true! – LVBen Jun 21 '14 at 04:36
  • @Baldrick That depends on the purpose. IMO, it is better to have 1 program (with the "Any CPU" option enabled) than to have a 32-bit program and a 64-bit program. – LVBen Jun 21 '14 at 04:38
  • @LVBen Elaborate? How do you conditionally load the DLL at runtime? – Jonathon Reinhart Jun 21 '14 at 05:10
  • @Jonathon You said the code won't work, but it does work! There is no failure. – LVBen Jun 21 '14 at 05:41
  • Perhaps the LoadLibrary call that happens under the hood takes place on the first call to that DLL. I'm not sure where that behavior is defined. – Jonathon Reinhart Jun 21 '14 at 14:43