Some of my partners, I have worked, have experienced the errors, while calling a native DLL (written in C++) from a managed .NET application using PInvoke; and that inspired me to write this blog.
The one of the most common errors is "System.DllNotFoundException" occurred in the <application>. Unable to load the dll and the specified module could not be found. (Exception from HRESULTL 0x8007007E).
One of the reasons behind this could be the name you are providing to the "EntryPoint" property of "DllImport" attribute is not matching with the function you are exporting from the native component.
But wait, you verified and checked, the names (lets assume "fnAddNumbers") in native DLL and the .net app are absolutely same. Then, why this error?
Actually, when you create a C++ native DLL, then compiler changes the names of the functions,by encoding the name of the symbols to include the type information. This is known as "Name Decoration" or "Name Mangling" which insures the type-safe checking. Also, this also make the functions unique when the export symbols are generated, in case of "function overloading".
You can use "dumpbin.exe" tool (/exports switch) to check what are the exported names.
This will something like this for the functions:
CPP2_API int fnAddNumbers(int x, int y)
CPP2_API int fnAddNumbers(int x, int y, int z)
ordinal hint RVA name
1 0 000110AA ??0CCPP2@@QAE@XZ = @ILT+165(??0CCPP2@@QAE@XZ)
2 1 0001118B ??4CCPP2@@QAEAAV0@ABV0@@Z = @ILT+390(??4CCPP2@@QAEAAV0@ABV0@@Z)
3 2 000110D7 ?fnAddNumbers@@YAHHH@Z = @ILT+210(?fnAddNumbers@@YAHHH@Z) -> This function takes two "int" parameters.
4 3 00011186 ?fnAddNumbers@@YAHHHH@Z = @ILT+385(?fnAddNumbers@@YAHHHH@Z) – -> This function takes three "int" parameters.
5 4 00011087 ?fnCPP2@@YAHXZ = @ILT+130(?fnCPP2@@YAHXZ)
6 5 00017138 ?nCPP2@@3HA = ?nCPP2@@3HA (int nCPP2)
So, in the "EntryPoint" you will need to pass the values as "?fnAddNumbers@@YAHHH@Z" and "?fnAddNumbers@@YAHHHH@Z":
[DllImport(@"CPP2.dll", EntryPoint = "?fnAddNumbers@@YAHHH@Z")]
public static extern int AddNumbers(int a, int b);
[DllImport(@"CPP2.dll", EntryPoint = "?fnAddNumbers@@YAHHHH@Z")]
public static extern int AddNumbers(int a, int b, int c);
However, if you don’t want to use the "Name decoration", then you can use "EXTERN_C", which will export the function without the name change and then you can use the same function name. Note: This will not work in case of "function overloading".
EXTERN_C CPP2_API int fnAddNumbers(int a, int b);