Introduction to the xInterop .NET bridge

Introduction

With the .NET open source movement, there will be more and more .NET libraries available to the managed world, there will be also a trend of using .NET libraries from all other languages, not every one is willing to re-invent the wheels in their favorite languages.

The best language to bridge to the .NET world is C/C++. There are existing technologies which can be used to call into C# libraries.

1. C++/CLI

C++/CLI is a bridging language which can be used to integrate .NET libraries by creating C++/CLI bridging/wrapper classes being exposed to the native world. The effort of creating such C++/CLI bridging/wrapper class is still considerable if there are many .NET classes and methods, the amount of time spent on marshaling different data types depends on size of the library. Ultimately, using C++/CLI is a manual process and requires big effort and it is not error prone, in fact, one may make many errors if not being careful enough.

(1) Lots of work, it is less than re-writing the library, but still lots of work for manually trying to figure out how to marshal the data types.

2. Unmanaged Exports

By adding MSIL .export directive to the original .NET function(must be static) then reassemble into a mixed-mode DLL, Unmanaged Exports can export static functions. You can download the nuget package from here. The features provided by Unmanaged Exports is very limited, for one, you can only export static functions with limited data primitive type and string, secondly, you will have to write the corresponding C/C++ portion in order to call the exported static methods from the .NET assembly, developers must load the library dynamically by calling LoadLibrary because you won’t have a .lib file you can link to, you must also define the type of a function type which corresponding to each C# static method signature.

(1) Any .NET class can not be exposed to the native world directly.

(2) Developers are responsible for creating C/C++ function type and loading individual functions.

(3) .NET assembly must be pre-processed and made into mixed mode DLL.

3. COM

Developers can also create a .NET COM component to expose COM interface for the C/C++ code to access the .NET assembly via COM. All the traditional COM limitation applies here.

(1) NET COM component must be registered.

(2) Generic and Generic type instance can not be used in COM interface.

(3) Static methods of any class will have to be re-wrapped in a new class as instance methods.

(4) Existing .NET class can not be just exposed via interface.

4. Reverse PInvoke

Reverse PInvoke merely means it is the reversed platform invoke from native application to .NET managed assembly, it basically sets up the callback function from .NET by using delegate so that the native DLL can retrieve the function pointer and call back into the .NET assembly. There are a few links listed below, you may want to read it for further information.

http://blogs.msdn.com/b/thottams/archive/2007/06/02/pinvoke-reverse-pinvoke-and-stdcall-cdecl.aspx

http://tigerang.blogspot.com/2008/09/reverse-pinvoke.html

(1) The features provided by Revers PInvoke is also very limited, only the data types supported by PInvoke may be supported by Reverse PInvoke. Array type is not supported, there is no way for the .NET to find out the size of an pointer passed from the native world without extra work.

(2) Only .NET static methods can be called by native application.

(3) .NET classes can not be exposed to native application via Reverse PInvoke.

(4) The type of function type corresponding to the .NET static methods must be defined by developers.

5. xInterop .NET bridge

What is xInterop .NET bridge.

It is an add-on feature to the existing xInterop NGen++ (which we will officially rename to xInterop .NET). xInterop .NET bridge automatically creates C++ DLL based on any given C# .NET assembly and export header files and lib file for the C++ DLL so that any native application can reference and use the DLL for further development. It supports the following features.

(1) Classes. It will bridge any classes and create corresponding C++ classes for accessing the .NET classes. All public methods, both static and instance methods can be called from the native world.

(2) Structs. It will bridge any classes and create corresponding C++ classes for accessing the .NET struct. All public methods, both static and instance methods can be called from the native world.

(3) Enums. It will create corresponding C++ enum for each C# .NET enum.

(4) Generic Instance Types. All public methods, both static and instance methods can be called from the native world.

(5) Event and Event Handlers.

(6) Properties

(7) Fields

(8) Inheritance architecture.

(9) Constants

(10) Interfaces

(11) Delegates

(12) All C++ classes are derived from NObject class so that the instance of any class can be referenced by using NObject.

much more.

We will detail each of the features in the next posts. Please continue reading.

Marshaling C++ string, a std::string or std::wstring in C#

Marshaling C++ std::string in C# is possible and doable and it is done

Marshaling C++ std::string in C# is difficult, developers asked questions for help on the web everywhere for many years since .NET was born and PInvoke Interop became a must between C++ and .NET.(C++/CLI uses PInvoke as well, it is implicit P/Invoke, the actual P/Invoke implementation is invisible to the developers, but it still uses P/Invoke), I have a list of questions asked on the web here, they are all different situations, but all they want to do is to able to marshal or access the std::string from C#.

