Utility.Marshal.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. //------------------------------------------------------------
  2. // Game Framework
  3. // Copyright © 2013-2021 loyalsoft. All rights reserved.
  4. // Homepage: http://www.game7000.com/
  5. // Feedback: http://www.game7000.com/
  6. //------------------------------------------------------------
  7. using System;
  8. namespace GameFramework
  9. {
  10. public static partial class Utility
  11. {
  12. /// <summary>
  13. /// Marshal 相关的实用函数。
  14. /// </summary>
  15. public static class Marshal
  16. {
  17. private const int BlockSize = 1024 * 4;
  18. private static IntPtr s_CachedHGlobalPtr = IntPtr.Zero;
  19. private static int s_CachedHGlobalSize = 0;
  20. /// <summary>
  21. /// 获取缓存的从进程的非托管内存中分配的内存的大小。
  22. /// </summary>
  23. public static int CachedHGlobalSize
  24. {
  25. get
  26. {
  27. return s_CachedHGlobalSize;
  28. }
  29. }
  30. /// <summary>
  31. /// 确保从进程的非托管内存中分配足够大小的内存并缓存。
  32. /// </summary>
  33. /// <param name="ensureSize">要确保从进程的非托管内存中分配内存的大小。</param>
  34. public static void EnsureCachedHGlobalSize(int ensureSize)
  35. {
  36. if (ensureSize < 0)
  37. {
  38. throw new GameFrameworkException("Ensure size is invalid.");
  39. }
  40. if (s_CachedHGlobalPtr == IntPtr.Zero || s_CachedHGlobalSize < ensureSize)
  41. {
  42. FreeCachedHGlobal();
  43. int size = (ensureSize - 1 + BlockSize) / BlockSize * BlockSize;
  44. s_CachedHGlobalPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(size);
  45. s_CachedHGlobalSize = size;
  46. }
  47. }
  48. /// <summary>
  49. /// 释放缓存的从进程的非托管内存中分配的内存。
  50. /// </summary>
  51. public static void FreeCachedHGlobal()
  52. {
  53. if (s_CachedHGlobalPtr != IntPtr.Zero)
  54. {
  55. System.Runtime.InteropServices.Marshal.FreeHGlobal(s_CachedHGlobalPtr);
  56. s_CachedHGlobalPtr = IntPtr.Zero;
  57. s_CachedHGlobalSize = 0;
  58. }
  59. }
  60. /// <summary>
  61. /// 将数据从对象转换为二进制流。
  62. /// </summary>
  63. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  64. /// <param name="structure">要转换的对象。</param>
  65. /// <returns>存储转换结果的二进制流。</returns>
  66. public static byte[] StructureToBytes<T>(T structure)
  67. {
  68. return StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)));
  69. }
  70. /// <summary>
  71. /// 将数据从对象转换为二进制流。
  72. /// </summary>
  73. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  74. /// <param name="structure">要转换的对象。</param>
  75. /// <param name="structureSize">要转换的对象的大小。</param>
  76. /// <returns>存储转换结果的二进制流。</returns>
  77. internal static byte[] StructureToBytes<T>(T structure, int structureSize)
  78. {
  79. if (structureSize < 0)
  80. {
  81. throw new GameFrameworkException("Structure size is invalid.");
  82. }
  83. EnsureCachedHGlobalSize(structureSize);
  84. System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true);
  85. byte[] result = new byte[structureSize];
  86. System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, 0, structureSize);
  87. return result;
  88. }
  89. /// <summary>
  90. /// 将数据从对象转换为二进制流。
  91. /// </summary>
  92. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  93. /// <param name="structure">要转换的对象。</param>
  94. /// <param name="result">存储转换结果的二进制流。</param>
  95. public static void StructureToBytes<T>(T structure, byte[] result)
  96. {
  97. StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, 0);
  98. }
  99. /// <summary>
  100. /// 将数据从对象转换为二进制流。
  101. /// </summary>
  102. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  103. /// <param name="structure">要转换的对象。</param>
  104. /// <param name="structureSize">要转换的对象的大小。</param>
  105. /// <param name="result">存储转换结果的二进制流。</param>
  106. internal static void StructureToBytes<T>(T structure, int structureSize, byte[] result)
  107. {
  108. StructureToBytes(structure, structureSize, result, 0);
  109. }
  110. /// <summary>
  111. /// 将数据从对象转换为二进制流。
  112. /// </summary>
  113. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  114. /// <param name="structure">要转换的对象。</param>
  115. /// <param name="result">存储转换结果的二进制流。</param>
  116. /// <param name="startIndex">写入存储转换结果的二进制流的起始位置。</param>
  117. public static void StructureToBytes<T>(T structure, byte[] result, int startIndex)
  118. {
  119. StructureToBytes(structure, System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), result, startIndex);
  120. }
  121. /// <summary>
  122. /// 将数据从对象转换为二进制流。
  123. /// </summary>
  124. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  125. /// <param name="structure">要转换的对象。</param>
  126. /// <param name="structureSize">要转换的对象的大小。</param>
  127. /// <param name="result">存储转换结果的二进制流。</param>
  128. /// <param name="startIndex">写入存储转换结果的二进制流的起始位置。</param>
  129. internal static void StructureToBytes<T>(T structure, int structureSize, byte[] result, int startIndex)
  130. {
  131. if (structureSize < 0)
  132. {
  133. throw new GameFrameworkException("Structure size is invalid.");
  134. }
  135. if (result == null)
  136. {
  137. throw new GameFrameworkException("Result is invalid.");
  138. }
  139. if (startIndex < 0)
  140. {
  141. throw new GameFrameworkException("Start index is invalid.");
  142. }
  143. if (startIndex + structureSize > result.Length)
  144. {
  145. throw new GameFrameworkException("Result length is not enough.");
  146. }
  147. EnsureCachedHGlobalSize(structureSize);
  148. System.Runtime.InteropServices.Marshal.StructureToPtr(structure, s_CachedHGlobalPtr, true);
  149. System.Runtime.InteropServices.Marshal.Copy(s_CachedHGlobalPtr, result, startIndex, structureSize);
  150. }
  151. /// <summary>
  152. /// 将数据从二进制流转换为对象。
  153. /// </summary>
  154. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  155. /// <param name="buffer">要转换的二进制流。</param>
  156. /// <returns>存储转换结果的对象。</returns>
  157. public static T BytesToStructure<T>(byte[] buffer)
  158. {
  159. return BytesToStructure<T>(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, 0);
  160. }
  161. /// <summary>
  162. /// 将数据从二进制流转换为对象。
  163. /// </summary>
  164. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  165. /// <param name="buffer">要转换的二进制流。</param>
  166. /// <param name="startIndex">读取要转换的二进制流的起始位置。</param>
  167. /// <returns>存储转换结果的对象。</returns>
  168. public static T BytesToStructure<T>(byte[] buffer, int startIndex)
  169. {
  170. return BytesToStructure<T>(System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)), buffer, startIndex);
  171. }
  172. /// <summary>
  173. /// 将数据从二进制流转换为对象。
  174. /// </summary>
  175. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  176. /// <param name="structureSize">要转换的对象的大小。</param>
  177. /// <param name="buffer">要转换的二进制流。</param>
  178. /// <returns>存储转换结果的对象。</returns>
  179. internal static T BytesToStructure<T>(int structureSize, byte[] buffer)
  180. {
  181. return BytesToStructure<T>(structureSize, buffer, 0);
  182. }
  183. /// <summary>
  184. /// 将数据从二进制流转换为对象。
  185. /// </summary>
  186. /// <typeparam name="T">要转换的对象的类型。</typeparam>
  187. /// <param name="structureSize">要转换的对象的大小。</param>
  188. /// <param name="buffer">要转换的二进制流。</param>
  189. /// <param name="startIndex">读取要转换的二进制流的起始位置。</param>
  190. /// <returns>存储转换结果的对象。</returns>
  191. internal static T BytesToStructure<T>(int structureSize, byte[] buffer, int startIndex)
  192. {
  193. if (structureSize < 0)
  194. {
  195. throw new GameFrameworkException("Structure size is invalid.");
  196. }
  197. if (buffer == null)
  198. {
  199. throw new GameFrameworkException("Buffer is invalid.");
  200. }
  201. if (startIndex < 0)
  202. {
  203. throw new GameFrameworkException("Start index is invalid.");
  204. }
  205. if (startIndex + structureSize > buffer.Length)
  206. {
  207. throw new GameFrameworkException("Buffer length is not enough.");
  208. }
  209. EnsureCachedHGlobalSize(structureSize);
  210. System.Runtime.InteropServices.Marshal.Copy(buffer, startIndex, s_CachedHGlobalPtr, structureSize);
  211. return (T)System.Runtime.InteropServices.Marshal.PtrToStructure(s_CachedHGlobalPtr, typeof(T));
  212. }
  213. }
  214. }
  215. }