简体   繁体   中英

Dynamically calling 32-bit or 64-bit DLL from c# application using Environment.Is64BitProcess

I am working on a project written in C# for .NET 4.0 (via Visual Studio 2010). There is a 3rd party tool that requires the use of a C/C++ DLL and there are examples for 32-bit applications and 64-bit applications in C#.

The problem is that the 32-bit demo statically links to the 32-bit DLL and the 64-bit demo statically links to the 64-bit DLL. Being a .NET application it could run as either a 32-bit or 64-bit process on the client PCs.

The .NET 4.0 framework provides the Environment.Is64BitProcess property that returns true if the application is running as a 64-bit process.

What I would like to do is to dynamically load the correct DLL after checking the Is64BitProcess property. However, when I research dynamically loading libraries I always come up with the following:

[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);

[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);

It would appear that these methods are specifically for the 32-bit operating system. Are there 64-bit equivalents?

Would it cause problems to statically link both the 32-bit and 64-bit libraries as long as the appropriate methods are called based on the Is64BitProcess check?

public class key32
{
    [DllImport("KEYDLL32.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

public class key64
{
    [DllImport("KEYDLL64.DLL", CharSet = CharSet.Auto)]
    private static extern uint KFUNC(int arg1, int arg2, int arg3, int arg4);

    public static bool IsValid()
    {
       ... calls KFUNC() ...
    }
}

...

if (Environment.Is64BitProcess)
{
    Key64.IsValid();
}
else
{
    Key32.IsValid();
}

Thank you!!

Lots of ways to do this:

  • this is a deployment problem, just get the right DLL copied by the installer, give them the same name

  • very few programs actually need the massive address space provided by 64-bit code. Just set the Platform target to x86

  • use the EntryPoint field of the [DllImport] attribute. Set it to "KFUNC". And give the methods different names. Now you can call one or the other, based on the value of IntPtr.Size

Demonstrating the last solution:

[DllImport("KEYDLL32.DLL", EntryPoint = "KFUNC")]
private static extern uint KFUNC32(int arg1, int arg2, int arg3, int arg4);

[DllImport("KEYDLL64.DLL", EntryPoint = "KFUNC")]
private static extern uint KFUNC64(int arg1, int arg2, int arg3, int arg4);

...

if (IntPtr.Size == 8) KFUNC64(1, 2, 3, 4);
else                  KFUNC32(1, 2, 3, 4);

Ironically, on a 64-bit system, kernel32.dll (residing in %windir%\\System32\\ ) is the 64-bit version, and the %windir%\\SysWOW64\\ version is the 32-bit system. Extremely unfortunate naming going on here...

Anyway, what you can do is bind to both versions, using the paths as I linked them, to two different variable names (say, LoadLibrary for the system32 version and LoadLibrary32 for the syswow64 version). Then on a 32 bit system you can just use LoadLibrary , and if you detect a 64 bit system, LoadLibrary will be the 64-bit version, while LoadLibrary32 will be the 32-bit version.

I question however that this will help you any since I don't think you can dynamically bind to mismatching bitness (gonna make this the word!) dynamic libraries... Would help your second example I guess, where you actually do get two different libraries, one for each case.

Instead of doing so low level interop I would consider going more .Net route - use plugin-like assemblies to deal with it.

  • create 2 assemblies that link to x86 and x64 versions of the DLL (and compiled for correct platform).
  • Make this assemblies to expose class(es) implementing the same interface (or some other way of making them the same). Make sure the rest of you code can use either of the libraries, may need third assembly with base types/interfaces.
  • At run time load the assembly that you need manually. Make sure that it does not happen to be in search path to avoid loading one automatically by mistake.

Note that your second approach (picking methods based on bitness) should work fine. I would still wrap all access to each DLL in classes with same interfaces and make sure that only correct one can be instantiated at run time.

Keeping the dlls in two different directories and call them dynamically.

Libs64\\ABC.dll
Libs32\\ABC.dll

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM