views:

46

answers:

3

I am using an unmanaged library in a .net application which is used on x86 and 64bit systems alike and therefore is compiled as 'Any CPU'. The unmanaged, native .dll however comes in two different .dlls for that (one for win32 and one for x64).

Is there any way to still keep the 'Any CPU' / one binary way with different native .dlls regarding the P/Invoke signatures for x86 & 64bit systems? Or -is- the only way to create separate configs & therefore distributions? If so, are there any compile #if/#endif flags I can use for that?

A: 

I would put the p/invoke code into a seperate assemblies (one for 32 and one for 64 bits) and then load the appropriate one at run time depending upon the platform.

There are many ways to determine the type of the system. Lots are documented here.

Preet Sangha
Thanks...! I'll go with this one - I have proper extensibility via MEF on my todo-list anyway (and I am bummed that I haven't thought about this before asking.. oh my). So I'll use MEF and I'll have to handle BadImageFormatExceptions there anyway in case strictly x86 or x64 extension-assemblies are loaded on an 'opposite' system.
Jörg B.
A: 

You can manually call LoadLbrary & GetProcAddress, convert function pointers to delegates by calling Marshal.GetDelegateForFunctionPointer(procAddress, delegateType). This results in more code but lets you keep all interop code in a single assembly. This approach is used by NHanspell for example.

max
+1  A: 

In your bin folder, you could add an additional two folders named x86 and x64. These folder will contain the x64 and x86 images of your native DLL.
On startup (before your application loads any external DLLs), you could modify your process's PATH environment variable so it will include the appropriate sub-directory according to the process's bitness (IntPtr.Size should indicate your bitness).

For managed DLL probing, you could subscribe to the AppDomain.AssemblyResolve event, so you could load the assembly from the correct sub-directory by yourself (e.g. by using Assembly.Load).

Liran
+1, modifying PATH is an interesting approach but it is rather important that it is done only once and by the starting EXE. Pinvoking SetDllDirectory() is another way, but that can have a (rare) failure mode too if the unmanaged code also uses it. Making this a deployment task or just forcing the platform target is all around the less riskier solution.
Hans Passant