Thursday, December 13, 2007

From Nish.

//code starts here
namespace msclr
{
    namespace interop
    {
        template<> ref class context_node<System::Drawing::Font^, HFONT> : public context_node_base
        {
        private:
            System::Drawing::Font^ _font;
	
        public:
            context_node(System::Drawing::Font^% to, HFONT from)
            {
                to = _font = System::Drawing::Font::FromHfont((IntPtr)from);
            }
	
            ~context_node()
            {
                this->!context_node();
            }
	
        protected:
            !context_node()
            {
                delete _font;
            }
        };
	
        template<> ref class context_node<HFONT, System::Drawing::Font^> : public context_node_base
        {
        private:
            HFONT _hFont;
	
        public:
            context_node(HFONT& to, System::Drawing::Font^ from)
            {
                to = _hFont = (HFONT)from->ToHfont().ToPointer();
            }
	
            ~context_node()
            {
                this->!context_node();
            }
	
        protected:
            !context_node()
            {
                DeleteObject(_hFont);
            }
        };
    }
}
//code ends here

Wow. Our first use of a context. Instead of writing a function that implements a specialization of the template function, you write a class that implements a specialization of the template class. Since it's a class, it can have member variables, which you clean up when the context goes out of scope.

Here's how you might use it:

HFONT hFont = CreateSampleFont();
	
//...
	
marshal_context context;
	
System::Drawing::Font^ font =
    context.marshal_as<System::Drawing::Font^>(hFont);
HFONT hFontCopy = context.marshal_as<HFONT>(font);
	
//...
	
DeleteObject(hFont);

Kate

posted on 12/13/2007 5:15:57 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]

From Nish.

//code starts here
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);
        }
    }
}
//code ends here

Why cast away const? Because System::Drawing::Rect is CLS-compliant and the properties (Top, Bottom, Left Right) are not flagged as keeping the object const. We know they don't change it, so we make a copy to use the properties on, thus keeping the compiler happy about our const ref argument.

To use these, it's as you'd expect:

//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);

Kate

posted on 12/13/2007 5:05:57 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]