Writing Managed Wrappers with Managed C++
Pages: 1, 2
Wrapper Construction
In this section of the article, I will show how to build the managed class that
will wrap our linked list, so that we can call the code from C#. First,
create a new Managed C++ class library project in VS.NET 2003 called
ManagedList, copy the files Item.h, Item.cpp, UnmanagedLinkedList.h,
and UnmanagedLinkedList.cpp into the project folder, and then add them to the
project.
Step 1: Declare a Member Pointer to the Unmanaged Class
The next thing to do is define a managed class called ManagedList, and declare
a data member whose type is a pointer to the class being wrapped; that is, an
UnmanagedLinkedList*. The code, so far, from ManagedList.h looks like this:
#pragma once
#include "UnmanagedLinkedList.h"
#pragma managed
#using <mscorlib.dll>
using namespace System;
namespace ManagedList
{
public __gc class ManagedList
{
public:
private:
UnmanagedLinkedList __nogc* m_pUnmanagedList;
};
}
Step 2: Wrapping Constructors
One piece of advice I would like to give you in regards to constructors is that you don't have to wrap every constructor of your unmanaged class. Again, writing managed wrappers affords you the ability to refactor and simplify your code. In addition, you should consider if the constructor in question will make sense in the managed environment. In other words, if your constructor is initializing types that you will no longer be using in an managed environment, then the constructor is not needed. These kind of decisions must be made on a case-by-case basis.
Default Constructor
The default constructor is trivial and simply instantiates the class being wrapped:
MList::MList()
{
m_pUnmanagedList = new UnmanagedLinkedList();
}
Copy Constructor
The copy constructor, on the other hand, brings up some interesting issues. In
native C++, we often find it necessary to have a user-defined copy constructor
and a copy assignment issue, to perform true "deep-copy" semantics and not just
member-wise copying. The way to do this in the .NET Framework, and thus in Managed
C++, is to implement the IClonable interface in our MList class:
public __gc class MList : public ICloneable
{
public:
MList();
virtual Object* Clone()
{
// Create new instance of the managed list
MList* mList = new MList();
// calls unmanaged copy constructor
*(mList->m_pUnmanagedList) = *m_pUnmanagedList;
// deep copy any other members from this-> to mList->
return mList;
}
private:
UnmanagedLinkedList __nogc* m_pUnmanagedList;
};
Step 3: Wrapping Destructors
Wrapping destructors is trivial: have the destructor in the managed wrapper call the destructor in the unmanaged class:
~MList() { m_pUnmanagedList->~UnmanagedLinkedList(); }
I hope right now you are asking yourself, "But Sam, .NET is all about love. It is supposed to take care of memory for me with that garbage collection thingie." While that is certainly true for managed code, the CLR and the garbage collector have no idea about unmanaged resources. Our class holds such a reference to the unmanaged class, and therefore we must call the destructor in the unmanaged class explicitly, so that the underlying unmanaged object is destroyed.
Step 4: Dealing with Overloaded Operators
Managed C++ does not allow overloaded operator=(), just as it does not allow
copy constructors. The workaround is to define a method named Assign() and call
it explicitly:
virtual MList* Assign(MList* otherOne)
{
if (otherOne != this)
{
*m_pUnmanagedList = *(otherOne->m_pUnmanagedList);
// Deep copy other members
}
return this;
}
Step 4: Wrap the Rest of the Member Functions
Believe it or not, we're done with the hard part! All that is left is to wrap
the rest of the member functions of the class, if it makes sense to wrap
them.. The good news is that almost all of the time, member functions
may simply be wrapped by delegating the implementation of the function to the
unmanaged class (except for Accessor functions, which I will discuss
separately). I also like to rename the managed versions to fit with the Camel
and Pascal casing standards of .NET. For a refresher, here are the remaining
member functions declared in the header file:
// Member insert methods
void insert( Item *ptr, int value );
void insert_all( const UnmanagedLinkedList &rhs );
void insert_end( int value );
void InsertFront(int value);
// Member remove methods
int remove( int value );
void remove_front();
void remove_all();
int isEmpty();
void DisplayList();
The completed implementation looks like the following:
void MList::Insert( Item *ptr, int value )
{
m_pUnmanagedList->insert(ptr, value);
}
void MList::InsertAll(const UnmanagedLinkedList &rhs)
{
m_pUnmanagedList->insert_all(rhs);
}
void MList::InsertEnd(int value)
{
m_pUnmanagedList->insert_end(value);
}
void MList::InsertFront(int value)
{
m_pUnmanagedList->InsertFront(value);
}
int MList::Remove( int value )
{
return(m_pUnmanagedList->remove(value));
}
void MList::RemoveFront()
{
m_pUnmanagedList->remove_front();
}
void MList::RemoveAll()
{
m_pUnmanagedList->remove_all();
}
void MList::DisplayList()
{
m_pUnmanagedList->DisplayList();
}
Accessor Functions
The only things left are the accessor functions. There's nothing much to discuss here, other than to note that MC++ has full support for properties, which formalizes the notion of C++ member accessor functions through them. We only have two to consider. Recall these from the unmanaged code:
// Accessors
Item* Front() const { return m_first; }
int Size() { return m_size; }
All we have to do with these is make them full properties in the MC++ header file:
// properties
__property Item* get_Front();
__property int get_Size();
A C# Test Client for the Managed Wrapper
All that remains now is to test our completed wrapper! Open up VS.NET 2003
and create a new Visual C# Console Project named TestManagedList. There is no
need to change the default name of Class1, but you do need to add a reference to
the DLL project we just built. I assume you know how to bring up the Add
Reference dialog, so simply choose the Projects tab, browse to the
ManagedList\debug directory, and select ManagedList.dll.
Upon adding the reference, we can add the line of syntactical sugar that allows us to reference names in the namespace with "shortcut" syntax:
using ManagedList;
We are now ready to rock and roll, and test our managed wrapper. The first
thing to do is "new up" an instance of the wrapper (ManagedList):
MList theList = new MList();
The next thing to do is to call the methods to insert values at the front and back of the list, and then display it:
// Insert at the front and back and display the results
for (int i=0; i < 10; ++i)
{
theList.InsertFront(i);
theList.InsertEnd(i);
}
theList.DisplayList();
The next thing to test out is the property:
int listSize = theList.Size;
Console.WriteLine("The size of the managed list is {0} items", listSize.ToString());
Now it is time to test the operation of the Clone() method, to act as C++'s copy constructor:
MList newList = (MList)theList.Clone();
listSize = newList.Size;
Console.WriteLine("Size of the clone is {0} items",
listSize.ToString());
Console.WriteLine("...and the members are...");
newList.DisplayList();
// test assignment operator
newList.InsertFront(42);
newList.InsertFront(420);
listSize = newList.Size;
Console.WriteLine("Size of the clone is now {0} items",
listSize.ToString());
Console.WriteLine("and the members are:");
newList.DisplayList();
// now assign to the original to test the assignment operator
theList.Assign(newList);
listSize = theList.Size;
Console.WriteLine("Size of the original is now {0} items",
listSize.ToString());
Console.WriteLine("and the members are:");
newList.DisplayList();
Where Are We?
We have concluded our whirlwind three-part look at Managed C++ and its place in the canon of CLR languages. In this article, we used an example piece of unmanaged C++ code, and wrote a managed wrapper for it, step by step. As you saw, this process is not rocket science, but requires close attention to some details to get right. Hopefully, with this material, you may get started writing wrappers for your legacy C++ code so you may use it from C# and VB.NET.
Sam Gentile is a well-known .NET consultant and is currently working with a large firm, using Visual C++ .NET 2003 to develop both unmanaged and managed C++ applications.
Return to ONDotnet.com
-
Mistake in the article
2007-06-11 00:33:20 villalvilla [View]
-
Automated C++ Wrapper
2006-09-15 01:49:19 RapidXLL_NET [View]
-
Wrapper for unmanaged C++ Template class
2006-08-16 04:38:39 Seetharam [View]
-
what about wrapping Item class
2004-08-17 06:29:58 dotnetnovice [View]
- Trackback from http://154.20.151.233/dottextweb/articles/205.aspx
MC by Sam Gentile
2004-06-09 15:24:29 [View]
- Trackback from http://154.20.151.233/dottextweb/archive/2004/06/09/205.aspx
MC by Sam Gentile
2004-06-09 15:24:07 [View]
- Trackback from http://samgentile.com/blog/archive/0001/01/01/11407.aspx
My new O'Reilly Article is Live - Writing Managed Wrappers with Managed C
2004-03-30 14:53:27 [View]
-
Answers
2004-04-07 09:09:34 samgentile [View]
-
My new O'Reilly Article is Live - Writing Managed Wrappers with Managed C
2004-04-07 01:17:01 madigan04 [View]
- Trackback from http://samgentile.com/blog/archive/0001/01/01/11407.aspx
My new O'Reilly Article is Live - Writing Managed Wrappers with Managed C
2004-03-30 14:50:31 [View]
- Trackback from http://samgentile.com/blog/archive/0001/01/01/11407.aspx
My new O'Reilly Article is Live - Writing Managed Wrappers with Managed C
2004-03-30 14:49:48 [View]

