Hopefully this is a brainlessly easy question, but it shows my lack of expertise with C++. I'm a C# programmer, and I've done extensive work with P/Invoke in the past with other people's C++/C dlls. However, this time I've decided to write a wrapper C++ dll (unmanaged) myself, and am then calling my wrapper dll from C#.
The problem I am immediately running into is that I am unable to define a C++ function that can be found by p/invoke. I don't know what the syntax for this is, but here's what I'm trying so far:
extern bool __cdecl TestFunc()
{
return true;
}
Originally I simply had this, but it did not work either:
bool TestFunc()
{
return true;
}
And then on the C# side, I have:
public const string InterfaceLibrary = @"Plugins\TestDLL.dll";
[DllImport( InterfaceLibrary, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "TestFunc" ), SuppressUnmanagedCodeSecurity]
internal static extern bool TestFunc();
Everything compiles, but when I execute this C# p/invoke call, I get a System.EntryPointNotFoundException: Unable to find an entry point named 'TestFunc' in DLL 'Plugins\TestDLL.dll'.
Surely this must be something incredibly simple on the C++ end that I just don't know the syntax for.
You'll want to use extern "C"
as well as __declspec(export)
, like so:
extern "C" _declspec(dllexport) bool TestFunc()
{
return true;
}
For full details, see MSDN on Marshalling Types.
Extending Reed's correct answer.
Another issue you can run into when exposing a C++ function via PInvoke is using invalid types. PInvoke can really only support marshalling of primitive types and plain old data struct / class types.
For example, suppose TestFunc had the following signature
void TestFunc(std::string input);
Even adding extern "C" and __declspec(dllexport)
would not be enough to expose the C++ function. Instead you would need to create a helper function which exposed only PInvoke compatible types and then called into the main function. For example
void TestFunc(const std::string& input) { ... }
extern "C" _declspec(dllexport) void TestFuncWrapper(char* pInput) {
std::string input(pInput);
TestFunc(input);
}
You have to expose this function with extern "C"
otherwise the name gets mangled.
The C++ compiler modifies the names of your functions to incorporate information about the parameters and return types. This is called name mangling. On the other hand, the C compiler doesn't mangle your function names.
You can tell the C++ compiler to work as a C compiler using extern "C"
:
extern "C" __declspec(dllexport) bool TestFunc { return true; }
To call functions from C# using P/Invoke, your names must not be mangled. Therefore, you can actually export C functions to C#. If you want the functionality to be implemented in C++, you can write a C function that just calls the C++ function implementing the functionality.
Do something likes this:
#define EXPORT extern "C" __declspec(dllexport)
And then declare any function with the EXPORT keyword, for example an c++ function
BOOL getString(TCHAR* string, DWORD size);
would become
EXPORT BOOL getString(TCHAR* string, DWORD size);
then the fun part: Go to your VS console and type :
dumpbin /EXPORTS <PATH_TO_GENERATED_DLL>
and you'l see the mangled name and ordinal of all your easily exported functions, then it's just an matter o pInvoking them
Build all project with Win32 platform and appropriate bit (e.g. x86 or x64) build option.