This demo consists of three small VS projects:
a) C++ DLL with exported functions
b) C++ Console App using headers from DLL
c) C# Console App using DllImport
The DLL Exports are as follows:
C++ Client App
The C++ App uses the Connector.h header from DLL to create a unique_ptr of the Connector class.
Connector utilizes internally the C++ REST SDK (Casablanca) to call a publicly available JSON Echo service.
To make this example a little bit more realistic the method GetJson expects a function object. This object (a function pointer) is used to display the JSON response. There's also a possibility to send additional headers.
Inside the GetJson method the server communication is handled asynchronously via objects & functions from the pplx namespace.
C# Client App
The .NET App imposes several restrictions to exported functions. Instead of C++ function templates I had to use old-style C function pointers. This is because .NET can only marshal Delegates to function pointers. The same happened to the C++ string class. It was replaced by raw wchar_t pointers. Ugly, but playing with .NET DllImport is always rather unpleasant.
This is how the whole DllImport soup looks like:
First, we declare a delegate and decorate it as an "unmanaged" (that is, non-NET callable) function pointer. Also, we set the calling convention to StdCall. This means that the callee (the DLL function) will be responsible to clean the stack and not the caller (the Client). More info on argument passing and calling conventions here.
Second, we grab the DLL which hopefully exports the desired function. In this case the Connector.dll should be located where the executing assembly is. In other cases we'd adjust the first argument after [DllImport] Attribute. Also, the same calling convention is applied. Now, it's important to know that functions from non-NET DLLs are statically imported externals and very often demand special treatment of passed arguments. In this case we have to marshal a pure .NET entity, the Delegate to a raw function pointer To achieve this we use attribute [MarshalAs] and decorate the OnCompletedDelegate as unmanaged function pointer.
Finally, the C++ DLL will be able to "call back" our delegate as soon as the JSON Echo Server delivers a response.
Example, C++ client calling service & passing additional headers
Example, C# client calling service
IMPORTANT
The clients need these two libraries to be located in their root folders:
Connector.dll
cpprest120d_2_4.dll (this is the library from C++ REST SDK and can be installed via Nuget)
LICENSE
MIT