A couple of blog entries ago, I had written about the marshal_as library that is introduced in Orcas and how it’s very useful for mixed-mode string conversions. While the built-in functionality only allows string conversions, it’s also possible to extend marshal_as functionality to support other type conversions. As an example of doing this, I have written a sample extension that supports converting between the Windows Forms Rectangle structure and the Win32 RECT structure. For the sake of completion I have also added specializations for the MFC CRect wrapper (which is a thin wrapper around the RECT structure). Here’s my extension (put into a separate header file) :-
namespace msclr
{
namespace interop
{
template<> System::Drawing::Rectangle
marshal_as<System::Drawing::Rectangle, RECT> (
const RECT& from)
{
return System::Drawing::Rectangle(from.left, from.top,
from.right - from.left, from.bottom - from.top);
}
template<> System::Drawing::Rectangle marshal_as<
System::Drawing::Rectangle, CRect> (
const CRect& from)
{
return System::Drawing::Rectangle(from.left, from.top,
from.Width(), from.Height());
}
template<> RECT marshal_as<RECT, System::Drawing::Rectangle>(
const System::Drawing::Rectangle& from)
{
System::Drawing::Rectangle rectangle = from; //remove const
RECT rect = {rectangle.Left, rectangle.Top,
rectangle.Right, rectangle.Bottom};
return rect;
}
template<> CRect marshal_as<CRect, System::Drawing::Rectangle>(
const System::Drawing::Rectangle& from)
{
System::Drawing::Rectangle rectangle = from; //remove const
return CRect (rectangle.Left, rectangle.Top,
rectangle.Right, rectangle.Bottom);
}
}
}
Effectively I’ve added four specializations for the four conversions that I need. Note how I have put the conversions into the msclr::interop namespace. This is to allow me (and anyone else) to use these additional conversions the same way I’d be using marshal_as for the regular conversions.
Now using these conversions would be quite trivial as show below.
//To Rectangle
RECT rect = {10, 10, 110, 110};
System::Drawing::Rectangle rectangle =
marshal_as<System::Drawing::Rectangle>(rect);
CRect mfcRect(20, 20, 220, 220);
rectangle = marshal_as<System::Drawing::Rectangle>(mfcRect);
//From Rectangle
RECT rectBack = marshal_as<RECT>(rectangle);
CRect mfcRectBack = marshal_as<CRect>(rectangle);
One important thing to be aware of is that in all four conversions I’ve added there is no need to handle context as there is no explicit need for memory deallocation. This may not always be the case as we’ll see in the next blog entry (hopefully soon).
Read Full Post »