COMEntryPoints.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. typedef std::map<Il2CppHString, ActivationFactoryWrapper, HStringLess> FactoryCache;
  52. static FactoryCache s_FactoryCache;
  53. static baselib::ReentrantLock s_FactoryCacheMutex;
  54. static bool s_InitializedIl2CppFromWindowsRuntime;
  55. typedef Il2CppIActivationFactory* (*FactoryCreationFunction)();
  56. // Returns:
  57. // IL2CPP_S_OK - on success
  58. // IL2CPP_E_INVALIDARG - if className or factory is null
  59. // IL2CPP_REGDB_E_CLASSNOTREG - if class was not found
  60. extern "C" IL2CPP_EXPORT il2cpp_hresult_t STDCALL DllGetActivationFactory(Il2CppHString className, Il2CppIActivationFactory** factory)
  61. {
  62. if (className == nullptr || factory == nullptr)
  63. return IL2CPP_E_INVALIDARG;
  64. il2cpp::os::FastAutoLock lock(&s_FactoryCacheMutex);
  65. if (!s_InitializedIl2CppFromWindowsRuntime)
  66. {
  67. if (!il2cpp::vm::Runtime::Init())
  68. return IL2CPP_COR_E_EXECUTIONENGINE;
  69. s_InitializedIl2CppFromWindowsRuntime = true;
  70. }
  71. FactoryCache::iterator it = s_FactoryCache.find(className);
  72. if (it != s_FactoryCache.end())
  73. {
  74. Il2CppIActivationFactory* cachedFactory = it->second;
  75. cachedFactory->AddRef();
  76. *factory = cachedFactory;
  77. return IL2CPP_S_OK;
  78. }
  79. uint32_t classNameLength;
  80. auto classNameUtf16 = il2cpp::os::WindowsRuntime::GetHStringBuffer(className, &classNameLength);
  81. il2cpp::vm::Exception::RaiseIfError(classNameUtf16.GetError());
  82. std::string classNameUtf8 = il2cpp::utils::StringUtils::Utf16ToUtf8(classNameUtf16.Get(), classNameLength);
  83. FactoryCreationFunction factoryCreationFunction = reinterpret_cast<FactoryCreationFunction>(il2cpp::vm::MetadataCache::GetWindowsRuntimeFactoryCreationFunction(classNameUtf8.c_str()));
  84. if (factoryCreationFunction == NULL)
  85. return IL2CPP_REGDB_E_CLASSNOTREG;
  86. Il2CppHString duplicatedClassName;
  87. il2cpp_hresult_t hr = il2cpp::os::WindowsRuntime::DuplicateHString(className, &duplicatedClassName);
  88. if (IL2CPP_HR_FAILED(hr))
  89. return hr;
  90. std::pair<FactoryCache::iterator, bool> insertionResult = s_FactoryCache.insert(std::make_pair(duplicatedClassName, std::make_pair(factoryCreationFunction(), duplicatedClassName)));
  91. IL2CPP_ASSERT(insertionResult.second && "Factory was already in the hash map!");
  92. Il2CppIActivationFactory* createdFactory = insertionResult.first->second;
  93. createdFactory->AddRef();
  94. *factory = createdFactory;
  95. return IL2CPP_S_OK;
  96. }
  97. extern "C" IL2CPP_EXPORT long STDCALL DllCanUnloadNow()
  98. {
  99. if (!s_InitializedIl2CppFromWindowsRuntime)
  100. return IL2CPP_S_OK;
  101. // TO DO: we need to track all instantiated COM objects in order to implement this correctly
  102. return IL2CPP_S_FALSE;
  103. }
  104. void il2cpp::vm::COMEntryPoints::FreeCachedData()
  105. {
  106. s_FactoryCache.clear();
  107. }
  108. // Prevent function name mangling on Windows/x86
  109. // The reason this needs to live here and not os layer is because if this file is not compiled,
  110. // those linker directives will cause unresolved external symbol errors
  111. #if IL2CPP_TARGET_WINDOWS && defined(_M_IX86)
  112. #pragma comment(linker, "/EXPORT:DllGetActivationFactory=_DllGetActivationFactory@8")
  113. #pragma comment(linker, "/EXPORT:DllCanUnloadNow=_DllCanUnloadNow@0")
  114. #endif