123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- #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 */
|