When implementing the ActiveX component, I did not need to do any marshaling since VARIANT is an OLE/COM type.
When implementing .Net component, I used similar to this:
VARIANT var;
//...
//Initialize the VARIANT value
//...
System::IntPtr p( &var );
System::Object ^o = System::Runtime::InteropServices::Marshal::GetObjectForNativeVariant( p );
return o;
In WinRT, there does not seem to be any similar Marshal class that will do the job. According to MSDN "The WinRT Platform::Runtime::InteropServices namespace is intended for internal use only, and is not intended to be used for development."
After posting a question on an MSDN (http://social.msdn.microsoft.com/Forums ... 1a654965d4) forum I got one reply suggesting that I try to use Windows::Foundation::IPropertyValue. After some investigation I wrote a simple utility class that makes use of Windows::Foundation::IPropertyValue to do implement marshalling of a VARIANT to Platform::Object ^ and the reverse, Platform::Object ^ to VARIANT.
Below is the code of this class.
Code: Select all
//////////////////////////////////////////////////////////////////////////////////
//
// Copyright AMYUNI Technologies, 1998-2012, All Rights Reserved
//
// Permission to use this work is granted for free and for any purpose
// with no restrictions and without any warranties
// For more information: AMYUNI Technologies, http://www.amyuni.com
//
// acMarshall: WinRT C++ utility class to Marshal VARIANT to Object and vice-versa
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <windows.h>
#include <stdint.h>
#include <atlconv.h>
using namespace Platform;
using namespace Windows::Foundation;
public ref class acMarshall
{
internal:
static LPSTR MarshalString(String ^s)
{
//The caller is responsible for freeing the allocated LPSTR memory
USES_CONVERSION;
UINT n = s->Length();
LPSTR str = (LPSTR) malloc( (n + 1) * sizeof(CHAR) );
str[0] = 0;
strncpy_s( str, n, W2CA(s->Begin()), n );
return str;
}
static LPWSTR MarshalStringW(String ^s)
{
//The caller is responsible for freeing the allocated LPWSTR memory
UINT n = s->Length();
LPWSTR str = (LPWSTR) malloc( (n + 1) * sizeof(WCHAR) );
str[0] = 0;
wcsncpy_s( str, n, s->Begin(), n );
return str;
}
static Object ^ MarshalVariantToObject(const VARIANT &var)
{
Object ^ obj = nullptr;
BOOL byRef = (var.vt & VT_BYREF) > 0;
BOOL isArray = (var.vt & VT_ARRAY) > 0;
VARTYPE vt = var.vt &~ (VT_BYREF | VT_ARRAY);
if ( isArray )
{
//if VARIANT contains an array
UINT len = 0;
SAFEARRAY *psa = (byRef ? *var.pparray : var.parray);
HRESULT hr;
if ( SUCCEEDED( hr = SafeArrayLock( psa ) ) &&
SUCCEEDED( hr = SafeArrayGetUBound( psa, 1, (LONG *) &len ) ) )
{
len++;
Object ^ arr = nullptr;
switch ( vt )
{
case VT_I2:
arr = ref new Array< short >( len );
break;
case VT_I4:
case VT_INT:
arr = ref new Array< int >( len );
break;
case VT_R4:
arr = ref new Array< float >( len );
break;
case VT_R8:
arr = ref new Array< double >( len );
break;
case VT_DATE:
arr = ref new Array< DateTime >( len );
break;
case VT_BSTR:
arr = ref new Array< String ^>( len );
break;
case VT_BOOL:
arr = ref new Array< bool >( len );
break;
case VT_VARIANT:
arr = ref new Array< Object ^ >( len );
break;
case VT_I1:
case VT_UI1:
arr = ref new Array< unsigned char >( len );
break;
case VT_UI2:
arr = ref new Array< unsigned short >( len );
break;
case VT_UI4:
case VT_UINT:
arr = ref new Array< unsigned int >( len );
break;
case VT_I8:
arr = ref new Array< int64_t >( len );
break;
case VT_UI8:
arr = ref new Array< uint64_t >( len );
break;
default:
break;
}
// read data into array in this loop
LPBYTE p = (LPBYTE) psa->pvData;
for ( UINT i = 0; i < len; i++ )
{
if ( arr == nullptr )
break;
switch ( vt )
{
case VT_I2:
((Array< short > ^)arr)->set( i, *(short *) p );
p += sizeof( short );
break;
case VT_I4:
case VT_INT:
((Array< int > ^)arr)->set( i, *(int *) p );
p += sizeof( int );
break;
case VT_R4:
((Array< float > ^)arr)->set( i, *(float *) p );
p += sizeof( float );
break;
case VT_R8:
((Array< double > ^)arr)->set( i, *(double *) p );
p += sizeof( double );
break;
case VT_DATE:
{
UDATE udate;
if SUCCEEDED( VarUdateFromDate( *(DATE *) p, 0, &udate ) )
{
Windows::Globalization::Calendar ^ c = ref new Windows::Globalization::Calendar();
c->Year = udate.st.wYear;
c->Month = udate.st.wMonth;
c->Day = udate.st.wDay;
c->Hour = udate.st.wHour;
c->Minute = udate.st.wMinute;
c->Second = udate.st.wSecond;
c->Nanosecond = udate.st.wMilliseconds * 1000000;
((Array< DateTime > ^)arr)->set( i, c->GetDateTime() );
}
}
p += sizeof( DATE );
break;
case VT_BSTR:
((Array< String ^ > ^)arr)->set( i, ref new String( *(BSTR *) p, SysStringLen(*(BSTR *) p) ) );
p += sizeof( BSTR );
break;
case VT_BOOL:
((Array< bool > ^)arr)->set( i, *(bool *) p );
p += sizeof( bool );
break;
case VT_VARIANT:
((Array< Object ^ > ^)arr)->set( i, MarshalVariantToObject( *(VARIANT *) p ) );
p += sizeof( VARIANT * );
break;
case VT_I1:
case VT_UI1:
((Array< unsigned char > ^)arr)->set( i, *(unsigned char *) p );
p += sizeof( unsigned char );
break;
case VT_UI2:
((Array< unsigned short > ^)arr)->set( i, *(unsigned short *) p );
p += sizeof( unsigned short );
break;
case VT_UI4:
case VT_UINT:
((Array< unsigned int > ^)arr)->set( i, *(unsigned int *) p );
p += sizeof( unsigned int );
break;
case VT_I8:
((Array< int64_t > ^)arr)->set( i, *(int64_t *) p );
p += sizeof( int64_t );
break;
case VT_UI8:
((Array< uint64_t > ^)arr)->set( i, *(uint64_t *) p );
p += sizeof( uint64_t );
break;
default:
arr = nullptr; // abort in case of unsupported VT in array
break;
}
}
SafeArrayUnlock( psa );
if ( arr != nullptr )
{
switch ( vt )
{
case VT_I2:
obj = PropertyValue::CreateInt16Array( (Array< short > ^) arr );
break;
case VT_I4:
case VT_INT:
obj = PropertyValue::CreateInt32Array( (Array< int > ^) arr );
break;
case VT_R4:
obj = PropertyValue::CreateSingleArray( (Array< float > ^) arr );
break;
case VT_R8:
obj = PropertyValue::CreateDoubleArray( (Array< double > ^) arr );
break;
case VT_DATE:
obj = PropertyValue::CreateDateTimeArray( (Array< DateTime > ^) arr );
break;
case VT_BSTR:
obj = PropertyValue::CreateStringArray( (Array< String ^ > ^) arr );
break;
case VT_BOOL:
obj = PropertyValue::CreateBooleanArray( (Array< bool > ^) arr );
break;
case VT_VARIANT:
obj = PropertyValue::CreateInspectableArray( (Array< Object ^ > ^) arr );
break;
case VT_I1:
case VT_UI1:
obj = PropertyValue::CreateUInt8Array( (Array< unsigned char > ^) arr );
break;
case VT_UI2:
obj = PropertyValue::CreateUInt16Array( (Array< unsigned short > ^) arr );
break;
case VT_UI4:
case VT_UINT:
obj = PropertyValue::CreateUInt32Array( (Array< unsigned int > ^) arr );
break;
case VT_I8:
obj = PropertyValue::CreateInt64Array( (Array< int64_t > ^) arr );
break;
case VT_UI8:
obj = PropertyValue::CreateUInt64Array( (Array< uint64_t > ^) arr );
break;
default:
break;
}
}
}
return obj;
}
//if VARIANT does not contain an array
switch ( vt )
{
case VT_I2:
obj = PropertyValue::CreateInt16( byRef ? *var.piVal : var.iVal );
break;
case VT_I4:
case VT_INT:
obj = PropertyValue::CreateInt32( byRef ? *var.plVal : var.lVal );
break;
case VT_R4:
obj = PropertyValue::CreateSingle( byRef ? *var.pfltVal : var.fltVal );
break;
case VT_R8:
obj = PropertyValue::CreateDouble( byRef ? *var.pdblVal : var.dblVal );
break;
case VT_DATE:
{
UDATE udate;
if SUCCEEDED( VarUdateFromDate( byRef ? *var.pdate : var.date, 0, &udate ) )
{
Windows::Globalization::Calendar ^ c = ref new Windows::Globalization::Calendar();
c->Year = udate.st.wYear;
c->Month = udate.st.wMonth;
c->Day = udate.st.wDay;
c->Hour = udate.st.wHour;
c->Minute = udate.st.wMinute;
c->Second = udate.st.wSecond;
c->Nanosecond = udate.st.wMilliseconds * 1000000;
obj = PropertyValue::CreateDateTime( c->GetDateTime() );
}
}
break;
case VT_BSTR:
{
const BSTR *pbstr = (byRef ? var.pbstrVal : &var.bstrVal);
obj = PropertyValue::CreateString( ref new String( *pbstr, SysStringLen(*pbstr) ) );
}
break;
case VT_BOOL:
{
const VARIANT_BOOL *pVarBool = ( byRef ? var.pboolVal : &var.boolVal );
obj = PropertyValue::CreateBoolean( *pVarBool == 0xFFFF );
}
break;
case VT_VARIANT:
obj = MarshalVariantToObject( *var.pvarVal );
break;
case VT_I1:
obj = PropertyValue::CreateUInt8( byRef ? (UCHAR) *var.pcVal: (UCHAR) var.cVal );
break;
case VT_UI1:
obj = PropertyValue::CreateUInt8( byRef ? *var.pbVal: var.bVal );
break;
case VT_UI2:
obj = PropertyValue::CreateUInt16( byRef ? *var.puiVal: var.uiVal );
break;
case VT_UI4:
case VT_UINT:
obj = PropertyValue::CreateUInt32( byRef ? *var.pulVal: var.ulVal );
break;
case VT_I8:
obj = PropertyValue::CreateInt64( byRef ? *var.pllVal: var.llVal );
break;
case VT_UI8:
obj = PropertyValue::CreateUInt64( byRef ? *var.pullVal: var.ullVal );
break;
case VT_EMPTY:
case VT_NULL:
case VT_CY:
case VT_DISPATCH:
case VT_ERROR:
case VT_UNKNOWN:
case VT_DECIMAL:
case VT_VOID:
case VT_HRESULT:
case VT_PTR:
case VT_CARRAY:
case VT_USERDEFINED:
case VT_LPSTR:
case VT_LPWSTR:
case VT_RECORD:
case VT_INT_PTR:
case VT_UINT_PTR:
case VT_FILETIME:
case VT_BLOB:
case VT_STREAM:
case VT_STORAGE:
case VT_STREAMED_OBJECT:
case VT_STORED_OBJECT:
case VT_BLOB_OBJECT:
case VT_CF:
case VT_CLSID:
case VT_VERSIONED_STREAM:
case VT_BSTR_BLOB:
case VT_VECTOR:
case VT_RESERVED:
case VT_ILLEGAL:
//case VT_ILLEGALMASKED:
//case VT_TYPEMASK:
break;
default:
break;
}
return obj;
}
static VARIANT MarshalObjectToVariant(Object ^ obj)
{
VARIANT var;
VariantInit( &var );
IPropertyValue ^ ipv = dynamic_cast<IPropertyValue ^>(obj);
PropertyType type = ipv->Type;
BOOL isArray = ((UINT) type & 1024) > 0;
if ( isArray )
{
//if Object contains an array
VARTYPE vt = VT_EMPTY;
type = (PropertyType) (((UINT)type) &~ 1024);
var.vt = VT_ARRAY;
switch (type)
{
case PropertyType::Boolean:
{
vt = VT_BOOL;
var.vt |= vt;
Array< bool > ^ arr;
ipv->GetBooleanArray(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
VARIANT_BOOL *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (bool value in arr)
{
*p = (value ? 0xFFFF : 0);
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::DateTime:
{
vt = VT_DATE;
var.vt |= vt;
Array< DateTime > ^ arr;
ipv->GetDateTimeArray(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
DATE *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
UDATE udate;
Windows::Globalization::Calendar ^ c = ref new Windows::Globalization::Calendar();
for each (DateTime value in arr)
{
c->SetDateTime( value );
udate.st.wYear = c->Year ;
udate.st.wMonth = c->Month;
udate.st.wDay = c->Day;
udate.st.wHour = c->Hour;
udate.st.wMinute = c->Minute;
udate.st.wSecond = c->Second;
udate.st.wMilliseconds = c->Nanosecond / 1000000;
var.vt = VT_DATE;
VarDateFromUdate( &udate, 0, p );
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::UInt8:
{
vt = VT_UI1;
var.vt |= vt;
Array< unsigned char > ^ arr;
ipv->GetUInt8Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
BYTE *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (unsigned char value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::Int16:
{
vt = VT_I2;
var.vt |= vt;
Array< short > ^ arr;
ipv->GetInt16Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
SHORT *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (short value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::UInt16:
{
vt = VT_UI2;
var.vt |= vt;
Array< unsigned short > ^ arr;
ipv->GetUInt16Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
USHORT *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (unsigned short value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::Int32:
{
vt = VT_I4;
var.vt |= vt;
Array< int > ^ arr;
ipv->GetInt32Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
LONG *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (int value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::UInt32:
{
vt = VT_UI4;
var.vt |= vt;
Array< unsigned int > ^ arr;
ipv->GetUInt32Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
ULONG *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each (unsigned int value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::Int64:
{
vt = VT_I8;
var.vt |= vt;
Array< int64_t > ^ arr;
ipv->GetInt64Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
LONGLONG *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each ( int64_t value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::UInt64:
{
vt = VT_UI8;
var.vt |= vt;
Array< uint64_t > ^ arr;
ipv->GetUInt64Array(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
ULONGLONG *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each ( uint64_t value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::Single:
{
vt = VT_R4;
var.vt |= vt;
Array< float > ^ arr;
ipv->GetSingleArray(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
FLOAT *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each ( float value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::Double:
{
vt = VT_R8;
var.vt |= vt;
Array< double > ^ arr;
ipv->GetDoubleArray(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
DOUBLE *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each ( double value in arr)
{
*p = value;
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
case PropertyType::String:
{
vt = VT_BSTR;
var.vt |= vt;
Array< String ^ > ^ arr;
ipv->GetStringArray(&arr);
SAFEARRAYBOUND sab;
sab.cElements = arr->Length;
sab.lLbound = 0;
SAFEARRAY *psa = SafeArrayCreate( vt, 1, &sab );
BSTR *p = NULL;
SafeArrayAccessData( psa, (void**) &p );
for each ( String ^ value in arr)
{
*p = SysAllocStringLen( value->Begin(), value->Length() );
p++;
}
SafeArrayUnaccessData( psa );
var.parray = psa;
}
break;
default:
var.vt = VT_EMPTY; //coudn't convert
break;
}
return var;
}
//if Object does not contain an array
switch (type)
{
case PropertyType::Boolean:
var.vt = VT_BOOL;
var.boolVal = (ipv->GetBoolean() ? 0xFFFF : 0);
break;
case PropertyType::DateTime:
{
Windows::Globalization::Calendar ^ c = ref new Windows::Globalization::Calendar();
c->SetDateTime( ipv->GetDateTime() );
UDATE udate;
udate.st.wYear = c->Year ;
udate.st.wMonth = c->Month;
udate.st.wDay = c->Day;
udate.st.wHour = c->Hour;
udate.st.wMinute = c->Minute;
udate.st.wSecond = c->Second;
udate.st.wMilliseconds = c->Nanosecond / 1000000;
var.vt = VT_DATE;
VarDateFromUdate( &udate, 0, &var.date );
}
break;
case PropertyType::UInt8:
var.vt = VT_UI1;
var.bVal = ipv->GetUInt8();
break;
case PropertyType::Int16:
var.vt = VT_I2;
var.iVal = ipv->GetInt16();
break;
case PropertyType::UInt16:
var.vt = VT_UI2;
var.uiVal = ipv->GetUInt16();
break;
case PropertyType::Int32:
var.vt = VT_I4;
var.lVal = ipv->GetInt32();
break;
case PropertyType::UInt32:
var.vt = VT_UI4;
var.ulVal = ipv->GetUInt32();
break;
case PropertyType::Int64:
var.vt = VT_I8;
var.llVal = ipv->GetInt64();
break;
case PropertyType::UInt64:
var.vt = VT_UI8;
var.ullVal = ipv->GetUInt64();
break;
case PropertyType::Single:
var.vt = VT_R4;
var.fltVal = ipv->GetSingle();
break;
case PropertyType::Double:
var.vt = VT_R8;
var.dblVal = ipv->GetDouble();
break;
case PropertyType::String:
{
String ^s = ipv->GetString();
var.vt = VT_BSTR;
var.bstrVal = SysAllocStringLen( s->Begin(), s->Length() );
}
break;
default:
break;
};
return var;
}
};