Rtl: Handle Tables

Robert Shearman rob at codeweavers.com
Thu Oct 21 10:01:17 CDT 2004


Hi,

I was a bit disappointed with Microsoft on their implementation of these 
handle tables. I thought it would have had more useful features, like 
ref counting and locking, like we have in MSI and WinInet. Really, all 
these handle tables are, are just a slightly fancy memory allocator. But 
here is the implementation anyway.

Rob

Changelog:
Implement handle table functions.
-------------- next part --------------
Index: wine/include/winternl.h
===================================================================
RCS file: /home/wine/wine/include/winternl.h,v
retrieving revision 1.96
diff -u -p -r1.96 winternl.h
--- wine/include/winternl.h	11 Oct 2004 20:59:06 -0000	1.96
+++ wine/include/winternl.h	21 Oct 2004 14:55:44 -0000
@@ -1153,6 +1153,24 @@ typedef struct _PORT_MESSAGE_HEADER {
   ULONG SectionSize;
 } PORT_MESSAGE_HEADER, *PPORT_MESSAGE_HEADER, PORT_MESSAGE, *PPORT_MESSAGE;
 
+/* FIXME: names probably not correct */
+typedef struct _RTL_HANDLE
+{
+    struct _RTL_HANDLE * Next;
+} RTL_HANDLE;
+
+/* FIXME: names probably not correct */
+typedef struct _RTL_HANDLE_TABLE
+{
+    ULONG MaxHandleCount;  /* 0x00 */
+    ULONG HandleSize;      /* 0x04 */
+    ULONG Unused[2];       /* 0x08-0x0c */
+    PCHAR NextFree;        /* 0x10 */
+    PCHAR FirstHandle;     /* 0x14 */
+    PCHAR ReservedMemory;  /* 0x18 */
+    PCHAR MaxHandle;       /* 0x1c */
+} RTL_HANDLE_TABLE;
+
 /***********************************************************************
  * Defines
  */
@@ -1384,6 +1402,7 @@ NTSTATUS  WINAPI RtlAddAccessDeniedAceEx
 PVOID     WINAPI RtlAddVectoredExceptionHandler(ULONG,PVECTORED_EXCEPTION_HANDLER);
 DWORD     WINAPI RtlAdjustPrivilege(DWORD,DWORD,DWORD,DWORD);
 BOOLEAN   WINAPI RtlAllocateAndInitializeSid(PSID_IDENTIFIER_AUTHORITY,BYTE,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,DWORD,PSID *);
+RTL_HANDLE * WINAPI RtlAllocateHandle(RTL_HANDLE_TABLE *,ULONG *);
 PVOID     WINAPI RtlAllocateHeap(HANDLE,ULONG,ULONG);
 DWORD     WINAPI RtlAnsiStringToUnicodeSize(const STRING *);
 NTSTATUS  WINAPI RtlAnsiStringToUnicodeString(PUNICODE_STRING,PCANSI_STRING,BOOLEAN);
@@ -1430,6 +1449,7 @@ void      WINAPI RtlDeleteResource(LPRTL
 DWORD     WINAPI RtlDeleteSecurityObject(DWORD);
 PRTL_USER_PROCESS_PARAMETERS WINAPI RtlDeNormalizeProcessParams(RTL_USER_PROCESS_PARAMETERS*);
 NTSTATUS  WINAPI RtlDestroyEnvironment(PWSTR);
+NTSTATUS  WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE *);
 HANDLE    WINAPI RtlDestroyHeap(HANDLE);
 void      WINAPI RtlDestroyProcessParameters(RTL_USER_PROCESS_PARAMETERS*);
 DOS_PATHNAME_TYPE WINAPI RtlDetermineDosPathNameType_U(PCWSTR);
