BsMonoUtil.h 5.0 KB

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