2025-07-03 12:53:49 +04:00

340 lines
12 KiB
C++

#include "il2cpp-config.h"
#include "il2cpp-object-internals.h"
#include "vm/Array.h"
#include "vm/COM.h"
#include "vm/Exception.h"
#include "vm/PlatformInvoke.h"
#include "vm/Reflection.h"
#include "os/COM.h"
namespace il2cpp
{
namespace vm
{
void COM::MarshalVariant(Il2CppObject* obj, Il2CppVariant* variant)
{
IL2CPP_ASSERT(variant);
os::COM::VariantInit(variant);
if (!obj)
return;
if (obj->klass == il2cpp_defaults.sbyte_class)
{
variant->n1.n2.type = IL2CPP_VT_I1;
variant->n1.n2.n3.cVal = *static_cast<int8_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.byte_class)
{
variant->n1.n2.type = IL2CPP_VT_UI1;
variant->n1.n2.n3.bVal = *static_cast<uint8_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.int16_class)
{
variant->n1.n2.type = IL2CPP_VT_I2;
variant->n1.n2.n3.iVal = *static_cast<int16_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.uint16_class)
{
variant->n1.n2.type = IL2CPP_VT_UI2;
variant->n1.n2.n3.uiVal = *static_cast<uint16_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.int32_class)
{
variant->n1.n2.type = IL2CPP_VT_I4;
variant->n1.n2.n3.lVal = *static_cast<int32_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.uint32_class)
{
variant->n1.n2.type = IL2CPP_VT_UI4;
variant->n1.n2.n3.ulVal = *static_cast<uint32_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.int64_class)
{
variant->n1.n2.type = IL2CPP_VT_I8;
variant->n1.n2.n3.llVal = *static_cast<int64_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.uint64_class)
{
variant->n1.n2.type = IL2CPP_VT_UI8;
variant->n1.n2.n3.ullVal = *static_cast<uint64_t*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.single_class)
{
variant->n1.n2.type = IL2CPP_VT_R4;
variant->n1.n2.n3.fltVal = *static_cast<float*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.double_class)
{
variant->n1.n2.type = IL2CPP_VT_R8;
variant->n1.n2.n3.dblVal = *static_cast<double*>(Object::Unbox(obj));
}
else if (obj->klass == il2cpp_defaults.boolean_class)
{
variant->n1.n2.type = IL2CPP_VT_BOOL;
variant->n1.n2.n3.boolVal = *static_cast<bool*>(Object::Unbox(obj)) ? IL2CPP_VARIANT_TRUE : IL2CPP_VARIANT_FALSE;
}
else if (obj->klass == il2cpp_defaults.string_class)
{
variant->n1.n2.type = IL2CPP_VT_BSTR;
variant->n1.n2.n3.bstrVal = PlatformInvoke::MarshalCSharpStringToCppBString(reinterpret_cast<Il2CppString*>(obj));
}
else if (obj->klass == il2cpp_defaults.dbnull_class)
{
variant->n1.n2.type = IL2CPP_VT_NULL;
}
else if (obj->klass == il2cpp_defaults.error_wrapper_class)
{
variant->n1.n2.type = IL2CPP_VT_ERROR;
variant->n1.n2.n3.scode = reinterpret_cast<Il2CppErrorWrapper*>(obj)->errorCode;
}
else if (obj->klass == il2cpp_defaults.missing_class)
{
variant->n1.n2.type = IL2CPP_VT_ERROR;
variant->n1.n2.n3.scode = IL2CPP_DISP_E_PARAMNOTFOUND;
}
else
{
Exception::Raise(IL2CPP_E_INVALIDARG, true);
}
}
Il2CppObject* COM::MarshalVariantResult(const Il2CppVariant* variant)
{
IL2CPP_ASSERT(variant);
switch (variant->n1.n2.type)
{
case IL2CPP_VT_EMPTY:
return NULL;
case IL2CPP_VT_NULL:
return Reflection::GetDBNullObject();
case IL2CPP_VT_ERROR:
{
int32_t val = variant->n1.n2.n3.scode;
return Object::Box(il2cpp_defaults.int32_class, &val);
}
case IL2CPP_VT_I1:
{
char val = variant->n1.n2.n3.cVal;
return Object::Box(il2cpp_defaults.sbyte_class, &val);
}
case IL2CPP_VT_UI1:
{
uint8_t val = variant->n1.n2.n3.bVal;
return Object::Box(il2cpp_defaults.byte_class, &val);
}
case IL2CPP_VT_I2:
{
int16_t val = variant->n1.n2.n3.iVal;
return Object::Box(il2cpp_defaults.int16_class, &val);
}
case IL2CPP_VT_UI2:
{
uint16_t val = variant->n1.n2.n3.uiVal;
return Object::Box(il2cpp_defaults.uint16_class, &val);
}
case IL2CPP_VT_I4:
{
int32_t val = variant->n1.n2.n3.lVal;
return Object::Box(il2cpp_defaults.int32_class, &val);
}
case IL2CPP_VT_UI4:
{
uint32_t val = variant->n1.n2.n3.ulVal;
return Object::Box(il2cpp_defaults.uint32_class, &val);
}
case IL2CPP_VT_I8:
{
int64_t val = variant->n1.n2.n3.llVal;
return Object::Box(il2cpp_defaults.int64_class, &val);
}
case IL2CPP_VT_UI8:
{
uint64_t val = variant->n1.n2.n3.ullVal;
return Object::Box(il2cpp_defaults.uint64_class, &val);
}
case IL2CPP_VT_R4:
{
float val = variant->n1.n2.n3.fltVal;
return Object::Box(il2cpp_defaults.single_class, &val);
}
case IL2CPP_VT_R8:
{
double val = variant->n1.n2.n3.dblVal;
return Object::Box(il2cpp_defaults.double_class, &val);
}
case IL2CPP_VT_BOOL:
{
IL2CPP_ASSERT(variant->n1.n2.n3.boolVal == IL2CPP_VARIANT_FALSE || variant->n1.n2.n3.boolVal == IL2CPP_VARIANT_TRUE);
bool value = variant->n1.n2.n3.boolVal != IL2CPP_VARIANT_FALSE;
return Object::Box(il2cpp_defaults.boolean_class, &value);
}
case IL2CPP_VT_BSTR:
return reinterpret_cast<Il2CppObject*>(PlatformInvoke::MarshalCppBStringToCSharpStringResult(variant->n1.n2.n3.bstrVal));
default:
Exception::Raise(IL2CPP_E_INVALIDARG, true);
return NULL;
}
}
void COM::DestroyVariant(Il2CppVariant* variant)
{
const il2cpp_hresult_t hr = os::COM::VariantClear(variant);
vm::Exception::RaiseIfFailed(hr, true);
}
Il2CppSafeArray* COM::MarshalSafeArray(uint16_t variantType, Il2CppArray* managedArray)
{
if (!managedArray)
return NULL;
Il2CppSafeArrayBound bounds[1];
bounds[0].element_count = Array::GetLength(managedArray);
bounds[0].lower_bound = 0;
Il2CppSafeArray* safeArray = os::COM::SafeArrayCreate(variantType, 1, bounds);
if (!safeArray)
Exception::Raise(IL2CPP_E_OUTOFMEMORY, true);
void* data;
il2cpp_hresult_t hr = os::COM::SafeArrayAccessData(safeArray, &data);
if (IL2CPP_HR_FAILED(hr))
{
os::COM::SafeArrayDestroy(safeArray);
Exception::Raise(hr, true);
}
::memcpy(data, Array::GetFirstElementAddress(managedArray), Array::GetByteLength(managedArray));
hr = os::COM::SafeArrayUnaccessData(safeArray);
if (IL2CPP_HR_FAILED(hr))
{
os::COM::SafeArrayDestroy(safeArray);
Exception::Raise(hr, true);
}
return safeArray;
}
Il2CppArray* COM::MarshalSafeArrayResult(uint16_t variantType, Il2CppClass* type, Il2CppSafeArray* safeArray)
{
if (!safeArray)
return NULL;
uint16_t actualVariantType;
il2cpp_hresult_t hr = os::COM::SafeArrayGetVartype(safeArray, &actualVariantType);
vm::Exception::RaiseIfFailed(hr, true);
if (actualVariantType != variantType)
Exception::Raise(IL2CPP_E_INVALIDARG, true);
const uint32_t actualDimentionCount = os::COM::SafeArrayGetDim(safeArray);
if (actualDimentionCount != 1)
Exception::Raise(IL2CPP_E_INVALIDARG, true);
int32_t lowerBound;
hr = os::COM::SafeArrayGetLBound(safeArray, 1, &lowerBound);
vm::Exception::RaiseIfFailed(hr, true);
int32_t upperBound;
hr = os::COM::SafeArrayGetUBound(safeArray, 1, &upperBound);
vm::Exception::RaiseIfFailed(hr, true);
const il2cpp_array_size_t size = static_cast<il2cpp_array_size_t>(upperBound - lowerBound + 1);
Il2CppArray* managedArray = Array::New(type, size);
void* data;
hr = os::COM::SafeArrayAccessData(safeArray, &data);
vm::Exception::RaiseIfFailed(hr, true);
::memcpy(Array::GetFirstElementAddress(managedArray), data, Array::GetByteLength(managedArray));
hr = os::COM::SafeArrayUnaccessData(safeArray);
vm::Exception::RaiseIfFailed(hr, true);
return managedArray;
}
Il2CppSafeArray* COM::MarshalSafeArrayBString(Il2CppArray* managedArray)
{
if (!managedArray)
return NULL;
const uint32_t size = Array::GetLength(managedArray);
Il2CppSafeArrayBound bounds[1];
bounds[0].element_count = size;
bounds[0].lower_bound = 0;
Il2CppSafeArray* safeArray = os::COM::SafeArrayCreate(IL2CPP_VT_BSTR, 1, bounds);
if (!safeArray)
Exception::Raise(IL2CPP_E_OUTOFMEMORY, true);
Il2CppChar** data;
il2cpp_hresult_t hr = os::COM::SafeArrayAccessData(safeArray, reinterpret_cast<void**>(&data));
if (IL2CPP_HR_FAILED(hr))
{
os::COM::SafeArrayDestroy(safeArray);
Exception::Raise(hr, true);
}
for (uint32_t i = 0; i < size; ++i)
{
Il2CppString* managedString = il2cpp_array_get(managedArray, Il2CppString*, i);
hr = PlatformInvoke::MarshalCSharpStringToCppBStringNoThrow(managedString, data + i);
if (IL2CPP_HR_FAILED(hr))
{
os::COM::SafeArrayUnaccessData(safeArray);
os::COM::SafeArrayDestroy(safeArray);
Exception::Raise(hr, true);
}
}
hr = os::COM::SafeArrayUnaccessData(safeArray);
if (IL2CPP_HR_FAILED(hr))
{
os::COM::SafeArrayDestroy(safeArray);
Exception::Raise(hr, true);
}
return safeArray;
}
Il2CppArray* COM::MarshalSafeArrayBStringResult(Il2CppClass* type, Il2CppSafeArray* safeArray)
{
if (!safeArray)
return NULL;
uint16_t actualVariantType;
il2cpp_hresult_t hr = os::COM::SafeArrayGetVartype(safeArray, &actualVariantType);
vm::Exception::RaiseIfFailed(hr, true);
if (actualVariantType != IL2CPP_VT_BSTR)
Exception::Raise(IL2CPP_E_INVALIDARG, true);
const uint32_t actualDimentionCount = os::COM::SafeArrayGetDim(safeArray);
if (actualDimentionCount != 1)
Exception::Raise(IL2CPP_E_INVALIDARG, true);
int32_t lowerBound;
hr = os::COM::SafeArrayGetLBound(safeArray, 1, &lowerBound);
vm::Exception::RaiseIfFailed(hr, true);
int32_t upperBound;
hr = os::COM::SafeArrayGetUBound(safeArray, 1, &upperBound);
vm::Exception::RaiseIfFailed(hr, true);
const il2cpp_array_size_t size = static_cast<il2cpp_array_size_t>(upperBound - lowerBound + 1);
Il2CppArray* managedArray = Array::New(il2cpp_defaults.string_class, size);
Il2CppChar** data;
hr = os::COM::SafeArrayAccessData(safeArray, reinterpret_cast<void**>(&data));
vm::Exception::RaiseIfFailed(hr, true);
for (il2cpp_array_size_t i = 0; i < size; ++i)
il2cpp_array_setref(managedArray, i, PlatformInvoke::MarshalCppBStringToCSharpStringResult(data[i]));
hr = os::COM::SafeArrayUnaccessData(safeArray);
vm::Exception::RaiseIfFailed(hr, true);
return managedArray;
}
} /* namespace vm */
} /* namespace il2cpp */