Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a 32bit or 64bit dll in C# DllImport

Here is the situation, I'm using a C based dll in my dot.net application. There are 2 dlls, one is 32bit called MyDll32.dll and the other is a 64bit version called MyDll64.dll.

There is a static variable holding the DLL file name: string DLL_FILE_NAME.

and it is used in the following way:

[DllImport(DLL_FILE_NAME, CallingConvention=CallingConvention.Cdecl, EntryPoint=Func1")] private static extern int is_Func1(int var1, int var2); 

Simple so far.

As you can imagine, the software is compiled with "Any CPU" turned on.

I also have the following code to determine if the system should use the 64bit file or the 32bit file.

#if WIN64         public const string DLL_FILE_NAME = "MyDll64.dll"; #else         public const string DLL_FILE_NAME = "MyDll32.dll";         #endif 

By now you should see the problem.. DLL_FILE_NAME is defined in compilation time and not in execution time so the right dll isn't loaded according to the execution context.

What would be the correct way to deal with this issue? I do not want two execution files (one for 32bit and the other for 64bit)? How can I set DLL_FILE_NAME before it is used in the DllImport statement?

like image 474
Gilad Avatar asked Jun 01 '12 14:06

Gilad


People also ask

Can we use 32-bit DLL in 64-bit application C#?

On 64-bit Windows, a 64-bit process cannot load a 32-bit dynamic-link library (DLL). Additionally, a 32-bit process cannot load a 64-bit DLL.

Can a 64-bit DLL call a 32-bit DLL?

Solution. You cannot call a 32-bit DLL from 64-bit LabVIEW, or vice versa. This is a limitation of 64-bit Windows, which does not support mixed 64-bit/32-bit processes.

Is it better to run 32-bit on 64-bit?

Simply put, a 64-bit processor is more capable than a 32-bit processor because it can handle more data at once. A 64-bit processor can store more computational values, including memory addresses, which means it can access over 4 billion times the physical memory of a 32-bit processor.


2 Answers

I've found the simplest way to do this is to import the two methods with different names, and calling the right one. The DLL won't be loaded until the call is made so it's fine:

[DllImport("MyDll32.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)] private static extern int Func1_32(int var1, int var2);  [DllImport("MyDll64.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)] private static extern int Func1_64(int var1, int var2);  public static int Func1(int var1, int var2) {     return IntPtr.Size == 8 /* 64bit */ ? Func1_64(var1, var2) : Func1_32(var1, var2); } 

Of course, if you have many imports, this can be become quite cumbersome to maintain manually.

like image 181
Julien Lebosquain Avatar answered Sep 17 '22 15:09

Julien Lebosquain


Here is another alternative that requires that the two DLLs have the same name and are placed in different folders. For instance:

  • win32/MyDll.dll
  • win64/MyDll.dll

The trick is to manually load the DLL with LoadLibrary before the CLR does it. It will then see that a MyDll.dll is already loaded and use it.

This can be done easily in the static constructor of the parent class.

static class MyDll {     static MyDll()     {                     var myPath = new Uri(typeof(MyDll).Assembly.CodeBase).LocalPath;         var myFolder = Path.GetDirectoryName(myPath);          var is64 = IntPtr.Size == 8;         var subfolder = is64 ? "\\win64\\" : "\\win32\\";          LoadLibrary(myFolder + subfolder + "MyDll.dll");     }      [DllImport("kernel32.dll")]     private static extern IntPtr LoadLibrary(string dllToLoad);      [DllImport("MyDll.dll")]     public static extern int MyFunction(int var1, int var2); } 

EDIT 2017/02/01: Use Assembly.CodeBase so that it works even if Shadow Copying is enabled.

like image 32
Benoit Blanchon Avatar answered Sep 18 '22 15:09

Benoit Blanchon