internal unsafe static extern uint GetRegionData( IntPtr hRgn, uint dwCount, NativeStructs.RGNDATA *lpRgnData);
private static unsafe void GetRegionScans(IntPtr hRgn, out Rectangle[] scans) { uint bytes = 0; int countdown = 100; int error = 0; // HACK: It seems that sometimes the GetRegionData will return ERROR_INVALID_HANDLE // even though the handle (the HRGN) is fine. Maybe the function is not // re-entrant? I'm not sure, but trying it again seems to fix it. while (countdown > 0) { bytes = SafeNativeMethods.GetRegionData(hRgn, 0, (NativeStructs.RGNDATA *)IntPtr.Zero); error = Marshal.GetLastWin32Error(); if (bytes == 0) { --countdown; System.Threading.Thread.Sleep(5); } else { break; } } // But if we retry several times and it still messes up then we will finally give up. if (bytes == 0) { throw new Win32Exception(error, "GetRegionData returned " + bytes.ToString(CultureInfo.CurrentCulture) + ", GetLastError() = " + error.ToString(CultureInfo.CurrentCulture)); } byte *data; // Up to 512 bytes, allocate on the stack. Otherwise allocate from the heap. if (bytes <= 512) { byte *data1 = stackalloc byte[(int)bytes]; data = data1; } else { data = (byte *)Memory.Allocate(bytes, false).ToPointer(); } try { NativeStructs.RGNDATA *pRgnData = (NativeStructs.RGNDATA *)data; uint result = SafeNativeMethods.GetRegionData(hRgn, bytes, pRgnData); if (result != bytes) { throw new OutOfMemoryException("SafeNativeMethods.GetRegionData returned 0"); } NativeStructs.RECT *pRects = NativeStructs.RGNDATA.GetRectsPointer(pRgnData); scans = new Rectangle[pRgnData->rdh.nCount]; for (int i = 0; i < scans.Length; ++i) { scans[i] = Rectangle.FromLTRB(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom); } pRects = null; pRgnData = null; } finally { if (bytes > 512) { Memory.Free(new IntPtr(data)); } } }
internal static extern unsafe uint GetRegionData([In()] IntPtr hrgn, [In()] uint nCount, [Out()] NativeStructs.RGNDATA *lpRgnData);