/*++ Copyright (c) 1990 Microsoft Corporation Module Name: atom.c Abstract: This module contains the Win32 Atom Management APIs Author: Steve Wood (stevewo) 24-Sep-1990 Revision History: --*/ #include "basedll.h" typedef ATOM *PATOM; BOOL InternalGetIntAtom( PUNICODE_STRING UnicodeAtomName, PATOM Atom ); ATOM InternalAddAtom( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, LPCSTR AtomName ); ATOM InternalFindAtom( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, LPCSTR AtomName ); ATOM InternalDeleteAtom( BOOLEAN UseLocalAtomTable, ATOM nAtom ); UINT InternalGetAtomName( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, ATOM nAtom, LPSTR AtomName, DWORD nSize ); ATOM GlobalAddAtomA( LPCSTR lpString ) { return( InternalAddAtom( FALSE, FALSE, lpString ) ); } ATOM GlobalFindAtomA( LPCSTR lpString ) { return( InternalFindAtom( FALSE, FALSE, lpString) ); } ATOM GlobalDeleteAtom( ATOM nAtom ) { return( InternalDeleteAtom( FALSE, nAtom ) ); } UINT GlobalGetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) { return( InternalGetAtomName( FALSE, FALSE, nAtom, lpBuffer, (DWORD)nSize ) ); } ATOM APIENTRY GlobalAddAtomW( LPCWSTR lpString ) { return( InternalAddAtom( FALSE, TRUE, (LPSTR)lpString ) ); } ATOM APIENTRY GlobalFindAtomW( LPCWSTR lpString ) { return( InternalFindAtom( FALSE, TRUE, (LPSTR)lpString) ); } UINT APIENTRY GlobalGetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) { return( InternalGetAtomName( FALSE, TRUE, nAtom, (LPSTR)lpBuffer, (DWORD)nSize ) ); } PVOID BaseLocalAtomTable; BOOL APIENTRY InitAtomTable( DWORD nSize ) { if (nSize < 4 || nSize > 511) { nSize = 37; } return RtlCreateAtomTable( nSize, &BaseLocalAtomTable ) == STATUS_SUCCESS; } ATOM AddAtomA( LPCSTR lpString ) { return( InternalAddAtom( TRUE, FALSE, lpString ) ); } ATOM FindAtomA( LPCSTR lpString ) { return( InternalFindAtom( TRUE, FALSE, lpString ) ); } ATOM DeleteAtom( ATOM nAtom ) { return( InternalDeleteAtom( TRUE, nAtom ) ); } UINT GetAtomNameA( ATOM nAtom, LPSTR lpBuffer, int nSize ) { return( InternalGetAtomName( TRUE, FALSE, nAtom, lpBuffer, (DWORD)nSize ) ); } ATOM APIENTRY AddAtomW( LPCWSTR lpString ) { return( InternalAddAtom( TRUE, TRUE, (LPSTR)lpString ) ); } ATOM APIENTRY FindAtomW( LPCWSTR lpString ) { return( InternalFindAtom( TRUE, TRUE, (LPSTR)lpString ) ); } UINT APIENTRY GetAtomNameW( ATOM nAtom, LPWSTR lpBuffer, int nSize ) { return( InternalGetAtomName( TRUE, TRUE, nAtom, (LPSTR)lpBuffer, (DWORD)nSize ) ); } PVOID InternalInitAtomTable( void ) { NTSTATUS Status; if (BaseLocalAtomTable == NULL) { Status = RtlCreateAtomTable( 0, &BaseLocalAtomTable ); } return BaseLocalAtomTable; } ATOM InternalAddAtom( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, LPCSTR AtomName ) { NTSTATUS Status; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; PUNICODE_STRING UnicodeAtomName; ATOM Atom; if ( (ULONG_PTR)AtomName <= 0xFFFF ) { Atom = (ATOM)PtrToShort((PVOID)AtomName); if (Atom >= MAXINTATOM) { BaseSetLastNTError( STATUS_INVALID_PARAMETER ); return( INVALID_ATOM ); } else { return( (ATOM)Atom ); } } else { try { if (IsUnicodeAtomName) { UnicodeAtomName = &UnicodeString; RtlInitUnicodeString( UnicodeAtomName, (PWSTR)AtomName ); Status = STATUS_SUCCESS; } else { RtlInitAnsiString( &AnsiString, AtomName ); if (AnsiString.MaximumLength > STATIC_UNICODE_BUFFER_LENGTH) { UnicodeAtomName = &UnicodeString; Status = RtlAnsiStringToUnicodeString( UnicodeAtomName, &AnsiString, TRUE ); } else { UnicodeAtomName = &NtCurrentTeb()->StaticUnicodeString; Status = RtlAnsiStringToUnicodeString( UnicodeAtomName, &AnsiString, FALSE ); } } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError( Status ); return( INVALID_ATOM ); } } Atom = INVALID_ATOM; try { if (UseLocalAtomTable) { Status = RtlAddAtomToAtomTable( InternalInitAtomTable(), UnicodeAtomName->Buffer, &Atom ); } else { Status = NtAddAtom( UnicodeAtomName->Buffer, UnicodeAtomName->Length, &Atom ); } if (!NT_SUCCESS( Status )) { BaseSetLastNTError( Status ); Atom = INVALID_ATOM; } } finally { if (!IsUnicodeAtomName && UnicodeAtomName == &UnicodeString) { RtlFreeUnicodeString( UnicodeAtomName ); } } return( (ATOM)Atom ); } ATOM InternalFindAtom( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, LPCSTR AtomName ) { NTSTATUS Status; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; PUNICODE_STRING UnicodeAtomName; ATOM Atom; if ( (ULONG_PTR)AtomName <= 0xFFFF ) { Atom = (ATOM)PtrToShort((PVOID)AtomName); if (Atom >= MAXINTATOM) { BaseSetLastNTError( STATUS_INVALID_PARAMETER ); return( INVALID_ATOM ); } else { return( (ATOM)Atom ); } } else { try { if (IsUnicodeAtomName) { UnicodeAtomName = &UnicodeString; RtlInitUnicodeString( UnicodeAtomName, (PWSTR)AtomName ); Status = STATUS_SUCCESS; } else { RtlInitAnsiString( &AnsiString, AtomName ); if (AnsiString.MaximumLength > STATIC_UNICODE_BUFFER_LENGTH) { UnicodeAtomName = &UnicodeString; Status = RtlAnsiStringToUnicodeString( UnicodeAtomName, &AnsiString, TRUE ); } else { UnicodeAtomName = &NtCurrentTeb()->StaticUnicodeString; Status = RtlAnsiStringToUnicodeString( UnicodeAtomName, &AnsiString, FALSE ); } } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } if ( !NT_SUCCESS(Status) ) { BaseSetLastNTError( Status ); return( INVALID_ATOM ); } } Atom = INVALID_ATOM; try { if (UseLocalAtomTable) { Status = RtlLookupAtomInAtomTable( InternalInitAtomTable(), UnicodeAtomName->Buffer, &Atom ); } else { if (UnicodeAtomName->Length == 0) { SetLastError( ERROR_INVALID_NAME ); leave; } Status = NtFindAtom( UnicodeAtomName->Buffer, UnicodeAtomName->Length, &Atom ); } if (!NT_SUCCESS( Status )) { BaseSetLastNTError( Status ); Atom = INVALID_ATOM; leave; } } finally { if (!IsUnicodeAtomName && UnicodeAtomName == &UnicodeString) { RtlFreeUnicodeString( UnicodeAtomName ); } } return( (ATOM)Atom ); } ATOM InternalDeleteAtom( BOOLEAN UseLocalAtomTable, ATOM nAtom ) { NTSTATUS Status; if (nAtom >= MAXINTATOM) { if (UseLocalAtomTable) { Status = RtlDeleteAtomFromAtomTable( InternalInitAtomTable(), nAtom ); } else { Status = NtDeleteAtom( nAtom ); } if (!NT_SUCCESS( Status )) { BaseSetLastNTError( Status ); return( INVALID_ATOM ); } } return( 0 ); } UINT InternalGetAtomName( BOOLEAN UseLocalAtomTable, BOOLEAN IsUnicodeAtomName, ATOM nAtom, LPSTR AtomName, DWORD nSize ) { NTSTATUS Status; PVOID FreeBuffer = NULL; ANSI_STRING AnsiString; UNICODE_STRING UnicodeString; PWSTR UnicodeAtomName; ULONG AtomInfoLength, AtomNameLength; DWORD ReturnValue; PATOM_BASIC_INFORMATION AtomInfo; // // Trim nSize so that it will not overflow the 16-bit unicode string // maximum length field. This prevents people that call us with a >=32KB // query buffer from stubbing their toes when they call the Ansi version // of the GetAtomName API // if (!IsUnicodeAtomName && nSize > 0x7000) { nSize = 0x7000; } if (nSize == 0) { BaseSetLastNTError( STATUS_BUFFER_OVERFLOW ); return( 0 ); } if (UseLocalAtomTable) { if (IsUnicodeAtomName) { UnicodeAtomName = (PWSTR)AtomName; } else { FreeBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nSize * sizeof( WCHAR ) ); if (FreeBuffer == NULL) { BaseSetLastNTError( STATUS_NO_MEMORY ); return( 0 ); } UnicodeAtomName = (PWSTR)FreeBuffer; } AtomNameLength = nSize * sizeof( WCHAR ); Status = RtlQueryAtomInAtomTable( InternalInitAtomTable(), nAtom, NULL, NULL, UnicodeAtomName, &AtomNameLength ); } else { AtomInfoLength = sizeof( *AtomInfo ) + (nSize * sizeof( WCHAR )); FreeBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), AtomInfoLength ); if (FreeBuffer == NULL) { BaseSetLastNTError( STATUS_NO_MEMORY ); return( 0 ); } AtomInfo = (PATOM_BASIC_INFORMATION)FreeBuffer; Status = NtQueryInformationAtom( nAtom, AtomBasicInformation, AtomInfo, AtomInfoLength, &AtomInfoLength ); if (NT_SUCCESS( Status )) { AtomNameLength = (ULONG)AtomInfo->NameLength; UnicodeAtomName = AtomInfo->Name; } } if (NT_SUCCESS( Status )) { if (IsUnicodeAtomName) { ReturnValue = AtomNameLength / sizeof( WCHAR ); if (UnicodeAtomName != (PWSTR)AtomName) { RtlMoveMemory( AtomName, UnicodeAtomName, AtomNameLength ); } if (ReturnValue < nSize) { *((PWSTR)AtomName + ReturnValue) = UNICODE_NULL; } } else { UnicodeString.Buffer = UnicodeAtomName; UnicodeString.Length = (USHORT)AtomNameLength; UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + sizeof( UNICODE_NULL )); AnsiString.Buffer = AtomName; AnsiString.Length = 0; AnsiString.MaximumLength = (USHORT)nSize; Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE ); if (NT_SUCCESS( Status )) { ReturnValue = AnsiString.Length; } } } if (FreeBuffer != NULL) { RtlFreeHeap( RtlProcessHeap(), 0, FreeBuffer ); } if (!NT_SUCCESS( Status )) { BaseSetLastNTError( Status ); return( 0 ); } else { return( ReturnValue ); } }