Reputation: 16502
I have a dll that comes in both 32bit and 64bit version. My .NET WinForm is configured for "Any CPU" and my boss will not let us have separate installs for the different OS versions. So I am wondering: if I package both dlls in the install, then is there a way to have the WinForm determine if its 64bit/32bit and load the proper dll.
I found this article for determining version. But i am not sure how to inject the proper way to define the DLLImport attribute on the methods i wish to use. Any ideas?
Upvotes: 9
Views: 7092
Reputation: 941465
You could take advantage of the SetDllDirectory API function, it alters the search path for unmanaged assemblies. Store your 32-bit DLLs in the x86 subdirectory of the app install directory, the 64-bit DLLs in the x64 subdirectory.
Run this code at app startup before you do any P/Invoke:
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
...
public static void SetUnmanagedDllDirectory() {
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, IntPtr.Size == 8 ? "x64 " : "x86");
if (!SetDllDirectory(path)) throw new System.ComponentModel.Win32Exception();
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
Upvotes: 15
Reputation: 11638
...or you can use Marshal.GetDelegateForFunctionPointer()
to do dynamic P/Invoke.
...or call LoadLibrary()
with a fully qualified path before the CLR tries to load it for you.
Upvotes: 2
Reputation: 564413
My solution is to create a single abstract class, with a concrete version which loads and wraps my 32bit DLL, and a separate implementation that loads and wraps the 64bit DLL. A single factory method in the base class can be used to instantiate the appropriate implementation based on the IntPtr.Size
.
The nice thing about this approach is that the rest of your code is completely isolated from the platform - it just constructs an object using your base class factory method, and works with it. It is also very easy to call into multiple methods within the DLLs in question, in a uniform manner, and all of your "native" code can easily be pushed into a private implementation.
Upvotes: 3
Reputation: 887443
You should make two different private extern
methods, and make an internal method that checks IntPtr.Size
and calls the correct version.
Upvotes: 3
Reputation: 27107
Can you import them both and make the decision about which one to call via .NET instead?
For example:
[DllImport("32bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe32 (IntPtr hWnd, String text, String caption, uint type);
[DllImport("64bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe64 (IntPtr hWnd, String text, String caption, uint type);
Upvotes: 6