Quantcast
Channel: xInterop C++ .NET Bridge
Viewing all 31 articles
Browse latest View live

Introduction to C# PInvoke Interop SDK for C++ DLL

$
0
0

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.


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

$
0
0

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.

StdString (std::string)
StdStringBuf (std::stringbuf)
StdStringIterator (std::string::iterator)
StdStringReverseIterator (std::string::reverse_iterator)
StdStringConstIterator (std::string::const_iterator)
StdStringConstReverseIterator (std::string::const_reverse_iterator)
StdWString (std::wstring)
StdWStringBuf (std::wstringbuf)
StdWStringIterator (std::wstring::iterator)
StdWStringReverseIterator (std::wstring::reverse_iterator)
StdWStringConstIterator (std::wstring::const_iterator)
StdWStringConstReverseIterator (std::wstring::const_reverse_iterator)
StdIOSBase (std::ios_base)
StdIOS (std::ios)
StdIOStream (std::iostream)
StdStream (std::stream)
StdStreamBuf  (std::streambuf)
StdIStream  (std::istream)
StdOStream  (std::ostream)
StdStreamPos  (std::streampos)
StdIFStream  (std::ifstream)
StdOFStream  (std::ofstream)
StdFStream  (std::fstream)
StdFileBuf  (std::filebuf)
StdWIOS (std::wios)
StdWIOStream (std::wiostream)
StdWStream (std::wstream)
StdWStreamBuf  (std::wstreambuf)
StdWIStream  (std::wistream)
StdWOStream  (std::wostream)
StdWIFStream  (std::wifstream)
StdWOFStream  (std::wofstream)
StdWFStream  (std::wfstream)
StdWFileBuf  (std::wfilebuf)

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.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace NSpeech.Win32.StdLib
{
    public class StdString : StdLibExpressBaseClass
    {
        public StdString();
        public StdString(IntPtr handle);
        public StdString(StdString that);
        public StdString(string s);
        public StdString(StdString str, ulong pos);
        public StdString(StdStringCIterator first, StdStringCIterator last);
        public StdString(StdStringCRIterator first, StdStringCRIterator last);
        public StdString(string s, ulong n);
        public StdString(ulong n, char c);
        public StdString(IntPtr thisObject, IntPtr thatObject, bool initialize);
        public StdString(StdString str, ulong pos, ulong len);

        public static implicit operator string(StdString o);
        public static implicit operator StdString(string o);

        protected override int StorageSize { get; }
        public string TemplateClassName { get; }

        public char this[ulong index] { get; set; }

        public StdString append(StdString right);
        public StdString append(string ptr);
        public StdString append(StdStringCIterator first, StdStringCIterator last);
        public StdString append(StdStringCRIterator first, StdStringCRIterator last);
        public StdString append(string first, string last);
        public StdString append(string ptr, ulong count);
        public StdString append(ulong count, char ch);
        public StdString append(StdString right, ulong roff, ulong count);
        public StdString assign(StdString right);
        public StdString assign(string ptr);
        public StdString assign(StdStringCIterator first, StdStringCIterator last);
        public StdString assign(StdStringCRIterator first, StdStringCRIterator last);
        public StdString assign(string first, string last);
        public StdString assign(string ptr, ulong count);
        public StdString assign(ulong count, char ch);
        public StdString assign(StdString right, ulong roff, ulong count);
        public char at(ulong off);
        public char back();
        public StdStringCIterator begin();
        public string c_str();
        public ulong capacity();
        public StdStringCIterator cbegin();
        public StdStringCIterator cend();
        protected override void CleanupNativeResource();
        public void clear();
        public int compare(StdString right);
        public int compare(string ptr);
        public int compare(ulong off, ulong n0, StdString right);
        public int compare(ulong off, ulong n0, string ptr);
        public int compare(ulong off, ulong n0, string ptr, ulong count);
        public int compare(ulong off, ulong n0, StdString right, ulong roff, ulong count);
        public ulong copy(StringBuilder ptr, ulong count, ulong off);
        public StdStringCRIterator crbegin();
        public StdStringCRIterator crend();
        public string data();
        public bool empty();
        public StdStringCIterator end();
        public StdStringIterator erase(StdStringCIterator p);
        public StdStringIterator erase(StdStringCIterator first, StdStringCIterator last);
        public StdString erase(ulong off, ulong count);
        public ulong find(char ch, ulong off);
        public ulong find(StdString right, ulong off);
        public ulong find(string ptr, ulong off);
        public ulong find(string ptr, ulong off, ulong count);
        public ulong find_first_not_of(char ch, ulong off);
        public ulong find_first_not_of(StdString right, ulong off);
        public ulong find_first_not_of(string ptr, ulong off);
        public ulong find_first_not_of(string ptr, ulong off, ulong count);
        public ulong find_first_of(char ch, ulong off);
        public ulong find_first_of(StdString right, ulong off);
        public ulong find_first_of(string ptr, ulong off);
        public ulong find_first_of(string ptr, ulong off, ulong count);
        public ulong find_last_not_of(char ch, ulong off);
        public ulong find_last_not_of(StdString right, ulong off);
        public ulong find_last_not_of(string ptr, ulong off);
        public ulong find_last_not_of(string ptr, ulong off, ulong count);
        public ulong find_last_of(char ch, ulong off);
        public ulong find_last_of(StdString right, ulong off);
        public ulong find_last_of(string ptr, ulong off);
        public ulong find_last_of(string ptr, ulong off, ulong count);
        public char front();
        public StdStringIterator insert(StdStringCIterator where);
        public StdStringIterator insert(StdStringCIterator p, char c);
        public StdString insert(ulong off, StdString right);
        public StdString insert(ulong off, string ptr);
        public void insert(StdStringCIterator p, StdStringCIterator first, StdStringCIterator last);
        public void insert(StdStringCIterator p, StdStringCRIterator first, StdStringCRIterator last);
        public void insert(StdStringCIterator where, string first, string last);
        public void insert(StdStringCIterator p, ulong n, char c);
        public StdString insert(ulong off, string ptr, ulong count);
        public StdString insert(ulong off, ulong count, char ch);
        public StdString insert(ulong off, StdString right, ulong roff, ulong count);
        public ulong length();
        public ulong max_size();
        protected IntPtr operator_get_set(ulong off);
        public StdString operator_plus_equal(char ch);
        public StdString operator_plus_equal(StdString right);
        public StdString operator_plus_equal(string ptr);
        public void pop_back();
        public void push_back(char ch);
        public StdStringCRIterator rbegin();
        public StdStringCRIterator rend();
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, StdString str);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, string s);
        public StdString replace(ulong off, ulong n0, StdString right);
        public StdString replace(ulong off, ulong n0, string ptr);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, StdStringCIterator first, StdStringCIterator last);
        public StdString replace(StdStringCIterator first, StdStringCIterator last, string first2, string last2);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, string s, ulong n);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, ulong n, char c);
        public StdString replace(ulong off, ulong n0, string ptr, ulong count);
        public StdString replace(ulong off, ulong n0, ulong count, char ch);
        public StdString replace(ulong off, ulong n0, StdString right, ulong roff, ulong count);
        public void reserve(ulong newcap);
        public void resize(ulong newsize);
        public void resize(ulong newsize, char ch);
        public ulong rfind(char ch, ulong off);
        public ulong rfind(StdString right, ulong off);
        public ulong rfind(string ptr, ulong off);
        public ulong rfind(string ptr, ulong off, ulong count);
        public void shrink_to_fit();
        public ulong size();
        public StdString substr(ulong off, ulong count);
        public void swap(StdString right);
        public override string ToString();

        public class Marshaller : ICustomMarshaler
        {
            public Marshaller();

            public void CleanUpManagedData(object ManagedObj);
            public void CleanUpNativeData(IntPtr pNativeData);
            public static ICustomMarshaler GetInstance(string pstrCookie);
            public int GetNativeDataSize();
            public IntPtr MarshalManagedToNative(object ManagedObj);
            public object MarshalNativeToManaged(IntPtr pNativeData);
        }
    }
}

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.

void __stdcall GetMyMessage(std::string& message)
{
    message = "A message sent from native 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,

// std::string& can be marshalled as IntPtr since StdString has conversion 
// operator defined.
[DllImport("Sample.dll", CallingConvention=CallingConvention.StdCall)]
public extern static void GetMyMessage(IntPtr message);

// You can also define the P/Invoke alternatively as following since the class has
// a custom marshaller.
[DllImport("Sample.dll", CallingConvention=CallingConvention.StdCall)]
public extern static void GetMyMessage([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(StdString.Marshaller))] StdString message);

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.

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

$
0
0

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.

StdStringVector      (std::vector<std::string>)
StdWStringVector      (std::vector<std::wstring>)
StdCharVector      (std::vector<char>)
StdWCharVector      (std::vector<wchar_t>)
StdShortVector      (std::vector<short>)
StdIntVector      (std::vector<int>)
StdLongVector      (std::vector<long>)
StdDoubleVector      (std::vector<double>)
StdFloatVector      (std::vector<float>)

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.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;

namespace NSpeech.Win32.StdLib
{
    public class StdStringVector : StdLibExpressBaseClass, IEnumerable<string>, IEnumerable
    {
        public StdStringVector();
        public StdStringVector(IntPtr handle = null);
        public StdStringVector(long count);
        public StdStringVector(StdStringVector that);
        public StdStringVector(StdStringVectorStructX86 objectStruct);
        public StdStringVector(string[] source);
        public StdStringVector(long count, StdString val);
        public StdStringVector(IntPtr thisObject, IntPtr thatObject, bool initialize);
        public StdStringVector(long count, StdString val, IntPtr al);

        public static implicit operator StdStringVectorStructX86(StdStringVector o);
        public static implicit operator string[](StdStringVector o);
        public static implicit operator StdStringVectorStructX64(StdStringVector o);

        protected override int StorageSize { get; }
        public string TemplateClassName { get; }

        public StdString this[long index] { get; set; }

        public StdStringVector Assign(StdStringVector thatObject);
        public void assign(long count, StdString val);
        public void assign(StdStringVectorConstIterator first, StdStringVectorConstIterator last);
        public void assign(StdStringVectorConstReverseIterator first, StdStringVectorConstReverseIterator last);
        public StdString at(long pos);
        public StdString back();
        public StdStringVectorConstIterator begin();
        public long capacity();
        public StdStringVectorConstIterator cbegin();
        public StdStringVectorConstIterator cend();
        protected override void CleanupNativeResource();
        public void clear();
        public StdStringVectorConstReverseIterator crbegin();
        public StdStringVectorConstReverseIterator crend();
        public StdString data();
        public void emplace_back(StdString val);
        public bool empty();
        public StdStringVectorConstIterator end();
        public StdStringVectorIterator erase(StdStringVectorConstIterator position);
        public StdStringVectorIterator erase(StdStringVectorConstIterator first, StdStringVectorConstIterator last);
        public StdString front();
        public IEnumerator<string> GetEnumerator();
        public StdStringVectorIterator insert(StdStringVectorConstIterator where, StdString val);
        public void insert(StdStringVectorConstIterator where, long count, StdString val);
        public void insert(StdStringVectorConstIterator position, StdStringVectorConstIterator first, StdStringVectorConstIterator last);
        public void insert(StdStringVectorConstIterator position, StdStringVectorConstReverseIterator first, StdStringVectorConstReverseIterator last);
        public long max_size();
        protected IntPtr operator_get_set(long pos);
        public void pop_back();
        public void push_back(StdString val);
        public StdStringVectorConstReverseIterator rbegin();
        public StdStringVectorConstReverseIterator rend();
        public void reserve(long count);
        public void resize(long newsize);
        public void resize(long newsize, StdString val);
        public void shrink_to_fit();
        public long size();
        public void swap(StdStringVector right);
        public string[] ToArray();

