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));
}
}
}