public static ushort GetOutline(UnmanagedPointer ipHeader, int size, out float2[] pnts, out sbyte[] onCurve) { ushort cTotal = 0; UnmanagedPointer endPtr = ipHeader + size; UnmanagedPointer ipCurve; int MaxPts = size / Marshal.SizeOf(typeof(POINTFX)); TTPOLYGONHEADER Header; TTPOLYCURVE Curve; POINTFX pntfx = new POINTFX(); pnts = new float2[MaxPts]; onCurve = new sbyte[MaxPts]; while (ipHeader < endPtr && pnts != null) { Header = (TTPOLYGONHEADER)Marshal.PtrToStructure(ipHeader, typeof(TTPOLYGONHEADER)); if (Header.dwType == GDI32.TT_POLYGON_TYPE) { pnts[cTotal].x = Header.pfxStart.x.ToSingle(); pnts[cTotal].y = Header.pfxStart.y.ToSingle(); onCurve[cTotal++] = -1; // new contour ipCurve = ipHeader + Marshal.SizeOf(typeof(TTPOLYGONHEADER)); while (ipCurve < ipHeader + Header.cb) { Curve = (TTPOLYCURVE)Marshal.PtrToStructure(ipCurve, typeof(TTPOLYCURVE)); ipCurve = ipCurve + Marshal.SizeOf(typeof(TTPOLYCURVE)); for (int i = 0; i < Curve.cpfx; i++) { pntfx = (POINTFX)Marshal.PtrToStructure(ipCurve, typeof(POINTFX)); pnts[cTotal].x = pntfx.x.ToSingle(); pnts[cTotal].y = pntfx.y.ToSingle(); onCurve[cTotal++] = (sbyte)((i == Curve.cpfx - 1) ? 1 : (Curve.wType == GDI32.TT_PRIM_LINE) ? 1 : 0); ipCurve = ipCurve + Marshal.SizeOf(typeof(POINTFX)); } } // check to see if first contour point is repeated and remove it if (Header.pfxStart == pntfx) cTotal--; } ipHeader = ipHeader + Header.cb; } return cTotal; }
public static GDIRegion CreateFromRectangles(RectangleI[] rects, Guid uniqueID) { // 1. Create a header RGNDATAHEADER header = new RGNDATAHEADER(); header.dwSize = Marshal.SizeOf(header); header.iType = 1; header.nCount = (uint)rects.Length; header.nRgnSize = (uint)Marshal.SizeOf(typeof(RECT)) * header.nCount; //header.rcBound = // 2. Allocate memory to hold the header plus the data for the rectangles int dataLengthNeeded = (int)(header.dwSize + header.nRgnSize); IntPtr memoryPtr = Marshal.AllocCoTaskMem((int)dataLengthNeeded); UnmanagedPointer structPtr = new UnmanagedPointer(memoryPtr); // 4. Copy the Header into the memory buffer Marshal.StructureToPtr(header, structPtr, false); // 5. Increment the memory buffer pointer to write the rectangles structPtr = structPtr + header.dwSize; // The nRgnSize / nCount will tell us how many bytes per rectangle structure // and therefore how much to advance the pointer as we turn the buffer // into a set of rectangles using PtrToStructure. int structIncrement = (int)(header.nRgnSize / header.nCount); // 6. Write the rectangles for (int i = 0; i < header.nCount; i++) { RECT aRect = new RECT(rects[i].Left, rects[i].Top, rects[i].Width, rects[i].Height); Marshal.StructureToPtr(aRect, structPtr, false); // Increment the structure pointer to the next position structPtr = structPtr + structIncrement; } // 7. Create the region IntPtr regionHandle = GDI32.ExtCreateRegion(IntPtr.Zero, (uint)rects.Length, memoryPtr); GDIRegion newRegion = new GDIRegion(regionHandle, true, uniqueID); // 8. Free the memory Marshal.FreeCoTaskMem(memoryPtr); return newRegion; }
public RectangleI[] GetRectangles() { // If the region is empty, return a single empty rectangle if (IsEmpty) { return new RectangleI[1]; } // 1. Call GetRgnData with null to get size uint dataLengthNeeded = GDI32.GetRegionData(DangerousGetHandle(), 0, IntPtr.Zero); // 2. allocate some memory to hold the data UnmanagedMemory uMem = new UnmanagedMemory((int)dataLengthNeeded); IntPtr memoryPtr = uMem.MemoryPointer; UnmanagedPointer structPtr = new UnmanagedPointer(memoryPtr); // 3. call again passing in memory uint bytesFilled = GDI32.GetRegionData(DangerousGetHandle(), dataLengthNeeded, structPtr); // If the return value is 0, then the call failed. if (0 == bytesFilled) return null; // 4. convert memory to data structures // First get the RGNDATAHEADER RGNDATAHEADER dataHeader; dataHeader = (RGNDATAHEADER)Marshal.PtrToStructure(structPtr, typeof(RGNDATAHEADER)); // dataHeader.dwSize - tells us how big the header is, and thus how many bytes to skip to get // to the rectangle information // dataHeader.nRgnSize - tells us how many bytes are needed for the rectangle information // dataHeader.nCount - tells us how many rectangles there are structPtr = structPtr + dataHeader.dwSize; // The nRgnSize / nCount will tell us how many bytes per rectangle structure // and therefore how much to advance the pointer as we turn the buffer // into a set of rectangles using PtrToStructure. int structIncrement = (int)(dataHeader.nRgnSize / dataHeader.nCount); // Create a list to add the rectangles to. This is simply convenient. RectangleI[] rects = new RectangleI[dataHeader.nCount]; // Loop through creating as many rectangles as indicated by the dataheader nCount field for (int i = 0; i < dataHeader.nCount; i++) { RECT rect = (RECT)Marshal.PtrToStructure(structPtr, typeof(RECT)); rects[i].x1 = rect.X; rects[i].y1 = rect.Y; rects[i].x2 = rect.X + rect.Width; rects[i].y2 = rect.Y + rect.Height; rects[i].Normalize(); structPtr = structPtr + structIncrement; } // 5. free memory uMem.Dispose(); return rects; }
public UnmanagedMemory(int size) { this.fSize = size; fMemoryPtr = new UnmanagedPointer(Marshal.AllocCoTaskMem((int)size)); }