        public class Marshaller : ICustomMarshaler
        {
            public Marshaller();

            public void CleanUpManagedData(object ManagedObj);
            public void CleanUpNativeData(IntPtr pNativeData);
            public static ICustomMarshaler GetInstance(string pstrCookie);
            public int GetNativeDataSize();
            public IntPtr MarshalManagedToNative(object ManagedObj);
            public object MarshalNativeToManaged(IntPtr pNativeData);
        }
    }
}

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.

void __stdcall SetVector(std::vector<std::string>& myVector)
{
    // ...
}

// or using a pointer

void __stdcall SetVector(std::vector<std::string>* myVector)
{
    // ...
}

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.

// std::vector<std::string>& can be marshalled as IntPtr since StdStringVector has conversion operator defined.
[DllImport("Sample.dll", CallingConvention=CallingConvention.StdCall)]
public extern static void SetVector(IntPtr myVector);

// You can also define the P/Invoke alternatively as following since 
// StdStringVector class has a custom marshaller.
[DllImport("Sample.dll", CallingConvention=CallingConvention.StdCall)]
public extern static void SetVector([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(StdStringVector.Marshaller))] StdStringVector myVector);

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.

// vector be the C++ object retrieved from a C/C++ method call, it is not
// necessary that it gets created from C#.
StdStringVector vector = new StdStringVector();
vector.push_back("String #1");
vector.push_back("String #2");
vector.push_back("String #3");
vector.push_back("String #4");
vector.push_back("String #5");
vector.push_back("String #6");
for (var iter = vector.begin(); iter < vector.end(); iter++)
{
    Console.WriteLine(iter.current());
}

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.

// Lets create an array of string.
List<string> list = new List<string>();
list.Add("String #1");
list.Add("String #2");
list.Add("String #3");
list.Add("String #4");
list.Add("String #5");
list.Add("String #6");
StdStringVector vector = new StdStringVector(list.ToArray());

// Now the vector can be passed to C/C++ DLL.
SetVector(vector);

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.

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

$
0
0

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.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

namespace NSpeech.Win32.StdLib
{
    public class StdString : StdLibExpressBaseClass
    {
        public StdString();
        public StdString(IntPtr handle);
        public StdString(StdString that);
        public StdString(string s);
        public StdString(StdString str, ulong pos);
        public StdString(StdStringCIterator first, StdStringCIterator last);
        public StdString(StdStringCRIterator first, StdStringCRIterator last);
        public StdString(string s, ulong n);
        public StdString(ulong n, char c);
        public StdString(IntPtr thisObject, IntPtr thatObject, bool initialize);
        public StdString(StdString str, ulong pos, ulong len);

        public static implicit operator string(StdString o);
        public static implicit operator StdString(string o);

        protected override int StorageSize { get; }
        public string TemplateClassName { get; }

        public char this[ulong index] { get; set; }

        public StdString append(StdString right);
        public StdString append(string ptr);
        public StdString append(StdStringCIterator first, StdStringCIterator last);
        public StdString append(StdStringCRIterator first, StdStringCRIterator last);
        public StdString append(string first, string last);
        public StdString append(string ptr, ulong count);
        public StdString append(ulong count, char ch);
        public StdString append(StdString right, ulong roff, ulong count);
        public StdString assign(StdString right);
        public StdString assign(string ptr);
        public StdString assign(StdStringCIterator first, StdStringCIterator last);
        public StdString assign(StdStringCRIterator first, StdStringCRIterator last);
        public StdString assign(string first, string last);
        public StdString assign(string ptr, ulong count);
        public StdString assign(ulong count, char ch);
        public StdString assign(StdString right, ulong roff, ulong count);
        public char at(ulong off);
        public char back();
        public StdStringCIterator begin();
        public string c_str();
        public ulong capacity();
        public StdStringCIterator cbegin();
        public StdStringCIterator cend();
        protected override void CleanupNativeResource();
        public void clear();
        public int compare(StdString right);
        public int compare(string ptr);
        public int compare(ulong off, ulong n0, StdString right);
        public int compare(ulong off, ulong n0, string ptr);
        public int compare(ulong off, ulong n0, string ptr, ulong count);
        public int compare(ulong off, ulong n0, StdString right, ulong roff, ulong count);
        public ulong copy(StringBuilder ptr, ulong count, ulong off);
        public StdStringCRIterator crbegin();
        public StdStringCRIterator crend();
        public string data();
        public bool empty();
        public StdStringCIterator end();
        public StdStringIterator erase(StdStringCIterator p);
        public StdStringIterator erase(StdStringCIterator first, StdStringCIterator last);
        public StdString erase(ulong off, ulong count);
        public ulong find(char ch, ulong off);
        public ulong find(StdString right, ulong off);
        public ulong find(string ptr, ulong off);
        public ulong find(string ptr, ulong off, ulong count);
        public ulong find_first_not_of(char ch, ulong off);
        public ulong find_first_not_of(StdString right, ulong off);
        public ulong find_first_not_of(string ptr, ulong off);
        public ulong find_first_not_of(string ptr, ulong off, ulong count);
        public ulong find_first_of(char ch, ulong off);
        public ulong find_first_of(StdString right, ulong off);
        public ulong find_first_of(string ptr, ulong off);
        public ulong find_first_of(string ptr, ulong off, ulong count);
        public ulong find_last_not_of(char ch, ulong off);
        public ulong find_last_not_of(StdString right, ulong off);
        public ulong find_last_not_of(string ptr, ulong off);
        public ulong find_last_not_of(string ptr, ulong off, ulong count);
        public ulong find_last_of(char ch, ulong off);
        public ulong find_last_of(StdString right, ulong off);
        public ulong find_last_of(string ptr, ulong off);
        public ulong find_last_of(string ptr, ulong off, ulong count);
        public char front();
        public StdStringIterator insert(StdStringCIterator where);
        public StdStringIterator insert(StdStringCIterator p, char c);
        public StdString insert(ulong off, StdString right);
        public StdString insert(ulong off, string ptr);
        public void insert(StdStringCIterator p, StdStringCIterator first, StdStringCIterator last);
        public void insert(StdStringCIterator p, StdStringCRIterator first, StdStringCRIterator last);
        public void insert(StdStringCIterator where, string first, string last);
        public void insert(StdStringCIterator p, ulong n, char c);
        public StdString insert(ulong off, string ptr, ulong count);
        public StdString insert(ulong off, ulong count, char ch);
        public StdString insert(ulong off, StdString right, ulong roff, ulong count);
        public ulong length();
        public ulong max_size();
        protected IntPtr operator_get_set(ulong off);
        public StdString operator_plus_equal(char ch);
        public StdString operator_plus_equal(StdString right);
        public StdString operator_plus_equal(string ptr);
        public void pop_back();
        public void push_back(char ch);
        public StdStringCRIterator rbegin();
        public StdStringCRIterator rend();
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, StdString str);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, string s);
        public StdString replace(ulong off, ulong n0, StdString right);
        public StdString replace(ulong off, ulong n0, string ptr);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, StdStringCIterator first, StdStringCIterator last);
        public StdString replace(StdStringCIterator first, StdStringCIterator last, string first2, string last2);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, string s, ulong n);
        public StdString replace(StdStringCIterator i1, StdStringCIterator i2, ulong n, char c);
        public StdString replace(ulong off, ulong n0, string ptr, ulong count);
        public StdString replace(ulong off, ulong n0, ulong count, char ch);
        public StdString replace(ulong off, ulong n0, StdString right, ulong roff, ulong count);
        public void reserve(ulong newcap);
        public void resize(ulong newsize);
        public void resize(ulong newsize, char ch);
        public ulong rfind(char ch, ulong off);
        public ulong rfind(StdString right, ulong off);
        public ulong rfind(string ptr, ulong off);
        public ulong rfind(string ptr, ulong off, ulong count);
        public void shrink_to_fit();
        public ulong size();
        public StdString substr(ulong off, ulong count);
        public void swap(StdString right);
        public override string ToString();

        public class Marshaller : ICustomMarshaler
        {
            public Marshaller();

            public void CleanUpManagedData(object ManagedObj);
            public void CleanUpNativeData(IntPtr pNativeData);
            public static ICustomMarshaler GetInstance(string pstrCookie);
            public int GetNativeDataSize();
            public IntPtr MarshalManagedToNative(object ManagedObj);
            public object MarshalNativeToManaged(IntPtr pNativeData);
        }
    }
}

 

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.

#include <string>

extern "C" __declspec(dllexport) std::string Encrypt(const std::string& s)
{
    // It is an example, it does not really encrypt anything for the std::string of s.
    return s;
}

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

// Let's just marshal everything to pointer using IntPtr, to C#, they are really just 
// memory pointer no matter whey they represent in native C++.
[DllImport("SampleDll.DLL")]
public static IntPtr Encrypt(IntPtr text);

// Calling the method
string text = "My Text";
// A returned IntPtr can be used to construct a StdString and then a 
// C# string.
string encryptedText = new StdString(Encrypt(new StdString(text));

Marsahl std::string to StdString

// Let's marshal std::string to StdString which can be converted to and converted// from a C# string implicitly
[DllImport("SampleDll.DLL")]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StdStringVector.Marshaller))]
public static StdString Encrypt([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StdStringVector.Marshaller))] StdString text);

// Calling the method
string text = "My Text";
// A C# string can be converted to StdString implicitly.
// A StdString can be converted to C# string implicitly.
string encryptedText = Encrypt(text);

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.

 

 

 

C# vs C++/CLI vs PInvoke Performance – Part I

$
0
0

C++/CLI vs Explicit PInvoke Performance – Part I

When I have a C++ DLL with a bunch of C++ classes and I would want to pinvoke those C++ classes from C#, I have two choices, either using C++/CLI to write a managed wrapper or using our C# wrapper generator to generate a managed C# wrapper of the native C++ DLL. I will create both of the wrappers today.

There is actually a false assumption all over the web which assumes that calling into native C++ DLL from C# via C++/CLI wrapper is faster than simply explicitly pinvoking the C++ DLL. That assumption is wrong and explicit pinvoke actually performs better than C++/CLI when C++/CLI is used to write a managed wrapper of C++ DLL, which is used from .NET. I am going to write a few blogs to talk about the performance difference of C++/CLI wapper and the C# wrapper via explicit PInvoke generated by our PInvoke Interop SDK tools.

This is the first part of my blog comparing C++/CLI to the C# wrapper generated by our C# wrapper generator for C++ DLL.

Let’s write a C++ class with 2 methods we will call from C# via different wrappers. We are going to use a sqrt method in C++ DLL, in this example, the parameter is simple and the type is blittable type and no marshal is needed from C# to the native dll.

#ifdef LIBCALCULATOR_EXPORTS
#define LIBCALCULATOR_API __declspec(dllexport)
#else
#define LIBCALCULATOR_API __declspec(dllimport)
#endif

public LIBCALCULATOR_API Calculator
{
public:
    Calculator() {};
    ~Calculator {};

    float sqrt(float x)
    {
        return ::sqrt(x);
    };

    double sqrt(double x)
    {
        return ::sqrt(x);
    };
};

The implementation of a managed C++/CLI wrapper for native C++ DLL is very simple for our example although it will become very tedious and time-consuming if you want to wrap a large scale of exported C++ classes in a C++ DLL, such as type marshaling and maintaining all the method signatures, but that is a different story, we may would want to talk about this in the future.

