Native library dependencies - how to debug
Suppose you have a managed library Foo.dll
, which P/Invokes DllImport(A.dll)
. A.dll
in turn references B.dll
, C.dll
, and so on. There could be two types of errors.
check for:
- bitness mistach?
- missing dependent libraries (e.p. msvc redistribution)
Tools that might help:
- dumpbin
- dependency walker
- corflags
- gflags
- procmon (sysinternals)
The below are the details.
Bitness mismatch
First, there could be a bitness mismatch between the native libraries and Foo.dll
. When this happens, you'll see
Unhandled Exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Usually it happens when the native libraries are built for amd64/x64, but foo.dll
is for AnyCPU
or x86
. The csproj
file must add following lines:
1 | <PropertyGroup Condition="'$(Platform)' == 'amd64'"> |
Several tools can be used to inspect a library's bitness.
For managed library, use corflags
. Look for PE
, ILONLY
, and 32BIT
fields:
A amd64
assembly:
1 | > CorFlags.exe /nologo .\CNTKLibraryManaged-2.0.dll |
An AnyCPU
assembly:
1 | > CorFlags.exe /nologo .\Newtonsoft.Json.dll |
For managed and native library, use dumpbin /headers
.
1 | > dumpbin.exe /headers .\CNTKLibraryManaged-2.0.dll |
1 | > dumpbin.exe /headers .\Newtonsoft.Json.dll |
Missing Dependencies (somewhere deep down the tree)
tldr; check if you're missing the Visual C++ Redistributable for Visual Studio XXXX.
This is much harder. You would get an exception:
1 | "Message":"An error has occurred.", |
It is as if CNTKLibraryCSBinding.dll
couldn't be found, but in fact it is some library that this native library depends.
How do you find out what is missing? For managed assembly loading issue, one could use Fuslogvw.exe, however it doesn't work for DllImport()
issues. There are several solutions suggested on the web. You could try sysinternals procmon
. Or gflags
. But I have luck with DependencyWalker. It can be used to statically analyze the dependency tree. But in case of DllImport()
, which is runtime load, use the profiling feature. Give it the application, start profiling, run to the place it would throw the exception. Look for libraries that are missing.
In my case, it happens to be the Visual C++ Redistributable for Visual Studio 2015 (msvcp140.dll
) that's missing from my test server. That explains why I could run the same program on dev box without problem.
Here're all the online articles that helped:
- DllImport generates System.DllNotFoundException
- DllNotFoundException with HRESULT 0x8007007E when loading 64-bit dll
- When a DLL is not found while P/Invoking, how can I get a message about the specific unmanaged DLL that is missing?
- System.DllNotFoundException: Unable to load DLL on window 2003
- DllNotFoundException PInvoke issue