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
2
3
<PropertyGroup Condition="'$(Platform)' == 'amd64'">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>

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
2
3
4
5
6
7
8
> CorFlags.exe /nologo .\CNTKLibraryManaged-2.0.dll
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 9
ILONLY : 1
32BIT : 0
Signed : 1

An AnyCPU assembly:

1
2
3
4
5
6
7
8
> CorFlags.exe /nologo .\Newtonsoft.Json.dll
Version : v2.0.50727
CLR Header: 2.5
PE : PE32
CorFlags : 9
ILONLY : 1
32BIT : 0
Signed : 1

For managed and native library, use dumpbin /headers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> dumpbin.exe /headers .\CNTKLibraryManaged-2.0.dll
PE signature found
File Type: DLL
FILE HEADER VALUES
8664 machine (x64)
...
2022 characteristics
Executable
Application can handle large (>2GB) addresses
DLL

OPTIONAL HEADER VALUES
20B magic # (PE32+)
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> dumpbin.exe /headers .\Newtonsoft.Json.dll
...
PE signature found
File Type: DLL
FILE HEADER VALUES
14C machine (x86)
...
2102 characteristics
Executable
32 bit word machine
DLL

OPTIONAL HEADER VALUES
10B magic # (PE32)
...

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
2
3
4
5
6
"Message":"An error has occurred.",
"ExceptionMessage":"Unable to load DLL 'CNTKLibraryCSBinding': The specified module could not be found. (Exception from HRESULT: 0x8007007E)",
"ExceptionType":"System.DllNotFoundException",
"StackTrace":" :
CNTK.CNTKLibPINVOKE.SWIGExceptionHelper.SWIGRegisterExceptionCallbacks_CNTKLib(...)
CNTK.CNTKLibPINVOKE.SWIGExceptionHelper..cctor()"

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: