Unmanaged Exports

Unmanaged Exports

The Ultimate Guide to Calling C# .NET Methods and Classes from Native C/C++ Using Unmanaged Exports

Introduction

Unmanaged Exports is a technique of exporting C# .NET methods from managed C# code to native C++ applications, which means those managed C# methods will be available to other languages such as C/C++, Delphi, Java, Python, PHP, etc.

The technique of making a C# .NET assembly exporting C# methods was disclosed first time in the book of Expert .NET 2.0 IL Assembler published in 2006 and authored by Serge Lidin.

The book is on also google book and you may be able to read the chapter (Chapter 18: Managed and Unmanaged Code Interoperation) describing the technique of creating such exportable .NET function by writing IL Assembly Language code. I believe the name was mentioned first time in that book.

In another book titled .NET IL Assembler published in 2014, Serge Lidin continued the discussion of this technique (Chapter 18: Managed and Unmanaged Code Interoperation).

Excerpts from the book,

Managed Methods as Unmanaged Exports

Exposing managed methods as unmanaged exports provides a way for unmanaged, non-COM clients to consume managed services. In fact, this technique opens the managed world in all its glory—with its secure and type-safe computing and with all the wealth of its class libraries—to unmanaged clients.

Of course, the managed methods are not exposed as such. Instead, inverse P/Invoke thunks, automatically created by the common language runtime, are exported. These thunks provide the same marshaling functions as “conventional” P/Invoke thunks, but in the opposite direction.

In order to expose managed methods as unmanaged exports, the IL assembler builds a v-table, a v-table fixup (VTableFixup) table, and a group of unmanaged export tables, which include the Export Address table, the Name Pointer table, the Ordinal table, the Export Name table, and the Export Directory table. Chapter 4 discusses all of these tables, their structures, and their positioning within a managed PE file. Now let’s see how it all is done.

Manually writing such unmanaged exports method or changing the existing .NET code using IL Assembly Language code is tedious and time-consuming. Robert Giesecke released a nuget package which provides a set of compile-time libraries (nothing to deploy) and a build task that enable you to export functions from managed code to native applications. Robert Giesecke actually said on stack overflow that he used the book “.Net 2.0 IL Assembler” to make sure that he didn’t end up doing any cargo cult stuff.

The procedure of exporting managed method is shown as below in a few simple steps.

  • Create a new C# class library or proceed with an existing .NET assembly.
  • Add Robert Giesecke‘s UnmanagedExports Nuget package by using Package Manager Console.

This will add the following assembly named RGiesecke.DllExport.Metadata.dll to the reference of the .NET project.

It will also modify the .NET project file by adding the new Import node.

  • Write any kind of static method, decorate it with [DllExport] and use it from native code.

  • During compilation, the Nuget task will modify the IL to add the required exports, the .export directive exactly. The process won’t output anything if everything goes well.

Robert Giesecke‘s UnmanagedExports Nuget package has been open sourced on github by both Robert Giesecke and Denis Kuzmin. It is under the MIT License (MIT).

 

Simple Example of Exporting C# Methods with Primitive Data Types only

First let’s create a new C# .NET assembly project. It will be a simple C# .NET assembly containing only one class named Calculator. Although the example is very simple, it is basically a guide of how to use unmanaged exports.

Creating C# dllexport example application

Once we create the C# assembly project, we must make sure the platform target is either set to x86 or x64, it can not be AnyCPU.

x86 or x64 must be defined to export C# method from .NET to native C++ application

And here is the complete code for this C# library.

There is nothing special about the Calculator class, the only thing you may have already noticed is all the 4 methods of Calculator are static methods. This is because .export directive can only be applied to static methods and only static methods can be exported.

Now, let’s install Robert Giesecke‘s UnmanagedExports nuget package.

Install rgiesecke.dllexport nuget example

Let’s add the namespace of RGiesecke.DllExport and then decorate each of the static methods with DllExport attribute. (DllExportAttribute)

By default, C and C++ uses __cdecl calling convention, so we define the C# method as __cdecl calling convention as well.

Now building this C# library project creates a .NET assembly. When we open the DLL by using CFF Explorer Suite, we can see all the 4 methods exported from the DLL as shown below. The DLL becomes a mixed mode assembly after being processed by MSBuild task.

Exporting C# method by using Unmanaged Exports

I tried to find the .export directive by opening the .NET assembly from ILSpy, but I was not able to find it.

ILSpy does not show .export attribute

ILSpy does not show the .export directive. I then tried ILDASM and I was finally able to find both the .vtentry and .export directive as shown below. The following screen-shots demonstrate we have accomplished Native DLL Exports from .NET Assembly.

ILDASM does show .export directive

Now that we have a mixed mode .NET assembly, let’s try to use it from native C/C++ code by creating a C/C++ console application.

image.png

image.png

image.png

Now you are looking at the initial code created by Visual Studio as shown below.

We will need to add the c function declarations for the 4 static methods we export from the .NET assembly in mixed mode. Since those methods are exported as C-style functions, we will need to use extern “C” statement. For the primitive types like integer, you just map C# int to C++ int, since it is cdecl calling convention and we use exactly method name as the export name, and C/C++ default calling convention is cdecl, we do not need to decorate the function with calling convention such as __cdecl, __stdcall, etc.

Before we can start using these methods, we will must link the lib file by setting up additional library directory and lib file.

image.png

image.png

Let’s add some additional code to use these 4 external methods exported from the C# assembly. The complete C/C++ code is shown below.

Before we start running this console application, we would want to copy the C# .NET assembly to where the console application is located. We do this in the command line of post build of the C/C++ console application.

image.png

To make sure we always build the C# .NET library assembly before we build the C/C++ console application, we set up the C# library as the dependency project of the C/C++ console application.

image.png

Now we have the whole solution looks like the following screen-shot.

image.png

Running the C/C++ console application, we got the resulting screen shot as shown below as expected.

image.png

Calling Convention of __stdcall

We have been using __cdecl calling convention from the very beginning, you might be wondering what if you want to use __stdcall calling convention after all, a lot of C style DLL do use __stdcall (WINAPI) calling convention.

Firstly, we will need to change the C# code for the Calculator class.

As you see the above code, we change the calling convention to CallingConvention.StdCall, but this is not enough, for __stdcall calling convention, Visual C++ compiler requires its function export name mangled as shown below.

The number at the end of any mangled name represents the number of bytes of all the parameters of the C-style export function, for example, for Add function, it has 2 integer parameter, so it is 8 bytes, the managed name is Add@8.

For the C/C++ console application side, what we only need to do is to decorate the external C function with __stdcall.

So far, we have been able to change the calling convention of the C-style function exported by the C# assembly by using Unmanaged Exports. This is very useful while we are getting deep into the power of Unmanaged Exports. You will see the point in the later section.

You probably have guessed already, this technique only works on .NET static methods. It is a limit. You might also continue thinking that any instance method of a class can’t be exported this way and further we won’t be able to call them. This is not true. let’s continue the journey of discovering new power of Unmanaged Export Technique.

Calling C# .NET Class and its instance methods from Native C/C++

As you see the previous example of the C# class of Calculator, all its 4 methods are static in order for us to export them. Considering we have a Calculator class with all instance methods as shown below.

Since all the methods are not static methods, we can not decorate them with [DllExport] attribute any more. If you try to, UnmanagedExports task will output error message like the following,

Export error EXP0016: MethodDeclarationParserAction: The method is not static. Only static methods can be exported.

The work-around of overcoming this limit is to write a wrapper class using static methods to bridge to the instance methods.

Let’s create a new class named CalculatorWrapper to wrap all the instance methods of the class, Calculator.

As you probably found out already, there is new method we added and new parameter we added to each method, those are 2 points we should talk about.

  1. We added a new static method to create the C# calculator instance as shown below. Just like in C#, we must create an instance of Calculator in the native C++ before we can call the instance methods. A wrapper method must be provided to native C++ to accomplish this requirement.

2. We added a new parameter named calculator as type of object marshaled as UnmanagedType.IUnknown. This is also a must because whenever we invoke any instance method, we will need to pass the instance of the Calculator from the native C/C++ code. From .NET to C#, any object can be marshaled as UnmanagedType.IUnknown.

On the native C/C++ side, since we are using IUnknown interface, we will need to include Windows.h header file.

And we also have 5 external functions to reference.

Since we are programming OOP, we would want to wrap everything in a class named Calculator so that we create a bridge class(wrapper class) completely simulate the .NET version of calculator class.

It is amazing that we now have a native C++ proxy class of the .NET version of Calculator class. Let’s put it in action then.

The result is of course similar to the result earlier when we use static methods in the Calculator class.

image.png

So far so good, we are able to call the instance methods of a calculator class in .NET from the native C/C++ code. But I am still not happy with this implementation because we still have to write a C++ proxy class. In the real world of native C++, if someone provides you a C++ DLL containing a class of Calculator, you would expect the following declaration in its header file, right?

Okay, then. Let’s introduce more complicated stuff to continue this topic.

Exporting C++ Class from .NET assembly just like Visual C++

The topic is kind of scaring, any one would probably think, it is a hack, isn’t it? Well, I would think every advanced coding technique is probably a hack anyway, and most of the stuff I am writing here is well documented, that it why I am able to write it, right? And I can explain why it is supposed to work in every detail, and mostly importantly, it just works.

Let me firstly present you the modified version of C# code of CalculatorWrapper and then I will explain the code in details. I am writing the code myself while I am writing this article, it does not mean it is simple, it is complicated and time-consuming, but it is a fundamental knowledge of how we can make it work.

There are a few points I would like to explain.

Calling Convention

Since we are simulating native C++ instance function calls, the calling convention can no longer be __stadcall or __cdecl, it must be __thiscall, which means for x86 CPU architecture, the this pointer is passed in the CX register.

Export Function Name

The export function name must be mangled name since it is C++ function instead of C-style function. The mangled names carry the exact name function declaration for Visual C++ compiler to find the right export function.

Constructor and Destructor

We do not want to write bridge proxy class in the native C++ any more, we completely rely on the C# .NET side to do the work, this make the native C++ interface quite neat and simple. The destructor is implemented in the C# side as well.

Structure of the C++ Class

Although we do not have to implement the proxy class in the native C++ code, but the class does exist. The size of the proxy class is 8 bytes for x86 CPU architecture. The first 4 bytes(a pointer) is for the virtual function table, the second 4 bytes (a pointer) is the storage of IUnknown pointer. And yes, you can guess, for x64 CPU architecture, the size shall be 16 bytes.

After we built the new C# assembly and open the mixed mode DLL, we can see the export functions and their mangled names exactly you would see in a traditional native C++ DLL exporting classes.

image.png

From the native C++ side, we will write the declaration for the C++ bridge class of Calculator as shown below.

As you see, the declaration of the native C++ proxy class Calculator defines the size of the proxy class, we do not implement the proxy class any more. We declare the destructor as virtual for the purpose of inheritance. We can discuss this in the future.

And this is the old method of testing the Calculator class, and you should have noticed I did not change anything except the words of the message.

The result is still same as before.

image.png

Create a Complete Mini Native C++ Library with Inheritance

In the preceding examples, we were able to discover that we can create native C++ library by using mangled names to export static function when using unmanaged exports, and the resulting library works exactly like those created by Visual C++. But I found there are 2 issues I have not addressed.

Virtual Function Table

The virtual function table is not required, there is no need to make any native C++ function virtual because any native C++ class is just proxy class, the .NET corresponding class will handle the the function routing. Without the virtual function table, each proxy class will have only a size of 4 bytes to store the IUnknown pointer from the .NET for x86 and 8 bytes for x64.

Inheritance

Inheritance must be implemented in order to simulate the similar object hierarchy of .NET system.

We are going to add and export the following classes so that we can create object in native C++ and output its full type name. The original calculator class still remains, but it is not our focus any more.

image.png

C# ObjectCppWrapper Class

C# TypeCppWrapper Class

C# StringCppWrapper Class

The complete native C++ code is listed as below.

image.png

There are a few points I would like to make,

Native object is always created in native C++

Instance of native C++ proxy class must be created in the native C++ code and pass to .NET and destroyed in the native C++ code as well. A proxy class instance always live in the native C++ world

String is bridged instead of being marshaled to const char

A .NET string can be copied to char only when it is required to, such as being printed out.

Function returning .NET object

When any .NET method returns an instance of a class, it must be returned to native C++ as the last parameter of the function by reference.

Limits of Unmanged Exports

Everything has limits, so does Unmanaged Exports.

  • We can only export static methods.
  • We have to set the platform target to either x86, ia64 or x64. AnyCPU assemblies cannot export functions.
  • We can’t put the exports in generic types or export generic methods. (The CLR wouldn’t know what type parameters to use)
  • It is not available for mono which does not support mixed mode very well and it does not support .export directive neither. It is not a cross-platform solution.
  • .NET exception can’t be caught in the native C/C++.

Adding Exception Handling

As we talked about in the preceding section, there is no exception handling when using Unmanaged Exports, but there is a work-around technique with which we can pass an instance of .NET exception back to the native C++ which then creates a native C++ exception based on the .NET exception. By using this technique, we can use try and catch at the native C++ side and do not have to worry about the exception on the .NET side since everything in the .NET exception can be passed back to the native C++ world, and we do not need to worry about anything related to stack unwind, etc. The .NET exception shall be caught on the .NET side in the wrapper method of the original method. I will give you example of how it works.

This is a simplified version of the Exception Handling Technique we implemented in xInterop Native C++ to .NET Bridge, a Native C++ Wrapper Generator for wrapping .NET assembly automatically.

The first thing we will have to do is to bridge the .NET class, Exception. For this, I created ExceptionCppWrapper class.

I only create two bridge methods for the class of Exception, getMessage for accessing Message property and getHResult for accessing HResult property respectively.

In an earlier example, we use a class name Calculator which contains a method of Divide, we ignored the fact Divide may throw exception in the .NET code when one value is divided by zero. We will need to change a little bit to that class. For simplicity, we are going to only change the method of Divide, which is only the method where exception may be raised.

The following is the enhanced version of CalculatorCppWrapper class.

If you pay attention, you may have found I added a new method as shown below once again. The method is wrapped in side of try catch block, so whatever exception occurs, it will be caught and the exception will be passed back to the native C++ code.

In the native C++, we also have to add a new bridge class to access the .NET exception class.

When such exception bridge class returns from any call from .NET world, I would like to transfer the information to a native C++ exception, so that we will be able to use C++ try catch block as well. So I derived a new class from std::exception.

Now, we need to go back to the native C++ bridge class of Calculator. We will need to add additional code in case exception occurs in the call to .NET from native C++.

When we receive a .NET exception from a bridge call to .NET, we will re-throw a native C++ exception by wrapping the information inside so that we can access the information all the way passed from .NET when an exception is caught.

 

xInterop .NET Bridge: Creating a C++ native DLL bridging to C# managed assembly

Creating a C++ native bridge DLL calling into C# classes and methods in a managed assembly using xInterop .NET Bridge

Terminology

Before we start talking about the features of xInterop .NET Bridge can offer, we would like to explain the terminology of such a Bridge. There are different words which may be used to describe such a technology for accessing and calling the C# method from a native C++ application. C++ wrapper, C++ binding, C++ Bridge, you name it. Our bridge technology provides 2 way communication between C++ native world and the .NET managed world. A “Bridge” may better represent our technology and product, it creates wrapper or binding in both directions from C/C++ to .NET and from .NET to C/C++.

Overview

When we started design xInterop .NET Bridge, one of the important requirements is the process of creating the C++ Bridge must be automatic and very use-friendly to users/developers. For any existing .NET assembly, since the information of all classes is already embedded in the assembly as the metadata.

xInterop .NET Bridge is able to retrieve all the class information including methods, properties, fields, etc., analyze the metadata and then create a C++ DLL bridging to the .NET assembly by exporting all the corresponding C++ classes to the .NET classes in the managed world.

Once built, A C++ Bridge DLL automatically loads .NET run-time and the corresponding .NET assembly which it Bridges to. There is no method required to make that happen, it is all handled by xInterop .NET Bridge.

Let’s take an example of how we can create a C++ Bridge DLL allowing developers to call C# assembly from native C++.

Step 1, create a C# .NET library project called CalculatorDemo

The assembly contains a single class named Calculator whose implementation is shown below.

Build the C# project, we will have a CalculatorDemo.dll, a C# .NET assembly. Now let’s feed the .NET assembly to xInterop .NET Bridge.

Step 2, Create xInterop C++ Bridge to C# assembly

Right click on the menu of “Create New C++ Bridge Project…” and bring up the following window for further configuration.

  • .NET assembly

It is the path to the file of .NET assembly which shall be Bridged to the C++ native DLL.

  • Platform Toolset

It is the compiler and also targeting the C++ runtime, depending on the Visual Studio installed on the local machine, the following versions of Visual Studio are supported.

Visual Studio 2013

Visual Studio 2012

Visual Studio 2010

It will be possible to support Visual Studio 2008 and Visual Studio 2005, Since we are building new C++ DLL, developers may prefer to using newer version of Visual Studio compiler. So both of Visual Studio 2008 and 2005 are currently not supported.

  • CPU Architecture

Either x86 or x64 version of the C++ Bridge DLL can be created and built. When AnyCPU is used, both of DLLs shall be created.

  • Unicode

