CCW.cpp 7.2 KB

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