PdnGraphics.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. using System;
  2. using System.ComponentModel;
  3. using System.Drawing;
  4. using System.Drawing.Imaging;
  5. using System.Runtime.InteropServices;
  6. namespace SmartCoalApplication.SystemLayer
  7. {
  8. public static class PdnGraphics
  9. {
  10. public static PropertyItem CreatePropertyItem()
  11. {
  12. PropertyItem2 pi2 = new PropertyItem2(0, 0, 0, new byte[0]);
  13. return pi2.ToPropertyItem();
  14. }
  15. public static PropertyItem ClonePropertyItem(PropertyItem pi)
  16. {
  17. byte[] valueClone;
  18. if (pi.Value == null)
  19. {
  20. valueClone = new byte[0];
  21. }
  22. else
  23. {
  24. valueClone = (byte[])pi.Value.Clone();
  25. }
  26. PropertyItem2 pi2 = new PropertyItem2(pi.Id, pi.Len, pi.Type, valueClone);
  27. return pi2.ToPropertyItem();
  28. }
  29. public static string SerializePropertyItem(PropertyItem pi)
  30. {
  31. PropertyItem2 pi2 = PropertyItem2.FromPropertyItem(pi);
  32. return pi2.ToBlob();
  33. }
  34. public static PropertyItem DeserializePropertyItem(string piBlob)
  35. {
  36. PropertyItem2 pi2 = PropertyItem2.FromBlob(piBlob);
  37. return pi2.ToPropertyItem();
  38. }
  39. internal unsafe static void GetRegionScans(IntPtr hRgn, out Rectangle[] scans, out int area)
  40. {
  41. uint bytes = 0;
  42. int countdown = 100;
  43. int error = 0;
  44. while (countdown > 0)
  45. {
  46. bytes = SafeNativeMethods.GetRegionData(hRgn, 0, (NativeStructs.RGNDATA*)IntPtr.Zero);
  47. error = Marshal.GetLastWin32Error();
  48. if (bytes == 0)
  49. {
  50. --countdown;
  51. System.Threading.Thread.Sleep(5);
  52. }
  53. else
  54. {
  55. break;
  56. }
  57. }
  58. // But if we retry several times and it still messes up then we will finally give up.
  59. if (bytes == 0)
  60. {
  61. throw new Win32Exception(error, "GetRegionData returned " + bytes.ToString() + ", GetLastError() = " + error.ToString());
  62. }
  63. byte* data;
  64. // Up to 512 bytes, allocate on the stack. Otherwise allocate from the heap.
  65. if (bytes <= 512)
  66. {
  67. byte* data1 = stackalloc byte[(int)bytes];
  68. data = data1;
  69. }
  70. else
  71. {
  72. data = (byte*)Memory.Allocate(bytes).ToPointer();
  73. }
  74. try
  75. {
  76. NativeStructs.RGNDATA* pRgnData = (NativeStructs.RGNDATA*)data;
  77. uint result = SafeNativeMethods.GetRegionData(hRgn, bytes, pRgnData);
  78. if (result != bytes)
  79. {
  80. throw new OutOfMemoryException("SafeNativeMethods.GetRegionData returned 0");
  81. }
  82. NativeStructs.RECT* pRects = NativeStructs.RGNDATA.GetRectsPointer(pRgnData);
  83. scans = new Rectangle[pRgnData->rdh.nCount];
  84. area = 0;
  85. for (int i = 0; i < scans.Length; ++i)
  86. {
  87. scans[i] = Rectangle.FromLTRB(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom);
  88. area += scans[i].Width * scans[i].Height;
  89. }
  90. pRects = null;
  91. pRgnData = null;
  92. }
  93. finally
  94. {
  95. if (bytes > 512)
  96. {
  97. Memory.Free(new IntPtr(data));
  98. }
  99. }
  100. }
  101. /// <summary>
  102. /// Retrieves an array of rectangles that approximates a region, and computes the
  103. /// pixel area of it. This method is necessary to work around some bugs in .NET
  104. /// and to increase performance for the way in which we typically use this data.
  105. /// </summary>
  106. /// <param name="region">The Region to retrieve data from.</param>
  107. /// <param name="scans">An array of Rectangle to put the scans into.</param>
  108. /// <param name="area">An integer to write the computed area of the region into.</param>
  109. /// <remarks>
  110. /// Note to implementors: Simple implementations may simple call region.GetRegionScans()
  111. /// and process the data for the 'out' variables.</remarks>
  112. public static void GetRegionScans(Region region, out Rectangle[] scans, out int area)
  113. {
  114. using (NullGraphics nullGraphics = new NullGraphics())
  115. {
  116. IntPtr hRgn = IntPtr.Zero;
  117. try
  118. {
  119. hRgn = region.GetHrgn(nullGraphics.Graphics);
  120. GetRegionScans(hRgn, out scans, out area);
  121. }
  122. finally
  123. {
  124. if (hRgn != IntPtr.Zero)
  125. {
  126. SafeNativeMethods.DeleteObject(hRgn);
  127. hRgn = IntPtr.Zero;
  128. }
  129. }
  130. }
  131. GC.KeepAlive(region);
  132. }
  133. }
  134. }