|  | /* | 
|  | * Atom table functions | 
|  | * | 
|  | * Copyright 1993, 1994, 1995 Alexandre Julliard | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Warning: The code assumes that LocalAlloc() returns a block aligned | 
|  | * on a 4-bytes boundary (because of the shifting done in | 
|  | * HANDLETOATOM).  If this is not the case, the allocation code will | 
|  | * have to be changed. | 
|  | */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #include <ctype.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winnls.h" | 
|  | #include "wine/winbase16.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "winerror.h" | 
|  | #include "instance.h" | 
|  | #include "stackframe.h" | 
|  | #include "debugtools.h" | 
|  | #include "server.h" | 
|  |  | 
|  | DEFAULT_DEBUG_CHANNEL(atom); | 
|  |  | 
|  | #define DEFAULT_ATOMTABLE_SIZE    37 | 
|  | #define MIN_STR_ATOM              0xc000 | 
|  | #define MAX_ATOM_LEN              255 | 
|  |  | 
|  | #define ATOMTOHANDLE(atom)        ((HANDLE16)(atom) << 2) | 
|  | #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2))) | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | HANDLE16    next; | 
|  | WORD        refCount; | 
|  | BYTE        length; | 
|  | BYTE        str[1]; | 
|  | } ATOMENTRY; | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | WORD        size; | 
|  | HANDLE16    entries[1]; | 
|  | } ATOMTABLE; | 
|  |  | 
|  | static WORD ATOM_UserDS = 0;  /* USER data segment */ | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_Init | 
|  | * | 
|  | * Global table initialisation. | 
|  | */ | 
|  | BOOL ATOM_Init( WORD globalTableSel ) | 
|  | { | 
|  | ATOM_UserDS = globalTableSel; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_GetTable | 
|  | * | 
|  | * Return a pointer to the atom table of a given segment, creating | 
|  | * it if necessary. | 
|  | * | 
|  | * RETURNS | 
|  | *	Pointer to table: Success | 
|  | *	NULL: Failure | 
|  | */ | 
|  | static ATOMTABLE *ATOM_GetTable( BOOL create  /* [in] Create */ ) | 
|  | { | 
|  | INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) ); | 
|  | if (ptr->atomtable) | 
|  | { | 
|  | ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable); | 
|  | if (table->size) return table; | 
|  | } | 
|  | if (!create) return NULL; | 
|  | if (!InitAtomTable16( 0 )) return NULL; | 
|  | /* Reload ptr in case it moved in linear memory */ | 
|  | ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) ); | 
|  | return (ATOMTABLE *)((char *)ptr + ptr->atomtable); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_Hash | 
|  | * RETURNS | 
|  | *	The hash value for the input string | 
|  | */ | 
|  | static WORD ATOM_Hash( | 
|  | WORD entries, /* [in] Total number of entries */ | 
|  | LPCSTR str,   /* [in] Pointer to string to hash */ | 
|  | WORD len      /* [in] Length of string */ | 
|  | ) { | 
|  | WORD i, hash = 0; | 
|  |  | 
|  | TRACE("%x, %s, %x\n", entries, str, len); | 
|  |  | 
|  | for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i; | 
|  | return hash % entries; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_IsIntAtomA | 
|  | */ | 
|  | static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid) | 
|  | { | 
|  | UINT atom = 0; | 
|  | if (!HIWORD(atomstr)) atom = LOWORD(atomstr); | 
|  | else | 
|  | { | 
|  | if (*atomstr++ != '#') return FALSE; | 
|  | while (*atomstr >= '0' && *atomstr <= '9') | 
|  | { | 
|  | atom = atom * 10 + *atomstr - '0'; | 
|  | atomstr++; | 
|  | } | 
|  | if (*atomstr) return FALSE; | 
|  | } | 
|  | if (!atom || (atom >= MIN_STR_ATOM)) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | atom = 0; | 
|  | } | 
|  | *atomid = atom; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_IsIntAtomW | 
|  | */ | 
|  | static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid) | 
|  | { | 
|  | UINT atom = 0; | 
|  | if (!HIWORD(atomstr)) atom = LOWORD(atomstr); | 
|  | else | 
|  | { | 
|  | if (*atomstr++ != '#') return FALSE; | 
|  | while (*atomstr >= '0' && *atomstr <= '9') | 
|  | { | 
|  | atom = atom * 10 + *atomstr - '0'; | 
|  | atomstr++; | 
|  | } | 
|  | if (*atomstr) return FALSE; | 
|  | } | 
|  | if (!atom || (atom >= MIN_STR_ATOM)) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | atom = 0; | 
|  | } | 
|  | *atomid = atom; | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           ATOM_MakePtr | 
|  | * | 
|  | * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()). | 
|  | */ | 
|  | static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ ) | 
|  | { | 
|  | return MapSL( MAKESEGPTR( CURRENT_DS, handle ) ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           InitAtomTable16   (KERNEL.68) | 
|  | */ | 
|  | WORD WINAPI InitAtomTable16( WORD entries ) | 
|  | { | 
|  | int i; | 
|  | HANDLE16 handle; | 
|  | ATOMTABLE *table; | 
|  |  | 
|  | /* We consider the first table to be initialized as the global table. | 
|  | * This works, as USER (both built-in and native) is the first one to | 
|  | * register ... | 
|  | */ | 
|  |  | 
|  | if (!ATOM_UserDS) | 
|  | { | 
|  | ATOM_UserDS = CURRENT_DS; | 
|  | /* return dummy local handle */ | 
|  | return LocalAlloc16( LMEM_FIXED, 1 ); | 
|  | } | 
|  |  | 
|  | /* Allocate the table */ | 
|  |  | 
|  | if (!entries) entries = DEFAULT_ATOMTABLE_SIZE;  /* sanity check */ | 
|  | handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) ); | 
|  | if (!handle) return 0; | 
|  | table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) ); | 
|  | table->size = entries; | 
|  | for (i = 0; i < entries; i++) table->entries[i] = 0; | 
|  |  | 
|  | /* Store a pointer to the table in the instance data */ | 
|  |  | 
|  | ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle; | 
|  | return handle; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetAtomHandle   (KERNEL.73) | 
|  | */ | 
|  | HANDLE16 WINAPI GetAtomHandle16( ATOM atom ) | 
|  | { | 
|  | if (atom < MIN_STR_ATOM) return 0; | 
|  | return ATOMTOHANDLE( atom ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           AddAtom16   (KERNEL.70) | 
|  | * | 
|  | * Windows DWORD aligns the atom entry size. | 
|  | * The remaining unused string space created by the alignment | 
|  | * gets padded with '\0's in a certain way to ensure | 
|  | * that at least one trailing '\0' remains. | 
|  | * | 
|  | * RETURNS | 
|  | *	Atom: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | ATOM WINAPI AddAtom16( LPCSTR str ) | 
|  | { | 
|  | char buffer[MAX_ATOM_LEN+1]; | 
|  | WORD hash; | 
|  | HANDLE16 entry; | 
|  | ATOMENTRY * entryPtr; | 
|  | ATOMTABLE * table; | 
|  | int len, ae_len; | 
|  | WORD	iatom; | 
|  |  | 
|  | if (ATOM_IsIntAtomA( str, &iatom )) return iatom; | 
|  |  | 
|  | TRACE("%s\n",debugstr_a(buffer)); | 
|  |  | 
|  | /* Make a copy of the string to be sure it doesn't move in linear memory. */ | 
|  | lstrcpynA( buffer, str, sizeof(buffer) ); | 
|  |  | 
|  | len = strlen( buffer ); | 
|  | if (!(table = ATOM_GetTable( TRUE ))) return 0; | 
|  | if (CURRENT_DS == ATOM_UserDS) return GlobalAddAtomA( str ); | 
|  |  | 
|  | hash = ATOM_Hash( table->size, buffer, len ); | 
|  | entry = table->entries[hash]; | 
|  | while (entry) | 
|  | { | 
|  | entryPtr = ATOM_MakePtr( entry ); | 
|  | if ((entryPtr->length == len) && | 
|  | (!strncasecmp( entryPtr->str, buffer, len ))) | 
|  | { | 
|  | entryPtr->refCount++; | 
|  | TRACE("-- existing 0x%x\n", entry); | 
|  | return HANDLETOATOM( entry ); | 
|  | } | 
|  | entry = entryPtr->next; | 
|  | } | 
|  |  | 
|  | ae_len = (sizeof(ATOMENTRY)+len+3) & ~3; | 
|  | entry = LocalAlloc16( LMEM_FIXED, ae_len ); | 
|  | if (!entry) return 0; | 
|  | /* Reload the table ptr in case it moved in linear memory */ | 
|  | table = ATOM_GetTable( FALSE ); | 
|  | entryPtr = ATOM_MakePtr( entry ); | 
|  | entryPtr->next = table->entries[hash]; | 
|  | entryPtr->refCount = 1; | 
|  | entryPtr->length = len; | 
|  | /* Some applications _need_ the '\0' padding provided by this strncpy */ | 
|  | strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 ); | 
|  | entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0'; | 
|  | table->entries[hash] = entry; | 
|  | TRACE("-- new 0x%x\n", entry); | 
|  | return HANDLETOATOM( entry ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           DeleteAtom16   (KERNEL.71) | 
|  | */ | 
|  | ATOM WINAPI DeleteAtom16( ATOM atom ) | 
|  | { | 
|  | ATOMENTRY * entryPtr; | 
|  | ATOMTABLE * table; | 
|  | HANDLE16 entry, *prevEntry; | 
|  | WORD hash; | 
|  |  | 
|  | if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */ | 
|  | if (CURRENT_DS == ATOM_UserDS) return GlobalDeleteAtom( atom ); | 
|  |  | 
|  | TRACE("0x%x\n",atom); | 
|  |  | 
|  | if (!(table = ATOM_GetTable( FALSE ))) return 0; | 
|  | entry = ATOMTOHANDLE( atom ); | 
|  | entryPtr = ATOM_MakePtr( entry ); | 
|  |  | 
|  | /* Find previous atom */ | 
|  | hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length ); | 
|  | prevEntry = &table->entries[hash]; | 
|  | while (*prevEntry && *prevEntry != entry) | 
|  | { | 
|  | ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry ); | 
|  | prevEntry = &prevEntryPtr->next; | 
|  | } | 
|  | if (!*prevEntry) return atom; | 
|  |  | 
|  | /* Delete atom */ | 
|  | if (--entryPtr->refCount == 0) | 
|  | { | 
|  | *prevEntry = entryPtr->next; | 
|  | LocalFree16( entry ); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           FindAtom16   (KERNEL.69) | 
|  | */ | 
|  | ATOM WINAPI FindAtom16( LPCSTR str ) | 
|  | { | 
|  | ATOMTABLE * table; | 
|  | WORD hash,iatom; | 
|  | HANDLE16 entry; | 
|  | int len; | 
|  |  | 
|  | if (CURRENT_DS == ATOM_UserDS) return GlobalFindAtomA( str ); | 
|  |  | 
|  | TRACE("%s\n",debugres_a(str)); | 
|  |  | 
|  | if (ATOM_IsIntAtomA( str, &iatom )) return iatom; | 
|  | if ((len = strlen( str )) > 255) len = 255; | 
|  | if (!(table = ATOM_GetTable( FALSE ))) return 0; | 
|  | hash = ATOM_Hash( table->size, str, len ); | 
|  | entry = table->entries[hash]; | 
|  | while (entry) | 
|  | { | 
|  | ATOMENTRY * entryPtr = ATOM_MakePtr( entry ); | 
|  | if ((entryPtr->length == len) && | 
|  | (!strncasecmp( entryPtr->str, str, len ))) | 
|  | { | 
|  | TRACE("-- found %x\n", entry); | 
|  | return HANDLETOATOM( entry ); | 
|  | } | 
|  | entry = entryPtr->next; | 
|  | } | 
|  | TRACE("-- not found\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetAtomName16   (KERNEL.72) | 
|  | */ | 
|  | UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count ) | 
|  | { | 
|  | ATOMTABLE * table; | 
|  | ATOMENTRY * entryPtr; | 
|  | HANDLE16 entry; | 
|  | char * strPtr; | 
|  | UINT len; | 
|  | char text[8]; | 
|  |  | 
|  | if (CURRENT_DS == ATOM_UserDS) return GlobalGetAtomNameA( atom, buffer, count ); | 
|  |  | 
|  | TRACE("%x\n",atom); | 
|  |  | 
|  | if (!count) return 0; | 
|  | if (atom < MIN_STR_ATOM) | 
|  | { | 
|  | sprintf( text, "#%d", atom ); | 
|  | len = strlen(text); | 
|  | strPtr = text; | 
|  | } | 
|  | else | 
|  | { | 
|  | if (!(table = ATOM_GetTable( FALSE ))) return 0; | 
|  | entry = ATOMTOHANDLE( atom ); | 
|  | entryPtr = ATOM_MakePtr( entry ); | 
|  | len = entryPtr->length; | 
|  | strPtr = entryPtr->str; | 
|  | } | 
|  | if (len >= count) len = count-1; | 
|  | memcpy( buffer, strPtr, len ); | 
|  | buffer[len] = '\0'; | 
|  | return len; | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           InitAtomTable   (KERNEL32.471) | 
|  | */ | 
|  | BOOL WINAPI InitAtomTable( DWORD entries ) | 
|  | { | 
|  | BOOL ret; | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct init_atom_table_request *req = server_alloc_req( sizeof(*req), 0 ); | 
|  | req->entries = entries; | 
|  | ret = !server_call( REQ_INIT_ATOM_TABLE ); | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local ) | 
|  | { | 
|  | ATOM atom = 0; | 
|  | if (!ATOM_IsIntAtomA( str, &atom )) | 
|  | { | 
|  | DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 ); | 
|  | if (len > MAX_ATOM_LEN) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct add_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) ); | 
|  | MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len ); | 
|  | req->local = local; | 
|  | if (!server_call( REQ_ADD_ATOM )) atom = req->atom + MIN_STR_ATOM; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  | TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom ); | 
|  | return atom; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalAddAtomA   (USER.268) (KERNEL32.313) | 
|  | * | 
|  | * Adds a character string to the global atom table and returns a unique | 
|  | * value identifying the string. | 
|  | * | 
|  | * RETURNS | 
|  | *	Atom: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] Pointer to string to add */ ) | 
|  | { | 
|  | return ATOM_AddAtomA( str, FALSE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           AddAtomA   (KERNEL32.0) | 
|  | * Adds a string to the atom table and returns the atom identifying the | 
|  | * string. | 
|  | * | 
|  | * RETURNS | 
|  | *	Atom: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | ATOM WINAPI AddAtomA( LPCSTR str /* [in] Pointer to string to add */ ) | 
|  | { | 
|  | return ATOM_AddAtomA( str, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local ) | 
|  | { | 
|  | ATOM atom = 0; | 
|  | if (!ATOM_IsIntAtomW( str, &atom )) | 
|  | { | 
|  | DWORD len = strlenW(str); | 
|  | if (len > MAX_ATOM_LEN) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct add_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) ); | 
|  | memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) ); | 
|  | req->local = local; | 
|  | if (!server_call( REQ_ADD_ATOM )) atom = req->atom + MIN_STR_ATOM; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  | TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom ); | 
|  | return atom; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalAddAtomW   (KERNEL32.314) | 
|  | */ | 
|  | ATOM WINAPI GlobalAddAtomW( LPCWSTR str ) | 
|  | { | 
|  | return ATOM_AddAtomW( str, FALSE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           AddAtomW   (KERNEL32.1) | 
|  | */ | 
|  | ATOM WINAPI AddAtomW( LPCWSTR str ) | 
|  | { | 
|  | return ATOM_AddAtomW( str, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ATOM ATOM_DeleteAtom( ATOM atom,  BOOL local) | 
|  | { | 
|  | TRACE( "(%s) %x\n", local ? "local" : "glbal", atom ); | 
|  | if (atom < MIN_STR_ATOM) atom = 0; | 
|  | else | 
|  | { | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct delete_atom_request *req = server_alloc_req( sizeof(*req), 0 ); | 
|  | req->atom = atom - MIN_STR_ATOM; | 
|  | req->local = local; | 
|  | if (!server_call( REQ_DELETE_ATOM )) atom = 0; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  | return atom; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalDeleteAtom   (USER.269) (KERNEL32.317) | 
|  | * Decrements the reference count of a string atom.  If the count is | 
|  | * zero, the string associated with the atom is removed from the table. | 
|  | * | 
|  | * RETURNS | 
|  | *	0: Success | 
|  | *	Atom: Failure | 
|  | */ | 
|  | ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ ) | 
|  | { | 
|  | return ATOM_DeleteAtom( atom, FALSE); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           DeleteAtom   (KERNEL32.69) | 
|  | * Decrements the reference count of a string atom.  If count becomes | 
|  | * zero, the string associated with the atom is removed from the table. | 
|  | * | 
|  | * RETURNS | 
|  | *	0: Success | 
|  | *	Atom: Failure | 
|  | */ | 
|  | ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ ) | 
|  | { | 
|  | return ATOM_DeleteAtom( atom, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local ) | 
|  | { | 
|  | ATOM atom = 0; | 
|  | if (!ATOM_IsIntAtomA( str, &atom )) | 
|  | { | 
|  | DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 ); | 
|  | if (len > MAX_ATOM_LEN) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct find_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) ); | 
|  | MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len ); | 
|  | req->local = local; | 
|  | if (!server_call( REQ_FIND_ATOM )) atom = req->atom + MIN_STR_ATOM; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  | TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom ); | 
|  | return atom; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalFindAtomA   (USER.270) (KERNEL32.318) | 
|  | * | 
|  | * Searches the atom table for the string and returns the atom | 
|  | * associated with it. | 
|  | * | 
|  | * RETURNS | 
|  | *	Atom: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ ) | 
|  | { | 
|  | return ATOM_FindAtomA( str, FALSE ); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           FindAtomA   (KERNEL32.117) | 
|  | * Searches the local atom table for the string and returns the atom | 
|  | * associated with that string. | 
|  | * | 
|  | * RETURNS | 
|  | *	Atom: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ ) | 
|  | { | 
|  | return ATOM_FindAtomA( str, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local ) | 
|  | { | 
|  | ATOM atom = 0; | 
|  | if (!ATOM_IsIntAtomW( str, &atom )) | 
|  | { | 
|  | DWORD len = strlenW(str); | 
|  | if (len > MAX_ATOM_LEN) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct find_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) ); | 
|  | memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) ); | 
|  | req->local = local; | 
|  | if (!server_call( REQ_FIND_ATOM )) atom = req->atom + MIN_STR_ATOM; | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  | TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom ); | 
|  | return atom; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalFindAtomW   (KERNEL32.319) | 
|  | */ | 
|  | ATOM WINAPI GlobalFindAtomW( LPCWSTR str ) | 
|  | { | 
|  | return ATOM_FindAtomW( str, FALSE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           FindAtomW   (KERNEL32.118) | 
|  | */ | 
|  | ATOM WINAPI FindAtomW( LPCWSTR str ) | 
|  | { | 
|  | return ATOM_FindAtomW( str, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local ) | 
|  | { | 
|  | INT len; | 
|  |  | 
|  | if (count <= 0) | 
|  | { | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | return 0; | 
|  | } | 
|  | if (atom < MIN_STR_ATOM) | 
|  | { | 
|  | char name[8]; | 
|  | if (!atom) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | len = sprintf( name, "#%d", atom ); | 
|  | lstrcpynA( buffer, name, count ); | 
|  | } | 
|  | else | 
|  | { | 
|  | len = 0; | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct get_atom_name_request *req = server_alloc_req( sizeof(*req), | 
|  | MAX_ATOM_LEN * sizeof(WCHAR) ); | 
|  | req->atom = atom - MIN_STR_ATOM; | 
|  | req->local = local; | 
|  | if (!server_call( REQ_GET_ATOM_NAME )) | 
|  | { | 
|  | len = WideCharToMultiByte( CP_ACP, 0, server_data_ptr(req), | 
|  | server_data_size(req) / sizeof(WCHAR), | 
|  | buffer, count - 1, NULL, NULL ); | 
|  | if (!len) len = count; /* overflow */ | 
|  | else buffer[len] = 0; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | } | 
|  |  | 
|  | if (len && count <= len) | 
|  | { | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | buffer[count-1] = 0; | 
|  | return 0; | 
|  | } | 
|  | TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) ); | 
|  | return len; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalGetAtomNameA   (USER.271) (KERNEL32.323) | 
|  | * | 
|  | * Retrieves a copy of the string associated with an atom. | 
|  | * | 
|  | * RETURNS | 
|  | *	Length of string in characters: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | UINT WINAPI GlobalGetAtomNameA( | 
|  | ATOM atom,    /* [in]  Atom identifier */ | 
|  | LPSTR buffer, /* [out] Pointer to buffer for atom string */ | 
|  | INT count )   /* [in]  Size of buffer */ | 
|  | { | 
|  | return ATOM_GetAtomNameA( atom, buffer, count, FALSE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetAtomNameA   (KERNEL32.149) | 
|  | * Retrieves a copy of the string associated with the atom. | 
|  | * | 
|  | * RETURNS | 
|  | *	Length of string: Success | 
|  | *	0: Failure | 
|  | */ | 
|  | UINT WINAPI GetAtomNameA( | 
|  | ATOM atom,    /* [in]  Atom */ | 
|  | LPSTR buffer, /* [out] Pointer to string for atom string */ | 
|  | INT count)    /* [in]  Size of buffer */ | 
|  | { | 
|  | return ATOM_GetAtomNameA( atom, buffer, count, TRUE ); | 
|  | } | 
|  |  | 
|  |  | 
|  | static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local ) | 
|  | { | 
|  | INT len; | 
|  |  | 
|  | if (count <= 0) | 
|  | { | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | return 0; | 
|  | } | 
|  | if (atom < MIN_STR_ATOM) | 
|  | { | 
|  | char name[8]; | 
|  | if (!atom) | 
|  | { | 
|  | SetLastError( ERROR_INVALID_PARAMETER ); | 
|  | return 0; | 
|  | } | 
|  | sprintf( name, "#%d", atom ); | 
|  | len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count ); | 
|  | if (!len) buffer[count-1] = 0;  /* overflow */ | 
|  | } | 
|  | else | 
|  | { | 
|  | len = 0; | 
|  | SERVER_START_REQ | 
|  | { | 
|  | struct get_atom_name_request *req = server_alloc_req( sizeof(*req), | 
|  | MAX_ATOM_LEN * sizeof(WCHAR) ); | 
|  | req->atom = atom - MIN_STR_ATOM; | 
|  | req->local = local; | 
|  | if (!server_call( REQ_GET_ATOM_NAME )) | 
|  | { | 
|  | len = server_data_size(req) / sizeof(WCHAR); | 
|  | if (count > len) count = len + 1; | 
|  | memcpy( buffer, server_data_ptr(req), (count-1) * sizeof(WCHAR) ); | 
|  | buffer[count-1] = 0; | 
|  | } | 
|  | } | 
|  | SERVER_END_REQ; | 
|  | if (!len) return 0; | 
|  | } | 
|  | if (count <= len) | 
|  | { | 
|  | SetLastError( ERROR_MORE_DATA ); | 
|  | return 0; | 
|  | } | 
|  | TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) ); | 
|  | return len; | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GlobalGetAtomNameW   (KERNEL32.324) | 
|  | */ | 
|  | UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | 
|  | { | 
|  | return ATOM_GetAtomNameW( atom, buffer, count, FALSE); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*********************************************************************** | 
|  | *           GetAtomNameW   (KERNEL32.150) | 
|  | */ | 
|  | UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count ) | 
|  | { | 
|  | return ATOM_GetAtomNameW( atom, buffer, count, TRUE ); | 
|  | } |