/* * Process Hacker - * handle table * * Copyright (C) 2009 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.Collections.Generic; namespace ProcessHacker.Common.Objects { public class HandleTableEntry { private int _handle; private IRefCounted _object; public int Handle { get { return _handle; } internal set { _handle = value; } } public IRefCounted Object { get { return _object; } internal set { _object = value; } } } /// /// Provides methods for managing handles to objects. /// public class HandleTable : HandleTable { } /// /// Provides methods for managing handles to objects. /// /// The type of each handle table entry. public class HandleTable : BaseObject where TEntry : HandleTableEntry, new() { /// /// Represents a callback function for handle table enumeration. /// /// The current handle. /// The current object. /// Return true to stop enumerating; otherwise return false. public delegate bool EnumerateHandleTableDelegate(int handle, TEntry entry); private IdGenerator _handleGenerator = new IdGenerator(4, 4); private Dictionary _handles = new Dictionary(); protected override void DisposeObject(bool disposing) { lock (_handles) { foreach (var entry in _handles.Values) entry.Object.Dereference(disposing); } } /// /// Creates a handle to the specified object. /// /// The object to reference. /// The new handle. public int Allocate(IRefCounted obj) { TEntry entry = new TEntry(); return this.Allocate(obj, entry); } /// /// Creates a handle to the specified object. /// /// The object to reference. /// The handle table entry to use. /// The new handle. public int Allocate(IRefCounted obj, TEntry entry) { int handle = _handleGenerator.Pop(); // Reference the object so it does not get freed while // it is stored in the handle table. obj.Reference(); // GC should not own the object. obj.Dispose(); // Initialize the entry. entry.Handle = handle; entry.Object = obj; // Add the handle entry. lock (_handles) { _handles.Add(handle, entry); } return handle; } /// /// Enumerates the handles in the handle table. /// /// The callback for the enumeration. /// Whether the enumeration was stopped by the callback. public bool Enumerate(EnumerateHandleTableDelegate callback) { lock (_handles) { foreach (var entry in _handles.Values) { if (callback(entry.Handle, entry)) return true; } return false; } } /// /// Closes a handle. /// /// The handle to close. /// Whether the handle was closed. public bool Free(int handle) { IRefCounted obj; lock (_handles) { if (!_handles.ContainsKey(handle)) return false; // Store the object reference for dereferencing later. obj = _handles[handle].Object; // Remove the handle so it can no longer be used. _handles.Remove(handle); } // Make the handle value available. _handleGenerator.Push(handle); // Dereference the object (this doesn't need to be in the locking block). obj.Dereference(); return true; } /// /// Gets the handle table entry for a handle. /// /// The handle to lookup. /// A handle table entry. public TEntry LookupEntry(int handle) { lock (_handles) { if (_handles.ContainsKey(handle)) return _handles[handle]; else return null; } } /// /// Gets the object referenced by a handle. /// /// The handle to lookup. /// /// An object. This object has not been referenced and is /// not guaranteed to be valid. /// public IRefCounted LookupObject(int handle) { return this.LookupEntry(handle).Object; } /// /// Gets the object referenced by a handle. /// /// The type of the object to retrieve. /// The handle to lookup. /// /// An object. This object has not been referenced and is /// not guaranteed to be valid. /// public T LookupObject(int handle) where T : class, IRefCounted { return this.LookupObject(handle) as T; } /// /// References an object using a handle. /// /// The handle to lookup. /// /// An object. This object has been referenced and must be /// dereferenced once it is no longer needed. /// public IRefCounted ReferenceByHandle(int handle) { TEntry entry; return this.ReferenceByHandle(handle, out entry); } /// /// References an object using a handle. /// /// The handle to lookup. /// The handle table entry. /// /// An object. This object has been referenced and must be /// dereferenced once it is no longer needed. /// public IRefCounted ReferenceByHandle(int handle, out TEntry entry) { lock (_handles) { if (_handles.ContainsKey(handle)) { IRefCounted obj = _handles[handle].Object; obj.Reference(); entry = _handles[handle]; return obj; } else { entry = null; return null; } } } /// /// References an object using a handle. /// /// The type of the object to reference. /// The handle to lookup. /// /// An object. This object has been referenced and must be /// dereferenced once it is no longer needed. /// public T ReferenceByHandle(int handle) where T : class, IRefCounted { TEntry entry; return this.ReferenceByHandle(handle, out entry); } /// /// References an object using a handle. /// /// The type of the object to reference. /// The handle to lookup. /// The handle table entry. /// /// An object. This object has been referenced and must be /// dereferenced once it is no longer needed. /// public T ReferenceByHandle(int handle, out TEntry entry) where T : class, IRefCounted { IRefCounted obj = this.ReferenceByHandle(handle, out entry); if (obj == null) return null; // Check the type. if (obj is T) { return (T)obj; } else { // Wrong type. Dereference and return. obj.Dereference(); return null; } } } }