/* * Process Hacker - * memory allocation wrapper * * Copyright (C) 2008 wj32 * * This file is part of Process Hacker. * * Process Hacker is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Process Hacker is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Process Hacker. If not, see . */ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Threading; namespace ProcessHacker.Native { /// /// Represents an unmanaged memory allocation. /// public class MemoryAlloc : IDisposable { private object _disposeLock = new object(); private bool _disposed = false; private Dictionary _sizeCache = new Dictionary(); private IntPtr _memory; private int _size; public static implicit operator int(MemoryAlloc memory) { return memory.Memory.ToInt32(); } public static implicit operator IntPtr(MemoryAlloc memory) { return memory.Memory; } public unsafe static implicit operator byte*(MemoryAlloc memory) { return (byte*)memory.Memory; } public unsafe static explicit operator void*(MemoryAlloc memory) { return (void*)memory.Memory; } public unsafe static explicit operator int*(MemoryAlloc memory) { return (int*)memory.Memory; } /// /// Creates a memory allocation from an existing pointer. The allocation /// referenced by the pointer will be freed automatically. The Size /// property will be set to 0. /// /// A pointer to an existing memory allocation. /// A new instance of a memory allocation. public static MemoryAlloc FromPointer(IntPtr memory) { return new MemoryAlloc(0) { _memory = memory }; } /// /// Creates a new, invalid memory allocation. /// You must set the pointer using the Memory property. /// protected MemoryAlloc() { } /// /// Creates a new memory allocation with the specified size. /// /// The amount of memory, in bytes, to allocate. public MemoryAlloc(int size) { _memory = Marshal.AllocHGlobal((int)size); _size = size; if (size > 0) GC.AddMemoryPressure(size); } ~MemoryAlloc() { this.Dispose(false); } /// /// Reads a signed integer. /// /// The offset at which to begin reading. /// The integer. public int ReadInt32(int offset) { return this.ReadInt32(offset, 0); } /// /// Reads a signed integer. /// /// The offset at which to begin reading. /// The index at which to begin reading, after the offset is added. /// The integer. public int ReadInt32(int offset, int index) { return Marshal.ReadInt32(_memory, offset + index * sizeof(int)); } public IntPtr ReadIntPtr(int offset) { return this.ReadIntPtr(offset, 0); } public IntPtr ReadIntPtr(int offset, int index) { return Marshal.ReadIntPtr(_memory, offset + index * IntPtr.Size); } /// /// Reads an unsigned integer. /// /// The offset at which to begin reading. /// The integer. public uint ReadUInt32(int offset) { return this.ReadUInt32(offset, 0); } /// /// Reads an unsigned integer. /// /// The offset at which to begin reading. /// The index at which to begin reading, after the offset is added. /// The integer. public uint ReadUInt32(int offset, int index) { return (uint)this.ReadInt32(offset, index); } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The new struct. public T ReadStruct() { return this.ReadStruct(0); } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The index at which to begin reading to the struct. This is multiplied by /// the size of the struct. /// The new struct. public T ReadStruct(int index) { return this.ReadStruct(0, index); } /// /// Creates a struct from the memory allocation. /// /// The type of the struct. /// The offset to add before reading. /// The index at which to begin reading to the struct. This is multiplied by /// the size of the struct. /// The new struct. public T ReadStruct(int offset, int index) { if (!_sizeCache.ContainsKey(typeof(T))) _sizeCache.Add(typeof(T), Marshal.SizeOf(typeof(T))); return (T)Marshal.PtrToStructure( new IntPtr(_memory.ToInt32() + offset + _sizeCache[typeof(T)] * index), typeof(T)); } /// /// Resizes the memory allocation. /// /// The new size of the allocation. public virtual void Resize(int newSize) { if (_size > 0) GC.RemoveMemoryPressure(_size); _memory = Marshal.ReAllocHGlobal(_memory, new IntPtr(newSize)); _size = newSize; if (_size > 0) GC.AddMemoryPressure(_size); } /// /// Writes a single byte to the memory allocation. /// /// The offset at which to write. /// The value of the byte. public void WriteByte(int offset, byte b) { Marshal.WriteByte(this, offset, b); } public void WriteBytes(int offset, byte[] b) { Marshal.Copy(b, 0, new IntPtr(this + offset), b.Length); } public void WriteInt32(int offset, int i) { Marshal.WriteInt32(this, offset, i); } /// /// Writes a Unicode string to the allocated memory. /// /// The offset to add. /// The string to write. public void WriteUnicodeString(int offset, string s) { byte[] b = UnicodeEncoding.Unicode.GetBytes(s); for (int i = 0; i < b.Length; i++) Marshal.WriteByte(this.Memory, offset + i, b[i]); } /// /// Gets a pointer to the allocated memory. /// public IntPtr Memory { get { return _memory; } protected set { _memory = value; } } /// /// Gets the size of the allocated memory. /// public virtual int Size { get { return _size; } protected set { _size = value; } } protected virtual void Free() { Marshal.FreeHGlobal(this); if (_size > 0) GC.RemoveMemoryPressure(_size); } private void Dispose(bool disposing) { try { if (disposing) Monitor.Enter(_disposeLock); if (!_disposed) { this.Free(); _disposed = true; } } finally { if (disposing) Monitor.Exit(_disposeLock); } } /// /// Frees the allocated memory. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } } }