Target 32 Bit or 64 Bit native DLL depending on environment

前端 未结 3 1907
一整个雨季
一整个雨季 2020-12-02 00:53

I have a native DLL which comes in both 32 bit and 64 bit versions (x86). I want to create a wrapper which works on both architectures (Any CPU) and loads the correct versio

相关标签:
3条回答
  • 2020-12-02 01:26

    Here is the solution I've used on many projects:

    • name the 32-bit assembly with a "32-bit oriented name". For example MyAssembly.Native.x86.dll
    • name the 64-bit assembly with a "64-bit oriented name". For example MyAssembly.Native.x64.dll
    • compile the managed assembly as 'Any Cpu'
    • ship everything in the same path

    Here is how I declare P/Invoke methods:

    [DllImport("MyAssembly.Native.x86.dll", EntryPoint = "MyTest")]
    private static extern void MyTest86(MyType myArg);
    
    [DllImport("MyAssembly.Native.x64.dll", EntryPoint = "MyTest")]
    private static extern void MyTest64(MyType myArg);
    

    And here is the corresponding 'MyTest' function which is the one I'll always use (the others are here just for correct bitness binding). It has the same signature than the other P/Invoke ones:

    public static void MyTest(MyType myArg)
    {
        if (IntPtr.Size == 8)
        {
            MyTest64(myArg);
            return;
        }
    
        MyTest86(myArg);
    }
    

    The advantages are:

    • you can ship all binaries (DLLs, EXEs, ...) in the same path
    • you support 32-bit and 64-bit processes and OSes with the same file layout
    • you don't have to resort to Win32 apis for changing dll load path

    The inconveniences are:

    • you'll have 3 method declarations for 1 'real' method
    • you'll loose some CPU cycles because of the bitness test
    • depending on your context, sometimes you can't change the native DLLs names, so you just can't do this
    0 讨论(0)
  • 2020-12-02 01:29

    Take a look at the Microsoft.WinAny.Helper and It'a DynamicNativeLibrary class which can help you with what you need.

    0 讨论(0)
  • 2020-12-02 01:40

    The way I do it is to p/invoke a call to LoadLibrary before calling any of the p/invokes to the library.

    • Use the bitness of the executing assembly to work out which version of the unmanaged DLL to load.
    • Then call LoadLibrary to load it passing the full path to the DLL.
    • Then when you call the p/invokes, the correct DLL is already loaded into the process and the p/invokes bind to it.

    This relies on the unmanaged DLL having the same name for both 32 and 64 bit. If that's not the case then you are in trouble. In that scenario you may need to bind explicitly to the DLL by p/invoking GetProcAddress. This is no fun at all. Or you implement the sort of scaffolding that Simon describes in his answer.

    0 讨论(0)
提交回复
热议问题