C# Strings in C++

Interface to C++ (unmanaged) DLL and std::string or std::wstring

Pass C# string to C++ and pass C++ result (string, char*.. whatever) to C#

 

All the answers point out that there is no way you can do in C# because the nature of std:string. Is that really true that you really do not have any way to marshal a std::string in C#? It is really a simple object in C++, right?

A std::string in C++, is not a sequence of char like char*, char[], it is an instance of C++ class, which means you will have to access it through the interface of the std::string class. You can not simply marshal a std::string in C++ to string, StringBuilder in C#, it is not going to work, it is just wrong, the .NET run-time will throw out memory access violation exception.

C# Wrapper Library for C++ Run-Time Classes

All that said, it is difficult to create and access a std::string from C#, but the truth is that you can, you can access any instance of C++ class from C# if it can be accessed from C++ code via dynamic linking. That is where the C# Wrapper Library for C++ run-time comes into play, it will make the std::string to C# string marshaling so easy. The C# Wrapper Library implements wrapper classes for most of the run-time standard C++ classes. It is certainly a big helper when automatically generating a C# wrapper for C++ DLL, It is also very useful when you have C DLL involving some standard C++ classes in its interface of C style methods. For any standard classes, such as std::string, std::wstring, std::iostream, std::fstream, you won’t be able to create or access them without such a wrapper library in C#.

A C++ std::string can be created and accessed from C# by using its C# wrapper class, StdString.(Same to std::wstring, it has wrapper class, StdWString)

Metadata of StdString, the C# wrapper class of std::string

I am showing the complete metadata of the C# wrapper class of StdString.

 

C# Wrapper Generator for C++ DLL

The class of StdString was generated by C# Wrapper Generator for C++ DLL automatically, it was pre-generated and put in the C# wrapper library for C++ runtime for convenience, since there won’t be difference between a pre-generated one and the one generated for a custom C++ DLL later, and a Custom C++ DLL mostly won’t have a std::string exported in the DLL anyway.

If you look into the StdString class, you will find all the methods you are familiar in C++. If you have pieces of code you have from C++ to manipulate the strings, you have do the same in C# now, the only thing is it will affect the performance because you will be calling each C++ method through P/Invoke.

Example of marshaling std::string from C#

Let’s write a real C function involving accepting a std::string and returning a std::string.

There are different ways to declare the P/Invoke signature in C#.

You can either marshal std::string to IntPtr or StdString depending on your preference.

Marshal std::string to IntPtr

Marsahl std::string to StdString

You have seen how a std::string can be marshaled from C# to C++ by using StdString from the C# Wrapper Library for C++ DLL. Without such a library, passing or accessing a std::string from C# is just so difficult, P/Invoke do not necessarily mean difficult, with certain tools such as the C# Wrapper Library for C++ DLL.

 

 

 

Creating and Accessing Instantiated std::vector Template Class from .NET

C++ Vectors are sequence containers representing arrays of certain data type, which can change in size. It is widely used by lots of C++ application, if we did not include in our C# wrapper library for C++ DLL, it would be very difficult for the C# wrapper generator to create wrapper classes for C++ class automatically and smoothly since lots of classes may contain interfaces using std::vector of any data type, it is so common that we just would not be able to ignore it. A template class is not a concrete class until it gets instantiated, so a vector template class is really lots of classes with different types contained in that class, in order to map all kinds of vector class of different data type, the C# wrapper library for C++ run-time contains a bunch of wrapper class for each of the instantiated template class, see the list below. All the wrapper classes were generated by the C# wrapper generator with fine tuning specifically done to the vector type of template class.

Not seeing the vector of the data type you want? no worry, the C# wrapper generator has the capability of generating any type of template classes of any types as long as they can be instantiated from C++ using that C++ DLL, for std::vector, you can have std:vector<any_of_your_type>, including your own class and structure. It actually can automatically discover the template class inside the C++ DLL interface, instantiate that type of template class and create the wrapper class for that instantiated C++ template class. It is quite powerful, we will be discussing that in later blogs. For developer’s convenience, we added the pre-instantiated template class in the C# wrapper library for C++ run-time, which makes it useful even when using C DLL.

Since most of the functionality of all of the wrapper classes, the only difference is that each wrapper class contain different type of data type. We will be discussing the wrapper class of std::vector<std::string>, StdStringVector.

