CCW.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #include "il2cpp-config.h"
  2. #include "il2cpp-object-internals.h"
  3. #include "il2cpp-class-internals.h"
  4. #include "vm/Object.h"
  5. #include "vm/CCW.h"
  6. #include "vm/Class.h"
  7. #include "vm/CachedCCWBase.h"
  8. #include "vm/Exception.h"
  9. #include "vm/MetadataCache.h"
  10. #include "vm/Method.h"
  11. #include "vm/RCW.h"
  12. #include "vm/Runtime.h"
  13. #include "vm/ScopedThreadAttacher.h"
  14. #include "vm/String.h"
  15. namespace il2cpp
  16. {
  17. namespace vm
  18. {
  19. struct ManagedObject : CachedCCWBase<ManagedObject>
  20. {
  21. inline ManagedObject(Il2CppObject* obj) :
  22. CachedCCWBase<ManagedObject>(obj)
  23. {
  24. }
  25. virtual il2cpp_hresult_t STDCALL QueryInterface(const Il2CppGuid& iid, void** object) IL2CPP_OVERRIDE
  26. {
  27. if (::memcmp(&iid, &Il2CppIUnknown::IID, sizeof(Il2CppGuid)) == 0
  28. || ::memcmp(&iid, &Il2CppIInspectable::IID, sizeof(Il2CppGuid)) == 0
  29. || ::memcmp(&iid, &Il2CppIAgileObject::IID, sizeof(Il2CppGuid)) == 0)
  30. {
  31. *object = GetIdentity();
  32. AddRefImpl();
  33. return IL2CPP_S_OK;
  34. }
  35. if (::memcmp(&iid, &Il2CppIManagedObjectHolder::IID, sizeof(Il2CppGuid)) == 0)
  36. {
  37. *object = static_cast<Il2CppIManagedObjectHolder*>(this);
  38. AddRefImpl();
  39. return IL2CPP_S_OK;
  40. }
  41. if (::memcmp(&iid, &Il2CppIMarshal::IID, sizeof(Il2CppGuid)) == 0)
  42. {
  43. *object = static_cast<Il2CppIMarshal*>(this);
  44. AddRefImpl();
  45. return IL2CPP_S_OK;
  46. }
  47. if (::memcmp(&iid, &Il2CppIWeakReferenceSource::IID, sizeof(Il2CppGuid)) == 0)
  48. {
  49. *object = static_cast<Il2CppIWeakReferenceSource*>(this);
  50. AddRefImpl();
  51. return IL2CPP_S_OK;
  52. }
  53. *object = NULL;
  54. return IL2CPP_E_NOINTERFACE;
  55. }
  56. };
  57. Il2CppIUnknown* CCW::CreateCCW(Il2CppObject* obj)
  58. {
  59. // check for ccw create function, which is implemented by objects that implement COM or Windows Runtime interfaces
  60. const Il2CppInteropData* interopData = obj->klass->interopData;
  61. if (interopData != NULL)
  62. {
  63. const CreateCCWFunc createCcw = interopData->createCCWFunction;
  64. if (createCcw != NULL)
  65. return createCcw(obj);
  66. }
  67. // otherwise create generic ccw object that "only" implements IUnknown, IMarshal, IInspectable, IAgileObject and IManagedObjectHolder interfaces
  68. void* memory = utils::Memory::Malloc(sizeof(ManagedObject));
  69. if (memory == NULL)
  70. Exception::RaiseOutOfMemoryException();
  71. return static_cast<Il2CppIManagedObjectHolder*>(new(memory) ManagedObject(obj));
  72. }
  73. Il2CppObject* CCW::Unpack(Il2CppIUnknown* unknown)
  74. {
  75. Il2CppIManagedObjectHolder* managedHolder;
  76. il2cpp_hresult_t hr = unknown->QueryInterface(Il2CppIManagedObjectHolder::IID, reinterpret_cast<void**>(&managedHolder));
  77. Exception::RaiseIfFailed(hr, true);
  78. Il2CppObject* instance = managedHolder->GetManagedObject();
  79. managedHolder->Release();
  80. IL2CPP_ASSERT(instance);
  81. return instance;
  82. }
  83. static Il2CppString* ValueToStringFallbackToEmpty(Il2CppObject* value)
  84. {
  85. Il2CppClass* klass = il2cpp::vm::Object::GetClass(value);
  86. const MethodInfo* toStringMethod = il2cpp::vm::Class::GetMethodFromName(klass, "ToString", 0);
  87. // check if the method we are to call is expecting a value type 'this' parameter or not.
  88. // handles edge case of enums where the 'value' is SomeEnum but the ToString method is Enum::ToString.
  89. // In this case, a boxed 'this' parameter is expected even though the object value is a valuetype.
  90. bool isValueTypeMethod = il2cpp::vm::Class::IsValuetype(il2cpp::vm::Method::GetClass(toStringMethod));
  91. Il2CppException* exception = NULL;
  92. Il2CppString* result = (Il2CppString*)il2cpp::vm::Runtime::Invoke(toStringMethod, isValueTypeMethod ? Object::Unbox(value) : value, NULL, &exception);
  93. if (exception != NULL)
  94. return String::Empty();
  95. return result;
  96. }
  97. static il2cpp_hresult_t HandleInvalidIPropertyConversionImpl(const std::string& exceptionMessage)
  98. {
  99. ScopedThreadAttacher scopedThreadAttacher; // Make sure we're attached before we create exceptions (aka allocate managed memory)
  100. Il2CppException* exception = Exception::GetInvalidCastException(exceptionMessage.c_str());
  101. Exception::PrepareExceptionForThrow(exception);
  102. Exception::StoreExceptionInfo(exception, ValueToStringFallbackToEmpty(exception));
  103. return exception->hresult;
  104. }
  105. il2cpp_hresult_t CCW::HandleInvalidIPropertyConversion(const char* fromType, const char* toType)
  106. {
  107. std::string message = il2cpp::utils::StringUtils::Printf("Object in an IPropertyValue is of type '%s', which cannot be converted to a '%s'.", fromType, toType);
  108. return HandleInvalidIPropertyConversionImpl(message);
  109. }
  110. il2cpp_hresult_t CCW::HandleInvalidIPropertyConversion(Il2CppObject* value, const char* fromType, const char* toType)
  111. {
  112. Il2CppString* valueStr = ValueToStringFallbackToEmpty(value);
  113. std::string message = il2cpp::utils::StringUtils::Printf(
  114. "Object in an IPropertyValue is of type '%s' with value '%s', which cannot be converted to a '%s'.",
  115. fromType,
  116. utils::StringUtils::Utf16ToUtf8(valueStr->chars, valueStr->length).c_str(),
  117. toType);
  118. return HandleInvalidIPropertyConversionImpl(message);
  119. }
  120. il2cpp_hresult_t CCW::HandleInvalidIPropertyArrayConversion(const char* fromArrayType, const char* fromElementType, const char* toElementType, il2cpp_array_size_t index)
  121. {
  122. std::string message = il2cpp::utils::StringUtils::Printf(
  123. "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'.",
  124. fromArrayType,
  125. toElementType,
  126. static_cast<int>(index),
  127. fromElementType,
  128. toElementType);
  129. return HandleInvalidIPropertyConversionImpl(message);
  130. }
  131. il2cpp_hresult_t CCW::HandleInvalidIPropertyArrayConversion(Il2CppObject* value, const char* fromArrayType, const char* fromElementType, const char* toElementType, il2cpp_array_size_t index)
  132. {
  133. Il2CppString* valueStr = ValueToStringFallbackToEmpty(value);
  134. std::string message = il2cpp::utils::StringUtils::Printf(
  135. "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'.",
  136. fromArrayType,
  137. toElementType,
  138. static_cast<int>(index),
  139. fromElementType,
  140. utils::StringUtils::Utf16ToUtf8(valueStr->chars, valueStr->length).c_str(),
  141. toElementType);
  142. return HandleInvalidIPropertyConversionImpl(message);
  143. }
  144. } /* namespace vm */
  145. } /* namespace il2cpp */