Search code examples
c#dllwindows-8pinvokeloadlibrary

Resolving native libraries inside WinRT package


Consider the following solution structure: Windows Store C# application + 2 native libraries PInvokeServer and PInvokeServer1. Native libraries code:

// PInvokeServer1
PINVOKESERVER1_API int TestFunction1(void)
{
    return 5;
}

// PInvokeServer
PINVOKESERVER_API int TestFunction(void)
{
    return TestFunction1();
}

Both functions are extern C. PInvokeServer depends on PInvokeServer1 (using linker dependencies). PInvokeServer.dll and PInvokeServer1.dll are added to C# project with build action Content, so they are part of the application package. C# declarations:

    const string dllName = @"Native\PInvokeServer.dll";
    const string dllName1 = @"Native\PInvokeServer1.dll";

    [System.Runtime.InteropServices.DllImport(dllName, CallingConvention = CallingConvention.Cdecl)]
    public static extern int TestFunction();

    [System.Runtime.InteropServices.DllImport(dllName1, CallingConvention = CallingConvention.Cdecl)]
    public static extern int TestFunction1();

Case 1, doesn't work (module not found):

    TestFunction();

Case 2, works:

    TestFunction1();

Case 3, works:

    TestFunction1();
    TestFunction();

Case 1: When PInvoke tries to load PInvokeServer.dll, it cannot resolve native runtime dependency, PInvokeServer1.dll is not loaded, and I get Module not found exception. Placing PInvokeServer1.dll, for example, to System32 directory doesn't help.

Case 2: PInvoke is able to load PInvokeServer1.dll directly.

Case 3. Once PInvokeServer1.dll is loaded, PInvokeServer.dll can be loaded successfully as well.

Im my real program I have native C library depending on several other libraries. All these libraries are added to C# Store application package. But high-level library cannot be loaded, because PInvoke fails to load dependencies. The only way I can think about is to load low-level libraries using LoadLibrary PInvoke call, and finally use PInvoke call to high-level library. Is there better way?


Solution

  • In a desktop application you could use AddDllDirectory or SetDllDirectory to modify the search path. But in a Windows Store application these functions are not available to you. So I see two options:

    1. Put the two DLLs in the same directory as the executable. This is, by some distance, the simplest and safest solution. The executable's directory is always the first location searched and so you can be sure that the right DLLs will be loaded.
    2. Before calling any function in either DLL, call LoadLibrary passing the absolute path to the DLLs to load them into the process. Load PInvokeServer1 before PInvokeServer. Change your p/invoke declarations to specify just the DLL filename. That is, remove the Native directory from the p/invoke declaration. By calling LoadLibrary explicitly, you make sure that the two DLLs are loaded into the process. Then subsequent calls to p/invoke functions will result in the already loaded DLLs being used.