using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Windows.Forms; namespace SmartCoalApplication.SystemLayer { public unsafe static class Memory { private static IntPtr hHeap; static Memory() { hHeap = SafeNativeMethods.HeapCreate(0, IntPtr.Zero, IntPtr.Zero); uint info = 2; try { SafeNativeMethods.HeapSetInformation(hHeap, NativeConstants.HeapCompatibilityInformation, (void*)&info, sizeof(uint)); } catch (Exception) { } Application.ApplicationExit += new EventHandler(Application_ApplicationExit); } private static void DestroyHeap() { IntPtr hHeap2 = hHeap; hHeap = IntPtr.Zero; SafeNativeMethods.HeapDestroy(hHeap2); } private static void Application_ApplicationExit(object sender, EventArgs e) { DestroyHeap(); } public static IntPtr Allocate(ulong bytes) { if (hHeap == IntPtr.Zero) { throw new InvalidOperationException("heap has already been destroyed"); } else { IntPtr block = SafeNativeMethods.HeapAlloc(hHeap, 0, new UIntPtr(bytes)); if (block == IntPtr.Zero) { throw new OutOfMemoryException("HeapAlloc returned a null pointer"); } if (bytes > 0) { GC.AddMemoryPressure((long)bytes); } return block; } } public static IntPtr AllocateLarge(ulong bytes) { IntPtr block = SafeNativeMethods.VirtualAlloc(IntPtr.Zero, new UIntPtr(bytes), NativeConstants.MEM_COMMIT, NativeConstants.PAGE_READWRITE); if (block == IntPtr.Zero) { throw new OutOfMemoryException("VirtualAlloc returned a null pointer"); } if (bytes > 0) { GC.AddMemoryPressure((long)bytes); } return block; } public static IntPtr AllocateBitmap(int width, int height, out IntPtr handle) { NativeStructs.BITMAPINFO bmi = new NativeStructs.BITMAPINFO(); bmi.bmiHeader.biSize = (uint)sizeof(NativeStructs.BITMAPINFOHEADER); bmi.bmiHeader.biWidth = width; bmi.bmiHeader.biHeight = -height; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = NativeConstants.BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = 96; bmi.bmiHeader.biYPelsPerMeter = 96; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; IntPtr pvBits; IntPtr hBitmap = SafeNativeMethods.CreateDIBSection( IntPtr.Zero, ref bmi, NativeConstants.DIB_RGB_COLORS, out pvBits, IntPtr.Zero, 0); if (hBitmap == IntPtr.Zero) { throw new OutOfMemoryException("CreateDIBSection returned NULL (" + Marshal.GetLastWin32Error().ToString() + ") while attempting to allocate " + width + "x" + height + " bitmap"); } handle = hBitmap; long bytes = (long)width * (long)height * 4; if (bytes > 0) { GC.AddMemoryPressure(bytes); } return pvBits; } /// /// Frees a bitmap previously allocated with AllocateBitmap. /// /// The handle that was returned from a previous call to AllocateBitmap. /// The width of the bitmap, as specified in the original call to AllocateBitmap. /// The height of the bitmap, as specified in the original call to AllocateBitmap. public static void FreeBitmap(IntPtr handle, int width, int height) { long bytes = (long)width * (long)height * 4; bool bResult = SafeNativeMethods.DeleteObject(handle); if (!bResult) { throw new Win32Exception("DeleteObject returned false"); } if (bytes > 0) { GC.RemoveMemoryPressure(bytes); } } /// /// Frees a block of memory previously allocated with Allocate(). /// /// The block to free. /// There was an error freeing the block. public static void Free(IntPtr block) { if (Memory.hHeap != IntPtr.Zero) { long bytes = (long)SafeNativeMethods.HeapSize(hHeap, 0, block); bool result = SafeNativeMethods.HeapFree(hHeap, 0, block); if (!result) { int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); throw new InvalidOperationException("HeapFree returned an error: " + error.ToString()); } if (bytes > 0) { GC.RemoveMemoryPressure(bytes); } } } /// /// Frees a block of memory previous allocated with AllocateLarge(). /// /// The block to free. /// The size of the block. public static void FreeLarge(IntPtr block, ulong bytes) { bool result = SafeNativeMethods.VirtualFree(block, UIntPtr.Zero, NativeConstants.MEM_RELEASE); if (!result) { int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); throw new InvalidOperationException("VirtualFree returned an error: " + error.ToString()); } if (bytes > 0) { GC.RemoveMemoryPressure((long)bytes); } } public static void Copy(void* dst, void* src, ulong length) { SafeNativeMethods.memcpy(dst, src, new UIntPtr(length)); } public static void SetToZero(void* dst, ulong length) { SafeNativeMethods.memset(dst, 0, new UIntPtr(length)); } } }