Unicode or ANSI, this defines the character encoding used in the C++ Bridge DLL, it is the same setting of a Visual Studio C++ project.

When using C++ smart pointers, any pointer of an instance will be wrapped in a C++ smart pointer, for capability with SWIG, shared_ptr is used for smart pointer. This is to make sure that any memory allocated when calling the .NET assembly get freed when they are going out of scope.

  • Undefine method name

A name of C# method, property, field may has conflict with existing C++ macro defined, “Undefine method name” can make sure the existing C++ macro undefine before defining the method using the same name.

  • Export interface

Any .NET interface can be Bridged to a C++ native DLL by creating a C++ Bridge class to wrap all the methods of any .NET interface. If such interfaces are not desired, they are not necessarily needed to be Bridged and exported since creating additional C++ Bridge class increases the size of the resulting C++ Bridge DLL.

  • Show build information

When the option is checked and enabled, there will be information printed out in the output window when the building process is going on.

  • Load .NET assembly automatically

The .NET assembly can be loaded by calling xiInitializeBridgeAssembly, it can also be loaded automatically when any of the C++ Bridge class is accessed. When this option is enabled, the .NET assembly must reside in the same directory when the C++ Bridge DLL is located.

  • Create testing application

For the convenience of setting up the C++ application along with the C# Bridge assembly, xInterop .NET Bridge creates a C++ console application(a visual studio solution) for testing when this option is enabled.

  • Number of iteration

There are lots of C# .NET classes referenced in a single .NET assembly directly or indirectly. Creating C++ Bridge classes for all the referenced .NET class is not necessary and it creates a C++ Bridge DLL with huge size. The number of iteration limits the loop which searches for .NET classes referenced by classes, methods, properties and fields. The default is 0 which means directly referenced by the .NET assembly.

  • Depth of base types

The .NET assembly contains classes defined in itself, it may also be derived from .NET classes defined in other assembly, such as the runtime, the depth of base types is to instruct how xInterop should create C++ Bridge class for those base classes. The default is zero, which means no C++ Bridge classes should be created for any of the base class. 1 means only the direct base class shall have a C++ Bridge class.

  • Output directory

This is the root directory where the C++ Bridge DLL project and the testing application project shall be created.

Once the C++ Bridge generating process is done. You should find very pleasant messages printed in the output window as shown below

Basically speaking, xInterop .NET Bridge creates a C# Bridge assembly project which builds a C# Bridge managed assembly. It also creates C++ Bridge native DLL with a header file so that the DLL can be referenced from your native C++ application. The C++ Bridge DLL access the original .NET assembly through the intermediate C# Bridge assembly. The C# Bridge assembly is a C# wrapper for the C++ Bridge DLL with additional features added.

The solution explorer contains the C# .NET Bridge assembly project which is the result of wrapping the C++ Bridge native DLL as shown in the screenshot below.

If you have selected “Create Testing Application”, you should be able simply open the directory where is the solution file is located by double-clicking the link.

Step 3, writing the C++ console testing application

It you open the TestApp.sln solution, there will be 2 projects shown up in the solution folder.

The TestApp is already set as the Startup application, it does not directly reference the C# Bridge assembly project because it can not. It does depend on the C# Bridge assembly project, and it will copy all the necessary DLL and assembly into it is $(Configuration) folder(Debug/Release) so that it can load the DLL/assembly at runtime.

If you open the TestApp.cpp, you will find all the header file and lib file are already included or linked programmatically.

Okay, both the C++ native DLL and the C# Bridge assembly are ready for use, we can now implement the C++ console application by simply adding a few lines.

And let’s look at how the C++ Calculator is defined in the header file of CalculatorDemoBridge.h.

As you can see, the C++ Bridge class of Calculator mimic the exact interface of the corresponding C# Calculator. The C++ Calculator is derived from NObject C++ class which represents the .NET System.Object class.

We have the declaration of the C++ NObject shown below.

You may have noticed that NObject implements all the methods of System.Object class except GetType method which will be implemented in a future version. The method of GetType may be useful when using .NET reflection from the native C++ application.

This is a very simple demonstration showing what xInterop .NET Bridge can offer. It only shows a little bit of the features of xInterop .NET Bridge. The little sample application is able to demonstrate how you can use xInterop .NET Bridge create the C++ Bridge DLL and the C# Bridge assembly.

In the future posts, we will describe more how this works and how you can create C++ Bridge native DLL for calling more complicated .NET assembly.

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.

Translate »