#pragma once

#include "Calculator.h"
#include "msclr\marshal_cppstd.h"

using namespace System;
using namespace Runtime::InteropServices;
using namespace msclr::interop;

namespace CalculatorManagedWrapper 
{
    public ref class ManagedCalculator
    {
        Calculator* cal;

     public:
        ManagedCalculator()
        {
            cal = new Calculator();
        }

        ~ManagedCalculator()
        {
            delete cal;
        }

        float sqrt(float x)
        {
            return cal->sqrt(x);
        }

        double sqrt(double x)
        {
            return cal->sqrt(x);
        }
    }
}

Now, I will present the C# class for testing the wrapper, I also wrote a managed C# sqrt for comparison.

namespace NSpeech.Win32.NLibCalculator.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NSpeech.Win32.StdLib;
    using NSpeech.Win32.NLibCalculator;
    using System.Runtime.InteropServices;
    using CalculatorManagedWrapper;

    public class SqrtFloatTestClass
    {
        public static void Test(int testCount, int iterationCount)
        {            
            double timeUsed1 = 0, timeUsed2 = 0, timeUsed3 = 0, timeUsed4 = 0;            
            for (int i = 0; i < testCount; i++)
            {                
                float result;
                Console.WriteLine("Testing float sqrt(float) of C#");
                result = CSharpSqrt(iterationCount, ref timeUsed1);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float sqrt(float) of Managed C++ Wrapper.");
                result = ManagedCppWrapper_Sqrt(iterationCount, ref timeUsed2);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float sqrt(float) of C# Wrapper");
                result = CSharpWrapper_Sqrt(iterationCount, ref timeUsed3);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float sqrt(float) of C# Wrapper with Direct Call.");
                result = CSharpWrapperDirectCall_Sqrt(iterationCount, ref timeUsed4);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("=================================================================================");
                Console.WriteLine("C# Sqrt -  Average Time used:                              {0}ms", timeUsed1 / (i + 1));
                Console.WriteLine("Managed C++ Wrapper Sqrt- Average Time used:               {0}ms", timeUsed2 / (i + 1));
                Console.WriteLine("PInvoke Wrapper - Average Time used:                       {0}ms", timeUsed3 / (i + 1));
                Console.WriteLine("PInvoke Wrapper Direct Call - Average Time used:           {0}ms", timeUsed4 / (i + 1));                
                Console.WriteLine("=================================================================================");

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("=========================Final Result of float sqrt(float)=============================");
            Console.WriteLine();
            Console.WriteLine("Total Iteration: {0}", iterationCount);
            Console.WriteLine();
            Console.WriteLine("Method of float sqrt(float)                                  Time             Percentage");
            Console.WriteLine();
            Console.WriteLine("C# Managed sqrt                                              {0} ms           1.0", (timeUsed1 / testCount).ToString("00.000"));
            Console.WriteLine("C++ PInvoke, Managed Wrapper of Native sqrt                  {0} ms           {1}", (timeUsed2 / testCount).ToString("00.000"), (timeUsed2 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper of Native sqrt                   {0} ms           {1}", (timeUsed3 / testCount).ToString("00.000"), (timeUsed3 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper with Direct Call of Native sqrt  {0} ms           {1}", (timeUsed4 / testCount).ToString("00.000"), (timeUsed4 / timeUsed1).ToString("0.000"));
            Console.WriteLine();
            Console.WriteLine("=======================================================================================");
        }

        static float CSharpSqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                result = Sqrt(value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float ManagedCppWrapper_Sqrt(int count, ref double timeUsed)
        {            
            DateTime start = DateTime.Now;
            var cal = new ManagedCalculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                result = cal.sqrt(value + result);
            }

            DateTime end = DateTime.Now;            
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float CSharpWrapper_Sqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                result = cal.sqrt(value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float CSharpWrapperDirectCall_Sqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                result = LibCalculatorWin32.Calculator_sqrt(cal.ptrObject, value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float Sqrt(float x)
        {
            return (float)Math.Sqrt(x);
        }        
    }
}

Here is the result for calling float sqrt(float) from C# via all different kinds of wrappers.

The C# version did not perform much faster than the explicit Pinvoke C# wrapper whose method call is made directly on the PInvoke method without going through the C# wrapper class of Calculator. That is because the C# version of Math.Sqrt accepts a double parameter while we passed float type, type conversion happens when we call Sqrt, type conversion happens again when we get back the return value of double.

Calling sqrt directly via the pinvoke method is faster than calling sqrt method of the C# wrapper class of Calculator because there is less stack push and pop.

The C++/CLI wrapper presents the worst performance. I was not surprised because C++/CLI wrapper adds additional layer to make the call and the underlying mechanism of calling into the C++ DLL is still the same, P/Invoke, it is implicit though.

Here is testing class for double version of sqrt and its result for the method of double sqrt(double x).

namespace NSpeech.Win32.NLibCalculator.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NSpeech.Win32.StdLib;
    using NSpeech.Win32.NLibCalculator;
    using System.Runtime.InteropServices;
    using CalculatorManagedWrapper;

    public class SqrtDoubleTestClass
    {
        public static void Test(int testCount, int iterationCount)
        {
            double timeUsed1 = 0, timeUsed2 = 0, timeUsed3 = 0, timeUsed4 = 0;
            int i = 0;
            for (; i < testCount; i++)
            {
                double result;
                Console.WriteLine("Testing double sqrt(double) of C#");
                result = CSharpSqrt(iterationCount, ref timeUsed1);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double sqrt(double) of Managed C++ Wrapper.");
                result = ManagedCppWrapper_Sqrt(iterationCount, ref timeUsed2);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double sqrt(double) of C# Wrapper");
                result = CSharpWrapper_Sqrt(iterationCount, ref timeUsed3);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double sqrt(double) of C# Wrapper with Direct Call.");
                result = CSharpWrapperDirectCall_Sqrt(iterationCount, ref timeUsed4);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("=================================================================================");
                Console.WriteLine("C# Sqrt -  Average Time used:                              {0}ms", timeUsed1 / (i + 1));
                Console.WriteLine("Managed C++ Wrapper Sqrt- Average Time used:               {0}ms", timeUsed2 / (i + 1));
                Console.WriteLine("PInvoke Wrapper - Average Time used:                       {0}ms", timeUsed3 / (i + 1));
                Console.WriteLine("PInvoke Wrapper Direct Call - Average Time used:           {0}ms", timeUsed4 / (i + 1));
                Console.WriteLine("=================================================================================");

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("=========================Final Result of double sqrt(double)============================");
            Console.WriteLine();
            Console.WriteLine("Total Iteration: {0}", iterationCount);
            Console.WriteLine();
            Console.WriteLine("Method of double sqrt(double)                                Time             Percentage");
            Console.WriteLine();
            Console.WriteLine("C# Managed sqrt                                              {0} ms           1.0", (timeUsed1 / testCount).ToString("00.000"));
            Console.WriteLine("C++ PInvoke, Managed Wrapper of Native sqrt                  {0} ms           {1}", (timeUsed2 / testCount).ToString("00.000"), (timeUsed2 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper of Native sqrt                   {0} ms           {1}", (timeUsed3 / testCount).ToString("00.000"), (timeUsed3 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper with Direct Call of Native sqrt  {0} ms           {1}", (timeUsed4 / testCount).ToString("00.000"), (timeUsed4 / timeUsed1).ToString("0.000"));
            Console.WriteLine();
            Console.WriteLine("========================================================================================");
        }

        static double ManagedCppWrapper_Sqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new ManagedCalculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                result = cal.sqrt(value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double CSharpWrapper_Sqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                result = cal.sqrt(value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double CSharpWrapperDirectCall_Sqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                result = LibCalculatorWin32.Calculator_sqrt(cal.CppPointer, value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double CSharpSqrt(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                result = Sqrt(value + result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double Sqrt(double x)
        {
            return Math.Sqrt(x);
        }       
    }
}

The result of C++/CLI, PInvoke Performance

This time, the C# managed sqrt performs better than the float version because it does not need to convert the input parameter and convert back the return value any more,  and conversion back and forth does take time.

And, unfortunately, the C++/CLI wrapper is again the worst performer.

To be fair to C++/CLI, I would mention that the

[SuppressUnmanagedCodeSecurity]

was added to the PInvoke declaration when building the C# Wrapper for the native C++ DLL.

[SuppressUnmanagedCodeSecurity]
[DllImport("LibCalculator.dll", EntryPoint="#28", CallingConvention=CallingConvention.ThisCall)]
public extern static float Calculator_sqrt(IntPtr thisObject, float x);

[SuppressUnmanagedCodeSecurity]
[DllImport("LibCalculator.dll", EntryPoint="#29", CallingConvention=CallingConvention.ThisCall)]
public extern static double Calculator_sqrt(IntPtr thisObject, double x);

Stay tuned for the second part of the blog of C++/CLI vs PInvoke Performance.

C# vs C++/CLI vs PInvoke Performance – Part II

$
0
0

C++/CLI vs Explicit PInvoke Performance – Part II

Today, I am going to continue the comparison of C++/CLI vs Explict PInvoke performance. It is the second part of the blog, you may want to read the first part if you have not already.

string or String is commonly used in .NET, if you know nothing about C++/CLI, you would expect it to be able to convert or marshal a .NET string to c string such as char* transparently with no data copy at all, but you will be disappointed to see the a different way of how C++/CLI actually bridges string between managed world and the native world. We will be talking about this later.

In order to test the performance of using the C++/CLI managed wrapper and a C# wrapper generated by our .NET PInvoke Interop SDK – A C# Wrapper Generator for C++ DLL, we will need to create a C++ class inside a native C++ DLL. We are going to use a sample C++ DLL from now on. We are going to write a single method IndexOf in a C++ class named StringHelper, the method is used to find the index of a key string in a value string. Here is the implementation of the C++ class.

#ifndef __STRING_HELPER_H__
#define __STRING_HELPER_H__

#pragma once

#include <string>

class SAMPLE_API StringHelper
{

public:

	StringHelper() {};

	~StringHelper() {};

	int IndexOf(const char* szValue, const char* szKey)
	{
		if (szValue == NULL || szKey == NULL)
			return -1;

		const char* p = strstr(szValue, szKey);
		if (p != NULL)
		{
			return (int)(p - szValue);
		}
		else
		{
			return -1;
		}
	};
};

#endif

In the preceding example of IndexOf method, we used strstr to find the pointer of the key string value, we did not use std::string::find method to find the index of the key string because std::string:find is far less efficient than strstr, and then it would undermine the efficiency of the Explicit P/Invoke when we do the performance comparison of C++/CLI vs Explicit P/Invoke.

Once again, let’s write the C++/CLI wrapper class first, it is a simple one because we have only one class with one method we will be using, if there are many of them, it is tedious, time-consuming, hard-to-maintain, because everything you want from the original C++ class, you will need to wrap them in C++/CLI, it has no such intelligence allowing you to automatically find the methods and wrap them for you.

#pragma once

#include "StringHelper.h"

#include "msclr\marshal_cppstd.h"

using namespace System;
using namespace Runtime::InteropServices;
using namespace msclr::interop;

namespace SampleManagedWrapper {

	public ref class ManagedStringHelper
	{
		StringHelper* pStringHelper;

	public:

		ManagedStringHelper()
		{
			pStringHelper = new StringHelper();
		}

		~ManagedStringHelper()
		{
			delete pStringHelper;
		}

		int IndexOf(String^ value, String^ key)
		{
			marshal_context context;
			return pStringHelper->IndexOf(context.marshal_as<const char*>(value), context.marshal_as<const char*>(key));
		}
	};
}

Remember I stated that the string conversion is not transparent, you would have to manually convert the .NET string to C++ const char*, which is being shown in the preceding code. That is where it performs so much worse than Explicit P/Invoke, I will show you the result later. In order to use a string parameter in C++/CLI to call into the native C++ DLL, we are responsible for converting it to const char* by using a class called marshal_context, I appreciate such a type conversion class is provided by C++/CLI, the issue with this kind of type conversion is it slows down the whole process of calling the native C++ classes, which makes me unwilling to use C++/CLI, not mentioning that I still get to maintain the code whenever I change the pubic interfaces of my C++ classes.

It took me only less than 5 seconds to use our PInvoke Interop SDK Tools to generate a C# wrapper for the sample C++ DLL. A new class named StringHelper is ready for me to use in C# code. I will show you the P/Invoke signature and the wrapper code.

[SuppressUnmanagedCodeSecurity]
[DllImport("Sample.dll", EntryPoint="#29", CallingConvention=CallingConvention.ThisCall)]
public extern static int StringHelper_IndexOf(IntPtr thisObject, string szValue, string szKey);

public int IndexOf(string szValue, string szKey)
{
    // this.ptrObject is the C++ pointer pointing to the C++ object.
    return StringHelper_IndexOf(this.ptrObject, szValue, szKey);
}

Now, let’s write the C# code to test the performance of C++/CLI and Explicit PInvoke. I would also want to know the performance difference of the C# wrapper for the native version of IndexOf and the C# version of String.IndexOf. Here is the complete test class.

using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NSpeech.Win32.StdLib;
    using NSpeech.Win32.NLibCalculator;
    using System.Runtime.InteropServices;
    using SampleManagedWrapper;

    public class StringHelperTestClass
    {
        public static void Test(int testCount, int iterationCount)
        {
            double timeUsed1 = 0, timeUsed2 = 0, timeUsed3 = 0, timeUsed4 = 0;
            for (int i = 0; i < testCount; i++)
            {
                int result;
                Console.WriteLine("Testing int IndexOf(string, string) of C#");
                result = CSharp_IndexOf(iterationCount, ref timeUsed1);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing int IndexOf(string, string) of Managed C++ Wrapper.");
                result = ManagedCppWrapper_IndexOf(iterationCount, ref timeUsed2);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing int IndexOf(string, string) of C# Wrapper");
                result = CSharpWrapper_IndexOf(iterationCount, ref timeUsed3);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing int IndexOf(string, string) of C# Wrapper with Direct Call.");
                result = CSharpWrapperDirectCall_IndexOf(iterationCount, ref timeUsed4);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("=================================================================================");
                Console.WriteLine("C# -  Average Time used:                              {0}ms", timeUsed1 / (i + 1));
                Console.WriteLine("Managed C++ Wrapper - Average Time used:              {0}ms", timeUsed2 / (i + 1));
                Console.WriteLine("PInvoke Wrapper - Average Time used:                  {0}ms", timeUsed3 / (i + 1));
                Console.WriteLine("PInvoke Wrapper Direct Call - Average Time used:      {0}ms", timeUsed4 / (i + 1));
                Console.WriteLine("=================================================================================");

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("=========================Final Result of int IndexOf(string, string)=============================");
            Console.WriteLine();
            Console.WriteLine("Total Iteration: {0}", iterationCount);
            Console.WriteLine();
            Console.WriteLine("Method of int IndexOf(string, string)                    Time         Percentage");
            Console.WriteLine();
            Console.WriteLine("C# Manged Implementation                                 {0} ms       1.0", (timeUsed1 / testCount).ToString("000.000"));
            Console.WriteLine("C++ PInvoke, Managed Wrapper                             {0} ms       {1}", (timeUsed2 / testCount).ToString("000.000"), (timeUsed2 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper                              {0} ms       {1}", (timeUsed3 / testCount).ToString("000.000"), (timeUsed3 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper with Direct Call             {0} ms       {1}", (timeUsed4 / testCount).ToString("000.000"), (timeUsed4 / timeUsed1).ToString("0.000"));
            Console.WriteLine();
            Console.WriteLine("=======================================================================================");
        }

        static int CSharp_IndexOf(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;                        
            string value = "123456789099765432112334567789899765655444";
            int result = 0;
            for (int i = 0; i < count; i++)
            {
                result += value.IndexOf(i.ToString());
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static int ManagedCppWrapper_IndexOf(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var stringHelper = new ManagedStringHelper();
            string value = "123456789099765432112334567789899765655444";
            int result = 0;
            for (int i = 0; i < count; i++)
            {                
                result += stringHelper.IndexOf(value, i.ToString());
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static int CSharpWrapper_IndexOf(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var stringHelper = new StringHelper();
            string value = "123456789099765432112334567789899765655444";
            int result = 0;
            for (int i = 0; i < count; i++)
            {
                result += stringHelper.IndexOf(value, i.ToString());
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static int CSharpWrapperDirectCall_IndexOf(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var stringHelper = new StringHelper();
            string value = "123456789099765432112334567789899765655444";
            int result = 0;
            for (int i = 0; i < count; i++)
            {                
                result += LibCalculatorWin32.StringHelper_IndexOf(stringHelper.ptrObject, value, i.ToString());
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }
    }

I was surprised to see the testing result, i ran the testing program a few times with different iteration numbers, but they all gave me similar result. Just like what you can see the following picture, the wrapper class generated by our PInvoke Interop SDK performs very close to the C# version of String.IndexOf.

The C# wrapper generated by our PInvoke Interop SDK Tools is 3 times faster than C++/CLI wrapper, it is so close to the C# version of String.IndexOf. From my experience of working with so many C++ DLL, I would say there is not much string copy at all when passing a string value to C++ DLL using Explicit P/Invoke when the C++ method accepts char* as parameter, I don’t know the details of .NET implementation though.

C++/CLI wrapper is once again the worst performer when passing string(char* type) from C# to the C++ DLL.

Stay tuned, we will be comparing the performance when using std::string in the C++ class next time. I hope the C++/CLI wrapper for C++ DLL could perform better.

 

C# vs C++/CLI vs PInvoke Performance – Part III

$
0
0

I have demonstrated that C++/CLI vs P/Invoke Performance difference in Part I by using all different wrappers to pinvoke C++ method of sqrt of a native C++ DLL. Since I already included C# version of sqrt in the comparison, I will include comparison of C# version of any native c++ method I used in the future blogs, I will try to optimize every piece of C#, C++ and C++/CLI code as possible as I can, otherwise, it won’t be accurate at all. The C# wrapper used to pinvoke C++ DLL was generated by our PInvoke Interop SDK – A C# Wrapper Generator for C++ DLL.

I added the following methods to the original C++ Calculator class. I choose a simplified implementation(it could overflow depending on the parameters passed in) of hypot because the implementation itself is not that important to our test.

float hypot(float x, float y)
{
	return ::sqrt(x * x + y * y);
}

double hypot(double x, double y)
{
	return ::sqrt(x * x + y * y);
}

When I built the C++ native DLL, I tried to optimize it as possible as I can, So I optimized the dll build for maximize speed and favor fast code.

And I also enabled SIMD Extensions 2, I tried and it did show it improved the performance.

C++/CLI wrapper code is still very simple, but I had to write the method signature one more time. This is why I do not prefer C++/CLI, I have to repeat every method signature I define in the C++ class even it does not require marshaling.

float hypot(float x, float y)
{
	return cal->hypot(x, y);
}

double hypot(double x, double y)
{
	return cal->hypot(x, y);
}

The C# Wrapper methods code are presented below.

[HandleProcessCorruptedStateExceptions]
[SuppressUnmanagedCodeSecurity]
[DllImport("LibCalculator.dll", EntryPoint="#32", CallingConvention=CallingConvention.ThisCall)]
public extern static double Calculator_hypot(IntPtr thisObject, double x, double y);

[HandleProcessCorruptedStateExceptions]
[SuppressUnmanagedCodeSecurity]
[DllImport("LibCalculator.dll", EntryPoint="#31", CallingConvention=CallingConvention.ThisCall)]
public extern static float Calculator_hypot(IntPtr thisObject, float x, float y);

public double hypot(double x, double y)
{
    return LibCalculatorWin32.Calculator_hypot(this.ptrObject, x, y);
}

public float hypot(float x, float y)
{
    return LibCalculatorWin32.Calculator_hypot(this.ptrObject, x, y);
}

Now, the complete C# testing code.

namespace NSpeech.Win32.NLibCalculator.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NSpeech.Win32.StdLib;
    using NSpeech.Win32.NLibCalculator;
    using System.Runtime.InteropServices;
    using SampleManagedWrapper;

    public class HypotFloatTestClass
    {
        public static void Test(int testCount, int iterationCount)
        {
            double timeUsed1 = 0, timeUsed2 = 0, timeUsed3 = 0, timeUsed4 = 0;
            for (int i = 0; i < testCount; i++)
            {
                float result;
                Console.WriteLine("Testing float hypot(float) of C#");
                result = CSharp_Hypot(iterationCount, ref timeUsed1);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float hypot(float) of Managed C++ Wrapper.");
                result = ManagedCppWrapper_Hypot(iterationCount, ref timeUsed2);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float hypot(float) of C# Wrapper");
                result = CSharpWrapper_Hypot(iterationCount, ref timeUsed3);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing float hypot(float) of C# Wrapper with Direct Call.");
                result = CSharpWrapperDirectCall_Hypot(iterationCount, ref timeUsed4);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("=================================================================================");
                Console.WriteLine("C# Hypot -  Average Time used:                             {0}ms", timeUsed1 / (i + 1));
                Console.WriteLine("Managed C++ Wrapper Hypot- Average Time used:              {0}ms", timeUsed2 / (i + 1));
                Console.WriteLine("PInvoke Wrapper - Average Time used:                       {0}ms", timeUsed3 / (i + 1));
                Console.WriteLine("PInvoke Wrapper Direct Call - Average Time used:           {0}ms", timeUsed4 / (i + 1));
                Console.WriteLine("=================================================================================");

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("=========================Final Result of float hypot(float)=============================");
            Console.WriteLine();
            Console.WriteLine("Total Iteration: {0}", iterationCount);
            Console.WriteLine();
            Console.WriteLine("Method of float hypot(float)                                 Time             Percentage");
            Console.WriteLine();
            Console.WriteLine("C# Managed hypot                                              {0} ms           1.0", (timeUsed1 / testCount).ToString("00.000"));
            Console.WriteLine("C++ PInvoke, Managed Wrapper of Native hypot                  {0} ms           {1}", (timeUsed2 / testCount).ToString("00.000"), (timeUsed2 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper of Native hypot                   {0} ms           {1}", (timeUsed3 / testCount).ToString("00.000"), (timeUsed3 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper with Direct Call of Native hypot  {0} ms           {1}", (timeUsed4 / testCount).ToString("00.000"), (timeUsed4 / timeUsed1).ToString("0.000"));
            Console.WriteLine();
            Console.WriteLine("========================================================================================");
        }

        static float CSharp_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {                
                result = (float)Math.Sqrt(value * value + result * result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float ManagedCppWrapper_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new ManagedCalculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                // PInvoke Managed C++/CLI class method
                result = cal.hypot(value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float CSharpWrapper_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                // PInvoke C++ class method
                result = cal.hypot(value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static float CSharpWrapperDirectCall_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            float result = 0f;
            float fCount = (float)count;
            for (float value = 0; value < fCount; value++)
            {
                // PInvoke C++ class method without using the Calculator class wrapper
                result = LibCalculatorWin32.Calculator_hypot1(cal.ptrObject, value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }        
    }
}

and then the testing code for double version Hypot.

namespace NSpeech.Win32.NLibCalculator.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NSpeech.Win32.StdLib;
    using NSpeech.Win32.NLibCalculator;
    using System.Runtime.InteropServices;
    using SampleManagedWrapper;

    public class HypotDoubleTestClass
    {
        public static void Test(int testCount, int iterationCount)
        {
            double timeUsed1 = 0, timeUsed2 = 0, timeUsed3 = 0, timeUsed4 = 0;
            for (int i = 0; i < testCount; i++)
            {
                double result;
                Console.WriteLine("Testing double hypot(double) of C#");
                result = CSharp_Hypot(iterationCount, ref timeUsed1);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double hypot(double) of Managed C++ Wrapper.");
                result = ManagedCppWrapper_Hypot(iterationCount, ref timeUsed2);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double hypot(double) of C# Wrapper");
                result = CSharpWrapper_Hypot(iterationCount, ref timeUsed3);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("Testing double hypot(double) of C# Wrapper with Direct Call.");
                result = CSharpWrapperDirectCall_Hypot(iterationCount, ref timeUsed4);
                Console.WriteLine("Result = {0}", result);

                Console.WriteLine("=================================================================================");
                Console.WriteLine("C# Hypot -  Average Time used:                             {0}ms", timeUsed1 / (i + 1));
                Console.WriteLine("Managed C++ Wrapper Hypot- Average Time used:              {0}ms", timeUsed2 / (i + 1));
                Console.WriteLine("PInvoke Wrapper - Average Time used:                       {0}ms", timeUsed3 / (i + 1));
                Console.WriteLine("PInvoke Wrapper Direct Call - Average Time used:           {0}ms", timeUsed4 / (i + 1));
                Console.WriteLine("=================================================================================");

                Console.WriteLine();
            }

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("=========================Final Result of double hypot(double)=============================");
            Console.WriteLine();
            Console.WriteLine("Total Iteration: {0}", iterationCount);
            Console.WriteLine();
            Console.WriteLine("Method of double hypot(double)                                 Time             Percentage");
            Console.WriteLine();
            Console.WriteLine("C# Managed hypot                                              {0} ms           1.0", (timeUsed1 / testCount).ToString("00.000"));
            Console.WriteLine("C++ PInvoke, Managed Wrapper of Native hypot                  {0} ms           {1}", (timeUsed2 / testCount).ToString("00.000"), (timeUsed2 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper of Native hypot                   {0} ms           {1}", (timeUsed3 / testCount).ToString("00.000"), (timeUsed3 / timeUsed1).ToString("0.000"));
            Console.WriteLine("Explicit PInvoke C# Wrapper with Direct Call of Native hypot  {0} ms           {1}", (timeUsed4 / testCount).ToString("00.000"), (timeUsed4 / timeUsed1).ToString("0.000"));
            Console.WriteLine();
            Console.WriteLine("==========================================================================================");
        }

        static double CSharp_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {                
                result = Math.Sqrt(value * value + result * result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double ManagedCppWrapper_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;
            // C++/CLI managed wrapper class of native class, Calculator
            var cal = new ManagedCalculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                // PInvoke C++/CLI class method of hypot
                result = cal.hypot(value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double CSharpWrapper_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;

            // C# Wrapper class of the native class, Calculator.
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                // PInvoke C++ Class method of hypot.
                result = cal.hypot(value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }

        static double CSharpWrapperDirectCall_Hypot(int count, ref double timeUsed)
        {
            DateTime start = DateTime.Now;

            // C# Wrapper class of the native class, Calculator.
            var cal = new Calculator();
            double result = 0f;
            double fCount = (double)count;
            for (double value = 0; value < fCount; value++)
            {
                // PInvoke C++ Class method of hypot without using the wrapper class method.
                result = LibCalculatorWin32.Calculator_hypot(cal.ptrObject, value, result);
            }

            DateTime end = DateTime.Now;
            timeUsed += (end - start).TotalMilliseconds;
            return result;
        }        
    }
}

Now, let’s look at the result of calling the two versions of Hypot methods.

Float Version of Hypot

Doube version of Hypot

The result is what I expected, C++/CLI is the worst performer in both case. The C# version of hypot is the best since there is not much math operation involved in this test and the time to setup the thunk is significant, and we had to push two float or double parameter to the stack, it did cost more CPU time for .NET framework to setup the calling stack. Our C# wrapper class performed very close to the C# version of hypot when the direct call to the P/Invoke method is used, that is the fastest way to pinvoke C++ class method. If you define the hypot as static method, the performance is so close to the C# version and it actually could be better if the math operation is more complicated, which means we can probably build a C# Math library wrapper on top of any existing fast-performance C++ library and the performance could be better than a C# version of Math library.

Stay tuned, I will present you C# vs C++/CLI vs PInvoke Performance – Part IV.

NGenerator, A C# .NET Wrapper Generator for Native C++ DLL

$
0
0

Here are some screen shots of NGenerator, A C# .NET Wrapper Generator for Native C++ DLL.

It is quite simple to use NGenerator which takes care of everything of generating a C# .NET wrapper for native C++ DLL.

When you want to create a C# wrapper for native C++ DLL, you simply need to create a new project by telling where the DLL files and the header files are, the DLL file and the header files are the only requirements of NGenerator.

You can also fine tune your C# method signature by using type marshaling designer as the following picture shows. Most of the C++ data type should have already been converted to the correct corresponding C# types. For example, a C++ const int * type shall be converted to [in] int[] in C#, a int * type shall be converted to [in, out] int[],

Once you apply the change and exit the type marshaling designer, the C# wrapper source code will be re-generated.

The C# source code it auto-generated looks like exactly what you would write manually.

The following screen shot is the UI when the type marshaling designer is dismissed and the new implementation of SetRect method was being displayed.

 

 


AnyOption Class, An Example of C# Wrapper Class of Native C++ Class

$
0
0

I have been blogging about the great amazing features of C# .NET PInvoke Interop SDK Tool, I have also shown the power of the C# .NET Library for the Standard C++ Library. It is time for me to present how easily and quickly a C# wrapper class for a native C++ class can be generated automatically in just a few seconds, you will be able to see how a native C++ class can be wrapped in a C# class instantly and gets integrated with .NET seamlessly, calling C++ class method from C# .NET can never be easier. If you are a developer like me who always wants to write code efficiently and productively using both C# and native C++, you would find the solution of bridging the native C++ and C# .NET can save you so much time of using native C++ DLL.

The class I picked for demonstration is AnyOption, you can find the C++ implementation at GitHub. I am not going to post the code here, you can take a look at the C++ source code there. AnyOption is a C++ class for easy parsing of complex command line options. It was written for Unix platform, but I was able to build the class into a windows native C++ DLL very quickly in less than a minute. Once I opened the C++ DLL from NGenerator, all the exported methods except the private methods were being shown in the following screen shot.

As you can see, all the public and protected functions of AnyOption class are being shown in the screen shot. Simply by looking at the prototypes of the functions, you will find that most of the function parameter types are not complicated, they are int, char, char const *(same as const char *), char **. There are configuration setting you can use to marshal the data type by default, for example, char const* will be marshaled as string by default, char * will be marshaled as StringBuilder by default, char ** will be marshaled as a string array. You can still use the type marshaling designer to change the marshaling for specific method. You do not need to change the type marshaling for the primitive C++ data type since there is only one marshaling for them in the C# world. In the solution explorer, you can choose to show only the functions with possible multiple type marshaling as shown below.

There are still too many of them which I don’t necessary do anything to them because I am happy with marshaling char const * to string, that is exactly what it represents in the native C++ DLL. Then I choose to show the function with possible multiple type marshaling without default type marshaling. After filtering all the functions with default type marshaling, the functions I will need to fine tune by using the type marshaling designer came down to 3 as shown below,

If you have read the source code of the C++ AnyOption class, you know that the type of char** in all three functions is string array, and its preceding parameter of an integer type of these 3 functions is the length of the string array. By using the type marshaling designer, this char ** type can be easily marshaled as string array without writing single line of code, I was able to do it in less than a minute.

The resulting implementation of the C# method looks like it was written by us, developers. Actually, we had iterated all the possible scenario of all the data types NGenerator supports in C++, so the code below was actually the code we usually writes to marshal the C++ data type in C#.

I also presented the source code of the other two methods implemented in C#.

public void processCommandArgs(string[] argv, int max_args)
{
	int argc = (int)argv.Length;
	IntPtr[] __argv = new IntPtr[argv.Length];
	for (int index = 0; index < argv.Length; index++)
	{
		__argv[index] = Marshal.StringToHGlobalAnsi(argv[index]);
	}
	AnyOptionWin32.AnyOption_processCommandArgs(this.ptrObject, argc, __argv, max_args);
	for (int index = 0; index < __argv.Length; index++)
	{
		Marshal.FreeHGlobal(__argv[index]);
	}
}

public void useCommandArgs(string[] argv)
{
	int argc = (int)argv.Length;
	IntPtr[] __argv = new IntPtr[argv.Length];
	for (int index = 0; index < argv.Length; index++)
	{
		__argv[index] = Marshal.StringToHGlobalAnsi(argv[index]);
	}
	AnyOptionWin32.AnyOption_useCommandArgs(this.ptrObject, argc, __argv);
	for (int index = 0; index < __argv.Length; index++)
	{
		Marshal.FreeHGlobal(__argv[index]);
	}
}

After building the C# wrapper project, a .NET assembly containing the single AnyOption class was created, here is the meta data of the C++ class I copied from Visual Studio.

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace NSpeech.Win32.NAnyOption
{
    public class AnyOption : AnyOptionBaseClass
    {
        public AnyOption();
        public AnyOption(IntPtr handle = null);
        public AnyOption(AnyOptionStructX86 objectStruct);
        public AnyOption(int maxoptions);
        public AnyOption(int maxoptions, int maxcharoptions);
        public AnyOption(IntPtr thisObject, IntPtr thatObject, bool initialize);

        public static implicit operator AnyOptionStructX86(AnyOption o);
        public static implicit operator AnyOptionStructX64(AnyOption o);

        protected override int StorageSize { get; }

        public void addUsage(string line);
        public AnyOption assign(AnyOption thatObject);
        public void autoUsagePrint(bool flag);
        protected override void CleanupNativeResource();
        public int getArgc();
        public string getArgv(int index);
        public bool getFlag(char option);
        public bool getFlag(string option);
        public string getValue(char option);
        public string getValue(string option);
        public bool hasOptions();
        public void noPOSIX();
        public void printAutoUsage();
        public void printUsage();
        public void processCommandArgs();
        public void processCommandArgs(int max_args);
        public void processCommandArgs(StringBuilder[] argv);
        public void processCommandArgs(string[] argv, int max_args);
        public bool processFile();
        public bool processFile(string filename);
        public void processOptions();
        public void setCommandFlag(char opt_string);
        public void setCommandFlag(string opt_string);
        public void setCommandFlag(string opt_string, char opt_char);
        public void setCommandLongPrefix(string prefix);
        public void setCommandOption(char opt_string);
        public void setCommandOption(string opt_string);
        public void setCommandOption(string opt_string, char opt_char);
        public void setCommandPrefixChar(char prefix);
        public void setFileCommentChar(char comment);
        public void setFileDelimiterChar(char delimiter);
        public void setFileFlag(char opt_string);
        public void setFileFlag(string opt_string);
        public void setFileFlag(string opt_string, char opt_char);
        public void setFileOption(char opt_string);
        public void setFileOption(string opt_string);
        public void setFileOption(string opt_string, char opt_char);
        public void setFlag(char opt_string);
        public void setFlag(string opt_string);
        public void setFlag(string opt_string, char opt_char);
        public void setOption(char opt_string);
        public void setOption(string opt_string);
        public void setOption(string opt_string, char opt_char);
        public void setVerbose();
        public void useCommandArgs(string[] argv);
        public void useFiileName(string filename);

        public class Marshaller : ICustomMarshaler
        {
            public Marshaller();

            public void CleanUpManagedData(object ManagedObj);
            public void CleanUpNativeData(IntPtr pNativeData);
            public static ICustomMarshaler GetInstance(string pstrCookie);
            public int GetNativeDataSize();
            public IntPtr MarshalManagedToNative(object ManagedObj);
            public object MarshalNativeToManaged(IntPtr pNativeData);
        }
    }
}

It has same neat interface as in the native C++ class. NGenerator allows you to remove the beginning underscore of a parameter name, so you don’t see any parameter starting with ‘_’ in the C# wrapper class.

With the help of C# .NET PInvoke Interop SDK, integrating any C++ native DLL is so easy and quick, you simply grab the native C++ DLL and the header files then feed them to NGenerator, you will get a C# .NET assembly which is ready for use in your C# application right away. Best of all, the maintenance if quite easy as well, all the custom type marshaling is saved, If you change the native C++ DLL and the change still applies to the C++ class function whose interface does not change, the only thing you need to do is to fine tune the newly added function and modified function which does require fine tuning, otherwise you will just need to re-generate the wrapper project and rebuild it.

In the near future, I will continue to demonstrate wrapping more complicated native C++ DLL in C# .NET.

 

Do you always marshal const char * to string in C# when calling native C++ class from C# ?

$
0
0

Do you always marshal “const char *” to string in C# when calling native C++ class method from C# ?

Most of time, yes, we would simply marshal “const char *” to string in C#/.NET and it just works. but it does not always work as expected from the native C++ DLL because “const char*” can also represent an array of binary data in bytes as read-only array. The reason of my writing this post is that I read a question from here, and I realized how NGen++ is superior than SWIG on generating C# wrapper for native C++ DLLs because SWIG has to reply on complicated macro called typemap. With all the respects to SWIG which is open source and brings the bridge between C++ and all other various languages with huge efforts, but I would say this is exactly the main reason I would not want to use SWIG even before I wrote NGen++, I would want an automated tool which only requires me to do a few minor configuration to generate the C# wrapper class automatically without writing any type of scripts. I guess that is one of the big reasons I have been writing my own C# wrapper generator for native C++ DLL.

When a parameter of “const char*” or “char *” contains binary data, it can also include zero(0) which represents the ending of a C/C++ string, so marshaling const char * or “char*” to a string definitely does not work as expected from the native C++ DLL because the string will get cut in the middle when being passed from C# code to the native C++ class, It must be marshaled to an array of bytes with a length if it is not a fixed-length array.

Since 90+% of the time, “const char*” does represent a string in C++, so NGen++ marshals “const char*” to string by default, but it will also allow developers to marshal “const char*” to an array of byte by using the C++ to C# type marshaling designer. You would probably think that using a type marshaling designer would be as inconvenient as using typemap scripting, but the fact is that you would only need to spend a few seconds to configure the type mapping using the type marshaling designer without any further knowledge of anything else beyond using the C++ to C# type marshaling designer, especially involving writing scripted typemap which would be also cause additional errors since it is a another type of language and very often developers would probably introduce new errors.

Here is the C++ implementation of C++ class of Buffer I made up. The function of SetData is what we will be discussing.

class DLLAPI Buffer
{
	char * pBuffer;
	int nLength;

public:

	Buffer()
	{
		pBuffer = NULL;
	}

	int GetLength() const
	{
		return nLength;
	}

	int SetData(const char* data, int length)
	{
		if (pBuffer != NULL)
		{
			free(pBuffer);
			pBuffer = NULL;
			length = 0;
		}

		if (data != NULL && length > 0)
		{
			pBuffer = (char *)malloc(length);
			memmove(pBuffer, data, length);
			nLength = length;
			return length;
		}

		return 0;
	};
};

By default, the following wrapper method of SetData will be generated by NGen++,

public int SetData(string data, int length)
{
    return LibPerfEvaluationWin32.Buffer_SetData(this.ptrObject, data, length);
}

// Explicit P/Invoke Signature for calling C++ class method from C# .NET
[HandleProcessCorruptedStateExceptions]
[SuppressUnmanagedCodeSecurity]
[DllImport("LibPerfEvaluation.dll", EntryPoint="#115", CallingConvention=CallingConvention.ThisCall)]
public extern static int Buffer_SetData(IntPtr thisObject, string data, int length);

By using the C++ to C# type marshaling designer shown below, I was able to quickly convert the implementation of the wrapper method to an array of bytes.

The implementation of SetData wrapper method will look like exactly as expected from the native C++ class of Buffer as shown below. As you see, the signature of the wrapper method changed, so did the P/Invoke signature. Since array parameter of the wrapper method already has the length of the array, it does not need another parameter to tell the length of the array.

// C# Wrapper Method calling C++ method via Explicit P/Invoke
public int SetData(sbyte[] data)
{
    int length = (int)data.Length;
    var localReturnValue = LibPerfEvaluationWin32.Buffer_SetData(this.ptrObject, data, length);
    return localReturnValue;
}

// Explicit P/Invoke Signature for calling C++ class method from C# .NET
[HandleProcessCorruptedStateExceptions]
[SuppressUnmanagedCodeSecurity]
[DllImport("LibPerfEvaluation.dll", EntryPoint="#115", CallingConvention=CallingConvention.ThisCall)]
public extern static int Buffer_SetData(IntPtr thisObject, sbyte[] data, int length);

Generating SFML C# .NET Wrapper Libraries in 10 minutes – Part I

$
0
0

Introduction

“SFML (Simple and Fast Multimedia Library) is a portable and easy-to-use API for multimedia programming. It is an object oriented alternative for the SDL. SFML provides 2D graphics that are hardware accelerated with OpenGL. SFML can also be used for OpenGL windowing. SFML also provides different modules made to ease programming games and multimedia applications. It is written in C++, it does already have a binding for .NET, which is not my concern, what I am caring about is that how I would be able to create the C# wrapper libraries for the whole packages of C++ DLLs automatically using xInterop NGen++. (By the way, this is going to be the official name of the C# .NET PInvoke Interop SDK for the native C++ DLL)

“The modules currently available are:

All the modules can be used independently, except the Graphics module that depends on the Window module, and all the modules that depend on the System module.

By using xInterop NGen++, I was able to build 5 individual C# .NET wrapper assemblies for all the 5 modules in less than 10 minutes. (I certainly spent a few hours testing them to make sure they work correctly with a couple of examples of using SFML, I did not have any knowledge of SFML, I went to its web site to learn all the samples, it was easy though since I just needed to change the syntax from C++ to C#.) Their assembly names and namespaces are automatically given based on the names of the original C++ native DLLs.

•    NSpeech.Win32.Nsfml_system_2
•    NSpeech.Win32.Nsfml_audio_2
•    NSpeech.Win32.Nsfml_network_2
•    NSpeech.Win32.Nsfml_window_2
•    NSpeech.Win32.Nsfml_graphics_2

Since I have both x86/win32 32 bits and x64 64 bits DLLs, I was able to build C# .NET Assemblies targeting AnyCPU, which means I will be able to use the DLL under x86, x64 platform or x64 WoW.

By using those C# .NET assemblies, I was able to write the C# example code which looks almost similar to the original C++ sample code since they share the same class names, same methods name inside of each class. All I had to do is to change the syntax of declaring variables and calling methods.

I studied the C++ samples from SFML tutorials herefor a few minutes and I picked up one simple sample of creating shapes. The following is the original C++ code to create an outline of a circle shape, which I shamefully copied from SFML web site with credits to Laurent Gomila.

// The following code was copied from SFML web site, credit to Laurent Gomila
sf::CircleShape shape(50);
shape.setFillColor(sf::Color(150, 50, 250));

// set a 10-pixel wide orange outline
shape.setOutlineThickness(-10);
shape.setOutlineColor(sf::Color(250, 150, 100));

Now, let’s write some C# code to call the SFML C++ code via the C# wrapper libraries generated by xInterop NGen++, remember, the auto-generated C# source code only replies on Explicit P/Invoke, but really, it is so easy and simple to call the C++ class methods or access the C++ internal properties from C# by using the auto-generated C# wrapper classes.

Here is a C# example to create a outline of  the shape of a circle.

CircleShape shape = new CircleShape(50);
shape.setFillColor(new Color(150, 50, 250));

// set a 10-pixel wide orange outline
shape.setOutlineThickness(-10);

// set the outline color.
shape.setOutlineColor(new Color(250, 150, 100));

// Draw the shape.
Draw(shape);

// Make sure that the shape object will not get GC-collected.
GC.KeepAlive(shape);

And here is the draw method which accepts a parameter of the base class of any drawable class, namely Drawable class. This way, I will be able to draw any supported drawable objects in a window.

static void Draw(Drawable drawable)
{
	// ContextSettings of Version 2.0
	ContextSettings contextSettings = new ContextSettings { majorVersion = 2 };

        // Create the render window.
	RenderWindow renderWindow = new RenderWindow();
	renderWindow.create(new VideoMode(750, 120), new NString(title), 4, contextSettings);

        // Convert render window to RenderTarget. NGen++ currently does not support multiple inheritance
        // This is a workaround to create RenderTarget based on a renderWindow C++ pointer. It will be fixed
        // in the near future.
	RenderTarget target = new RenderTarget(renderWindow.CppPointer + (new Window()).Size, IntPtr.Zero, false);
	target.Disposable = false;

	while (renderWindow.isOpen())
	{
		// Clear screen
		target.clear(Color.Black);

		// Draw the sprite.
		target.draw(drawable, RenderStates.Default);

		// Update the window
		renderWindow.display();

		// Check any input.
		using (Event inputEvent = new Event(IntPtr.Zero, IntPtr.Zero, false, true))
		{
			while (renderWindow.pollEvent(inputEvent))
			{
				if (inputEvent.type == EventType.Closed)
				{
					// Close the window if it is closed event.
					renderWindow.close();
					break;
				}
			}
		}
	}

	// Dispose the render window. Clean up the native C++ resource.
	renderWindow.Dispose();
}

Here is the captured image by running the preceding sample C# code. You can find the similar image created by the original C++ code from here.

This is the Part I. Stay tuned, I will present the Part II soon.

 

 

Wrapping the native C++ class with multiple inheritance in C#

$
0
0

Generating C# wrapper class for the native C++ class with multiple inheritance

xInterop NGen++ fully supports wrapping the native C++ class with multiple inheritance by using C# .NET Explicit P/Invoke.

Let’s talk about the concept of C++ multiple inheritance first briefly. In C++, you can derive a class from any number of base classes. Deriving a class from more than one direct base class is called multiple inheritance.

On the other hand, C# unfortunately only supports deriving from a single base class.

Take a look at the following class diagram for example. The following classes are part of SFML implementation with our version of SFML C# Wrapper libraries as I discussed in the previous blog.

In the preceding example, class Window, RenderTarget are direct base classes for the derived class RenderWindow:

class Window
{
/* ... */
}

class RenderTarget
{
/* ... */
}

class RenderWindow : public Window, public RenderTarget
{
/* ... */
}

We will be able to wrap each class one-to-one in C# for class RenderWindow, class Window and RenderTarget. While in C#, we won’t be able to do the following like in C++ because C# only supports single inheritance.

public class RenderWindow : Window, RenderTarget
{
/* ... */
}

The solution we use in xInterop NGen++ is to let class RenderWindow derive from the first class, in this case, class Window and then generate code to implement the public methods of all other classes in a way of interface, more clearly, explicit interface, so the implementation of class RenderWindow in C# shall look like the following,

public class RenderWindow : Window, IRenderTarget
{
/* ... */
}

In the C# wrapper library, IRenderTarget defines all the public methods in the wrapper class of RenderTarget. The reason we chose to implement C# explicit interface instead of C# implicit interface is that we want to guarantee that there is no method with the same name and the same signature in class Window and the interface of IRenderTarget since generating C# wrapper code is an automated process.

public interface IRenderTarget
{
	void clear(Color color);
	void draw(Drawable drawable, RenderStates states);
	void draw(Vertex vertices, int vertexCount, PrimitiveType type, RenderStates states);
	View getDefaultView();
	UIntVector2 getSize();
	View getView();
	IntRect getViewport(View view);
	IntVector2 mapCoordsToPixel(FloatVector2 point);
	IntVector2 mapCoordsToPixel(FloatVector2 point, View view);
	FloatVector2 mapPixelToCoords(IntVector2 point);
	FloatVector2 mapPixelToCoords(IntVector2 point, View view);
	void popGLStates();
	void pushGLStates();
	void resetGLStates();
	void setView(View view);
}

This does introduce inconvenience because the method implemented in class RenderWindow via explicit interface is private, you will have to type-cast RenderWindow to IRenderTarget before you can access the methods of IRenderTarget.

// Create the render window.
RenderWindow renderWindow = new RenderWindow();
renderWindow.create(new VideoMode(800, 600, 24), new NString("SFML works!"), 4, contextSettings);

// type-cast render window to IRenderTarget inteface.
IRenderTarget target = (IRenderTarget)renderWindow;

How is nested class in native C++ handled by xInterop NGen++ ?

$
0
0

How is inner class in C++ wrapped in C# by xInterop NGen++?

In C++, an inner class or nested class is a class declared entirely within the body of another class, nesting class. Inner classes are basically a form of scope. C# supports inner class or nested class as well, so mapping a nested C++ class in a nesting C++ class to a nested C# wrapper class in a nesting C# wrapper class is doable in theory. But how?

The following native C++ code is a very simple example of declaring a nested class inside another class, a nesting C++ class. In the following example, the nested native C++ class is called NestedObject which is declared and implemented inside of the nesting C++ native class named SimpleObject.

class SimpleObject
{	
public:
        SimpleObject() 
        {
        }

        ~SimpleObject() 
        {
        }

	class NestedObject
	{
        private:
		char szName[100];

	public:

		NestedObject() 
		{
			strcpy(szName, "NestedObject");
		};

                ~NestedObject() 
                {
                }

		const char * GetName()
		{
			return szName;
		};		
	};

        ...
}

xInterop NGen++ (A C# wrapper generator for the native C++ DLL) fully supports nested class, nested struct/structure, nested enum, even nested anonymous struct/structure and nested anonymous enum via pure Explicit P/Invoke. Calling into a native nested C++ class from C# .NET and accessing its method and fields has no difference of calling a regular native C++ class.

We always look into the issues which other code generators such as like SWIG (Simplified Wrapper and Interface Generator) and CXXI are facing while working on implementing and improving xInterop NGen++. CXXI is not very active as of today. SWIG does not really support nested classes or its support is limited from reading its document, but it does provide some workarounds with defining the nested class inside the nesting class where it is forward declared, which means the actual declaration and implementation should be defined outside of the class where the nested class is forward declared in order for SWIG to process it. On SWIG’s to-do-list of 2013 Google Summer of Code, the difficulty is marked as medium to hard. I am not an expert of SWIG implementation or using SWIG to create C# wrapper semi-automatically, but I think its difficulty may have something to do with the fact that SWIG’s underlying mechanism of wrapping C++ is another layer of C style DLL, which means SWIG must wrap the native C++ DLL in a C style DLL which then gets wrapped in C# by using Explicit P/Invoke.

When wrapping the native un-managed native C++ class residing in a native C++ DLL, xInterop NGen++ takes a different approach than SWIG. xInterop NGen++ does not try to wrap the original C++ native un-managed DLL in another C style DLL except that it needs to generate a supplement C++ DLL when any instantiated template class is not exported in the original C++ DLL in order to export the instantiated template class, xInterop NGen++ uses the native C++ DLL as it is. The C# .NET code generated by xInterop NGen++ operates on the pointer of C++ object/instance exactly like a traditional C++ application linking with that native C++ DLL based on the information of the memory layout and the method signatures of a C++ object, including both exported methods and virtual methods. The resulting C# wrapper class has exact same interface of the corresponding native C++ class does, which enables developers to easily convert a C++ application to a C# application when using the native C++ DLL via the generated C# wrapper library.

To xInterop NGen++, any native un-managed C++ object is basically just a pointer pointing to the beginning of a specific block of memory in the un-managed native world. The layout, virtual function table and the exported methods of the C++ object are all known to xInterop NGen++. An instance of a nested class is just another native pointer. So it does not matter if the class of the object is nested or not. Basically speaking, being nested or not is just a name scope of the class definition in the original C++ source code.

The way which xInterop NGen++ chose to handle the native nested C++ class is same as the way of handling other regular native C++ classes, a corresponding C# .NET wrapper class gets generated for each native nested C++ class. As for the name scope or namespace, the C# .NET wrapper class of the native nested C++ class will be put inside of the C# .NET wrapper class of the C++ nesting class where the native C++ nested class resides so that the original C++ class structure can be maintained.

I have listed the meta data and class definition of the C# .NET wrapper class of the native nseting C++ class along with nested class below.

public class SimpleObject : SimpleLibraryBaseClass
{
	public class NestedObject : SimpleLibraryBaseClass
	{
		public NestedObject();
		public NestedObject(NestedObjectStruct objectStruct);
		public NestedObject(IntPtr thisObject, IntPtr thatObject, bool initialize, bool allocate = false);
		public static implicit operator NestedObjectStruct(SimpleObject.NestedObject o);
		public override string NativeClassName { get; }
		protected override int StorageSize { get; }
		public char szName { get; set; }
		public SimpleObject.NestedObject assign(SimpleObject.NestedObject thatObject);
		protected override void CleanupNativeResource();
		public string GetName();
	}

	public SimpleObject();
	public SimpleObject(SimpleObjectStruct objectStruct);
	public SimpleObject(IntPtr thisObject, IntPtr thatObject, bool initialize, bool allocate = false);
	public static implicit operator SimpleObjectStruct(SimpleObject o);
	public override string NativeClassName { get; }
	protected override int StorageSize { get; }
	public NestedStruct tagNestedStruct { get; set; }
	public int Add(int x, int y);
	public SimpleObject assign(SimpleObject thatObject);
	protected override void CleanupNativeResource();
	public void SetEnum(ref NestedEnum e);
	public void SetStruct(NestedStruct s);	
}

If you look into the preceding code carefully, you would find that the structure of the interface of the C# nested inner class has no much difference than a regular top-level C# wrapper class, they are both derived from the same base C# class, the only difference is that the nested inner class is declared and implemented in another C# wrapper class like it does in C++. It is a difference on the name scope in C++ native world, it is also just the same difference on the name scope in the C# managed world, so they are perfectly matched in both worlds.

Advanced technology to wrap native C++ template class in C# automatically

$
0
0

XInterop NGen++‘s amazing abilities of wrapping C++ class in C# .NET automatically

The bridge between C++ and C# .NET world is getting much more advanced than ever.

.NET P/Invoke technology has been around since the beginning of .NET framework. We all know that P/Invoke can be used to call C-style methods in a native DLL from C#. It is a misunderstanding that P/Invoke is only good for C-style DLLs, and popular with people who want to call into the Windows API. The fact is that P/Invoke can also be used to call member methods of a C++ class from C# as well. P/Invoke is designed with the ability of calling any method written in C/C++ in the native un-managed world.

The way we use to call C++ class and method via P/Invoke from C# is really new. When I just started writing xInterop NGen++(A C# wrapper generator for native C++ DLL), I really did not have this feature in mind and I could not image that I would end up with such a powerful tool with so many great features with which allows me to create C# wrapper class for whatever template class appearing in any of the methods of the native C++ classes. Other C# wrapper generators for C++, such as SWIG, do not support template class very well, you will have to find the instantiated template classes first by yourself and then write additional script manually to support creating the C# wrapper class.

In C++, you can use instantiated template class in the C++ class once the template class is defined.

Let me give you an example of how powerful xInterop NGen++ is when dealing with the instantiated template class. We have a SimpleObject containing one method to initialize the data contained in the class.

public EXPORT_API class SimpleObject
{

public:

    SimpleObject()
    {
    }

    void Initialize(std::map<std::string, std::vector<std::vector<std::string>>>& data)
    {
	/* code to initialize the SimpleClass by using the given data.
    }
};

By exporting the class of SimpleObject, the method of Initialize gets exported in the native C++ DLL with a very long mangled name and a ordinal number. Developers do not have to worry about the mangled name when using xInterop NGen++ since it is handled automatically by the tool.

Looking at the preceding C++ code carefully, you would notice the input parameter of method of Initialize is very complicated, it is a map, the key of the map is std::string while the value of map is vector of vector of string, vector<vector<string>>. The template classes do not get exported automatically, and the compiler(Visual C++ compiler) actually outputs a warning of the classes being used in the interfaces are not exported. Considering there may be many instantiated template classes being used in all different interfaces, just finding the instantiated template class, exporting them and maintaining such a list could be a big effort in a long run.

Normally, you would need to export all the instantiated template classes in the interfaces if you want to use them. But in the case of using xInterop NGen++ to create C# wrapper class for the native C++ class, developers don’t need to do anything with any instantiated template classes, all they need to do is just define the instantiated template class in their interface.

xInterop NGen++ automatically looks into all the methods, fields, it iterates each type of all the parameters, and discovers that all the instantiated template classes which do not get exported already in the original native C++ DLL, and export them in a supplement native c++ DLL which links to the original native C++ DLL.

xInterop NGen++ automatically generates friendly name of the C# wrapper class for the corresponding native instantiated template class.

Let’s take the following example of an instantiated template class,

std::map<std::string, std::vector<std::vector<std::string>>>

xInterop NGen++ generates a C# wrapper class of StdStringStdStringVectorVectorMap.

public class StdStringStdStringVectorVectorMap : SimpleLibraryWin32SupplementBaseClass, IDictionary<StdString, StdStringVectorVector>, ICollection<KeyValuePair<StdString, StdStringVectorVector>>, IEnumerable<KeyValuePair<StdString, StdStringVectorVector>>, IEnumerable
{
	public StdStringStdStringVectorVectorMap();
	public StdStringStdStringVectorVectorMap(StdStringStdStringVectorVectorMap that);
	public StdStringStdStringVectorVectorMap(StdStringStdStringVectorVectorMapStruct objectStruct);
	public StdStringStdStringVectorVectorMap(IntPtr thisObject, IntPtr thatObject, bool initialize, bool allocate = false);

	public static implicit operator StdStringStdStringVectorVectorMapStruct(StdStringStdStringVectorVectorMap o);

	public int Count { get; }
	public bool IsReadOnly { get; }
	public ICollection<StdString> Keys { get; }
	public override string NativeClassName { get; }
	protected override int StorageSize { get; }
	public override string TemplateClassName { get; }
	public ICollection<StdStringVectorVector> Values { get; }

	public StdStringVectorVector this[StdString index] { get; set; }

	public void Add(KeyValuePair<StdString, StdStringVectorVector> item);
	public void Add(StdString key, StdStringVectorVector value);
	public StdStringStdStringVectorVectorMap assign(StdStringStdStringVectorVectorMap thatObject);
	public StdStringVectorVector at(StdString keyval);
	public StdStringStdStringVectorVectorMapConstIterator begin();
	public StdStringStdStringVectorVectorMapConstIterator cbegin();
	public StdStringStdStringVectorVectorMapConstIterator cend();
	protected override void CleanupNativeResource();
	public void Clear();
	public void clear();
	public bool Contains(KeyValuePair<StdString, StdStringVectorVector> item);
	public bool ContainsKey(StdString key);
	public void CopyTo(KeyValuePair<StdString, StdStringVectorVector>[] array, int arrayIndex);
	public long count(StdString keyval);
	public bool empty();
	public StdStringStdStringVectorVectorMapConstIterator end();
	public StdStringStdStringVectorVectorMapConstIteratorStdStringStdStringVectorVectorMapConstIteratorPair equal_range(StdString keyval);
	public long erase(StdString keyval);
	public StdStringStdStringVectorVectorMapIterator erase(StdStringStdStringVectorVectorMapConstIterator where);
	public void erase(StdString first, StdString last);
	public StdStringStdStringVectorVectorMapIterator erase(StdStringStdStringVectorVectorMapConstIterator first, StdStringStdStringVectorVectorMapConstIterator last);
	public StdStringStdStringVectorVectorMapConstIterator find(StdString keyval);
	public StdStringStdStringVectorVectorPairAllocator get_allocator();
	public StdStringStdStringVectorVectorMapIteratorBoolPair insert(StdStringStdStringVectorVectorPair val);
	public StdStringStdStringVectorVectorMapIteratorBoolPair insert(StdString first, StdStringVectorVector second);
	public StdStringStdStringVectorVectorMapIterator insert(StdStringStdStringVectorVectorMapConstIterator where, StdStringStdStringVectorVectorPair val);
	public StdStringStdStringVectorVectorMapIteratorBoolPair insert(StdStringStdStringVectorVectorPair val, bool leftish);
	public StdStringLess key_comp();
	public StdStringStdStringVectorVectorMapConstIterator lower_bound(StdString keyval);
	public long max_size();
	protected IntPtr operator_get_set(StdString keyval);
	public bool Remove(KeyValuePair<StdString, StdStringVectorVector> item);
	public bool Remove(StdString key);
	public long size();
	public void swap(StdStringStdStringVectorVectorMap right);
	public bool TryGetValue(StdString key, out StdStringVectorVector value);
	public StdStringStdStringVectorVectorMapConstIterator upper_bound(StdString keyval);
	public StdStringStdStringVectorVectorMapTraits value_comp();
}

Not only does the C# map class support the interface(methods and fields) of the corresponding native C++ class, it also implements IDictionary interface, so you will be able to manipulate the C# map class just like a C# native dictionary class. With IDictionary interface implemented for the C# wrapper class, developers can even use LINQ to manipulate the C# wrapper class of the C++ native map class.

The template class actually contains several other template classes, corresponding C# wrapper class get generated.

std::vector<std::vector<std::string>>
==> StdStringVectorVector (Supports IEnumerable)

std::vector<std::string>
==> StdStringVector (Supports IEnumerable)

std::string 
==> StdString

xInterop NGen++ 2.0 is released

$
0
0

We are pleased to announce the release of xInterop NGen++ 2.0, a C# wrapper generator for native C++ DLLs.

xInterop NGen++ 2.0 is available to the public for evaluation. To anyone who is interested in using xInterop NGen++ to generate C# .NET Wrapper for native C++ DLLs, you may want to download it from the link below and start evaluating it and experience how powerful xInterop NGen++ is. Once you start using xInterop NGen++, you will find that it is so easy to bridge the C++ native world to C# .NET managed world by using xInterop NGen++. You will be able to evaluate the software for free for 30 days. A free version will be available to the public very soon as well.

To anyone who is interested in purchasing xInterop NGen++, the licensing model and pricing will be available to you soon. If you have any questions regarding xInterop NGen++ software, licensing or pricing, please feel free to contact us.


Supporting C style DLL exporting functions

$
0
0

The current version of xInterop NGen++ only supports generating C# wrapper for native C++ DLL exporting C++ class. Developers have been asking for supporting C style DLL and we have started working on supporting this feature. Since the xInterop NGen++ has been able to generate C# wrapper assembly wrapping C++ classes quite well, we will not try to change anything to the existing code base, instead, we will take a approach by creating a new C++ DLL with a wrapper C++ class to wrap the existing export functions in the C style DLL as static methods and then it will simply use the existing mechanism to generate C# wrapper for the new C++ DLL and class.

For now, you may want to manually create a C++ class to wrap the functions exported from a c style DLL, and then use xInterop NGen++ to generate a C# wrapper library. It won’t take very long to create a C++ wrapper class, you are basically going to copy and paste the function signatures and wrap them as public static methods inside a new C++ class.

Creating C# Wrapper for Windows System DLL

$
0
0

We have been working on adding the feature of creating C# wrapper for C style DLLs for quite a while, and the current version of xInterop NGen++ works very well, xInterop NGen++ created whatever C style DLL we threw to it. There is not much difference between creating C# wrapper for C style DLL and creating C# wrapper for windows system DLL which is indeed C style DLL as well. But there is enough difference for us decide to create a wizard for creating C# wrapper for windows system DLL.The process of creating a C# wrapper is fully automated, all we need to do is to choose a windows system DLL and the header file defining all the export functions in that DLL, and then we pick a folder where we want to place the newly generated C# wrapper project.

 

image

 

When creating C# wrapper for Windows System DLL, the header file is chosen by xInterop NGen++ automatically once the Windows System DLL is selected. For some DLLs, such as advapi32.dll, there are multiple header files required to create the C# wrapper, Winbase.h, Wincrypt.h and Winefs.h.

 

image

 

We can choose to create C# wrapper for difference CPU architecture, such as x86, x64 and AnyCPU.

 

The Windows System DLL we picked for this demonstration is the native assembly of Windows Biometric Framework API which is supported beginning with Windows Server 2008 R2 and Windows 7.

 

Once we created the C# wrapper project, the solution explore will show all the functions exported by the Windows System DLL as shown by the following screenshot.

 

image

 

In a few minutes, a complete C# wrapper project was generated.

 

image

 

image

 

 

image

 

 

The following screenshot shows the implementation of C# wrapper method of WinBioEnrollBegin.

 

image

 

Any callback function type is marshaled to C# delegate shown below.

 

public static int WinBioCaptureSampleWithCallback(uint SessionHandle, byte Purpose, byte Flags, PWINBIO_CAPTURE_CALLBACKDelegate CaptureCallback, IntPtr CaptureCallbackContext)
{
      var __CaptureCallback = Marshal.GetFunctionPointerForDelegate(CaptureCallback);
      var ___localReturnValue___ = WinbioWin32.RzBTLsIfXOBJXGlNHjeAmiMmOMA(SessionHandle, Purpose, Flags, __CaptureCallback, CaptureCallbackContext);
      return ___localReturnValue___;
}

 

With this new feature, we virtually can create C# wrapper for any Windows System DLL. This new feature will be available to the professional version, premium version and enterprise version of xInterop NGen++ with no additional charge.

xInterop C++ .NET Bridge 3.0 is available now

$
0
0

xInterop C++ .NET Bridge 3.0 is available now

We are pleased to announce the release of xInterop C++ .NET Bridge 3.0, a Code Generator for Creating Two-Ways Bridges between C++ Native World and .NET World.

xInterop C++ .NET Bridge 3.0 is available to the public for evaluation. To anyone who is interested in using xInterop C++ .NET Bridge to

  • Generating C# .NET Wrapper/Bridge for native C++ DLLs so that you can call native C++ DLL from .NET.
  • Generating C++ Native DLL Bridge for .NET assemblies so that you can call .NET assemblies from native C++.

You may want to download it from the link below and start evaluating it and experiencing how powerful xInterop C++ .NET Bridge is. Once you start using xInterop C++ .NET Bridge, you will find that it is so easy to bridge between the C++ native world to C# .NET managed world by using xInterop C++ .NET Bridge. You will be able to evaluate the software for free for 30 days.

To anyone who is interested in purchasing xInterop C++ .NET Bridge, the licensing model and pricing is available to you upon request. If you have any questions regarding xInterop C++ .NET Bridge software, licensing or pricing, please feel free to contact us using the Contact Us Page.

The post xInterop C++ .NET Bridge 3.0 is available now appeared first on xInterop C++ .NET Bridge.

xInterop C++ .NET Bridge 3.1 is available for free download now

$
0
0

xInterop C++ .NET Bridge 3.1 is available for free download

We are pleased to announce the release of xInterop C++ .NET Bridge 3.1, a Code Generator for Creating Two-Ways Bridges between C++ Native World and .NET World.

xInterop C++ .NET Bridge 3.1 is available to the public for evaluation. To anyone who is interested in using xInterop C++ .NET Bridge to

  • Generating C# .NET Wrapper/Bridge for native C++ DLLs so that you can call native C++ DLL from .NET.
  • Generating C++ Native DLL Bridge for .NET assemblies so that you can call .NET assemblies from native C++.

You may want to download it from the link below and start evaluating it and experiencing how powerful xInterop C++ .NET Bridge is. Once you start using xInterop C++ .NET Bridge, you will find that it is so easy to bridge between the C++ native world and C# .NET managed world by using xInterop C++ .NET Bridge. You will be able to evaluate the software for free for 30 days. Please be advised that we provide free basic technical support to any user during the trial period, so please do not hesitate to contact us using Contact Us Page.

To anyone who is interested in purchasing xInterop C++ .NET Bridge, the licensing model and pricing is available to you upon request. If you have any questions regarding xInterop C++ .NET Bridge software, licensing or pricing, please feel free to contact us using the Contact Us Page.

The post xInterop C++ .NET Bridge 3.1 is available for free download now appeared first on xInterop C++ .NET Bridge.

xInterop C++ .NET Bridge 3.3 is available now

$
0
0

xInterop C++ .NET Bridge 3.3 is available now

We are pleased to announce the release of xInterop C++ .NET Bridge 3.3, a Code Generator for Creating Two-Ways Bridges between C++ Native World and .NET World.

xInterop C++ .NET Bridge 3.3 is available to the public for evaluation. To anyone who is interested in using xInterop C++ .NET Bridge to

  • Generating C# .NET Wrapper/Bridge for native C++ DLLs so that you can call native C++ DLL from .NET.
  • Generating C++ Native DLL Bridge for .NET assemblies so that you can call .NET assemblies from native C++.

You may want to download it from the link below and start evaluating it and experiencing how powerful xInterop C++ .NET Bridge is. Once you start using xInterop C++ .NET Bridge, you will find that it is so easy to bridge between the C++ native world to C# .NET managed world by using xInterop C++ .NET Bridge. You will be able to evaluate the software for free for 30 days.

 

To anyone who is interested in purchasing xInterop C++ .NET Bridge, the licensing model and pricing is available to you upon request. If you have any questions regarding xInterop C++ .NET Bridge software, licensing or pricing, please feel free to contact us using the Contact Us Page.

The post xInterop C++ .NET Bridge 3.3 is available now appeared first on xInterop C++ .NET Bridge.

Viewing all 31 articles
Browse latest View live