167 lines
7.1 KiB
C++
167 lines
7.1 KiB
C++
#include "il2cpp-config.h"
|
|
#include "il2cpp-object-internals.h"
|
|
#include "il2cpp-class-internals.h"
|
|
#include "vm/Object.h"
|
|
#include "vm/CCW.h"
|
|
#include "vm/Class.h"
|
|
#include "vm/CachedCCWBase.h"
|
|
#include "vm/Exception.h"
|
|
#include "vm/MetadataCache.h"
|
|
#include "vm/Method.h"
|
|
#include "vm/RCW.h"
|
|
#include "vm/Runtime.h"
|
|
#include "vm/ScopedThreadAttacher.h"
|
|
#include "vm/String.h"
|
|
|
|
namespace il2cpp
|
|
{
|
|
namespace vm
|
|
{
|
|
struct ManagedObject : CachedCCWBase<ManagedObject>
|
|
{
|
|
inline ManagedObject(Il2CppObject* obj) :
|
|
CachedCCWBase<ManagedObject>(obj)
|
|
{
|
|
}
|
|
|
|
virtual il2cpp_hresult_t STDCALL QueryInterface(const Il2CppGuid& iid, void** object) IL2CPP_OVERRIDE
|
|
{
|
|
if (::memcmp(&iid, &Il2CppIUnknown::IID, sizeof(Il2CppGuid)) == 0
|
|
|| ::memcmp(&iid, &Il2CppIInspectable::IID, sizeof(Il2CppGuid)) == 0
|
|
|| ::memcmp(&iid, &Il2CppIAgileObject::IID, sizeof(Il2CppGuid)) == 0)
|
|
{
|
|
*object = GetIdentity();
|
|
AddRefImpl();
|
|
return IL2CPP_S_OK;
|
|
}
|
|
|
|
if (::memcmp(&iid, &Il2CppIManagedObjectHolder::IID, sizeof(Il2CppGuid)) == 0)
|
|
{
|
|
*object = static_cast<Il2CppIManagedObjectHolder*>(this);
|
|
AddRefImpl();
|
|
return IL2CPP_S_OK;
|
|
}
|
|
|
|
if (::memcmp(&iid, &Il2CppIMarshal::IID, sizeof(Il2CppGuid)) == 0)
|
|
{
|
|
*object = static_cast<Il2CppIMarshal*>(this);
|
|
AddRefImpl();
|
|
return IL2CPP_S_OK;
|
|
}
|
|
|
|
if (::memcmp(&iid, &Il2CppIWeakReferenceSource::IID, sizeof(Il2CppGuid)) == 0)
|
|
{
|
|
*object = static_cast<Il2CppIWeakReferenceSource*>(this);
|
|
AddRefImpl();
|
|
return IL2CPP_S_OK;
|
|
}
|
|
|
|
*object = NULL;
|
|
return IL2CPP_E_NOINTERFACE;
|
|
}
|
|
};
|
|
|
|
Il2CppIUnknown* CCW::CreateCCW(Il2CppObject* obj)
|
|
{
|
|
// check for ccw create function, which is implemented by objects that implement COM or Windows Runtime interfaces
|
|
const Il2CppInteropData* interopData = obj->klass->interopData;
|
|
if (interopData != NULL)
|
|
{
|
|
const CreateCCWFunc createCcw = interopData->createCCWFunction;
|
|
|
|
if (createCcw != NULL)
|
|
return createCcw(obj);
|
|
}
|
|
|
|
// otherwise create generic ccw object that "only" implements IUnknown, IMarshal, IInspectable, IAgileObject and IManagedObjectHolder interfaces
|
|
void* memory = utils::Memory::Malloc(sizeof(ManagedObject));
|
|
if (memory == NULL)
|
|
Exception::RaiseOutOfMemoryException();
|
|
return static_cast<Il2CppIManagedObjectHolder*>(new(memory) ManagedObject(obj));
|
|
}
|
|
|
|
Il2CppObject* CCW::Unpack(Il2CppIUnknown* unknown)
|
|
{
|
|
Il2CppIManagedObjectHolder* managedHolder;
|
|
il2cpp_hresult_t hr = unknown->QueryInterface(Il2CppIManagedObjectHolder::IID, reinterpret_cast<void**>(&managedHolder));
|
|
Exception::RaiseIfFailed(hr, true);
|
|
|
|
Il2CppObject* instance = managedHolder->GetManagedObject();
|
|
managedHolder->Release();
|
|
|
|
IL2CPP_ASSERT(instance);
|
|
return instance;
|
|
}
|
|
|
|
static Il2CppString* ValueToStringFallbackToEmpty(Il2CppObject* value)
|
|
{
|
|
Il2CppClass* klass = il2cpp::vm::Object::GetClass(value);
|
|
const MethodInfo* toStringMethod = il2cpp::vm::Class::GetMethodFromName(klass, "ToString", 0);
|
|
// check if the method we are to call is expecting a value type 'this' parameter or not.
|
|
// handles edge case of enums where the 'value' is SomeEnum but the ToString method is Enum::ToString.
|
|
// In this case, a boxed 'this' parameter is expected even though the object value is a valuetype.
|
|
bool isValueTypeMethod = il2cpp::vm::Class::IsValuetype(il2cpp::vm::Method::GetClass(toStringMethod));
|
|
|
|
Il2CppException* exception = NULL;
|
|
Il2CppString* result = (Il2CppString*)il2cpp::vm::Runtime::Invoke(toStringMethod, isValueTypeMethod ? Object::Unbox(value) : value, NULL, &exception);
|
|
if (exception != NULL)
|
|
return String::Empty();
|
|
|
|
return result;
|
|
}
|
|
|
|
static il2cpp_hresult_t HandleInvalidIPropertyConversionImpl(const std::string& exceptionMessage)
|
|
{
|
|
ScopedThreadAttacher scopedThreadAttacher; // Make sure we're attached before we create exceptions (aka allocate managed memory)
|
|
|
|
Il2CppException* exception = Exception::GetInvalidCastException(exceptionMessage.c_str());
|
|
Exception::PrepareExceptionForThrow(exception);
|
|
Exception::StoreExceptionInfo(exception, ValueToStringFallbackToEmpty(exception));
|
|
return exception->hresult;
|
|
}
|
|
|
|
il2cpp_hresult_t CCW::HandleInvalidIPropertyConversion(const char* fromType, const char* toType)
|
|
{
|
|
std::string message = il2cpp::utils::StringUtils::Printf("Object in an IPropertyValue is of type '%s', which cannot be converted to a '%s'.", fromType, toType);
|
|
return HandleInvalidIPropertyConversionImpl(message);
|
|
}
|
|
|
|
il2cpp_hresult_t CCW::HandleInvalidIPropertyConversion(Il2CppObject* value, const char* fromType, const char* toType)
|
|
{
|
|
Il2CppString* valueStr = ValueToStringFallbackToEmpty(value);
|
|
std::string message = il2cpp::utils::StringUtils::Printf(
|
|
"Object in an IPropertyValue is of type '%s' with value '%s', which cannot be converted to a '%s'.",
|
|
fromType,
|
|
utils::StringUtils::Utf16ToUtf8(valueStr->chars, valueStr->length).c_str(),
|
|
toType);
|
|
return HandleInvalidIPropertyConversionImpl(message);
|
|
}
|
|
|
|
il2cpp_hresult_t CCW::HandleInvalidIPropertyArrayConversion(const char* fromArrayType, const char* fromElementType, const char* toElementType, il2cpp_array_size_t index)
|
|
{
|
|
std::string message = il2cpp::utils::StringUtils::Printf(
|
|
"Object in an IPropertyValue is of type '%s' which cannot be converted to a '%s[]' due to array element '%d': Object in an IPropertyValue is of type '%s', which cannot be converted to a '%s'.",
|
|
fromArrayType,
|
|
toElementType,
|
|
static_cast<int>(index),
|
|
fromElementType,
|
|
toElementType);
|
|
return HandleInvalidIPropertyConversionImpl(message);
|
|
}
|
|
|
|
il2cpp_hresult_t CCW::HandleInvalidIPropertyArrayConversion(Il2CppObject* value, const char* fromArrayType, const char* fromElementType, const char* toElementType, il2cpp_array_size_t index)
|
|
{
|
|
Il2CppString* valueStr = ValueToStringFallbackToEmpty(value);
|
|
std::string message = il2cpp::utils::StringUtils::Printf(
|
|
"Object in an IPropertyValue is of type '%s' which cannot be converted to a '%s[]' due to array element '%d': Object in an IPropertyValue is of type '%s' with value '%s', which cannot be converted to a '%s'.",
|
|
fromArrayType,
|
|
toElementType,
|
|
static_cast<int>(index),
|
|
fromElementType,
|
|
utils::StringUtils::Utf16ToUtf8(valueStr->chars, valueStr->length).c_str(),
|
|
toElementType);
|
|
return HandleInvalidIPropertyConversionImpl(message);
|
|
}
|
|
} /* namespace vm */
|
|
} /* namespace il2cpp */
|