Quantcast
Viewing all articles
Browse latest Browse all 31

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

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

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

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.


Viewing all articles
Browse latest Browse all 31

Trending Articles