@@ -1478,6 +1498,7 @@ BOOLEAN   WINAPI RtlFirstFreeAce(PACL,PA
 NTSTATUS  WINAPI RtlFormatCurrentUserKeyPath(PUNICODE_STRING);
 NTSTATUS  WINAPI RtlFormatMessage(LPWSTR,UCHAR,BOOLEAN,BOOLEAN,BOOLEAN,va_list *,LPWSTR,ULONG);
 void      WINAPI RtlFreeAnsiString(PANSI_STRING);
+BOOLEAN   WINAPI RtlFreeHandle(RTL_HANDLE_TABLE *,RTL_HANDLE *);
 BOOLEAN   WINAPI RtlFreeHeap(HANDLE,ULONG,PVOID);
 void      WINAPI RtlFreeOemString(POEM_STRING);
 DWORD     WINAPI RtlFreeSid(PSID);
@@ -1510,6 +1531,7 @@ NTSTATUS  WINAPI RtlInitUnicodeStringEx(
 NTSTATUS  WINAPI RtlInitializeCriticalSection(RTL_CRITICAL_SECTION *);
 NTSTATUS  WINAPI RtlInitializeCriticalSectionAndSpinCount(RTL_CRITICAL_SECTION *,DWORD);
 void      WINAPI RtlInitializeBitMap(PRTL_BITMAP,PULONG,ULONG);
+void      WINAPI RtlInitializeHandleTable(ULONG,ULONG,RTL_HANDLE_TABLE *);
 void      WINAPI RtlInitializeResource(LPRTL_RWLOCK);
 BOOL      WINAPI RtlInitializeSid(PSID,PSID_IDENTIFIER_AUTHORITY,BYTE);
 
@@ -1519,6 +1541,8 @@ NTSTATUS  WINAPI RtlIntegerToUnicodeStri
 ULONG     WINAPI RtlIsDosDeviceName_U(PCWSTR);
 BOOLEAN   WINAPI RtlIsNameLegalDOS8Dot3(const UNICODE_STRING*,POEM_STRING,PBOOLEAN);
 DWORD     WINAPI RtlIsTextUnicode(LPVOID,DWORD,DWORD *);
+BOOLEAN   WINAPI RtlIsValidHandle(const RTL_HANDLE_TABLE *, const RTL_HANDLE *);
+BOOLEAN   WINAPI RtlIsValidIndexHandle(const RTL_HANDLE_TABLE *, ULONG Index, RTL_HANDLE **);
 
 LONGLONG  WINAPI RtlLargeIntegerAdd(LONGLONG,LONGLONG);
 LONGLONG  WINAPI RtlLargeIntegerArithmeticShift(LONGLONG,INT);
Index: wine/dlls/ntdll/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/Makefile.in,v
retrieving revision 1.97
diff -u -p -r1.97 Makefile.in
--- wine/dlls/ntdll/Makefile.in	19 Aug 2004 01:20:45 -0000	1.97
+++ wine/dlls/ntdll/Makefile.in	21 Oct 2004 14:55:44 -0000
@@ -16,6 +16,7 @@ C_SRCS = \
 	error.c \
 	exception.c \
 	file.c \
+	handletable.c \
 	heap.c \
 	large_int.c \
 	loader.c \
Index: wine/dlls/ntdll/ntdll.spec
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/ntdll.spec,v
retrieving revision 1.166
diff -u -p -r1.166 ntdll.spec
--- wine/dlls/ntdll/ntdll.spec	11 Oct 2004 20:11:01 -0000	1.166
+++ wine/dlls/ntdll/ntdll.spec	21 Oct 2004 14:55:44 -0000
@@ -295,6 +295,7 @@
 @ stdcall RtlAddVectoredExceptionHandler(long ptr)
 @ stdcall RtlAdjustPrivilege(long long long long)
 @ stdcall RtlAllocateAndInitializeSid (ptr long long long long long long long long long ptr)
+@ stdcall RtlAllocateHandle(ptr ptr)
 @ stdcall RtlAllocateHeap(long long long)
 @ stub RtlAnsiCharToUnicodeChar
 @ stdcall RtlAnsiStringToUnicodeSize(ptr)
@@ -372,6 +373,7 @@
 @ stdcall RtlDeleteResource(ptr)
 @ stdcall RtlDeleteSecurityObject(long)
 @ stdcall RtlDestroyEnvironment(ptr)
+@ stdcall RtlDestroyHandleTable(ptr)
 @ stdcall RtlDestroyHeap(long)
 @ stdcall RtlDestroyProcessParameters(ptr)
 @ stdcall RtlDestroyQueryDebugBuffer(ptr)
@@ -430,7 +432,7 @@
 @ stdcall RtlFormatCurrentUserKeyPath(ptr)
 @ stdcall RtlFormatMessage(ptr long long long long ptr ptr long)
 @ stdcall RtlFreeAnsiString(long)
-@ stub RtlFreeHandle
+@ stdcall RtlFreeHandle(ptr ptr)
 @ stdcall RtlFreeHeap(long long long)
 @ stdcall RtlFreeOemString(ptr)
 @ stdcall RtlFreeSid (long)
@@ -474,6 +476,7 @@
 @ stdcall RtlInitializeCriticalSection(ptr)
 @ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long)
 @ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr)