std::vector<std::string> is commonly used to pass or retrieve an array of C++ strings, without the help of the C# wrapper library for C++ run-time, it would be very complex for developers to marshal this data type from C++ from C#. Any other kinds of solution targeting marshaling the data type would be time-consuming, or just wasting developers’ valuable time.

Developers asked questions on stackoverflow, I listed a few of them below,

How to Get array of string from Native Code(C++) in Managed Code(C#)

How to marshal collection in c# to pass to native (C++) code

C# pinvoke marshalling structure containg vector<structure>

Without a wrapper class for std::vector<std::string>, such as StdStringVector, there are really no simple answer for those questions, developers would have to do a lot of work to marshal this kind of instantiated template class, besides this, std::string still needs to be marshaled before std::vector<std::string> can be marshaled.

Let’s look into the details of the class of StdStringVector, the .NET wrapper class for std::vector<std::string>. The followings are the metadata I copied and pasted from VS IDE.

StdStringVector wraps all the public methods of the C++ counterpart, std::vector<std::string>, so you can find all the methods familiar in C++ world, like push_back, pop_back, size, etc, to make it easier for developers to use in .NET, the names of all the methods are not kept without change.

How do developers to marshal std::vector<std::string> from C# to C++? let’s take an earlier example of the wrapper class of StdString, we would need to change a little bit of it.

Again, let’s write a P/Invoke for it, remember, every C# wrapper class can be converted to a .NET IntPtr, and they also have a public marshaller class for each of them.

Okay, now we have figured out the way to pass the object from C# to C++ via P/Invoke, let’s talk about the ways to access the data inside of the C++ vector instance.

There are two different ways to access StdStringVector class hence the C++ vector depending how developers would want to. Let’s give an example of how to iterate the vector and print them out to the console.

If developers prefer the way they usually do in C++ as a C++ developer, they can use iterator as they usually do in C++, It also allow them to convert any part of C++ code to C# more easily.

If you look carefully, you would find there are other interfaces and additional methods implemented in the C# version of std::vector<std::string>, those interfaces and methods allow the developer access StdStringVector without using an iterator which is really not a native way to access an array in .NET world. You may have already noticed that it implements IEnumerable interface, ToArray method and string[] type conversion, etc.

Quite simple, right? Developers do not have to do anything else, they would just have the capabilities of manipulating the C++ vector object when using the C# wrapper library for C++ run-time.

A C# .NET Wrapper Library for Standard C++ Classes

In order for our C# wrapper generator for C++ DLL to automatically generate C# source code for C++ DLL, we would have to have a C# wrapper library for the standard C++ run-time library first. Since we were already writing the C# wrapper generator, we used the C# wrapper generator to create the C# wrapper library for the C++ standard run-time classes after some fine-tuning specifically done to the C# wrapper generator for C++ standard classes.

Here are the list of all the C# wrapper classes in the C# wrapper library and the corresponding standard C++ classes.

C++ is one of most widely used programming languages, and std::string is one of the most widely used C++ standard classes. In a C DLL, we use char *, const char* as a string parameter, and in C# you can use string, String, StringBuilder which are automatically marshaled by .NET framework to map the C style string. But, for std::string used in C DLL or C++ DLL, we do not have that luxury any more. The problem is that .NET does not marshal std::string, you simply can not use .NET string to marshal a c++ std::string which is a C++ class instance, it is not just a pointer to a buffer like char*.

Let’s start discussing StdString, the C# wrapper class for C++ std::string.

The following is the metadata of the StdString C# .NET class. It is exactly what I copied from VS studio IDE.

As you can see, the C# wrapper class, StdString has the exact same interface of the corresponding C++ std::string class in .NET, you can use it just like you use it in C++ language, it also provides a Marshaller class which shall allow it to be used as a customer marshaller.

Let’s look at an example of how we can use StdString.

Assuming we have a c style method in a DLL named sample.dll.

Without the C# .NET Wrapper library and the StdString C# wrapper class for the std::string class, we would not able to marshal the std::string in C#, we can not marshal it as string or StringBuilder, both of them won’t work. Now, since we have StdString wrapper class, we will be able to marshal the std::string as StdString as following,

One last thing we would want to be clear at the end of this blog, since the underlying C++ DLL only works with certain version of C++ run-time library, and specifically, Microsoft Visual C++ run-time library, the C# .NET Wrapper library will only with that version of C++ run-time.

Translate »