Anmerkung: Hier geht es zum deutschen Beitrag.

As posted before (sorry just in German) Visual Studio 2008 comes with a nice marshaling library for C++/CLI. With that it is easier to convert various native types into managed types and vice versa. Unfortunately the library just supports string conversion. But the good thing is that the library is extensible to support more scenarios. I will show a little example on how to extend the library with a CComVariant to String^ conversion.

CComVariant is an ATL wrapper for VARIANT. I'm not sure how many people used Variants in function declarations as passing parameters. I have done lot of COM development with focus on providing OLE Automation conform interfaces so I used it quite a lot.

Therefore I see some need in providing native Variant to managed type conversion. First we have to extend the marshaling library. This is pretty simple. I just provide two inline methods for the conversions I want to include, which are a CComVariant to String^ and a String^ to CComVariant conversion.

   1: #include "StdAfx.h"
   2: #include "MyVariantMarshal.h"
   3:  
   4: namespace msclr 
   5: {
   6:     namespace interop 
   7:     {
   8:         using namespace cli;
   9:         using namespace System;
  10:         using namespace System::Runtime::InteropServices;
  11:  
  12:         template<>
  13:         inline String^ marshal_as(const CComVariant& from) 
  14:         {
  15:             if( from.bstrVal == NULL )
  16:             {
  17:                 return nullptr;
  18:             }
  19:  
  20:             return Marshal::PtrToStringBSTR( IntPtr( from.bstrVal ) );
  21:         }
  22:  
  23:         template<>
  24:         inline CComVariant marshal_as(String^ const& from)
  25:         {
  26:             if( from == nullptr )
  27:             {
  28:                 return CComVariant( static_cast<const wchar_t*>( NULL ) );
  29:             }
  30:  
  31:             if( from->Length == 0 )
  32:             {
  33:                 return CComVariant( static_cast<const wchar_t*>( L"" ) );
  34:             }
  35:  
  36:             pin_ptr<const wchar_t> pinnedString = PtrToStringChars( from );
  37:             CComBSTR bstr( from->Length, static_cast<const wchar_t*>( pinnedString ) );
  38:             return CComVariant( bstr );
  39:         }
  40:     }
  41: }
  42:  

That's it.

The following CLR console application is just reusing my templates and another example on how to make "Hello, world." complicated.

   1: #include "stdafx.h"
   2: #include "MyVariantMarshal.hpp"
   3:  
   4: using namespace System;
   5: using namespace msclr::interop;
   6:  
   7: int main(array<System::String ^> ^args)
   8: {
   9:     String^ text = L"Hello, World.";
  10:     
  11:     CComVariant variant = marshal_as<CComVariant>(text);
  12:     String^ string = marshal_as<String^>(variant);
  13:  
  14:     Console::WriteLine( "{0}", string );
  15:  
  16:     return 0;
  17: }

The point is that even the current implementation of the marshaling library is not providing more than string conversions it is a nice and clean implementation which can be easily extended.