A C# .NET Managed Wrapper Generator for Wrapping Native C++ DLL Automatically
– A tool capable of creating C# .NET managed wrappers for native C++ DLLs instantly
We are so excited to announce that we are about to release our C# .NET PInvoke Interop SDK which includes a C# .NET ( PInvoke ) Managed Wrapper Generator for native unmanaged C++ DLLs and a C# .NET Managed library for wrapping native C++ standard classes exported in a C++ native unmanaged DLL via PInvoke. It is in beta-testing right now.
For years, developers have been struggling with being unable to call into native C++ DLL exporting native C++ class from C# .NET easily. To access or call native C++ classes exported in a C++ DLL from C# .NET world, there are a few existing technologies, all of them require developers’ extra effort to write either script or C++ code to create a managed C# .NET wrapper DLL via PInvoke to access or call the original native C++ DLL, and there will be more work when you consider the maintenance, none of them are automatic.
Wrapping C++ classes from C# .NET via PInvoke enables developers to access and call their existing native C++ code base in the C# .NET world without manually changing anything or writing anything extra. The only things this SDK tool requires is the native unmanaged C++ DLL itself and all the header files for that native unmanaged C++ DLL, just like being referenced from a native C++ project, further, it does not even require the corresponding lib file for the native unmanaged C++ DLL as normally being required by a C++ compiler when using the native unmanaged C++ DLL from a native unamanged C++ project.
Here are the list of the most important features of our C#/.NET PInvoke Interop SDK.
1. Calling C++ class methods from C# .NET into the native unamanged C++ DLL via PInvoke including all the data type marshaling which is completely automatically handled by the C# .NET PInvoke Interop SDK tool.
2. Instantiating native C++ class instances from C# .NET, the life time of the C++ instances are controlled by the C# .NET code.
3. Invoking or calling all the native C++ class methods implemented in native unmanaged C++ classes from C#/.NET code, including both static and non-static methods, both of the exported methods in the native C++ DLL and any of the virtual methods of the C++ classes.
4. Accessing C++ fields implemented in the native C++ classes from C# .NET managed code, including both static and non-static fields. The types of the native C++ fields exposed in C# .NET managed code includes all the primitive types, all the native C++ classes exported in the nateive C++ DLL, struct types, enum types and the standard native C++ classes and instantiated template classes.
5. Subclassing the native unmanaged C++ classes from C# .NET managed code. All the virtual methods in the C++ classes exported from the native unmanaged C++ DLL can be overridden in C# .NET managed code. An instance of such a C# .NET class can then be passed to native C++ DLL as an object of the native C++ derived class. The native unmanaged C++ DLL does not see any difference between C# .NET managed instance and the instance of the C++ derived class.
6. Supporting AnyCPU. If both x86 32 bits and x64 64 bits native C++ DLL are available, building a AnyCPU C# .NET DLL is supported. Both native unmanaged C++ DLLs can be built into the final C# .NET DLL as embedded resource to support the single C# .NET DLL to be used in both x86 and x64 running mode. If only the x86 or the x64 native unmanaged C++ DLL is available, then a C# .NET DLL targeting either x86 or x64 will be built.
7. Wrapping almost all the standard C++ native unmanaged classes to C# .NET managed classes, such as C++ string (std::string), C++ wide character string (std::wstring), C++ io stream (std::iostream), C++ file stream (std::fstream), etc. Providing such a library will enable developers to instantiate and access the standard C++ classes without doing any other data type marshaling from their C# .NET managed code, which is basically impossible without such as C#/.NET library.
8. Automatically recognizing the standard C++ classes used in any of the native C++ class interface. If the native unmanaged C++ DLL happens to have a method like,
std::string& GetIdByCustomerName(std::string& name);
The type of std::string will be automatically mapped to the corresponding C# .NET managed class, StdString or simply string depending on how you want to use the method, and there is no extra code or script to write.
StdString GetIdByCustomerName(StdString name); string GetIdByCustomerName(string name);
9. Automatically recognizing the standard container classes used in the native unmanaged C++ interface and then export the instantiated template classes from a new supplement native C++ DLL to support the C++ class interface, without adding the support of the instantiated template class, any of such class will not be available to the C# .NET managed world. For example, if you happened to define a method with a parameter type of std::vector<int> in one of your C++ classes and std::vector<int> is not exported, std::vector<int> class will be exported in a supplement native C++ DLL and a corresponding C# .NET managed wrapper class for std::vector<int> will be created to support accessing the std::vector<int>. The SDK tool can actually go further if you happened to have std::vector<Rect> where Rect is a struct of rectangle, it will export std::vector<Rect> from the supplement native C++ DLL, implement C# .NET Managed version of Rect and a C# .NET Managed wrapper class for std::vector<Rect> named StdRectVector. In the case that the new supplement requires to access the native unmanaged C++ DLL, it will build a lib file from the native unmanaged C++ DLL and link itself to the library, It is done all automatically, developers do not need to do anything manually. This is one of the most important and most powerful features of our C# .NET PInvoke Interop SDK.
The SDK Tool will try to find all the types in the C++ interface used in the exported classes in the native unmanaged C++ DLL and create corresponding C# type for them if it is needed. For example, If the SDK Tool discovers that a type of std::vector<int> is used in the native unmanaged C++ class interface, a C# .NET managed class named StdIntVector will be generated, and all the types of std::vector<int>*, std::vector<int>&, return type of std::vector<int> will be marshaled as StdIntVector, further std::vector<int>* * can be possibly marshaled as StdIntVector array.
bool SetVector(std::vector<int>& data);
bool SetVector(StdIntVector data);
This great feature releases developers from exporting any native template classes when they design their class interface, they will just need to make sure that their non-template classes do get exported in the native unmanaged C++ DLL.
10. Automatically recognizing any of non-standard container template classes in the native unmanaged C++ DLL interface. As long as the template classes is implemented inside of header files, any instantiated template classes can be exported in a supplement native unmanaged C++ DLL and a corresponding C# .NET managed wrapper class will be generated.
11. Automatically recognizing both struct type definitions and enum type definitions in the native unmanaged C++ DLL and then defining the corresponding struct and enum types in C# .NET. Developers have the choice of keeping the same name or renaming them.
12. Automatically recognizing native unmanged C++ function type definitions and implementing the corresponding delegates in C# .NET managed code. If a type of function defined as following in the native unmanaged C++ DLL,
typedef int (__cdecl *addfunc)(int x, int y);
A C# .NET managed delegate of the following will be defined in the C# .NET managed wrapper DLL.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate int addfuncDelegate(int x, int y);
13. Automatically recognizing std::function<function_signature> which will then be implemented as a C# .NET managed class and can be instantiated by using a corresponding C# .NET managed delegate for that function signature, just like the function type definition.
14. Implementing multiple overrides for the same native unmanaged C++ method. For methods with T* C++ parameter, the SDK’s wrapper generator will implement multiple overrides of the same native unmanaged C++ class method in C# .NET managed code.
A type of T* in the native unmanaged C++ does introduce ambiguity in the .NET world because the real meaning of T* is not really clear from C# .NET without looking into the implementation of native unmanaged C++ class method. A workaround of this issue is to implement multiple overrides of the same native unmanaged C++ class method and let developers to pick one since they know what the C++ class method really does.
For example, if you have the following C++ .NET managed method in one of your native unmanaged C++ class,
int SendData(char* dataBuffer, int dataBufferLength);
The following C# .NET managed methods will be implemented to support the method depending on what the C++ native unmanaged method really does, the wrapper generator does not really know what the method really does though.
int SendData(IntPtr dataBuffer, int dataBufferLength); int SendData(ref byte dataBuffer, int dataBufferLength); int SendData(byte[] dataBuffer); int SendData(string dataBuffer, int dataBufferLength);
Among the 4 C# .NET method overrides, the first one is always correct no matter what native unmanaged c++ method really does, but it is inconvenient to use since the developer will have to manually copy the input data to the buffer from the source data. If what the native unmanaged C++ method really does is to accept a byte buffer with another parameter of the number of bytes in the buffer, then the third override is a perfect match. The toolkit will allow you to generate all the possible overrides of the same C++ method, and the developer just need to pick up the one which best fits the original native unmanaged c++ method.
15. Both of the C++ ANSI and Unicode encoded characters and strings are automatically recognized and the corresponding encoding is used to generate the PInvoke function or method signatures.
16. Limited support of pass-by-value when passing an native unmanaged C++ class instance from C# .NET managed code to native unmanaged C++ DLL.
17. The automatically generated source code of the C# .NET managed wrapper is available. And best of all, the C# .NET managed wrapper code is very much readable and it is just like any C# code Developer manually write. It can be modified easily by developers who know C# .NET PInvoke and data type marshaling.
18. When the C++ source code is changed and a new C++ native unmanaged DLL is generated, all you need to is to rebuild the C# .NET managed wrapper automatically by running the C# .NET PInvoke Interop SDK tool against the new C++ native unmanaged DLL and the modified header files one more time, you are done. You can even automate it from a post-build command. You will be able to call or pinvoke into the C++ native DLL on the new interface you just added via PInvoke.
Our C# .NET PInvoke Interop SDK focuses on native unmanaged C++ DLL instead of both native C and native C++ DLLs since there are existing tools which can wrap a native unmanaged C style DLL automatically without developer’s manual involvement. We will add this feature in the future.
Stay tuned, we will be publishing the first demo application of using the C# .NET PInvoke Interop SDK.