I wrote a custom marshaler for SAFEARRAY, but its performance was about twice lower than that default marshaller's performance. I perform arrays' marshaling element by element because they may have more than 1-2 dimensions. There is a piece of code that I use for this. Can I improve my marshaler's performance?
void ArrayIterator::GetValue(Array^ pManagedArray, Object^% managedObject)
{
managedObject = pManagedArray->GetValue(m_pManagedArrayIndices);
}
void ArrayIterator::GetValue(SAFEARRAY* pNativeArray, LPVOID* ppNativeValue)
{
CHECK_HR(::SafeArrayLock(pNativeArray));
CHECK_HR(::SafeArrayPtrOfIndex(pNativeArray, m_pNativeArrayIndices, ppNativeValue));
CHECK_HR(::SafeArrayUnlock(pNativeArray));
}
void ArrayIterator::SetValue(Array^ pManagedArray, Object^ managedValue)
{
pManagedArray->SetValue(managedValue, m_pManagedArrayIndices);
}
void ArrayIterator::SetValue(SAFEARRAY* pNativeArray, LPVOID pNativeValue)
{
CHECK_HR(::SafeArrayPutElement(pNativeArray, m_pNativeArrayIndices, pNativeValue));
}
void SafeArrayMarshaler::PutManagedElementToNativeArray(SAFEARRAY* pNativeArray, ArrayIterator^ pArrayIterator, ArrayElementType^ pArrayElementType, Object^ pManagedObject)
{
if (IsBlittableType(pArrayElementType->ManagedType))
{
GCHandle^ gcHandle = GCHandle::Alloc(pManagedObject, GCHandleType::Pinned);
pArrayIterator->SetValue(pNativeArray, gcHandle->AddrOfPinnedObject().ToPointer());
gcHandle->Free();
}
else if (pArrayElementType->NativeType == VT_BOOL)
{
Boolean managedBooleanValue = safe_cast<Boolean>(pManagedObject);
IntPtr nativeBoolPointer = Marshal::AllocHGlobal(sizeof(VARIANT_BOOL));
VARIANT_BOOL* pNativeBool = reinterpret_cast<VARIANT_BOOL*>(nativeBoolPointer.ToPointer());
*pNativeBool = managedBooleanValue == true ? VARIANT_TRUE : VARIANT_FALSE;
pArrayIterator->SetValue(pNativeArray, pNativeBool);
Marshal::FreeHGlobal(nativeBoolPointer);
}
else if (pArrayElementType->NativeType == VT_DATE)
{
DateTime managedDateValue = safe_cast<DateTime>(pManagedObject);
IntPtr nativeDatePointer = Marshal::AllocHGlobal(sizeof(DATE));
DATE* pNativeDate = reinterpret_cast<DATE*>(nativeDatePointer.ToPointer());
*pNativeDate = managedDateValue.ToOADate();
pArrayIterator->SetValue(pNativeArray, pNativeDate);
Marshal::FreeHGlobal(nativeDatePointer);
}
else if (pArrayElementType->NativeType == VT_BSTR)
{
IntPtr nativeBSTRHandle = Marshal::StringToBSTR(safe_cast<String^>(pManagedObject));
pArrayIterator->SetValue(pNativeArray, nativeBSTRHandle.ToPointer());
Marshal::FreeBSTR(nativeBSTRHandle);
}
else if (pArrayElementType->NativeType == VT_INT)
{
IntPtr managedPointer = safe_cast<IntPtr>(pManagedObject);
pArrayIterator->SetValue(pNativeArray, managedPointer.ToPointer());
}
else if (pArrayElementType->NativeType == VT_UINT)
{
UIntPtr managedPointer = safe_cast<UIntPtr>(pManagedObject);
pArrayIterator->SetValue(pNativeArray, managedPointer.ToPointer());
}
else if (pArrayElementType->NativeType == VT_DISPATCH)
{
IntPtr nativeInterfacePointer = Marshal::GetIDispatchForObject(pManagedObject);
pArrayIterator->SetValue(pNativeArray, nativeInterfacePointer.ToPointer());
Marshal::Release(nativeInterfacePointer);
}
else if (pArrayElementType->NativeType == VT_UNKNOWN)
{
IntPtr nativeInterfacePointer = Marshal::GetIUnknownForObject(pManagedObject);
pArrayIterator->SetValue(pNativeArray, nativeInterfacePointer.ToPointer());
Marshal::Release(nativeInterfacePointer);
}
else if (pArrayElementType->NativeType == VT_VARIANT)
{
IntPtr nativeVariantHandle = Marshal::AllocHGlobal(sizeof(VARIANT));
Marshal::GetNativeVariantForObject(pManagedObject, nativeVariantHandle);
pArrayIterator->SetValue(pNativeArray, nativeVariantHandle.ToPointer());
Marshal::FreeHGlobal(nativeVariantHandle);
}
else
{
throw gcnew InvalidOperationException();
}
}
void SafeArrayMarshaler::PutNativeElementToManagedArray(Array^ pManagedArray, ArrayIterator^ pArrayIterator, ArrayElementType^ pArrayElementType, LPVOID pNativeObject)
{
if (IsBlittableType(pArrayElementType->ManagedType))
{
switch (Type::GetTypeCode(pArrayElementType->ManagedType))
{
case TypeCode::SByte:
{
SByte managedSignedByte = Marshal::ReadByte(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedSignedByte);
break;
}
case TypeCode::Byte:
{
Byte managedUnsignedByte = Marshal::ReadByte(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedUnsignedByte);
break;
}
case TypeCode::Int16:
{
Int16 managedValue = Marshal::ReadInt16(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::UInt16:
{
UInt16 managedValue = Marshal::ReadInt16(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::Int32:
{
Int32 managedValue = Marshal::ReadInt32(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::UInt32:
{
UInt32 managedValue = Marshal::ReadInt32(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::Int64:
{
Int64 managedValue = Marshal::ReadInt64(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::UInt64:
{
UInt64 managedValue = Marshal::ReadInt64(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::Single:
{
Single managedValue;
pin_ptr<Single> pManagedValue = &managedValue;
::memcpy_s(pManagedValue, Marshal::SizeOf(Single::typeid), pNativeObject, Marshal::SizeOf(Single::typeid));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
case TypeCode::Double:
{
Double managedValue;
pin_ptr<Double> pManagedValue = &managedValue;
::memcpy_s(pManagedValue, Marshal::SizeOf(Double::typeid), pNativeObject, Marshal::SizeOf(Double::typeid));
pArrayIterator->SetValue(pManagedArray, managedValue);
break;
}
default:
throw gcnew NotImplementedException();
}
}
else if (pArrayElementType->NativeType == VT_BOOL)
{
VARIANT_BOOL* pNativeBooleanValue = reinterpret_cast<VARIANT_BOOL*>(pNativeObject);
pArrayIterator->SetValue(pManagedArray, *pNativeBooleanValue == VARIANT_TRUE ? true : false);
}
else if (pArrayElementType->NativeType == VT_DATE)
{
DATE* pNativeDateValue = reinterpret_cast<DATE*>(pNativeObject);
pArrayIterator->SetValue(pManagedArray, DateTime::FromOADate(*pNativeDateValue));
}
else if (pArrayElementType->NativeType == VT_BSTR)
{
String^ pManagedString = Marshal::PtrToStringBSTR(IntPtr(*reinterpret_cast<void**>(pNativeObject)));
pArrayIterator->SetValue(pManagedArray, pManagedString);
}
else if (pArrayElementType->NativeType == VT_INT)
{
INT_PTR nativePointer = reinterpret_cast<INT_PTR>(pNativeObject);
pArrayIterator->SetValue(pManagedArray, IntPtr(nativePointer));
}
else if (pArrayElementType->NativeType == VT_UINT)
{
UINT_PTR nativePointer = reinterpret_cast<UINT_PTR>(pNativeObject);
pArrayIterator->SetValue(pManagedArray, UIntPtr(nativePointer));
}
else if (pArrayElementType->NativeType == VT_DISPATCH ||
pArrayElementType->NativeType == VT_UNKNOWN)
{
Object^ pManagedObject = Marshal::GetObjectForIUnknown(IntPtr(*reinterpret_cast<void**>(pNativeObject)));
pArrayIterator->GetValue(pManagedArray, pManagedObject);
}
else if (pArrayElementType->NativeType == VT_VARIANT)
{
Object^ pManagedObject = Marshal::GetObjectForNativeVariant(IntPtr(pNativeObject));
pArrayIterator->SetValue(pManagedArray, pManagedObject);
}
else
{
throw gcnew InvalidOperationException();
}
}