4 * Copyright 1993, 1994, 1995 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Warning: The code assumes that LocalAlloc() returns a block aligned
23 * on a 4-bytes boundary (because of the shifting done in
24 * HANDLETOATOM). If this is not the case, the allocation code will
29 #include "wine/port.h"
41 #include "wine/exception.h"
43 #include "wine/server.h"
44 #include "wine/unicode.h"
45 #include "kernel_private.h"
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(atom);
51 #define MAX_ATOM_LEN 255
53 /* filter for page-fault exceptions */
54 static WINE_EXCEPTION_FILTER(page_fault)
56 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
57 return EXCEPTION_EXECUTE_HANDLER;
58 return EXCEPTION_CONTINUE_SEARCH;
61 static struct atom_table* get_local_table(DWORD entries)
63 static struct atom_table* local_table;
68 struct atom_table* table;
70 SERVER_START_REQ( init_atom_table )
72 req->entries = entries;
73 status = wine_server_call( req );
79 SetLastError( RtlNtStatusToDosError( status ) );
80 else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL)
81 NtClose((HANDLE)table);
86 /***********************************************************************
89 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
92 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
95 if (*atomstr++ != '#') return FALSE;
96 while (*atomstr >= '0' && *atomstr <= '9')
98 atom = atom * 10 + *atomstr - '0';
101 if (*atomstr) return FALSE;
103 if (atom >= MAXINTATOM)
105 SetLastError( ERROR_INVALID_PARAMETER );
113 /***********************************************************************
116 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
119 if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
122 if (*atomstr++ != '#') return FALSE;
123 while (*atomstr >= '0' && *atomstr <= '9')
125 atom = atom * 10 + *atomstr - '0';
128 if (*atomstr) return FALSE;
130 if (atom >= MAXINTATOM)
132 SetLastError( ERROR_INVALID_PARAMETER );
140 /***********************************************************************
141 * InitAtomTable (KERNEL32.@)
143 * Initialise the global atom table.
146 * entries [I] The number of entries to reserve in the table.
152 BOOL WINAPI InitAtomTable( DWORD entries )
154 return get_local_table( entries ) ? TRUE : FALSE;
158 static ATOM ATOM_AddAtomA( LPCSTR str, struct atom_table* table )
161 if (!ATOM_IsIntAtomA( str, &atom ))
163 WCHAR buffer[MAX_ATOM_LEN];
165 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
168 SetLastError( ERROR_INVALID_PARAMETER );
171 SERVER_START_REQ( add_atom )
173 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
175 if (!wine_server_call_err(req)) atom = reply->atom;
179 TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
184 /***********************************************************************
185 * GlobalAddAtomA (KERNEL32.@)
187 * Add a character string to the global atom table and return a unique
188 * value identifying it.
191 * Success: The atom allocated to str.
194 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
199 ret = ATOM_AddAtomA( str, NULL );
203 SetLastError( ERROR_INVALID_PARAMETER );
211 /***********************************************************************
212 * AddAtomA (KERNEL32.@)
214 * Add a character string to the global atom table and return a unique
215 * value identifying it.
218 * Success: The atom allocated to str.
221 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
223 return ATOM_AddAtomA( str, get_local_table(0) );
227 static ATOM ATOM_AddAtomW( LPCWSTR str, struct atom_table* table )
230 if (!ATOM_IsIntAtomW( str, &atom ))
232 DWORD len = strlenW(str);
233 if (len > MAX_ATOM_LEN)
235 SetLastError( ERROR_INVALID_PARAMETER );
238 SERVER_START_REQ( add_atom )
241 wine_server_add_data( req, str, len * sizeof(WCHAR) );
242 if (!wine_server_call_err(req)) atom = reply->atom;
246 TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
251 /***********************************************************************
252 * GlobalAddAtomW (KERNEL32.@)
254 * Unicode version of GlobalAddAtomA.
256 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
258 return ATOM_AddAtomW( str, NULL );
262 /***********************************************************************
263 * AddAtomW (KERNEL32.@)
265 * Unicode version of AddAtomA.
267 ATOM WINAPI AddAtomW( LPCWSTR str )
269 return ATOM_AddAtomW( str, get_local_table(0) );
273 static ATOM ATOM_DeleteAtom( ATOM atom, struct atom_table* table )
275 TRACE( "(%s) %x\n", table ? "local" : "global", atom );
276 if (atom >= MAXINTATOM)
278 SERVER_START_REQ( delete_atom )
282 wine_server_call_err( req );
290 /***********************************************************************
291 * GlobalDeleteAtom (KERNEL32.@)
293 * Decrement the reference count of a string atom. If the count is
294 * zero, the string associated with the atom is removed from the table.
300 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
302 return ATOM_DeleteAtom( atom, NULL);
306 /***********************************************************************
307 * DeleteAtom (KERNEL32.@)
309 * Decrement the reference count of a string atom. If the count becomes
310 * zero, the string associated with the atom is removed from the table.
316 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
318 return ATOM_DeleteAtom( atom, get_local_table(0) );
322 static ATOM ATOM_FindAtomA( LPCSTR str, struct atom_table* table )
325 if (!ATOM_IsIntAtomA( str, &atom ))
327 WCHAR buffer[MAX_ATOM_LEN];
329 DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
332 SetLastError( ERROR_INVALID_PARAMETER );
335 SERVER_START_REQ( find_atom )
338 wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
339 if (!wine_server_call_err(req)) atom = reply->atom;
343 TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
348 /***********************************************************************
349 * GlobalFindAtomA (KERNEL32.@)
351 * Get the atom associated with a string.
354 * Success: The associated atom.
357 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
359 return ATOM_FindAtomA( str, NULL );
362 /***********************************************************************
363 * FindAtomA (KERNEL32.@)
365 * Get the atom associated with a string.
368 * Success: The associated atom.
371 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
373 return ATOM_FindAtomA( str, get_local_table(0) );
377 static ATOM ATOM_FindAtomW( LPCWSTR str, struct atom_table* table )
380 if (!ATOM_IsIntAtomW( str, &atom ))
382 DWORD len = strlenW(str);
383 if (len > MAX_ATOM_LEN)
385 SetLastError( ERROR_INVALID_PARAMETER );
388 SERVER_START_REQ( find_atom )
390 wine_server_add_data( req, str, len * sizeof(WCHAR) );
392 if (!wine_server_call_err( req )) atom = reply->atom;
396 TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
401 /***********************************************************************
402 * GlobalFindAtomW (KERNEL32.@)
404 * Unicode version of GlobalFindAtomA.
406 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
408 return ATOM_FindAtomW( str, NULL );
412 /***********************************************************************
413 * FindAtomW (KERNEL32.@)
415 * Unicode version of FindAtomA.
417 ATOM WINAPI FindAtomW( LPCWSTR str )
419 return ATOM_FindAtomW( str, get_local_table(0) );
423 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, struct atom_table* table )
429 SetLastError( ERROR_MORE_DATA );
432 if (atom < MAXINTATOM)
437 SetLastError( ERROR_INVALID_PARAMETER );
440 len = sprintf( name, "#%d", atom );
441 lstrcpynA( buffer, name, count );
445 WCHAR full_name[MAX_ATOM_LEN];
448 SERVER_START_REQ( get_atom_information )
452 wine_server_set_reply( req, full_name, sizeof(full_name) );
453 if (!wine_server_call_err( req ))
455 len = WideCharToMultiByte( CP_ACP, 0, full_name,
456 wine_server_reply_size(reply) / sizeof(WCHAR),
457 buffer, count - 1, NULL, NULL );
458 if (!len) len = count; /* overflow */
459 else buffer[len] = 0;
465 if (len && count <= len)
467 SetLastError( ERROR_MORE_DATA );
471 TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_a(buffer) );
476 /***********************************************************************
477 * GlobalGetAtomNameA (KERNEL32.@)
479 * Get a copy of the string associated with an atom.
482 * Success: The length of the returned string in characters.
485 UINT WINAPI GlobalGetAtomNameA(
486 ATOM atom, /* [in] Atom identifier */
487 LPSTR buffer, /* [out] Pointer to buffer for atom string */
488 INT count ) /* [in] Size of buffer */
490 return ATOM_GetAtomNameA( atom, buffer, count, NULL );
494 /***********************************************************************
495 * GetAtomNameA (KERNEL32.@)
497 * Get a copy of the string associated with an atom.
500 * Success: The length of the returned string in characters.
503 UINT WINAPI GetAtomNameA(
504 ATOM atom, /* [in] Atom */
505 LPSTR buffer, /* [out] Pointer to string for atom string */
506 INT count) /* [in] Size of buffer */
508 return ATOM_GetAtomNameA( atom, buffer, count, get_local_table(0) );
512 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, struct atom_table* table )
518 SetLastError( ERROR_MORE_DATA );
521 if (atom < MAXINTATOM)
526 SetLastError( ERROR_INVALID_PARAMETER );
529 sprintf( name, "#%d", atom );
530 len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
531 if (!len) buffer[count-1] = 0; /* overflow */
535 WCHAR full_name[MAX_ATOM_LEN];
538 SERVER_START_REQ( get_atom_information )
542 wine_server_set_reply( req, full_name, sizeof(full_name) );
543 if (!wine_server_call_err( req ))
545 len = wine_server_reply_size(reply) / sizeof(WCHAR);
546 if (count > len) count = len + 1;
547 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
554 TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_w(buffer) );
559 /***********************************************************************
560 * GlobalGetAtomNameW (KERNEL32.@)
562 * Unicode version of GlobalGetAtomNameA.
564 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
566 return ATOM_GetAtomNameW( atom, buffer, count, NULL);
570 /***********************************************************************
571 * GetAtomNameW (KERNEL32.@)
573 * Unicode version of GetAtomNameA.
575 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
577 return ATOM_GetAtomNameW( atom, buffer, count, get_local_table(0) );