+@ stdcall RtlInitializeHandleTable(long long ptr)
 @ stub RtlInitializeRXact
 @ stdcall RtlInitializeResource(ptr)
 @ stdcall RtlInitializeSid(ptr ptr long)
@@ -485,6 +488,8 @@
 @ stub RtlIsGenericTableEmpty
 @ stdcall RtlIsNameLegalDOS8Dot3(ptr ptr ptr)
 @ stdcall RtlIsTextUnicode(ptr long ptr)
+@ stdcall RtlIsValidHandle(ptr ptr)
+@ stdcall RtlIsValidIndexHandle(ptr long ptr)
 @ stdcall -ret64 RtlLargeIntegerAdd(long long long long)
 @ stdcall -ret64 RtlLargeIntegerArithmeticShift(long long long)
 @ stdcall -ret64 RtlLargeIntegerDivide(long long long long ptr)
@@ -1081,10 +1086,7 @@
 @ stub NtSignalAndWaitForSingleObject
 @ stub NtWriteFileGather
 @ stub RtlAddAtomToAtomTable
-@ stub RtlAllocateHandle
 @ stub RtlCreateAtomTable
-@ stub RtlInitializeHandleTable
-@ stub RtlIsValidHandle
 @ stub RtlLookupAtomInAtomTable
 @ stdcall RtlTryEnterCriticalSection(ptr)
 @ stub RtlEnumerateProperties
Index: wine/dlls/ntdll/tests/rtl.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/tests/rtl.c,v
retrieving revision 1.10
diff -u -p -r1.10 rtl.c
--- wine/dlls/ntdll/tests/rtl.c	14 Aug 2004 00:42:12 -0000	1.10
+++ wine/dlls/ntdll/tests/rtl.c	21 Oct 2004 14:55:45 -0000
@@ -40,7 +40,11 @@ static ULONG     (WINAPI  *pRtlRandom)(P
 static BOOLEAN   (WINAPI  *pRtlAreAllAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
 static BOOLEAN   (WINAPI  *pRtlAreAnyAccessesGranted)(ACCESS_MASK, ACCESS_MASK);
 static DWORD     (WINAPI  *pRtlComputeCrc32)(DWORD,const BYTE*,INT);
-
+static void      (WINAPI * pRtlInitializeHandleTable)(ULONG, ULONG, RTL_HANDLE_TABLE *);
+static BOOLEAN   (WINAPI * pRtlIsValidIndexHandle)(const RTL_HANDLE_TABLE *, ULONG, RTL_HANDLE **);
+static NTSTATUS  (WINAPI * pRtlDestroyHandleTable)(RTL_HANDLE_TABLE *);
+static RTL_HANDLE * (WINAPI * pRtlAllocateHandle)(RTL_HANDLE_TABLE *, ULONG *);
+static BOOLEAN   (WINAPI * pRtlFreeHandle)(RTL_HANDLE_TABLE *, RTL_HANDLE *);
 #define LEN 16
 static const char* src_src = "This is a test!"; /* 16 bytes long, incl NUL */
 static ULONG src_aligned_block[4];
@@ -65,6 +69,11 @@ static void InitFunctionPtrs(void)
 	pRtlAreAllAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAllAccessesGranted");
 	pRtlAreAnyAccessesGranted = (void *)GetProcAddress(hntdll, "RtlAreAnyAccessesGranted");
 	pRtlComputeCrc32 = (void *)GetProcAddress(hntdll, "RtlComputeCrc32");
+	pRtlInitializeHandleTable = (void *)GetProcAddress(hntdll, "RtlInitializeHandleTable");
+	pRtlIsValidIndexHandle = (void *)GetProcAddress(hntdll, "RtlIsValidIndexHandle");
+	pRtlDestroyHandleTable = (void *)GetProcAddress(hntdll, "RtlDestroyHandleTable");
+	pRtlAllocateHandle = (void *)GetProcAddress(hntdll, "RtlAllocateHandle");
+	pRtlFreeHandle = (void *)GetProcAddress(hntdll, "RtlFreeHandle");
     }
     strcpy((char*)src_aligned_block, src_src);
     ok(strlen(src) == 15, "Source must be 16 bytes long!\n");
@@ -816,6 +825,40 @@ static void test_RtlComputeCrc32()
   ok(crc == 0x40861dc2,"Expected 0x40861dc2, got %8lx\n", crc);
 }
 
