0

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();
    }
}
4

0 回答 0