7

I have to use a C++ DLL file from an ASP.NET site. The site will be hosted on both 32 and 64 bits environments.

I have a 32 and 64 bits version of the unmanaged DLL file. How do I import the methods from the correct one according the current server architecture?

Like someone posted, this could be handled as a deployment problem. My concern is: the web application consuming this DLL file is huge, and we don't have a deployment document. No one will remember to deploy the correct DLL file, so I'm trying to remove the human factor from the solution :)

Cœur
  • 37,241
  • 25
  • 195
  • 267
StackOverflower
  • 5,463
  • 13
  • 58
  • 89
  • Are you attempting to debug it? What are you importing the symbols into or for? – linuxuser27 Sep 03 '10 at 19:04
  • @linuxuser27: Not sure if I understand your question. I'm trying to USE the dll on my project, call some methods. – StackOverflower Sep 03 '10 at 19:07
  • I see. When you said symbols, that most often refers to the resulting PDB file that is created during compilation. I would edit your question to avoid that confusion. Are you doing a p\invoke in your .NET code to use the assembly or are you using a Managed C++ wrapper to bring the assembly into the .NET project? – linuxuser27 Sep 03 '10 at 19:12
  • @linuxuser27: I changed "symbols" by "methods". Thanks for the suggestion! I'm using [DllImport("unmanaged.dll")]. – StackOverflower Sep 03 '10 at 19:16
  • If they have different names, the answer is: painfully, you would have to use LoadLibrary and get the proc pointers and marshal them to delegates. Edit: I would just compile 2 versions... – leppie Sep 03 '10 at 19:19
  • @leppie: 2 versions of the site that will use the dll?? – StackOverflower Sep 03 '10 at 19:25
  • This is a deployment issue. Handling it in code is very painful. – Hans Passant Sep 03 '10 at 20:38

3 Answers3

5

Simplest approach would be to give the two native libraries the same filename in two different directories, then adjust your application DLL search path depending on the bitness.

http://www.pinvoke.net/default.aspx/kernel32.setdlldirectory

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    How do you arrange your assemblies so as to call this Kernal function to extend the dll search path before the loading of the assembly that needs the extended search path? – Greg Domjan Sep 03 '10 at 21:28
  • P/invoke doesn't cause the native libraries to be listed in the import table where the OS loader will look for them at startup. Instead, it internally calls `LoadLibrary` the first time any method marked `[DllImport]` with that particular library name is called. So putting the call to `SetDllDirectory` in the type initializer (a/k/a class constructor a/k/a static constructor) of the class where the imported methods are declared guarantees it will happen before p/invoke tries to load the DLL. – Ben Voigt Sep 03 '10 at 21:45
  • Some other useful information here: http://www.codeproject.com/Messages/1199816/Re-Yuck.aspx – Ben Voigt Sep 03 '10 at 21:57
1

To get the compiler/framework to do most of the work you need to

  1. have multiple build 'platforms' (typically x86, x64 - remove AnyCPU)
  2. set each "platform target" configuration for each build config
  3. we added conditional compilation symbols __WIN32 & __X64

List the different implementations for your functions according to platform, including different dll names if you need to have both installed at once.

#if __WIN32
        public delegate int Move(int target);
        [DllImport("my.dll", SetLastError = true, CharSet = CharSet.Auto)]
#elif __X64
        public delegate int Move(int target);
        [DllImport("my64.dll", SetLastError = true, CharSet = CharSet.Auto)]
#endif

Otherwise you can use loadlib and manage the marshalling yourself.

Greg Domjan
  • 13,943
  • 6
  • 43
  • 59
  • 2
    You definitely don't need to marshal yourself. – Ben Voigt Sep 03 '10 at 20:27
  • 1
    Now you don't just have two unmanaged DLLs, you've also got two different assemblies. Double the problem. – Hans Passant Sep 03 '10 at 20:40
  • Sure, I don't like it much either, but it has been the common advice I've found so far that you should make the assmebly processor specific, including on MSDN/forums. – Greg Domjan Sep 03 '10 at 21:27
  • 1
    Could you post the MSDN forum link? Still a moderator there, I might be able to delete that. – Hans Passant Sep 03 '10 at 21:50
  • MSDN forums recommend `SetDllDirectory` here, with `LoadLibrary` as an alternative solution that works on older Windows versions: http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/46535653-46e1-4412-a436-b818abfe4b07 – Ben Voigt Sep 03 '10 at 22:02
  • @Hans: My comment is a reply to Greg, not a request for you to delete. That thread looks like it has good information. – Ben Voigt Sep 03 '10 at 22:03
  • Agreed, makes it a deployment detail instead of a programming problem. The comment I already made in the OP. Infinitely better than what was proposed in this answer. Managing the right SetDllDirectory call when you don't actually control the process initialization is a problem that is deferrable. – Hans Passant Sep 03 '10 at 22:17
  • @Hans: if I can find it again, lost in the depths of browser history. – Greg Domjan Sep 03 '10 at 22:18
1

As we know that we cannot add unmanaged DLL files using add reference. So we need an alternative way to handle unmanaged DLLS files according to CPU architecture that is add DLL files in your project directories.

  1. Create new folders into your project named x32 and x64.
  2. Copy your DLL files into these folders according to architecture.
  3. Select the files and open properties, Change "Copy to output directory: Copy always"
  4. Repeat this on all files in both folders

Now build your project in any platform when you will build the project both x86 and x64 folder will be copyed in bin folder. When this will run on server it will use unmanaged DLL files according to CPU architecture.

habib
  • 2,366
  • 5
  • 25
  • 41