dotnet/runtime

DllImport does not find DLL without specifying the .dll extension

ektrah opened this issue · 6 comments

I've created a nupkg with the following contents:

└── runtimes
    ├── fedora.23-x64
    │   └── native
    │       └── runtime.native.MyNativeLibrary.so
    ├── ubuntu.16.04-x64
    │   └── native
    │       └── runtime.native.MyNativeLibrary.so
    └── win10-x64
        └── native
            └── runtime.native.MyNativeLibrary.dll

I'm p/invoking into the native library as follows:

[DllImport("runtime.native.MyNativeLibrary")]
internal static extern void my_native_function();

The DllImport argument does not include the file extension (".dll"/".so") of the native library, because the C# code is the same for all platforms.

Results:

  • Fedora 23, dotnet version 1.0.0-preview4-004233, works ✓
  • Ubuntu 16.04, dotnet version 1.0.0-preview4-004233, works ✓
  • Windows 10, dotnet version 1.0.0-preview4-004233, DllNotFoundException
  • Windows 10, dotnet version 1.0.0-preview5-004478, DllNotFoundException

Observations:

  • If the DllImport argument is changed to "runtime.native.MyNativeLibrary.dll", then it works on Windows but not on Linux.
  • If the name of the native library is changed to "libmynative.dll"/"libmynative.so" and the DllImport argument is changed to "libmynative", then it works on all platforms.

So there seems to be a bug on Windows if the DllImport argument does not include the extension but does include a dot.

@ektrah This seems to be an artifact of Windows LoadLibraryExW API which CLR use to load the native library. It looks like having dot in filename trick LoadLibraryExW to not append dll to filename.
Did you try renaming the "runtime.native.MyNativeLibrary.dll" to "runtime.native.MyNativeLibrary" ie drop the "dll" extension , i tried it and it seems to work.

@ektrah , something like below

── runtimes
├── fedora.23-x64
│ └── native
│ └── runtime.native.MyNativeLibrary.so
├── ubuntu.16.04-x64
│ └── native
│ └── runtime.native.MyNativeLibrary.so
└── win10-x64
└── native
└── runtime.native.MyNativeLibrary

@tijoytom No, I didn't try that. Since "libmynative.dll"/"libmynative.so" works on all platforms, I went with that. If dropping the ".dll" part from the filename works, it looks like that is another viable workaround.

I guess fixing LoadLibraryExW is non-trivial. Maybe a result of this issue could be some addition to the documentation?

@ektrah Yes fixing LoadLibraryExW is not trivial , the MSDN documentation does mention about "dot" in file name , but it's inaccurate in saying

"If the string specifies a module name without a path and the file name extension is omitted, the function appends the default library extension .dll to the module name. To prevent the function from appending .dll to the module name, include a trailing point character (.) in the module name string."

I am going to close this bug since there is not much we can do now.

Regardless of how LoadLibraryExW behaves, is this how we want DllImport to work? It seems weird and arbitrary to me that this doesn't work if your library has a period in its name, but does otherwise.

We can try to re-load with a ".dll" appended to the filename and it will succeeded . But then there are compact issues especially with Desktop. Moreover there might be security concerns around loading a file which the used did not explicitly mention ( ie for "Foo.Bar" we try "Foo.Bar.dll" . Given there are more than one viable work-around i am tempted not to fix this.