+
+typedef struct MY_HANDLE
+{
+    RTL_HANDLE RtlHandle;
+    void * MyValue;
+} MY_HANDLE;
+
+static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
+{
+    PCHAR AllocatedBit = (PCHAR)(&Handle->Next);
+    *AllocatedBit = *AllocatedBit | 1;
+}
+
+static void test_HandleTables()
+{
+    BOOLEAN result;
+    NTSTATUS status;
+    ULONG Index;
+    MY_HANDLE * MyHandle;
+    RTL_HANDLE_TABLE HandleTable;
+
+    pRtlInitializeHandleTable(0x3FFF, sizeof(MY_HANDLE), &HandleTable);
+    MyHandle = (MY_HANDLE *)pRtlAllocateHandle(&HandleTable, &Index);
+    ok(MyHandle != NULL, "RtlAllocateHandle failed\n");
+    RtlpMakeHandleAllocated(&MyHandle->RtlHandle);
+    MyHandle = NULL;
+    result = pRtlIsValidIndexHandle(&HandleTable, Index, (RTL_HANDLE **)&MyHandle);
+    ok(result, "Handle %p wasn't valid\n", MyHandle);
+    result = pRtlFreeHandle(&HandleTable, &MyHandle->RtlHandle);
+    ok(result, "Couldn't free handle %p\n", MyHandle);
+    status = pRtlDestroyHandleTable(&HandleTable);
+    ok(status == STATUS_SUCCESS, "RtlDestroyHandleTable failed with error 0x%08lx\n", status);
+}
+
 START_TEST(rtl)
 {
     InitFunctionPtrs();
@@ -844,4 +887,6 @@ START_TEST(rtl)
         test_RtlAreAnyAccessesGranted();
     if (pRtlComputeCrc32)
         test_RtlComputeCrc32();
+    if (pRtlInitializeHandleTable)
+        test_HandleTables();
 }
