/*++ Copyright (c) 1990 Microsoft Corporation Module Name: atom.c Abstract: This file contains the common code to implement atom tables. It is called by both the user mode Win32 Atom API functions (Local/GlobalxxxAtom) and by the kernel mode window manager code to access global atoms. Author: Steve Wood (stevewo) 26-Oct-1990 Revision History: --*/ #include "ntrtlp.h" #include "atom.h" #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) PVOID RtlpAllocateAtom( IN ULONG NumberOfBytes, IN ULONG Tag ); void RtlpFreeAtom( IN PVOID p ); void RtlpInitializeLockAtomTable( IN OUT PRTL_ATOM_TABLE AtomTable ); BOOLEAN RtlpLockAtomTable( IN PRTL_ATOM_TABLE AtomTable ); void RtlpUnlockAtomTable( IN PRTL_ATOM_TABLE AtomTable ); void RtlpDestroyLockAtomTable( IN OUT PRTL_ATOM_TABLE AtomTable ); BOOLEAN RtlpInitializeHandleTableForAtomTable( PRTL_ATOM_TABLE AtomTable ); void RtlpDestroyHandleTableForAtomTable( PRTL_ATOM_TABLE AtomTable ); PRTL_ATOM_TABLE_ENTRY RtlpAtomMapAtomToHandleEntry( IN PRTL_ATOM_TABLE AtomTable, IN ULONG HandleIndex ); BOOLEAN RtlpCreateHandleForAtom( PRTL_ATOM_TABLE p, PRTL_ATOM_TABLE_ENTRY a ); void RtlpFreeHandleForAtom( PRTL_ATOM_TABLE p, PRTL_ATOM_TABLE_ENTRY a ); BOOLEAN RtlpGetIntegerAtom( PWSTR Name, PRTL_ATOM Atom OPTIONAL ); PRTL_ATOM_TABLE_ENTRY RtlpHashStringToAtom( IN PRTL_ATOM_TABLE p, IN PWSTR Name, OUT PRTL_ATOM_TABLE_ENTRY **PreviousAtom OPTIONAL, OUT PULONG NameLength ); #pragma alloc_text(PAGE,RtlpAllocateAtom) #pragma alloc_text(PAGE,RtlpFreeAtom) #pragma alloc_text(PAGE,RtlpInitializeLockAtomTable) #pragma alloc_text(PAGE,RtlInitializeAtomPackage) #pragma alloc_text(PAGE,RtlpLockAtomTable) #pragma alloc_text(PAGE,RtlpUnlockAtomTable) #pragma alloc_text(PAGE,RtlpDestroyLockAtomTable) #pragma alloc_text(PAGE,RtlpInitializeHandleTableForAtomTable) #pragma alloc_text(PAGE,RtlpDestroyHandleTableForAtomTable) #pragma alloc_text(PAGE,RtlpAtomMapAtomToHandleEntry) #pragma alloc_text(PAGE,RtlpCreateHandleForAtom) #pragma alloc_text(PAGE,RtlpFreeHandleForAtom) #pragma alloc_text(PAGE,RtlInitializeAtomPackage) #pragma alloc_text(PAGE,RtlCreateAtomTable) #pragma alloc_text(PAGE,RtlDestroyAtomTable) #pragma alloc_text(PAGE,RtlEmptyAtomTable) #pragma alloc_text(PAGE,RtlpGetIntegerAtom) #pragma alloc_text(PAGE,RtlpHashStringToAtom) #pragma alloc_text(PAGE,RtlAddAtomToAtomTable) #pragma alloc_text(PAGE,RtlLookupAtomInAtomTable) #pragma alloc_text(PAGE,RtlDeleteAtomFromAtomTable) #pragma alloc_text(PAGE,RtlPinAtomInAtomTable) #pragma alloc_text(PAGE,RtlQueryAtomInAtomTable) #pragma alloc_text(PAGE,RtlQueryAtomsInAtomTable) #endif #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) #pragma data_seg("PAGEDATA") #endif ULONG RtlpAtomAllocateTag; PVOID RtlpAllocateAtom( IN ULONG NumberOfBytes, IN ULONG Tag ) { #if defined(NTOS_KERNEL_RUNTIME) return ExAllocatePoolWithTag( PagedPool, NumberOfBytes, Tag ); #else return RtlAllocateHeap( RtlProcessHeap(), RtlpAtomAllocateTag, NumberOfBytes ); #endif } void RtlpFreeAtom( IN PVOID p ) { #if defined(NTOS_KERNEL_RUNTIME) ExFreePool( p ); #else RtlFreeHeap( RtlProcessHeap(), 0, p ); #endif return; } void RtlpInitializeLockAtomTable( IN OUT PRTL_ATOM_TABLE AtomTable ) { #if defined(NTOS_KERNEL_RUNTIME) // ExInitializeFastMutex( &AtomTable->FastMutex ); ExInitializePushLock( &AtomTable->PushLock ); #else RtlInitializeCriticalSection( &AtomTable->CriticalSection ); #endif return; } BOOLEAN RtlpLockAtomTable( IN PRTL_ATOM_TABLE AtomTable ) { if (AtomTable == NULL || AtomTable->Signature != RTL_ATOM_TABLE_SIGNATURE) { return FALSE; } #if defined(NTOS_KERNEL_RUNTIME) KeEnterCriticalRegion (); ExAcquirePushLockExclusive( &AtomTable->PushLock ); #else RtlEnterCriticalSection( &AtomTable->CriticalSection ); #endif return TRUE; } void RtlpUnlockAtomTable( IN PRTL_ATOM_TABLE AtomTable ) { #if defined(NTOS_KERNEL_RUNTIME) ExReleasePushLockExclusive( &AtomTable->PushLock ); KeLeaveCriticalRegion (); #else RtlLeaveCriticalSection( &AtomTable->CriticalSection ); #endif } void RtlpDestroyLockAtomTable( IN OUT PRTL_ATOM_TABLE AtomTable ) { #if defined(NTOS_KERNEL_RUNTIME) #else RtlDeleteCriticalSection( &AtomTable->CriticalSection ); #endif } BOOLEAN RtlpInitializeHandleTableForAtomTable( PRTL_ATOM_TABLE AtomTable ) { #if defined(NTOS_KERNEL_RUNTIME) AtomTable->ExHandleTable = ExCreateHandleTable( NULL ); if (AtomTable->ExHandleTable != NULL) { // // Make sure atom handle tables are NOT part of object handle enumeration // ExRemoveHandleTable( AtomTable->ExHandleTable ); return TRUE; } else { return FALSE; } #else RtlInitializeHandleTable( (ULONG)(USHORT)~RTL_ATOM_MAXIMUM_INTEGER_ATOM, sizeof( RTL_ATOM_HANDLE_TABLE_ENTRY ), &AtomTable->RtlHandleTable ); return TRUE; #endif } void RtlpDestroyHandleTableForAtomTable( PRTL_ATOM_TABLE AtomTable ) { #if defined(NTOS_KERNEL_RUNTIME) ExDestroyHandleTable( AtomTable->ExHandleTable, NULL ); #else RtlDestroyHandleTable( &AtomTable->RtlHandleTable ); #endif return; } PRTL_ATOM_TABLE_ENTRY RtlpAtomMapAtomToHandleEntry( IN PRTL_ATOM_TABLE AtomTable, IN ULONG HandleIndex ) { #if defined(NTOS_KERNEL_RUNTIME) PHANDLE_TABLE_ENTRY ExHandleEntry; PRTL_ATOM_TABLE_ENTRY a; EXHANDLE ExHandle; ExHandle.GenericHandleOverlay = 0; ExHandle.Index = HandleIndex; ExHandleEntry = ExMapHandleToPointer( AtomTable->ExHandleTable, ExHandle.GenericHandleOverlay ); if (ExHandleEntry != NULL) { a = ExHandleEntry->Object; ExUnlockHandleTableEntry( AtomTable->ExHandleTable, ExHandleEntry ); return a; } #else PRTL_ATOM_HANDLE_TABLE_ENTRY HandleEntry; if (RtlIsValidIndexHandle( &AtomTable->RtlHandleTable, HandleIndex, (PRTL_HANDLE_TABLE_ENTRY *)&HandleEntry ) ) { return HandleEntry->Atom; } #endif return NULL; } BOOLEAN RtlpCreateHandleForAtom( PRTL_ATOM_TABLE p, PRTL_ATOM_TABLE_ENTRY a ) { #if defined(NTOS_KERNEL_RUNTIME) EXHANDLE ExHandle; HANDLE_TABLE_ENTRY ExHandleEntry; ExHandleEntry.Object = a; ExHandleEntry.GrantedAccess = 0; ExHandle.GenericHandleOverlay = ExCreateHandle( p->ExHandleTable, &ExHandleEntry ); if (ExHandle.GenericHandleOverlay != NULL) { a->HandleIndex = (USHORT)ExHandle.Index; a->Atom = (RTL_ATOM)((USHORT)a->HandleIndex | RTL_ATOM_MAXIMUM_INTEGER_ATOM); return TRUE; } #else PRTL_ATOM_HANDLE_TABLE_ENTRY HandleEntry; ULONG HandleIndex; HandleEntry = (PRTL_ATOM_HANDLE_TABLE_ENTRY)RtlAllocateHandle( &p->RtlHandleTable, &HandleIndex ); if (HandleEntry != NULL) { if (HandleIndex < RTL_ATOM_MAXIMUM_INTEGER_ATOM) { a->HandleIndex = (USHORT)HandleIndex; a->Atom = (RTL_ATOM)((USHORT)HandleIndex | RTL_ATOM_MAXIMUM_INTEGER_ATOM); HandleEntry->Atom = a; HandleEntry->LockCount = 0; HandleEntry->Flags = RTL_HANDLE_ALLOCATED; return TRUE; } RtlFreeHandle( &p->RtlHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry ); } #endif return FALSE; } void RtlpFreeHandleForAtom( PRTL_ATOM_TABLE p, PRTL_ATOM_TABLE_ENTRY a ) { #if defined(NTOS_KERNEL_RUNTIME) EXHANDLE ExHandle; ExHandle.GenericHandleOverlay = 0; ExHandle.Index = a->HandleIndex; ExDestroyHandle( p->ExHandleTable, ExHandle.GenericHandleOverlay, NULL ); #else PRTL_ATOM_HANDLE_TABLE_ENTRY HandleEntry; if (RtlIsValidIndexHandle( &p->RtlHandleTable, a->HandleIndex, (PRTL_HANDLE_TABLE_ENTRY *)&HandleEntry ) ) { RtlFreeHandle( &p->RtlHandleTable, (PRTL_HANDLE_TABLE_ENTRY)HandleEntry ); } #endif return; } NTSTATUS RtlInitializeAtomPackage( IN ULONG AllocationTag ) { RTL_PAGED_CODE(); RtlpAtomAllocateTag = AllocationTag; return STATUS_SUCCESS; } NTSTATUS RtlCreateAtomTable( IN ULONG NumberOfBuckets, OUT PVOID *AtomTableHandle ) { NTSTATUS Status; PRTL_ATOM_TABLE p; ULONG Size; RTL_PAGED_CODE(); Status = STATUS_SUCCESS; if (*AtomTableHandle == NULL) { if (NumberOfBuckets <= 1) { NumberOfBuckets = RTL_ATOM_TABLE_DEFAULT_NUMBER_OF_BUCKETS; } Size = sizeof( RTL_ATOM_TABLE ) + (sizeof( RTL_ATOM_TABLE_ENTRY ) * (NumberOfBuckets-1)); p = (PRTL_ATOM_TABLE)RtlpAllocateAtom( Size, 'TmtA' ); if (p == NULL) { Status = STATUS_NO_MEMORY; } else { RtlZeroMemory( p, Size ); p->NumberOfBuckets = NumberOfBuckets; if (RtlpInitializeHandleTableForAtomTable( p )) { RtlpInitializeLockAtomTable( p ); p->Signature = RTL_ATOM_TABLE_SIGNATURE; *AtomTableHandle = p; } else { Status = STATUS_NO_MEMORY; RtlpFreeAtom( p ); } } } return Status; } NTSTATUS RtlDestroyAtomTable( IN PVOID AtomTableHandle ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a, aNext, *pa; ULONG i; RTL_PAGED_CODE(); Status = STATUS_SUCCESS; if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { pa = &p->Buckets[ 0 ]; for (i=0; iNumberOfBuckets; i++) { aNext = *pa; *pa++ = NULL; while ((a = aNext) != NULL) { aNext = a->HashLink; a->HashLink = NULL; RtlpFreeAtom( a ); } } p->Signature = 0; RtlpUnlockAtomTable( p ); RtlpDestroyHandleTableForAtomTable( p ); RtlpDestroyLockAtomTable( p ); RtlZeroMemory( p, sizeof( RTL_ATOM_TABLE ) ); RtlpFreeAtom( p ); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } return Status; } NTSTATUS RtlEmptyAtomTable( IN PVOID AtomTableHandle, IN BOOLEAN IncludePinnedAtoms ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a, aNext, *pa, *pa1; ULONG i; RTL_PAGED_CODE(); Status = STATUS_SUCCESS; if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { pa = &p->Buckets[ 0 ]; for (i=0; iNumberOfBuckets; i++) { pa1 = pa++; while ((a = *pa1) != NULL) { if (IncludePinnedAtoms || !(a->Flags & RTL_ATOM_PINNED)) { *pa1 = a->HashLink; a->HashLink = NULL; RtlpFreeHandleForAtom( p, a ); RtlpFreeAtom( a ); } else { pa1 = &a->HashLink; } } } RtlpUnlockAtomTable( p ); } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } return Status; } BOOLEAN RtlpGetIntegerAtom( PWSTR Name, PRTL_ATOM Atom OPTIONAL ) { NTSTATUS Status; UNICODE_STRING UnicodeString; PWSTR s; ULONG n; RTL_ATOM Temp; if (((ULONG_PTR)Name & -0x10000) == 0) { Temp = (RTL_ATOM)(USHORT)PtrToUlong(Name); if (Temp >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { return FALSE; } else { if (Temp == RTL_ATOM_INVALID_ATOM) { Temp = RTL_ATOM_MAXIMUM_INTEGER_ATOM; } if (ARGUMENT_PRESENT( Atom )) { *Atom = Temp; } return TRUE; } } else if (*Name != L'#') { return FALSE; } s = ++Name; while (*s != UNICODE_NULL) { if (*s < L'0' || *s > L'9') { return FALSE; } else { s++; } } n = 0; UnicodeString.Buffer = Name; UnicodeString.Length = (USHORT)((PCHAR)s - (PCHAR)Name); UnicodeString.MaximumLength = UnicodeString.Length; Status = RtlUnicodeStringToInteger( &UnicodeString, 10, &n ); if (NT_SUCCESS( Status )) { if (ARGUMENT_PRESENT( Atom )) { if (n == 0 || n > RTL_ATOM_MAXIMUM_INTEGER_ATOM) { *Atom = RTL_ATOM_MAXIMUM_INTEGER_ATOM; } else { *Atom = (RTL_ATOM)n; } } return TRUE; } else { return FALSE; } } PRTL_ATOM_TABLE_ENTRY RtlpHashStringToAtom( IN PRTL_ATOM_TABLE p, IN PWSTR Name, OUT PRTL_ATOM_TABLE_ENTRY **PreviousAtom OPTIONAL, OUT PULONG NameLength ) { ULONG Length, Hash; WCHAR c; PWCH s; RTL_ATOM Atom; PRTL_ATOM_TABLE_ENTRY *pa, a; if (((ULONG_PTR)Name & -0x10000) == 0) { Atom = (RTL_ATOM)(USHORT)PtrToUlong(Name); a = NULL; if (Atom >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { a = RtlpAtomMapAtomToHandleEntry( p, (ULONG)(Atom & (USHORT)~RTL_ATOM_MAXIMUM_INTEGER_ATOM) ); } if (ARGUMENT_PRESENT( PreviousAtom )) { *PreviousAtom = NULL; } return a; } s = Name; Hash = 0; while (*s != UNICODE_NULL) { c = RtlUpcaseUnicodeChar( *s++ ); Hash = Hash + (c << 1) + (c >> 1) + c; } Length = (ULONG) (s - Name); if (Length > RTL_ATOM_MAXIMUM_NAME_LENGTH) { pa = NULL; a = NULL; } else { pa = &p->Buckets[ Hash % p->NumberOfBuckets ]; while (a = *pa) { if (a->NameLength == Length && !_wcsicmp( a->Name, Name )) { break; } else { pa = &a->HashLink; } } } if (ARGUMENT_PRESENT( PreviousAtom )) { *PreviousAtom = pa; } if (a == NULL && ARGUMENT_PRESENT( NameLength )) { *NameLength = Length * sizeof( WCHAR ); } return a; } NTSTATUS RtlAddAtomToAtomTable( IN PVOID AtomTableHandle, IN PWSTR AtomName OPTIONAL, IN OUT PRTL_ATOM Atom OPTIONAL ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a, *pa; ULONG NameLength; RTL_ATOM Temp; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { if (RtlpGetIntegerAtom( AtomName, &Temp )) { if (Temp >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { Temp = RTL_ATOM_INVALID_ATOM; Status = STATUS_INVALID_PARAMETER; } else { Status = STATUS_SUCCESS; } if (ARGUMENT_PRESENT( Atom )) { *Atom = Temp; } } else if (*AtomName == UNICODE_NULL) { Status = STATUS_OBJECT_NAME_INVALID; } else { a = RtlpHashStringToAtom( p, AtomName, &pa, &NameLength ); if (a == NULL) { if (pa != NULL) { Status = STATUS_NO_MEMORY; a = RtlpAllocateAtom( FIELD_OFFSET( RTL_ATOM_TABLE_ENTRY, Name ) + NameLength + sizeof( UNICODE_NULL ), 'AmtA' ); if (a != NULL) { a->HashLink = NULL; a->ReferenceCount = 1; a->Flags = 0; RtlCopyMemory( a->Name, AtomName, NameLength ); a->NameLength = (UCHAR)(NameLength / sizeof( WCHAR )); a->Name[ a->NameLength ] = UNICODE_NULL; if (RtlpCreateHandleForAtom( p, a )) { a->Atom = (RTL_ATOM)a->HandleIndex | RTL_ATOM_MAXIMUM_INTEGER_ATOM; *pa = a; if (ARGUMENT_PRESENT( Atom )) { *Atom = a->Atom; } Status = STATUS_SUCCESS; } else { RtlpFreeAtom( a ); } } } else { Status = STATUS_INVALID_PARAMETER; } } else { if (!(a->Flags & RTL_ATOM_PINNED)) { if (a->ReferenceCount == 0xFFFF) { KdPrint(( "RTL: Pinning atom (%x) as reference count about to wrap\n", Atom )); a->Flags |= RTL_ATOM_PINNED; } else { a->ReferenceCount += 1; } } if (ARGUMENT_PRESENT( Atom )) { *Atom = a->Atom; } Status = STATUS_SUCCESS; } } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; } NTSTATUS RtlLookupAtomInAtomTable( IN PVOID AtomTableHandle, IN PWSTR AtomName, OUT PRTL_ATOM Atom OPTIONAL ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a; RTL_ATOM Temp; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { if (RtlpGetIntegerAtom( AtomName, &Temp )) { if (Temp >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { Temp = RTL_ATOM_INVALID_ATOM; Status = STATUS_INVALID_PARAMETER; } else { Status = STATUS_SUCCESS; } if (ARGUMENT_PRESENT( Atom )) { *Atom = Temp; } } else if (*AtomName == UNICODE_NULL) { Status = STATUS_OBJECT_NAME_INVALID; } else { a = RtlpHashStringToAtom( p, AtomName, NULL, NULL ); if (a == NULL) { Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { if (RtlpAtomMapAtomToHandleEntry( p, (ULONG)a->HandleIndex ) != NULL) { Status = STATUS_SUCCESS; if (ARGUMENT_PRESENT( Atom )) { *Atom = a->Atom; } } else { Status = STATUS_INVALID_HANDLE; } } } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; } NTSTATUS RtlDeleteAtomFromAtomTable( IN PVOID AtomTableHandle, IN RTL_ATOM Atom ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a, *pa; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { Status = STATUS_INVALID_HANDLE; if (Atom >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { a = RtlpAtomMapAtomToHandleEntry( p, (ULONG)(Atom & (USHORT)~RTL_ATOM_MAXIMUM_INTEGER_ATOM) ); if (a != NULL && a->Atom == Atom) { Status = STATUS_SUCCESS; if (a->Flags & RTL_ATOM_PINNED) { KdPrint(( "RTL: Ignoring attempt to delete a pinned atom (%x)\n", Atom )); Status = STATUS_WAS_LOCKED; // This is a success status code! } else if (--a->ReferenceCount == 0) { a = RtlpHashStringToAtom( p, a->Name, &pa, NULL ); if (a != NULL) { if (pa != NULL) { *pa = a->HashLink; } RtlpFreeHandleForAtom( p, a ); RtlpFreeAtom( a ); } } } } else if (Atom != RTL_ATOM_INVALID_ATOM) { Status = STATUS_SUCCESS; } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; } NTSTATUS RtlPinAtomInAtomTable( IN PVOID AtomTableHandle, IN RTL_ATOM Atom ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a, *pa; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { Status = STATUS_INVALID_HANDLE; if (Atom >= RTL_ATOM_MAXIMUM_INTEGER_ATOM) { a = RtlpAtomMapAtomToHandleEntry( p, (ULONG)(Atom & (USHORT)~RTL_ATOM_MAXIMUM_INTEGER_ATOM) ); if (a != NULL && a->Atom == Atom) { Status = STATUS_SUCCESS; a->Flags |= RTL_ATOM_PINNED; } } else if (Atom != RTL_ATOM_INVALID_ATOM) { Status = STATUS_SUCCESS; } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; } NTSTATUS RtlQueryAtomInAtomTable( IN PVOID AtomTableHandle, IN RTL_ATOM Atom, OUT PULONG AtomUsage OPTIONAL, OUT PULONG AtomFlags OPTIONAL, IN OUT PWSTR AtomName OPTIONAL, IN OUT PULONG AtomNameLength OPTIONAL ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a; WCHAR AtomNameBuffer[ 16 ]; ULONG CopyLength; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } try { if (Atom < RTL_ATOM_MAXIMUM_INTEGER_ATOM) { if (Atom == RTL_ATOM_INVALID_ATOM) { Status = STATUS_INVALID_PARAMETER; } else { Status = STATUS_SUCCESS; if (ARGUMENT_PRESENT( AtomUsage )) { *AtomUsage = 1; } if (ARGUMENT_PRESENT( AtomFlags )) { *AtomFlags = RTL_ATOM_PINNED; } if (ARGUMENT_PRESENT( AtomName )) { CopyLength = _snwprintf( AtomNameBuffer, sizeof( AtomNameBuffer ) / sizeof( WCHAR ), L"#%u", Atom ) * sizeof( WCHAR ); if (CopyLength >= *AtomNameLength) { if (*AtomNameLength >= sizeof( UNICODE_NULL )) { CopyLength = *AtomNameLength - sizeof( UNICODE_NULL ); } else { CopyLength = 0; } } if (CopyLength != 0) { RtlCopyMemory( AtomName, AtomNameBuffer, CopyLength ); AtomName[ CopyLength / sizeof( WCHAR ) ] = UNICODE_NULL; *AtomNameLength = CopyLength; } else { Status = STATUS_BUFFER_TOO_SMALL; } } } } else { a = RtlpAtomMapAtomToHandleEntry( p, (ULONG)(Atom & (USHORT)~RTL_ATOM_MAXIMUM_INTEGER_ATOM) ); if (a != NULL && a->Atom == Atom) { Status = STATUS_SUCCESS; if (ARGUMENT_PRESENT( AtomUsage )) { *AtomUsage = a->ReferenceCount; } if (ARGUMENT_PRESENT( AtomFlags )) { *AtomFlags = a->Flags; } if (ARGUMENT_PRESENT( AtomName )) { // // Fill in as much of the atom string as possible, and // always zero terminate. This is what win3.1 does. // CopyLength = a->NameLength * sizeof( WCHAR ); if (CopyLength >= *AtomNameLength) { if (*AtomNameLength >= sizeof( UNICODE_NULL )) { CopyLength = *AtomNameLength - sizeof( UNICODE_NULL ); } else { *AtomNameLength = CopyLength; CopyLength = 0; } } if (CopyLength != 0) { RtlCopyMemory( AtomName, a->Name, CopyLength ); AtomName[ CopyLength / sizeof( WCHAR ) ] = UNICODE_NULL; *AtomNameLength = CopyLength; } else { Status = STATUS_BUFFER_TOO_SMALL; } } } else { Status = STATUS_INVALID_HANDLE; } } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; } NTSTATUS RtlQueryAtomsInAtomTable( IN PVOID AtomTableHandle, IN ULONG MaximumNumberOfAtoms, OUT PULONG NumberOfAtoms, OUT PRTL_ATOM Atoms ) { NTSTATUS Status; PRTL_ATOM_TABLE p = (PRTL_ATOM_TABLE)AtomTableHandle; PRTL_ATOM_TABLE_ENTRY a; ULONG i; ULONG CurrentAtomIndex; RTL_PAGED_CODE(); if (!RtlpLockAtomTable( p )) { return STATUS_INVALID_PARAMETER; } Status = STATUS_SUCCESS; try { CurrentAtomIndex = 0; for (i=0; iNumberOfBuckets; i++) { a = p->Buckets[ i ]; while (a) { if (CurrentAtomIndex < MaximumNumberOfAtoms) { Atoms[ CurrentAtomIndex ] = a->Atom; } else { Status = STATUS_INFO_LENGTH_MISMATCH; } CurrentAtomIndex += 1; a = a->HashLink; } } *NumberOfAtoms = CurrentAtomIndex; } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } RtlpUnlockAtomTable( p ); return Status; }