COMEntryPoints.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include "il2cpp-config.h"
  2. #include "COMEntryPoints.h"
  3. #include "il2cpp-windowsruntime-types.h"
  4. #include "os/Mutex.h"
  5. #include "os/WindowsRuntime.h"
  6. #include "utils/StringUtils.h"
  7. #include "vm/Exception.h"
  8. #include "vm/MetadataCache.h"
  9. #include "vm/Runtime.h"
  10. #include <map>
  11. struct HStringLess
  12. {
  13. bool operator()(Il2CppHString left, Il2CppHString right) const
  14. {
  15. uint32_t lengthLeft = 0;
  16. uint32_t lengthRight = 0;
  17. auto charsLeft = il2cpp::os::WindowsRuntime::GetHStringBuffer(left, &lengthLeft);
  18. il2cpp::vm::Exception::RaiseIfError(charsLeft.GetError());
  19. auto charsRight = il2cpp::os::WindowsRuntime::GetHStringBuffer(right, &lengthRight);
  20. il2cpp::vm::Exception::RaiseIfError(charsRight.GetError());
  21. if (lengthLeft != lengthRight)
  22. return lengthLeft < lengthRight;
  23. return memcmp(charsLeft.Get(), charsRight.Get(), sizeof(Il2CppChar) * lengthLeft) < 0;
  24. }
  25. };
  26. struct ActivationFactoryWrapper
  27. {
  28. ActivationFactoryWrapper(const std::pair<Il2CppIActivationFactory*, Il2CppHString>& factoryNamePair) :
  29. m_Factory(factoryNamePair.first),
  30. m_Name(factoryNamePair.second)
  31. {
  32. // NOTE: No add ref here since this constructor is only called with newly created factory
  33. // Also, name is already pre-duplicated since we cannot deal with hresult failure in a constructor
  34. }
  35. ActivationFactoryWrapper(const ActivationFactoryWrapper&); // = delete;
  36. ActivationFactoryWrapper& operator=(const ActivationFactoryWrapper&); // = delete;
  37. ~ActivationFactoryWrapper()
  38. {
  39. m_Factory->Release();
  40. il2cpp_hresult_t hr = il2cpp::os::WindowsRuntime::DeleteHString(m_Name);
  41. IL2CPP_ASSERT(IL2CPP_HR_SUCCEEDED(hr));
  42. }
  43. operator Il2CppIActivationFactory*() const
  44. {
  45. return m_Factory;
  46. }
  47. private:
  48. Il2CppIActivationFactory* m_Factory;
  49. Il2CppHString m_Name;
  50. };
  51. #if !IL2CPP_TRIM_COM
  52. typedef std::map<Il2CppHString, ActivationFactoryWrapper, HStringLess> FactoryCache;
  53. static FactoryCache s_FactoryCache;
  54. #endif
  55. static baselib::ReentrantLock s_FactoryCacheMutex;
  56. static bool s_InitializedIl2CppFromWindowsRuntime;
  57. typedef Il2CppIActivationFactory* (*FactoryCreationFunction)();
  58. // Returns:
  59. // IL2CPP_S_OK - on success
  60. // IL2CPP_E_INVALIDARG - if className or factory is null
  61. // IL2CPP_REGDB_E_CLASSNOTREG - if class was not found
  62. extern "C" IL2CPP_EXPORT il2cpp_hresult_t STDCALL DllGetActivationFactory(Il2CppHString className, Il2CppIActivationFactory** factory)
  63. {
  64. #if IL2CPP_TRIM_COM
  65. IL2CPP_NOT_IMPLEMENTED(DllGetActivationFactory);
  66. return 0;
  67. #else
  68. if (className == nullptr || factory == nullptr)
  69. return IL2CPP_E_INVALIDARG;
  70. il2cpp::os::FastAutoLock lock(&s_FactoryCacheMutex);
  71. if (!s_InitializedIl2CppFromWindowsRuntime)
  72. {
  73. if (!il2cpp::vm::Runtime::Init())
  74. return IL2CPP_COR_E_EXECUTIONENGINE;
  75. s_InitializedIl2CppFromWindowsRuntime = true;
  76. }
  77. FactoryCache::iterator it = s_FactoryCache.find(className);
  78. if (it != s_FactoryCache.end())
  79. {
  80. Il2CppIActivationFactory* cachedFactory = it->second;
  81. cachedFactory->AddRef();
  82. *factory = cachedFactory;
  83. return IL2CPP_S_OK;
  84. }
  85. uint32_t classNameLength;
  86. auto classNameUtf16 = il2cpp::os::WindowsRuntime::GetHStringBuffer(className, &classNameLength);
  87. il2cpp::vm::Exception::RaiseIfError(classNameUtf16.GetError());
  88. std::string classNameUtf8 = il2cpp::utils::StringUtils::Utf16ToUtf8(classNameUtf16.Get(), classNameLength);
  89. FactoryCreationFunction factoryCreationFunction = reinterpret_cast<FactoryCreationFunction>(il2cpp::vm::MetadataCache::GetWindowsRuntimeFactoryCreationFunction(classNameUtf8.c_str()));
  90. if (factoryCreationFunction == NULL)
  91. return IL2CPP_REGDB_E_CLASSNOTREG;
  92. Il2CppHString duplicatedClassName;
  93. il2cpp_hresult_t hr = il2cpp::os::WindowsRuntime::DuplicateHString(className, &duplicatedClassName);
  94. if (IL2CPP_HR_FAILED(hr))
  95. return hr;
  96. std::pair<FactoryCache::iterator, bool> insertionResult = s_FactoryCache.insert(std::make_pair(duplicatedClassName, std::make_pair(factoryCreationFunction(), duplicatedClassName)));
  97. IL2CPP_ASSERT(insertionResult.second && "Factory was already in the hash map!");
  98. Il2CppIActivationFactory* createdFactory = insertionResult.first->second;
  99. createdFactory->AddRef();
  100. *factory = createdFactory;
  101. return IL2CPP_S_OK;
  102. #endif
  103. }
  104. extern "C" IL2CPP_EXPORT long STDCALL DllCanUnloadNow()
  105. {
  106. #if IL2CPP_TRIM_COM
  107. IL2CPP_NOT_IMPLEMENTED(DllCanUnloadNow);
  108. return 0;
  109. #else
  110. if (!s_InitializedIl2CppFromWindowsRuntime)
  111. return IL2CPP_S_OK;
  112. // TO DO: we need to track all instantiated COM objects in order to implement this correctly
  113. return IL2CPP_S_FALSE;
  114. #endif
  115. }
  116. void il2cpp::vm::COMEntryPoints::FreeCachedData()
  117. {
  118. #if IL2CPP_TRIM_COM
  119. IL2CPP_NOT_IMPLEMENTED(COMEntryPoints::FreeCachedData);
  120. return;
  121. #else
  122. s_FactoryCache.clear();
  123. #endif
  124. }
  125. // Prevent function name mangling on Windows/x86
  126. // The reason this needs to live here and not os layer is because if this file is not compiled,
  127. // those linker directives will cause unresolved external symbol errors
  128. #if IL2CPP_TARGET_WINDOWS && defined(_M_IX86)
  129. #pragma comment(linker, "/EXPORT:DllGetActivationFactory=_DllGetActivationFactory@8")
  130. #pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0")
  131. #endif