--- /dev/null	2003-09-15 14:40:47.000000000 +0100
+++ wine/dlls/ntdll/handletable.c	2004-10-21 15:54:32.489231992 +0100
@@ -0,0 +1,295 @@
+/*
+ * Handle Tables
+ *
+ * Copyright (C) 2004 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winternl.h"
+#include "wine/debug.h"
+#include "ntdll_misc.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
+
+/**************************************************************************
+ *	RtlInitializeHandleTable   (NTDLL.@)
+ *
+ * Initializes a handle table.
+ *
+ * PARAMS
+ *  MaxHandleCount [I] The maximum number of handles the handle table will support.
+ *  HandleSize     [I] The size of each handle.
+ *  HandleTable    [I/O] The handle table.
+ *
+ * RETURNS
+ *  Nothing.
+ *
+ * SEE
+ *  RtlDestroyHandleTable().
+ */
+void WINAPI RtlInitializeHandleTable(ULONG MaxHandleCount, ULONG HandleSize, RTL_HANDLE_TABLE * HandleTable)
+{
+    TRACE("(%lu, %lu, %p)\n", MaxHandleCount, HandleSize, HandleTable);
+
+    memset(HandleTable, 0, sizeof(*HandleTable));
+    HandleTable->MaxHandleCount = MaxHandleCount;
+    HandleTable->HandleSize = HandleSize;
+}
+
+/**************************************************************************
+ *	RtlDestroyHandleTable   (NTDLL.@)
+ *
+ * Destroys a handle table and frees associated resources.
+ *
+ * PARAMS
+ *  HandleTable    [I] The handle table.
+ *
+ * RETURNS
+ *  Any status code returned by NtFreeVirtualMemory().
+ *
+ * NOTES
+ *  The native version of this API doesn't free the virtual memory that has
+ *  been previously reserved, only the committed memory. There is no harm
+ *  in also freeing the reserved memory because it won't have been handed out
+ *  to any callers. I believe it is "more polite" to free everything.
+ *
+ * SEE
+ *  RtlInitializeHandleTable().
+ */
+NTSTATUS WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE * HandleTable)
+{
+    ULONG Size = 0;
+
+    TRACE("(%p)\n", HandleTable);
+
+    /* native version only releases committed memory, but we also release reserved */
+    return NtFreeVirtualMemory(
+        GetCurrentProcess(),
+        (PVOID *)&HandleTable->FirstHandle,
+        &Size,
+        MEM_RELEASE);
+}
+
+/**************************************************************************
+ *	RtlpAllocateSomeHandles   (internal)
+ *
+ * Reserves memory for the handles if not previously done and commits memory
+ * for a batch of handles if none are free and adds them to the free list.
+ *
+ * PARAMS
+ *  HandleTable    [I/O] The handle table.
+ *
+ * RETURNS
+ *  NTSTATUS code.
+ */
+static NTSTATUS RtlpAllocateSomeHandles(RTL_HANDLE_TABLE * HandleTable)
+{
+    NTSTATUS status;
+    if (!HandleTable->FirstHandle)
+    {
+        PVOID FirstHandleAddr = NULL;
+        ULONG MaxSize = HandleTable->MaxHandleCount * HandleTable->HandleSize;
+
+        /* reserve memory for the handles, but don't commit it yet because we
+         * probably won't use most of it and it will use up physical memory */
+        status = NtAllocateVirtualMemory(
+            GetCurrentProcess(),
+            &FirstHandleAddr,
+            0,
+            &MaxSize,
+            MEM_RESERVE,
+            PAGE_READWRITE);
+        if (status != STATUS_SUCCESS)
+            return status;
+        HandleTable->FirstHandle = (PCHAR)FirstHandleAddr;
+        HandleTable->ReservedMemory = HandleTable->FirstHandle;
+        HandleTable->MaxHandle = HandleTable->FirstHandle + MaxSize;
+    }
+    if (!HandleTable->NextFree)
+    {
+        ULONG CommitSize = 4096; /* one page */
+        ULONG Offset;
+        RTL_HANDLE * FreeHandle = NULL;
+        PVOID NextAvailAddr = (PVOID)HandleTable->ReservedMemory;
+
+        if (HandleTable->ReservedMemory >= HandleTable->MaxHandle)
+            return STATUS_NO_MEMORY; /* the handle table is completely full */
+
+        status = NtAllocateVirtualMemory(
+            GetCurrentProcess(),
+            &NextAvailAddr,
+            0,
+            &CommitSize,
+            MEM_COMMIT,
+            PAGE_READWRITE);
+        if (status != STATUS_SUCCESS)
+            return status;
+
+        for (Offset = 0; Offset < CommitSize; Offset += HandleTable->HandleSize)
+        {
+            /* make sure we don't go over handle limit, even if we can
+             * because of rounding of the table size up to the next page
+             * boundary */
+            if (HandleTable->ReservedMemory + Offset >= HandleTable->MaxHandle)
+                break;
+
+            FreeHandle = (RTL_HANDLE *)(HandleTable->ReservedMemory + Offset);
+
+            FreeHandle->Next = (RTL_HANDLE *)(HandleTable->ReservedMemory + 
+                Offset + HandleTable->HandleSize);
+        }
+
+        /* shouldn't happen because we already test for this above, but
+         * handle it just in case */
+        if (!FreeHandle)
+            return STATUS_NO_MEMORY;
+
+        /* set the last handle's Next pointer to NULL so that when we run
+         * out of free handles we trigger another commit of memory and
+         * initialize the free pointers */
+        FreeHandle->Next = NULL;
+
+        HandleTable->NextFree = HandleTable->ReservedMemory;
+
+        HandleTable->ReservedMemory += CommitSize;
+    }
+    return STATUS_SUCCESS;
+}
+
+/**************************************************************************
+ *	RtlAllocateHandle   (NTDLL.@)
+ *
+ * Allocates a handle from the handle table.
+ *
+ * PARAMS
+ *  HandleTable    [I/O] The handle table.
+ *  HandleIndex    [O] Index of the handle returned. Optional.
+ *
+ * RETURNS
+ *  Success: Pointer to allocated handle.
+ *  Failure: NULL.
+ *
+ * SEE
+ *  RtlFreeHandle().
+ */
+RTL_HANDLE * WINAPI RtlAllocateHandle(RTL_HANDLE_TABLE * HandleTable, ULONG * HandleIndex)
+{
+    RTL_HANDLE * ret;
+
+    TRACE("(%p, %p)\n", HandleTable, HandleIndex);

+    if (!HandleTable->NextFree && RtlpAllocateSomeHandles(HandleTable) != STATUS_SUCCESS)
+        return NULL;
+    
+    ret = (RTL_HANDLE *)HandleTable->NextFree;
+    HandleTable->NextFree = (PCHAR)ret->Next;
+
+    if (HandleIndex)
+        *HandleIndex = (ULONG)(((PCHAR)ret - HandleTable->FirstHandle) / HandleTable->HandleSize);
+
+    return ret;
+}
+
+/**************************************************************************
+ *	RtlFreeHandle   (NTDLL.@)
+ *
+ * Frees an allocated handle.
+ *
+ * PARAMS
+ *  HandleTable    [I/O] The handle table.
+ *  Handle         [I] The handle to be freed.
+ *
+ * RETURNS
+ *  Success: TRUE.
+ *  Failure: FALSE.
+ *
+ * SEE
+ *  RtlAllocateHandle().
+ */
+BOOLEAN WINAPI RtlFreeHandle(RTL_HANDLE_TABLE * HandleTable, RTL_HANDLE * Handle)
+{
+    TRACE("(%p, %p)\n", HandleTable, Handle);
+    /* NOTE: we don't validate the handle and we don't make Handle->Next even
+     * again to signal that it is no longer in user - that is done as a side
+     * effect of setting Handle->Next to the previously next free handle in
+     * the handle table */
+    memset(Handle, 0, HandleTable->HandleSize);
+    Handle->Next = (RTL_HANDLE *)HandleTable->NextFree;
+    HandleTable->NextFree = (PCHAR)Handle;
+    return TRUE;
+}
+
+/**************************************************************************
+ *	RtlIsValidHandle   (NTDLL.@)
+ *
+ * Determines whether a handle is valid or not.
+ *
+ * PARAMS
+ *  HandleTable    [I] The handle table.
+ *  Handle         [I] The handle to be tested.
+ *
+ * RETURNS
+ *  Valid: TRUE.
+ *  Invalid: FALSE.
+ */
+BOOLEAN WINAPI RtlIsValidHandle(const RTL_HANDLE_TABLE * HandleTable, const RTL_HANDLE * Handle)
+{
+    TRACE("(%p, %p)\n", HandleTable, Handle);
+    /* make sure handle is within used region and that it is aligned on
+     * a HandleTable->HandleSize boundary and that Handle->Next is odd,
+     * indicating that the handle is active */
+    if ((Handle >= (RTL_HANDLE *)HandleTable->FirstHandle) &&
+      (Handle < (RTL_HANDLE *)HandleTable->ReservedMemory) &&
+      !((ULONG)Handle & (HandleTable->HandleSize - 1)) &&
+      ((ULONG)Handle->Next & 1))
+        return TRUE;
+    else
+        return FALSE;
+}
+
+/**************************************************************************
+ *	RtlIsValidIndexHandle   (NTDLL.@)
+ *
+ * Determines whether a handle index is valid or not.
+ *
+ * PARAMS
+ *  HandleTable    [I] The handle table.
+ *  Index          [I] The index of the handle to be tested.
+ *  ValidHandle    [O] The handle Index refers to.
+ *
+ * RETURNS
+ *  Valid: TRUE.
+ *  Invalid: FALSE.
+ */
+BOOLEAN WINAPI RtlIsValidIndexHandle(const RTL_HANDLE_TABLE * HandleTable, ULONG Index, RTL_HANDLE ** ValidHandle)
+{
+    RTL_HANDLE * Handle;
+
+    TRACE("(%p, %lu, %p)\n", HandleTable, Index, ValidHandle);
+    Handle = (RTL_HANDLE *)
+        (HandleTable->FirstHandle + Index * HandleTable->HandleSize);
+
+    if (RtlIsValidHandle(HandleTable, Handle))
+    {
+        *ValidHandle = Handle;
+        return TRUE;
+    }
+    return FALSE;
+}


More information about the wine-patches mailing list