Moved TaskFindHandle16 to toolhelp16.c.
[wine] / dlls / kernel / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 /*
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
25  * have to be changed.
26  */
27
28 #include "config.h"
29 #include "wine/port.h"
30
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40
41 #include "wine/exception.h"
42 #include "excpt.h"
43 #include "wine/server.h"
44 #include "wine/unicode.h"
45 #include "kernel_private.h"
46
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(atom);
50
51 #define MAX_ATOM_LEN 255
52
53 /* filter for page-fault exceptions */
54 static WINE_EXCEPTION_FILTER(page_fault)
55 {
56     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
57         return EXCEPTION_EXECUTE_HANDLER;
58     return EXCEPTION_CONTINUE_SEARCH;
59 }
60
61 static struct atom_table* get_local_table(DWORD entries)
62 {
63     static struct atom_table*   local_table;
64
65     if (!local_table)
66     {
67         NTSTATUS                status;
68         struct atom_table*      table;
69
70         SERVER_START_REQ( init_atom_table )
71         {
72             req->entries = entries;
73             status = wine_server_call( req );
74             table = reply->table;
75         }
76         SERVER_END_REQ;
77
78         if (status)
79             SetLastError( RtlNtStatusToDosError( status ) );
80         else if (InterlockedCompareExchangePointer((void*)&local_table, table, NULL) != NULL)
81             NtClose((HANDLE)table);
82     }
83     return local_table;
84 }
85
86 /***********************************************************************
87  *           ATOM_IsIntAtomA
88  */
89 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
90 {
91     UINT atom = 0;
92     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
93     else
94     {
95         if (*atomstr++ != '#') return FALSE;
96         while (*atomstr >= '0' && *atomstr <= '9')
97         {
98             atom = atom * 10 + *atomstr - '0';
99             atomstr++;
100         }
101         if (*atomstr) return FALSE;
102     }
103     if (atom >= MAXINTATOM)
104     {
105         SetLastError( ERROR_INVALID_PARAMETER );
106         atom = 0;
107     }
108     *atomid = atom;
109     return TRUE;
110 }
111
112
113 /***********************************************************************
114  *           ATOM_IsIntAtomW
115  */
116 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
117 {
118     UINT atom = 0;
119     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
120     else
121     {
122         if (*atomstr++ != '#') return FALSE;
123         while (*atomstr >= '0' && *atomstr <= '9')
124         {
125             atom = atom * 10 + *atomstr - '0';
126             atomstr++;
127         }
128         if (*atomstr) return FALSE;
129     }
130     if (atom >= MAXINTATOM)
131     {
132         SetLastError( ERROR_INVALID_PARAMETER );
133         atom = 0;
134     }
135     *atomid = atom;
136     return TRUE;
137 }
138
139
140 /***********************************************************************
141  *           InitAtomTable   (KERNEL32.@)
142  *
143  * Initialise the global atom table.
144  *
145  * PARAMS
146  *  entries [I] The number of entries to reserve in the table.
147  *
148  * RETURNS
149  *  Success: TRUE.
150  *  Failure: FALSE.
151  */
152 BOOL WINAPI InitAtomTable( DWORD entries )
153 {
154     return get_local_table( entries ) ? TRUE : FALSE;
155 }
156
157
158 static ATOM ATOM_AddAtomA( LPCSTR str, struct atom_table* table )
159 {
160     ATOM atom = 0;
161     if (!ATOM_IsIntAtomA( str, &atom ))
162     {
163         WCHAR buffer[MAX_ATOM_LEN];
164
165         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
166         if (!len)
167         {
168             SetLastError( ERROR_INVALID_PARAMETER );
169             return 0;
170         }
171         SERVER_START_REQ( add_atom )
172         {
173             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
174             req->table = table;
175             if (!wine_server_call_err(req)) atom = reply->atom;
176         }
177         SERVER_END_REQ;
178     }
179     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
180     return atom;
181 }
182
183
184 /***********************************************************************
185  *           GlobalAddAtomA   (KERNEL32.@)
186  *
187  * Add a character string to the global atom table and return a unique
188  * value identifying it.
189  *
190  * RETURNS
191  *      Success: The atom allocated to str.
192  *      Failure: 0.
193  */
194 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] String to add */ )
195 {
196     ATOM ret;
197     __TRY
198     {
199         ret = ATOM_AddAtomA( str, NULL );
200     }
201     __EXCEPT(page_fault)
202     {
203         SetLastError( ERROR_INVALID_PARAMETER );
204         return 0;
205     }
206     __ENDTRY
207     return ret;
208 }
209
210
211 /***********************************************************************
212  *           AddAtomA   (KERNEL32.@)
213  *
214  * Add a character string to the global atom table and return a unique
215  * value identifying it.
216  *
217  * RETURNS
218  *      Success: The atom allocated to str.
219  *      Failure: 0.
220  */
221 ATOM WINAPI AddAtomA( LPCSTR str /* [in] String to add */ )
222 {
223     return ATOM_AddAtomA( str, get_local_table(0) );
224 }
225
226
227 static ATOM ATOM_AddAtomW( LPCWSTR str, struct atom_table* table )
228 {
229     ATOM atom = 0;
230     if (!ATOM_IsIntAtomW( str, &atom ))
231     {
232         DWORD len = strlenW(str);
233         if (len > MAX_ATOM_LEN)
234         {
235             SetLastError( ERROR_INVALID_PARAMETER );
236             return 0;
237         }
238         SERVER_START_REQ( add_atom )
239         {
240             req->table = table;
241             wine_server_add_data( req, str, len * sizeof(WCHAR) );
242             if (!wine_server_call_err(req)) atom = reply->atom;
243         }
244         SERVER_END_REQ;
245     }
246     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
247     return atom;
248 }
249
250
251 /***********************************************************************
252  *           GlobalAddAtomW   (KERNEL32.@)
253  *
254  * Unicode version of GlobalAddAtomA.
255  */
256 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
257 {
258     return ATOM_AddAtomW( str, NULL );
259 }
260
261
262 /***********************************************************************
263  *           AddAtomW   (KERNEL32.@)
264  *
265  * Unicode version of AddAtomA.          
266  */
267 ATOM WINAPI AddAtomW( LPCWSTR str )
268 {
269     return ATOM_AddAtomW( str, get_local_table(0) );
270 }
271
272
273 static ATOM ATOM_DeleteAtom( ATOM atom, struct atom_table* table )
274 {
275     TRACE( "(%s) %x\n", table ? "local" : "global", atom );
276     if (atom >= MAXINTATOM)
277     {
278         SERVER_START_REQ( delete_atom )
279         {
280             req->atom = atom;
281             req->table = table;
282             wine_server_call_err( req );
283         }
284         SERVER_END_REQ;
285     }
286     return 0;
287 }
288
289
290 /***********************************************************************
291  *           GlobalDeleteAtom   (KERNEL32.@)
292  *
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.
295  *
296  * RETURNS
297  *      Success: 0.
298  *      Failure: atom.
299  */
300 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
301 {
302     return ATOM_DeleteAtom( atom, NULL);
303 }
304
305
306 /***********************************************************************
307  *           DeleteAtom   (KERNEL32.@)
308  *
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.
311  *
312  * RETURNS
313  *      Success: 0.
314  *      Failure: atom
315  */
316 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
317 {
318     return ATOM_DeleteAtom( atom, get_local_table(0) );
319 }
320
321
322 static ATOM ATOM_FindAtomA( LPCSTR str, struct atom_table* table )
323 {
324     ATOM atom = 0;
325     if (!ATOM_IsIntAtomA( str, &atom ))
326     {
327         WCHAR buffer[MAX_ATOM_LEN];
328
329         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
330         if (!len)
331         {
332             SetLastError( ERROR_INVALID_PARAMETER );
333             return 0;
334         }
335         SERVER_START_REQ( find_atom )
336         {
337             req->table = table;
338             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
339             if (!wine_server_call_err(req)) atom = reply->atom;
340         }
341         SERVER_END_REQ;
342     }
343     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_a(str), atom );
344     return atom;
345 }
346
347
348 /***********************************************************************
349  *           GlobalFindAtomA   (KERNEL32.@)
350  *
351  * Get the atom associated with a string.
352  *
353  * RETURNS
354  *      Success: The associated atom.
355  *      Failure: 0.
356  */
357 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
358 {
359     return ATOM_FindAtomA( str, NULL );
360 }
361
362 /***********************************************************************
363  *           FindAtomA   (KERNEL32.@)
364  *
365  * Get the atom associated with a string.
366  *
367  * RETURNS
368  *      Success: The associated atom.
369  *      Failure: 0.
370  */
371 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
372 {
373     return ATOM_FindAtomA( str, get_local_table(0) );
374 }
375
376
377 static ATOM ATOM_FindAtomW( LPCWSTR str, struct atom_table* table )
378 {
379     ATOM atom = 0;
380     if (!ATOM_IsIntAtomW( str, &atom ))
381     {
382         DWORD len = strlenW(str);
383         if (len > MAX_ATOM_LEN)
384         {
385             SetLastError( ERROR_INVALID_PARAMETER );
386             return 0;
387         }
388         SERVER_START_REQ( find_atom )
389         {
390             wine_server_add_data( req, str, len * sizeof(WCHAR) );
391             req->table = table;
392             if (!wine_server_call_err( req )) atom = reply->atom;
393         }
394         SERVER_END_REQ;
395     }
396     TRACE( "(%s) %s -> %x\n", table ? "local" : "global", debugstr_w(str), atom );
397     return atom;
398 }
399
400
401 /***********************************************************************
402  *           GlobalFindAtomW   (KERNEL32.@)
403  *
404  * Unicode version of GlobalFindAtomA.
405  */
406 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
407 {
408     return ATOM_FindAtomW( str, NULL );
409 }
410
411
412 /***********************************************************************
413  *           FindAtomW   (KERNEL32.@)
414  *
415  * Unicode version of FindAtomA.
416  */
417 ATOM WINAPI FindAtomW( LPCWSTR str )
418 {
419     return ATOM_FindAtomW( str, get_local_table(0) );
420 }
421
422
423 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, struct atom_table* table )
424 {
425     INT len;
426
427     if (count <= 0)
428     {
429         SetLastError( ERROR_MORE_DATA );
430         return 0;
431     }
432     if (atom < MAXINTATOM)
433     {
434         char name[8];
435         if (!atom)
436         {
437             SetLastError( ERROR_INVALID_PARAMETER );
438             return 0;
439         }
440         len = sprintf( name, "#%d", atom );
441         lstrcpynA( buffer, name, count );
442     }
443     else
444     {
445         WCHAR full_name[MAX_ATOM_LEN];
446
447         len = 0;
448         SERVER_START_REQ( get_atom_information )
449         {
450             req->atom = atom;
451             req->table = table;
452             wine_server_set_reply( req, full_name, sizeof(full_name) );
453             if (!wine_server_call_err( req ))
454             {
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;
460             }
461         }
462         SERVER_END_REQ;
463     }
464
465     if (len && count <= len)
466     {
467         SetLastError( ERROR_MORE_DATA );
468         buffer[count-1] = 0;
469         return 0;
470     }
471     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_a(buffer) );
472     return len;
473 }
474
475
476 /***********************************************************************
477  *           GlobalGetAtomNameA   (KERNEL32.@)
478  *
479  * Get a copy of the string associated with an atom.
480  *
481  * RETURNS
482  *      Success: The length of the returned string in characters.
483  *      Failure: 0.
484  */
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 */
489 {
490     return ATOM_GetAtomNameA( atom, buffer, count, NULL );
491 }
492
493
494 /***********************************************************************
495  *           GetAtomNameA   (KERNEL32.@)
496  *
497  * Get a copy of the string associated with an atom.
498  *
499  * RETURNS
500  *      Success: The length of the returned string in characters.
501  *      Failure: 0.
502  */
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 */
507 {
508     return ATOM_GetAtomNameA( atom, buffer, count, get_local_table(0) );
509 }
510
511
512 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, struct atom_table* table )
513 {
514     INT len;
515
516     if (count <= 0)
517     {
518         SetLastError( ERROR_MORE_DATA );
519         return 0;
520     }
521     if (atom < MAXINTATOM)
522     {
523         char name[8];
524         if (!atom)
525         {
526             SetLastError( ERROR_INVALID_PARAMETER );
527             return 0;
528         }
529         sprintf( name, "#%d", atom );
530         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
531         if (!len) buffer[count-1] = 0;  /* overflow */
532     }
533     else
534     {
535         WCHAR full_name[MAX_ATOM_LEN];
536
537         len = 0;
538         SERVER_START_REQ( get_atom_information )
539         {
540             req->atom = atom;
541             req->table = table;
542             wine_server_set_reply( req, full_name, sizeof(full_name) );
543             if (!wine_server_call_err( req ))
544             {
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) );
548                 buffer[count-1] = 0;
549             }
550         }
551         SERVER_END_REQ;
552         if (!len) return 0;
553     }
554     TRACE( "(%s) %x -> %s\n", table ? "local" : "global", atom, debugstr_w(buffer) );
555     return len;
556 }
557
558
559 /***********************************************************************
560  *           GlobalGetAtomNameW   (KERNEL32.@)
561  *
562  * Unicode version of GlobalGetAtomNameA.
563  */
564 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
565 {
566     return ATOM_GetAtomNameW( atom, buffer, count, NULL);
567 }
568
569
570 /***********************************************************************
571  *           GetAtomNameW   (KERNEL32.@)
572  *
573  * Unicode version of GetAtomNameA.
574  */
575 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
576 {
577     return ATOM_GetAtomNameW( atom, buffer, count, get_local_table(0) );
578 }