BsMonoUtil.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #pragma once
  2. #include "BsMonoPrerequisites.h"
  3. #include "BsException.h"
  4. #include "BsDebug.h"
  5. #include "BsMonoArray.h"
  6. #include <mono/jit/jit.h>
  7. #include <codecvt>
  8. namespace BansheeEngine
  9. {
  10. /**
  11. * @brief Utility class containing methods for various common Mono/Script related
  12. * operations.
  13. */
  14. class BS_MONO_EXPORT MonoUtil
  15. {
  16. public:
  17. /**
  18. * @brief Converts a Mono (i.e. managed) string to a native wide string.
  19. */
  20. static WString monoToWString(MonoString* str)
  21. {
  22. if(str == nullptr)
  23. return StringUtil::WBLANK;
  24. int len = mono_string_length(str);
  25. mono_unichar2* monoChars = mono_string_chars(str);
  26. WString ret(len, '0');
  27. for(int i = 0; i < len; i++)
  28. ret[i] = monoChars[i];
  29. return ret;
  30. }
  31. /**
  32. * @brief Converts a Mono (i.e. managed) string to a native narrow string.
  33. */
  34. static String monoToString(MonoString* str)
  35. {
  36. if(str == nullptr)
  37. return StringUtil::BLANK;
  38. int len = mono_string_length(str);
  39. mono_unichar2* monoChars = mono_string_chars(str);
  40. String ret(len, '0');
  41. for(int i = 0; i < len; i++)
  42. ret[i] = (char)monoChars[i];
  43. return ret;
  44. }
  45. /**
  46. * @brief Converts a native wide string to a Mono (i.e. managed) string.
  47. */
  48. static MonoString* wstringToMono(const WString& str)
  49. {
  50. if (sizeof(wchar_t) == 2) // Assuming UTF-16
  51. return mono_string_from_utf16((mono_unichar2*)str.c_str());
  52. else // Assuming UTF-32
  53. {
  54. const std::codecvt_mode convMode = (std::codecvt_mode)(std::little_endian);
  55. typedef std::codecvt_utf16<char32_t, 1114111, convMode> utf16utf32;
  56. std::wstring_convert<utf16utf32, char32_t> conversion("?");
  57. char32_t* start = (char32_t*)str.data();
  58. char32_t* end = (start + (str.size() - 1) / 4);
  59. mono_unichar2* convertedStr = (mono_unichar2*)conversion.to_bytes(start, end).c_str();
  60. return mono_string_from_utf16(convertedStr);
  61. }
  62. }
  63. /**
  64. * @brief Converts a native narrow string to a Mono (i.e. managed) string.
  65. */
  66. static MonoString* stringToMono(const String& str)
  67. {
  68. return wstringToMono(toWString(str));
  69. }
  70. /**
  71. * @brief Outputs name and namespace for the type of the specified object.
  72. */
  73. static void getClassName(MonoObject* obj, String& ns, String& typeName)
  74. {
  75. if (obj == nullptr)
  76. return;
  77. ::MonoClass* monoClass = mono_object_get_class(obj);
  78. getClassName(monoClass, ns, typeName);
  79. }
  80. /**
  81. * @brief Outputs name and namespace for the specified type.
  82. */
  83. static void getClassName(::MonoClass* monoClass, String& ns, String& typeName)
  84. {
  85. ::MonoClass* nestingClass = mono_class_get_nesting_type(monoClass);
  86. if (nestingClass == nullptr)
  87. {
  88. ns = mono_class_get_namespace(monoClass);
  89. typeName = mono_class_get_name(monoClass);
  90. return;
  91. }
  92. else
  93. {
  94. typeName = String("+") + mono_class_get_name(monoClass);
  95. do
  96. {
  97. ::MonoClass* nextNestingClass = mono_class_get_nesting_type(nestingClass);
  98. if (nextNestingClass != nullptr)
  99. {
  100. typeName = String("+") + mono_class_get_name(nestingClass) + typeName;
  101. nestingClass = nextNestingClass;
  102. }
  103. else
  104. {
  105. ns = mono_class_get_namespace(nestingClass);
  106. typeName = mono_class_get_name(nestingClass) + typeName;
  107. break;
  108. }
  109. } while (true);
  110. }
  111. }
  112. /**
  113. * @copydoc throwIfException
  114. */
  115. static void throwIfException(MonoException* exception)
  116. {
  117. throwIfException(reinterpret_cast<MonoObject*>(exception));
  118. }
  119. /**
  120. * @brief Throws a native exception if the provided object is a valid managed exception.
  121. */
  122. static void throwIfException(MonoObject* exception)
  123. {
  124. if(exception != nullptr)
  125. {
  126. ::MonoClass* exceptionClass = mono_object_get_class(exception);
  127. ::MonoProperty* exceptionMsgProp = mono_class_get_property_from_name(exceptionClass, "Message");
  128. ::MonoMethod* exceptionMsgGetter = mono_property_get_get_method(exceptionMsgProp);
  129. MonoString* exceptionMsg = (MonoString*)mono_runtime_invoke(exceptionMsgGetter, exception, nullptr, nullptr);
  130. ::MonoProperty* exceptionStackProp = mono_class_get_property_from_name(exceptionClass, "StackTrace");
  131. ::MonoMethod* exceptionStackGetter = mono_property_get_get_method(exceptionStackProp);
  132. MonoString* exceptionStackTrace = (MonoString*)mono_runtime_invoke(exceptionStackGetter, exception, nullptr, nullptr);
  133. String msg = "Managed exception: " + toString(monoToWString(exceptionMsg)) + "\n" + toString(monoToWString(exceptionStackTrace));
  134. LOGERR(msg);
  135. BS_EXCEPT(InternalErrorException, msg);
  136. }
  137. }
  138. template<class T, class... Args>
  139. static void invokeThunk(T* thunk, Args... args)
  140. {
  141. MonoException* exception = nullptr;
  142. thunk(std::forward<Args>(args)..., &exception);
  143. throwIfException(exception);
  144. }
  145. };
  146. }