Added missing prototypes to avoid compile warnings on Solaris.
[wine] / memory / atom.c
1 /*
2  * Atom table functions
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  */
6
7 /*
8  * Warning: The code assumes that LocalAlloc() returns a block aligned
9  * on a 4-bytes boundary (because of the shifting done in
10  * HANDLETOATOM).  If this is not the case, the allocation code will
11  * have to be changed.
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <ctype.h>
18
19 #include "windef.h"
20 #include "winnls.h"
21 #include "wine/winbase16.h"
22 #include "wine/unicode.h"
23 #include "winerror.h"
24 #include "instance.h"
25 #include "stackframe.h"
26 #include "debugtools.h"
27 #include "server.h"
28
29 DEFAULT_DEBUG_CHANNEL(atom);
30
31 #define DEFAULT_ATOMTABLE_SIZE    37
32 #define MIN_STR_ATOM              0xc000
33 #define MAX_ATOM_LEN              255
34
35 #define ATOMTOHANDLE(atom)        ((HANDLE16)(atom) << 2)
36 #define HANDLETOATOM(handle)      ((ATOM)(0xc000 | ((handle) >> 2)))
37
38 typedef struct
39 {
40     HANDLE16    next;
41     WORD        refCount;
42     BYTE        length;
43     BYTE        str[1];
44 } ATOMENTRY;
45
46 typedef struct
47 {
48     WORD        size;
49     HANDLE16    entries[1];
50 } ATOMTABLE;
51                 
52 static WORD ATOM_UserDS = 0;  /* USER data segment */
53
54 /***********************************************************************
55  *           ATOM_Init
56  *
57  * Global table initialisation.
58  */
59 BOOL ATOM_Init( WORD globalTableSel )
60 {
61     ATOM_UserDS = globalTableSel;
62     return TRUE;
63 }
64
65
66 /***********************************************************************
67  *           ATOM_GetTable
68  *
69  * Return a pointer to the atom table of a given segment, creating
70  * it if necessary.
71  *
72  * RETURNS
73  *      Pointer to table: Success
74  *      NULL: Failure
75  */
76 static ATOMTABLE *ATOM_GetTable( BOOL create  /* [in] Create */ )
77 {
78     INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
79     if (ptr->atomtable)
80     {
81         ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable);
82         if (table->size) return table;
83     }
84     if (!create) return NULL;
85     if (!InitAtomTable16( 0 )) return NULL;
86     /* Reload ptr in case it moved in linear memory */
87     ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) );
88     return (ATOMTABLE *)((char *)ptr + ptr->atomtable);
89 }
90
91
92 /***********************************************************************
93  *           ATOM_Hash
94  * RETURNS
95  *      The hash value for the input string
96  */
97 static WORD ATOM_Hash(
98             WORD entries, /* [in] Total number of entries */
99             LPCSTR str,   /* [in] Pointer to string to hash */
100             WORD len      /* [in] Length of string */
101 ) {
102     WORD i, hash = 0;
103
104     TRACE("%x, %s, %x\n", entries, str, len);
105     
106     for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i;
107     return hash % entries;
108 }
109
110
111 /***********************************************************************
112  *           ATOM_IsIntAtomA
113  */
114 static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid)
115 {
116     UINT atom = 0;
117     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
118     else
119     {
120         if (*atomstr++ != '#') return FALSE;
121         while (*atomstr >= '0' && *atomstr <= '9')
122         {
123             atom = atom * 10 + *atomstr - '0';
124             atomstr++;
125         }
126         if (*atomstr) return FALSE;
127     }
128     if (!atom || (atom >= MIN_STR_ATOM))
129     {
130         SetLastError( ERROR_INVALID_PARAMETER );
131         atom = 0;
132     }
133     *atomid = atom;
134     return TRUE;
135 }
136
137
138 /***********************************************************************
139  *           ATOM_IsIntAtomW
140  */
141 static BOOL ATOM_IsIntAtomW(LPCWSTR atomstr,WORD *atomid)
142 {
143     UINT atom = 0;
144     if (!HIWORD(atomstr)) atom = LOWORD(atomstr);
145     else
146     {
147         if (*atomstr++ != '#') return FALSE;
148         while (*atomstr >= '0' && *atomstr <= '9')
149         {
150             atom = atom * 10 + *atomstr - '0';
151             atomstr++;
152         }
153         if (*atomstr) return FALSE;
154     }
155     if (!atom || (atom >= MIN_STR_ATOM))
156     {
157         SetLastError( ERROR_INVALID_PARAMETER );
158         atom = 0;
159     }
160     *atomid = atom;
161     return TRUE;
162 }
163
164
165 /***********************************************************************
166  *           ATOM_MakePtr
167  *
168  * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()).
169  */
170 static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ )
171 {
172     return MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
173 }
174
175
176 /***********************************************************************
177  *           InitAtomTable16   (KERNEL.68)
178  */
179 WORD WINAPI InitAtomTable16( WORD entries )
180 {
181     int i;
182     HANDLE16 handle;
183     ATOMTABLE *table;
184
185       /* We consider the first table to be initialized as the global table. 
186        * This works, as USER (both built-in and native) is the first one to 
187        * register ... 
188        */
189
190     if (!ATOM_UserDS)
191     {
192         ATOM_UserDS = CURRENT_DS; 
193         /* return dummy local handle */
194         return LocalAlloc16( LMEM_FIXED, 1 );
195     }
196
197       /* Allocate the table */
198
199     if (!entries) entries = DEFAULT_ATOMTABLE_SIZE;  /* sanity check */
200     handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) );
201     if (!handle) return 0;
202     table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) );
203     table->size = entries;
204     for (i = 0; i < entries; i++) table->entries[i] = 0;
205
206       /* Store a pointer to the table in the instance data */
207
208     ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle;
209     return handle;
210 }
211
212 /***********************************************************************
213  *           GetAtomHandle   (KERNEL.73)
214  */
215 HANDLE16 WINAPI GetAtomHandle16( ATOM atom )
216 {
217     if (atom < MIN_STR_ATOM) return 0;
218     return ATOMTOHANDLE( atom );
219 }
220
221
222 /***********************************************************************
223  *           AddAtom16   (KERNEL.70)
224  *
225  * Windows DWORD aligns the atom entry size.
226  * The remaining unused string space created by the alignment
227  * gets padded with '\0's in a certain way to ensure
228  * that at least one trailing '\0' remains.
229  *
230  * RETURNS
231  *      Atom: Success
232  *      0: Failure
233  */
234 ATOM WINAPI AddAtom16( LPCSTR str )
235 {
236     char buffer[MAX_ATOM_LEN+1];
237     WORD hash;
238     HANDLE16 entry;
239     ATOMENTRY * entryPtr;
240     ATOMTABLE * table;
241     int len, ae_len;
242     WORD        iatom;
243
244     if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
245
246     TRACE("%s\n",debugstr_a(buffer));
247     
248     /* Make a copy of the string to be sure it doesn't move in linear memory. */
249     lstrcpynA( buffer, str, sizeof(buffer) );
250
251     len = strlen( buffer );
252     if (!(table = ATOM_GetTable( TRUE ))) return 0;
253     if (CURRENT_DS == ATOM_UserDS) return GlobalAddAtomA( str );
254
255     hash = ATOM_Hash( table->size, buffer, len );
256     entry = table->entries[hash];
257     while (entry)
258     {
259         entryPtr = ATOM_MakePtr( entry );
260         if ((entryPtr->length == len) && 
261             (!strncasecmp( entryPtr->str, buffer, len )))
262         {
263             entryPtr->refCount++;
264             TRACE("-- existing 0x%x\n", entry);
265             return HANDLETOATOM( entry );
266         }
267         entry = entryPtr->next;
268     }
269
270     ae_len = (sizeof(ATOMENTRY)+len+3) & ~3;
271     entry = LocalAlloc16( LMEM_FIXED, ae_len );
272     if (!entry) return 0;
273     /* Reload the table ptr in case it moved in linear memory */
274     table = ATOM_GetTable( FALSE );
275     entryPtr = ATOM_MakePtr( entry );
276     entryPtr->next = table->entries[hash];
277     entryPtr->refCount = 1;
278     entryPtr->length = len;
279     /* Some applications _need_ the '\0' padding provided by this strncpy */
280     strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 );
281     entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0';
282     table->entries[hash] = entry;
283     TRACE("-- new 0x%x\n", entry);
284     return HANDLETOATOM( entry );
285 }
286
287
288 /***********************************************************************
289  *           DeleteAtom16   (KERNEL.71)
290  */
291 ATOM WINAPI DeleteAtom16( ATOM atom )
292 {
293     ATOMENTRY * entryPtr;
294     ATOMTABLE * table;
295     HANDLE16 entry, *prevEntry;
296     WORD hash;
297
298     if (atom < MIN_STR_ATOM) return 0;  /* Integer atom */
299     if (CURRENT_DS == ATOM_UserDS) return GlobalDeleteAtom( atom );
300
301     TRACE("0x%x\n",atom);
302
303     if (!(table = ATOM_GetTable( FALSE ))) return 0;
304     entry = ATOMTOHANDLE( atom );
305     entryPtr = ATOM_MakePtr( entry );
306
307     /* Find previous atom */
308     hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length );
309     prevEntry = &table->entries[hash];
310     while (*prevEntry && *prevEntry != entry)
311     {
312         ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry );
313         prevEntry = &prevEntryPtr->next;
314     }    
315     if (!*prevEntry) return atom;
316
317     /* Delete atom */
318     if (--entryPtr->refCount == 0)
319     {
320         *prevEntry = entryPtr->next;
321         LocalFree16( entry );
322     }    
323     return 0;
324 }
325
326
327 /***********************************************************************
328  *           FindAtom16   (KERNEL.69)
329  */
330 ATOM WINAPI FindAtom16( LPCSTR str )
331 {
332     ATOMTABLE * table;
333     WORD hash,iatom;
334     HANDLE16 entry;
335     int len;
336
337     if (CURRENT_DS == ATOM_UserDS) return GlobalFindAtomA( str );
338
339     TRACE("%s\n",debugres_a(str));
340
341     if (ATOM_IsIntAtomA( str, &iatom )) return iatom;
342     if ((len = strlen( str )) > 255) len = 255;
343     if (!(table = ATOM_GetTable( FALSE ))) return 0;
344     hash = ATOM_Hash( table->size, str, len );
345     entry = table->entries[hash];
346     while (entry)
347     {
348         ATOMENTRY * entryPtr = ATOM_MakePtr( entry );
349         if ((entryPtr->length == len) && 
350             (!strncasecmp( entryPtr->str, str, len )))
351         {
352             TRACE("-- found %x\n", entry);
353             return HANDLETOATOM( entry );
354         }
355         entry = entryPtr->next;
356     }
357     TRACE("-- not found\n");
358     return 0;
359 }
360
361
362 /***********************************************************************
363  *           GetAtomName16   (KERNEL.72)
364  */
365 UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count )
366 {
367     ATOMTABLE * table;
368     ATOMENTRY * entryPtr;
369     HANDLE16 entry;
370     char * strPtr;
371     UINT len;
372     char text[8];
373
374     if (CURRENT_DS == ATOM_UserDS) return GlobalGetAtomNameA( atom, buffer, count );
375     
376     TRACE("%x\n",atom);
377     
378     if (!count) return 0;
379     if (atom < MIN_STR_ATOM)
380     {
381         sprintf( text, "#%d", atom );
382         len = strlen(text);
383         strPtr = text;
384     }
385     else
386     {
387        if (!(table = ATOM_GetTable( FALSE ))) return 0;
388         entry = ATOMTOHANDLE( atom );
389         entryPtr = ATOM_MakePtr( entry );
390         len = entryPtr->length;
391         strPtr = entryPtr->str;
392     }
393     if (len >= count) len = count-1;
394     memcpy( buffer, strPtr, len );
395     buffer[len] = '\0';
396     return len;
397 }
398
399 /***********************************************************************
400  *           InitAtomTable   (KERNEL32.471)
401  */
402 BOOL WINAPI InitAtomTable( DWORD entries )
403 {
404     BOOL ret;
405     SERVER_START_REQ
406     {
407         struct init_atom_table_request *req = server_alloc_req( sizeof(*req), 0 );
408         req->entries = entries;
409         ret = !server_call( REQ_INIT_ATOM_TABLE );
410     }
411     SERVER_END_REQ;
412     return ret;
413 }
414
415
416 static ATOM ATOM_AddAtomA( LPCSTR str, BOOL local )
417 {
418     ATOM atom = 0;
419     if (!ATOM_IsIntAtomA( str, &atom ))
420     {
421         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 );
422         if (len > MAX_ATOM_LEN)
423         {
424             SetLastError( ERROR_INVALID_PARAMETER );
425             return 0;
426         }
427         SERVER_START_REQ
428         {
429             struct add_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
430             MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len );
431             req->local = local;
432             if (!server_call( REQ_ADD_ATOM )) atom = req->atom + MIN_STR_ATOM;
433         }
434         SERVER_END_REQ;
435     }
436     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
437     return atom;
438 }
439
440
441 /***********************************************************************
442  *           GlobalAddAtomA   (USER.268) (KERNEL32.313)
443  *
444  * Adds a character string to the global atom table and returns a unique
445  * value identifying the string.
446  *
447  * RETURNS
448  *      Atom: Success
449  *      0: Failure
450  */
451 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
452 {
453     return ATOM_AddAtomA( str, FALSE );
454 }
455
456
457 /***********************************************************************
458  *           AddAtomA   (KERNEL32.0)
459  * Adds a string to the atom table and returns the atom identifying the
460  * string.
461  *
462  * RETURNS
463  *      Atom: Success
464  *      0: Failure
465  */
466 ATOM WINAPI AddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
467 {
468     return ATOM_AddAtomA( str, TRUE );
469 }
470
471
472 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
473 {
474     ATOM atom = 0;
475     if (!ATOM_IsIntAtomW( str, &atom ))
476     {
477         DWORD len = strlenW(str);
478         if (len > MAX_ATOM_LEN)
479         {
480             SetLastError( ERROR_INVALID_PARAMETER );
481             return 0;
482         }
483         SERVER_START_REQ
484         {
485             struct add_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
486             memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) );
487             req->local = local;
488             if (!server_call( REQ_ADD_ATOM )) atom = req->atom + MIN_STR_ATOM;
489         }
490         SERVER_END_REQ;
491     }
492     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
493     return atom;
494 }
495
496
497 /***********************************************************************
498  *           GlobalAddAtomW   (KERNEL32.314)
499  */
500 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
501 {
502     return ATOM_AddAtomW( str, FALSE );
503 }
504
505
506 /***********************************************************************
507  *           AddAtomW   (KERNEL32.1)
508  */
509 ATOM WINAPI AddAtomW( LPCWSTR str )
510 {
511     return ATOM_AddAtomW( str, TRUE );
512 }
513
514
515 static ATOM ATOM_DeleteAtom( ATOM atom,  BOOL local)
516 {
517     TRACE( "(%s) %x\n", local ? "local" : "glbal", atom );
518     if (atom < MIN_STR_ATOM) atom = 0;
519     else
520     {
521         SERVER_START_REQ
522         {
523             struct delete_atom_request *req = server_alloc_req( sizeof(*req), 0 );
524             req->atom = atom - MIN_STR_ATOM;
525             req->local = local;
526             if (!server_call( REQ_DELETE_ATOM )) atom = 0;
527         }
528         SERVER_END_REQ;
529     }
530     return atom;
531 }
532
533
534 /***********************************************************************
535  *           GlobalDeleteAtom   (USER.269) (KERNEL32.317)
536  * Decrements the reference count of a string atom.  If the count is
537  * zero, the string associated with the atom is removed from the table.
538  *
539  * RETURNS
540  *      0: Success
541  *      Atom: Failure
542  */
543 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
544 {
545     return ATOM_DeleteAtom( atom, FALSE);
546 }
547
548
549 /***********************************************************************
550  *           DeleteAtom   (KERNEL32.69)
551  * Decrements the reference count of a string atom.  If count becomes
552  * zero, the string associated with the atom is removed from the table.
553  *
554  * RETURNS
555  *      0: Success
556  *      Atom: Failure
557  */
558 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
559 {
560     return ATOM_DeleteAtom( atom, TRUE ); 
561 }
562
563
564 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
565 {
566     ATOM atom = 0;
567     if (!ATOM_IsIntAtomA( str, &atom ))
568     {
569         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), NULL, 0 );
570         if (len > MAX_ATOM_LEN)
571         {
572             SetLastError( ERROR_INVALID_PARAMETER );
573             return 0;
574         }
575         SERVER_START_REQ
576         {
577             struct find_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
578             MultiByteToWideChar( CP_ACP, 0, str, strlen(str), server_data_ptr(req), len );
579             req->local = local;
580             if (!server_call( REQ_FIND_ATOM )) atom = req->atom + MIN_STR_ATOM;
581         }
582         SERVER_END_REQ;
583     }
584     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
585     return atom;
586 }
587
588
589 /***********************************************************************
590  *           GlobalFindAtomA   (USER.270) (KERNEL32.318)
591  *
592  * Searches the atom table for the string and returns the atom
593  * associated with it.
594  *
595  * RETURNS
596  *      Atom: Success
597  *      0: Failure
598  */
599 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
600 {
601     return ATOM_FindAtomA( str, FALSE );
602 }
603
604 /***********************************************************************
605  *           FindAtomA   (KERNEL32.117)
606  * Searches the local atom table for the string and returns the atom
607  * associated with that string.
608  *
609  * RETURNS
610  *      Atom: Success
611  *      0: Failure
612  */
613 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
614 {
615     return ATOM_FindAtomA( str, TRUE );
616 }
617
618
619 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
620 {
621     ATOM atom = 0;
622     if (!ATOM_IsIntAtomW( str, &atom ))
623     {
624         DWORD len = strlenW(str);
625         if (len > MAX_ATOM_LEN)
626         {
627             SetLastError( ERROR_INVALID_PARAMETER );
628             return 0;
629         }
630         SERVER_START_REQ
631         {
632             struct find_atom_request *req = server_alloc_req( sizeof(*req), len * sizeof(WCHAR) );
633             memcpy( server_data_ptr(req), str, len * sizeof(WCHAR) );
634             req->local = local;
635             if (!server_call( REQ_FIND_ATOM )) atom = req->atom + MIN_STR_ATOM;
636         }
637         SERVER_END_REQ;
638     }
639     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
640     return atom;
641 }
642
643
644 /***********************************************************************
645  *           GlobalFindAtomW   (KERNEL32.319)
646  */
647 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
648 {
649     return ATOM_FindAtomW( str, FALSE );
650 }
651
652
653 /***********************************************************************
654  *           FindAtomW   (KERNEL32.118)
655  */
656 ATOM WINAPI FindAtomW( LPCWSTR str )
657 {
658     return ATOM_FindAtomW( str, TRUE );
659 }
660
661
662 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
663 {
664     INT len;
665
666     if (count <= 0)
667     {
668         SetLastError( ERROR_MORE_DATA );
669         return 0;
670     }
671     if (atom < MIN_STR_ATOM)
672     {
673         char name[8];
674         if (!atom)
675         {
676             SetLastError( ERROR_INVALID_PARAMETER );
677             return 0;
678         }
679         len = sprintf( name, "#%d", atom );
680         lstrcpynA( buffer, name, count );
681     }
682     else
683     {
684         len = 0;
685         SERVER_START_REQ
686         {
687             struct get_atom_name_request *req = server_alloc_req( sizeof(*req),
688                                                                   MAX_ATOM_LEN * sizeof(WCHAR) );
689             req->atom = atom - MIN_STR_ATOM;
690             req->local = local;
691             if (!server_call( REQ_GET_ATOM_NAME ))
692             {
693                 len = WideCharToMultiByte( CP_ACP, 0, server_data_ptr(req),
694                                            server_data_size(req) / sizeof(WCHAR),
695                                            buffer, count - 1, NULL, NULL );
696                 if (!len) len = count; /* overflow */
697                 else buffer[len] = 0;
698             }
699         }
700         SERVER_END_REQ;
701     }
702
703     if (len && count <= len)
704     {
705         SetLastError( ERROR_MORE_DATA );
706         buffer[count-1] = 0;
707         return 0;
708     }
709     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
710     return len;
711 }
712
713
714 /***********************************************************************
715  *           GlobalGetAtomNameA   (USER.271) (KERNEL32.323)
716  *
717  * Retrieves a copy of the string associated with an atom.
718  *
719  * RETURNS
720  *      Length of string in characters: Success
721  *      0: Failure
722  */
723 UINT WINAPI GlobalGetAtomNameA(
724               ATOM atom,    /* [in]  Atom identifier */
725               LPSTR buffer, /* [out] Pointer to buffer for atom string */
726               INT count )   /* [in]  Size of buffer */
727 {
728     return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
729 }
730
731
732 /***********************************************************************
733  *           GetAtomNameA   (KERNEL32.149)
734  * Retrieves a copy of the string associated with the atom.
735  *
736  * RETURNS
737  *      Length of string: Success
738  *      0: Failure
739  */
740 UINT WINAPI GetAtomNameA(
741               ATOM atom,    /* [in]  Atom */
742               LPSTR buffer, /* [out] Pointer to string for atom string */
743               INT count)    /* [in]  Size of buffer */
744 {
745     return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
746 }
747
748
749 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
750 {
751     INT len;
752
753     if (count <= 0)
754     {
755         SetLastError( ERROR_MORE_DATA );
756         return 0;
757     }
758     if (atom < MIN_STR_ATOM)
759     {
760         char name[8];
761         if (!atom)
762         {
763             SetLastError( ERROR_INVALID_PARAMETER );
764             return 0;
765         }
766         sprintf( name, "#%d", atom );
767         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
768         if (!len) buffer[count-1] = 0;  /* overflow */
769     }
770     else
771     {
772         len = 0;
773         SERVER_START_REQ
774         {
775             struct get_atom_name_request *req = server_alloc_req( sizeof(*req),
776                                                                   MAX_ATOM_LEN * sizeof(WCHAR) );
777             req->atom = atom - MIN_STR_ATOM;
778             req->local = local;
779             if (!server_call( REQ_GET_ATOM_NAME ))
780             {
781                 len = server_data_size(req) / sizeof(WCHAR);
782                 if (count > len) count = len + 1;
783                 memcpy( buffer, server_data_ptr(req), (count-1) * sizeof(WCHAR) );
784                 buffer[count-1] = 0;
785             }
786         }
787         SERVER_END_REQ;
788         if (!len) return 0;
789     }
790     if (count <= len)
791     {
792         SetLastError( ERROR_MORE_DATA );
793         return 0;
794     }
795     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
796     return len;
797 }
798
799
800 /***********************************************************************
801  *           GlobalGetAtomNameW   (KERNEL32.324)
802  */
803 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
804 {
805     return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
806 }
807
808
809 /***********************************************************************
810  *           GetAtomNameW   (KERNEL32.150)
811  */
812 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
813 {
814     return ATOM_GetAtomNameW( atom, buffer, count, TRUE );
815 }