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