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]
 Friday, November 30, 2007

Would you like to try writing a marshal_as<> specialization? They're super simple, after all. Here's a list of some that we're sure to need:

Array Conversions

FROM TYPE TO TYPE
array<String^>^ std::vector<std::string>
std::vector<std::string>  array<String^>^
array<String^>^ std::vector<std::wstring>
std::vector<std::wstring>  array<String^>^
array<String^>^ CArray<ATL::CStringT<char>>
CArray<ATL::CStringT<char>> array<String^>^
array<String^>^ CArray<ATL::CStringT<wchar_t>>
CArray<ATL::CStringT<wchar_t>> array<String^>^
array<String^>^ CSimpleArray<ATL::CStringT<char>>
CSimpleArray<ATL::CStringT<char>> array<String^>^
array<String^>^ CSimpleArray<ATL::CStringT<wchar_t>>
CSimpleArray<ATL::CStringT<wchar_t>> array<String^>^
array<String^>^ CSimpleArray<CComBSTR>
CSimpleArray<CComBSTR> array<String^>^
array<String^>^ CArray<CComBSTR>
CArray<CComBSTR> array<String^>^
array<T>^ std::vector<T>
std::vector<T> array<T>^
array<T>^ CComSafeArray<T,U>
CComSafeArray<T, U> array<T>^
array<T>^ CArray<T>
CArray<T> array<T>^
array<T>^ CAtlArray<T>
CAtlArray<T> array<T>^
array<String^>^ CAtlArray<ATL::CStringT<char>>
CAtlArray<ATL::CStringT<char>> array<String^>^
array<String^>^ CAtlArray<ATL::CStringT<wchar_t>>
CAtlArray<ATL::CStringT<wchar_t>> array<String^>^
array<T>^ CSimpleArray<T>
CSimpleArray<T> array<T>^

Other Conversions:

FROM TYPE TO TYPE
System::IntPtr ATL::CHandle
ATL::CHandle System::IntPtr
System::DateTime  SYSTEMTIME
SYSTEMTIME System::DateTime
System::Object^ IUnknown*
IUnknown * System::Object^
System::Object ^ com_ptr<IUnknown>
System::Object ^ CComPtr<Iunknown>
System::Object^ VARIANT
VARIANT System::Object^
System::Guid GUID
GUID System::GUID
System::DateTime CTime
CTime System::DateTime
System::DateTime COleDateTime
COleDateTime System::DateTime

I've pasted the table in as I received it, and linked to things we already have. I'd like to come back to this list and add links as you send me things.

Kate

 

posted on 11/30/2007 8:24:46 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]
 Thursday, November 22, 2007

From Jason Olson.

//code starts here

#pragma once
#include
<msclr\marshal.h>
#include <msclr\marshal_windows.h>

namespace msclr {
namespace interop {

////////////////////////////////////////////////////////////////////
// GUID Conversions
////////////////////////////////////////////////////////////////////

template<>
inline _GUID marshal_as<_GUID, System::Guid>(const System::Guid& from) {

    System::Guid^ source = from;
    array<Byte>^ guidData = source->ToByteArray();
    pin_ptr<Byte> data = &(guidData[ 0 ]);
    return *(_GUID *)data;

}

template<>
inline Guid marshal_as<System::Guid, _GUID>(const _GUID& from) {
    
return System::Guid( from.Data1, from.Data2, from.Data3, from.Data4[ 0 ], from.Data4[ 1 ],
                                 from.Data4[ 2 ], from.Data4[ 3 ], from.Data4[ 4 ], from.Data4[ 5 ],
                                 from.Data4[ 6 ], from.Data4[ 7 ] );

}

}

}

//code ends here

At first glance the pin_ptr is a little scary, but this code doesn't return it, it dereferences it. So no "GC hole" to worry about.

Kate

posted on 11/22/2007 8:41:32 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]

From Jason Olson.

//code starts here

#pragma once
#include
<msclr\marshal.h>
#include <msclr\marshal_windows.h>
namespace msclr {
namespace interop {

////////////////////////////////////////////////////////////////////
// File I/O Conversions (constants from System::IO)
///////////////////////////////////////////////////////////////////

template<>
inline DWORD marshal_as<DWORD, System::IO::FileMode>(const System::IO::FileMode& from) {

if (from != System::IO::FileMode::Append)
   
return (DWORD)from;
else
   
return (DWORD)System::IO::FileMode::OpenOrCreate;

}

template<>
inline DWORD marshal_as<DWORD, System::IO::FileAccess>(const System::IO::FileAccess& from) {
if (from == System::IO::FileAccess::Read)
   
return GENERIC_READ;
else
   
return GENERIC_WRITE;

}

template<>
inline DWORD marshal_as<DWORD, System::IO::FileShare>(const System::IO::FileShare& from) {
   
return (DWORD)from;

}

}

}

//code ends here

Nice and simple.

Kate

posted on 11/22/2007 8:35:35 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]
 Monday, November 19, 2007

Here we are!

What's going on here? Think pinvoke.net for the marshaling library. Send me your specializations (my email address isn't hard to find, or comment on this post -- if I use comments I'll remove them from here as I go) and I'll post them, one post per specialization, after the barest of quality control (I might make sure your code compiles) and then others can find them and comment on them. Together we will build a full-size marshaling library for all the common structs and classes that might pass back and forth across the managed-native boundary.

Some of you may have some specializations already written. Great! I'll post them as I get them and if I can't keep up, I have a volunteer team waiting to help. So let's go!

Kate Gregory

 

posted on 11/19/2007 10:00:51 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0]