Removed unnecessary includes.
[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 "winbase.h"
23 #include "winerror.h"
24
25 #include "wine/server.h"
26 #include "wine/unicode.h"
27 #include "wine/winbase16.h"
28 #include "global.h"
29 #include "instance.h"
30 #include "stackframe.h"
31
32 #include "debugtools.h"
33
34 DEFAULT_DEBUG_CHANNEL(atom);
35
36 #define DEFAULT_ATOMTABLE_SIZE    37
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 >= MAXINTATOM))
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 >= MAXINTATOM))
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 < MAXINTATOM) 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 < MAXINTATOM) 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 < MAXINTATOM)
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 = !wine_server_call_err( req );
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         WCHAR buffer[MAX_ATOM_LEN];
425
426         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
427         if (!len)
428         {
429             SetLastError( ERROR_INVALID_PARAMETER );
430             return 0;
431         }
432         SERVER_START_REQ( add_atom )
433         {
434             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
435             req->local = local;
436             if (!wine_server_call_err(req)) atom = reply->atom;
437         }
438         SERVER_END_REQ;
439     }
440     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
441     return atom;
442 }
443
444
445 /***********************************************************************
446  *           GlobalAddAtomA   (KERNEL32.@)
447  *
448  * Adds a character string to the global atom table and returns a unique
449  * value identifying the string.
450  *
451  * RETURNS
452  *      Atom: Success
453  *      0: Failure
454  */
455 ATOM WINAPI GlobalAddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
456 {
457     return ATOM_AddAtomA( str, FALSE );
458 }
459
460
461 /***********************************************************************
462  *           AddAtomA   (KERNEL32.@)
463  * Adds a string to the atom table and returns the atom identifying the
464  * string.
465  *
466  * RETURNS
467  *      Atom: Success
468  *      0: Failure
469  */
470 ATOM WINAPI AddAtomA( LPCSTR str /* [in] Pointer to string to add */ )
471 {
472     return ATOM_AddAtomA( str, TRUE );
473 }
474
475
476 static ATOM ATOM_AddAtomW( LPCWSTR str, BOOL local )
477 {
478     ATOM atom = 0;
479     if (!ATOM_IsIntAtomW( str, &atom ))
480     {
481         DWORD len = strlenW(str);
482         if (len > MAX_ATOM_LEN)
483         {
484             SetLastError( ERROR_INVALID_PARAMETER );
485             return 0;
486         }
487         SERVER_START_REQ( add_atom )
488         {
489             req->local = local;
490             wine_server_add_data( req, str, len * sizeof(WCHAR) );
491             if (!wine_server_call_err(req)) atom = reply->atom;
492         }
493         SERVER_END_REQ;
494     }
495     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
496     return atom;
497 }
498
499
500 /***********************************************************************
501  *           GlobalAddAtomW   (KERNEL32.@)
502  */
503 ATOM WINAPI GlobalAddAtomW( LPCWSTR str )
504 {
505     return ATOM_AddAtomW( str, FALSE );
506 }
507
508
509 /***********************************************************************
510  *           AddAtomW   (KERNEL32.@)
511  */
512 ATOM WINAPI AddAtomW( LPCWSTR str )
513 {
514     return ATOM_AddAtomW( str, TRUE );
515 }
516
517
518 static ATOM ATOM_DeleteAtom( ATOM atom,  BOOL local)
519 {
520     TRACE( "(%s) %x\n", local ? "local" : "global", atom );
521     if (atom < MAXINTATOM) atom = 0;
522     else
523     {
524         SERVER_START_REQ( delete_atom )
525         {
526             req->atom = atom;
527             req->local = local;
528             if (!wine_server_call_err( req )) atom = 0;
529         }
530         SERVER_END_REQ;
531     }
532     return atom;
533 }
534
535
536 /***********************************************************************
537  *           GlobalDeleteAtom   (KERNEL32.@)
538  * Decrements the reference count of a string atom.  If the count is
539  * zero, the string associated with the atom is removed from the table.
540  *
541  * RETURNS
542  *      0: Success
543  *      Atom: Failure
544  */
545 ATOM WINAPI GlobalDeleteAtom( ATOM atom /* [in] Atom to delete */ )
546 {
547     return ATOM_DeleteAtom( atom, FALSE);
548 }
549
550
551 /***********************************************************************
552  *           DeleteAtom   (KERNEL32.@)
553  * Decrements the reference count of a string atom.  If count becomes
554  * zero, the string associated with the atom is removed from the table.
555  *
556  * RETURNS
557  *      0: Success
558  *      Atom: Failure
559  */
560 ATOM WINAPI DeleteAtom( ATOM atom /* [in] Atom to delete */ )
561 {
562     return ATOM_DeleteAtom( atom, TRUE ); 
563 }
564
565
566 static ATOM ATOM_FindAtomA( LPCSTR str, BOOL local )
567 {
568     ATOM atom = 0;
569     if (!ATOM_IsIntAtomA( str, &atom ))
570     {
571         WCHAR buffer[MAX_ATOM_LEN];
572
573         DWORD len = MultiByteToWideChar( CP_ACP, 0, str, strlen(str), buffer, MAX_ATOM_LEN );
574         if (!len)
575         {
576             SetLastError( ERROR_INVALID_PARAMETER );
577             return 0;
578         }
579         SERVER_START_REQ( find_atom )
580         {
581             req->local = local;
582             wine_server_add_data( req, buffer, len * sizeof(WCHAR) );
583             if (!wine_server_call_err(req)) atom = reply->atom;
584         }
585         SERVER_END_REQ;
586     }
587     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_a(str), atom );
588     return atom;
589 }
590
591
592 /***********************************************************************
593  *           GlobalFindAtomA   (KERNEL32.@)
594  *
595  * Searches the atom table for the string and returns the atom
596  * associated with it.
597  *
598  * RETURNS
599  *      Atom: Success
600  *      0: Failure
601  */
602 ATOM WINAPI GlobalFindAtomA( LPCSTR str /* [in] Pointer to string to search for */ )
603 {
604     return ATOM_FindAtomA( str, FALSE );
605 }
606
607 /***********************************************************************
608  *           FindAtomA   (KERNEL32.@)
609  * Searches the local atom table for the string and returns the atom
610  * associated with that string.
611  *
612  * RETURNS
613  *      Atom: Success
614  *      0: Failure
615  */
616 ATOM WINAPI FindAtomA( LPCSTR str /* [in] Pointer to string to find */ )
617 {
618     return ATOM_FindAtomA( str, TRUE );
619 }
620
621
622 static ATOM ATOM_FindAtomW( LPCWSTR str, BOOL local )
623 {
624     ATOM atom = 0;
625     if (!ATOM_IsIntAtomW( str, &atom ))
626     {
627         DWORD len = strlenW(str);
628         if (len > MAX_ATOM_LEN)
629         {
630             SetLastError( ERROR_INVALID_PARAMETER );
631             return 0;
632         }
633         SERVER_START_REQ( find_atom )
634         {
635             wine_server_add_data( req, str, len * sizeof(WCHAR) );
636             req->local = local;
637             if (!wine_server_call_err( req )) atom = reply->atom;
638         }
639         SERVER_END_REQ;
640     }
641     TRACE( "(%s) %s -> %x\n", local ? "local" : "global", debugres_w(str), atom );
642     return atom;
643 }
644
645
646 /***********************************************************************
647  *           GlobalFindAtomW   (KERNEL32.@)
648  */
649 ATOM WINAPI GlobalFindAtomW( LPCWSTR str )
650 {
651     return ATOM_FindAtomW( str, FALSE );
652 }
653
654
655 /***********************************************************************
656  *           FindAtomW   (KERNEL32.@)
657  */
658 ATOM WINAPI FindAtomW( LPCWSTR str )
659 {
660     return ATOM_FindAtomW( str, TRUE );
661 }
662
663
664 static UINT ATOM_GetAtomNameA( ATOM atom, LPSTR buffer, INT count, BOOL local )
665 {
666     INT len;
667
668     if (count <= 0)
669     {
670         SetLastError( ERROR_MORE_DATA );
671         return 0;
672     }
673     if (atom < MAXINTATOM)
674     {
675         char name[8];
676         if (!atom)
677         {
678             SetLastError( ERROR_INVALID_PARAMETER );
679             return 0;
680         }
681         len = sprintf( name, "#%d", atom );
682         lstrcpynA( buffer, name, count );
683     }
684     else
685     {
686         WCHAR full_name[MAX_ATOM_LEN];
687
688         len = 0;
689         SERVER_START_REQ( get_atom_name )
690         {
691             req->atom = atom;
692             req->local = local;
693             wine_server_set_reply( req, full_name, sizeof(full_name) );
694             if (!wine_server_call_err( req ))
695             {
696                 len = WideCharToMultiByte( CP_ACP, 0, full_name,
697                                            wine_server_reply_size(reply) / sizeof(WCHAR),
698                                            buffer, count - 1, NULL, NULL );
699                 if (!len) len = count; /* overflow */
700                 else buffer[len] = 0;
701             }
702         }
703         SERVER_END_REQ;
704     }
705
706     if (len && count <= len)
707     {
708         SetLastError( ERROR_MORE_DATA );
709         buffer[count-1] = 0;
710         return 0;
711     }
712     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_a(buffer) );
713     return len;
714 }
715
716
717 /***********************************************************************
718  *           GlobalGetAtomNameA   (KERNEL32.@)
719  *
720  * Retrieves a copy of the string associated with an atom.
721  *
722  * RETURNS
723  *      Length of string in characters: Success
724  *      0: Failure
725  */
726 UINT WINAPI GlobalGetAtomNameA(
727               ATOM atom,    /* [in]  Atom identifier */
728               LPSTR buffer, /* [out] Pointer to buffer for atom string */
729               INT count )   /* [in]  Size of buffer */
730 {
731     return ATOM_GetAtomNameA( atom, buffer, count, FALSE );
732 }
733
734
735 /***********************************************************************
736  *           GetAtomNameA   (KERNEL32.@)
737  * Retrieves a copy of the string associated with the atom.
738  *
739  * RETURNS
740  *      Length of string: Success
741  *      0: Failure
742  */
743 UINT WINAPI GetAtomNameA(
744               ATOM atom,    /* [in]  Atom */
745               LPSTR buffer, /* [out] Pointer to string for atom string */
746               INT count)    /* [in]  Size of buffer */
747 {
748     return ATOM_GetAtomNameA( atom, buffer, count, TRUE );
749 }
750
751
752 static UINT ATOM_GetAtomNameW( ATOM atom, LPWSTR buffer, INT count, BOOL local )
753 {
754     INT len;
755
756     if (count <= 0)
757     {
758         SetLastError( ERROR_MORE_DATA );
759         return 0;
760     }
761     if (atom < MAXINTATOM)
762     {
763         char name[8];
764         if (!atom)
765         {
766             SetLastError( ERROR_INVALID_PARAMETER );
767             return 0;
768         }
769         sprintf( name, "#%d", atom );
770         len = MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, count );
771         if (!len) buffer[count-1] = 0;  /* overflow */
772     }
773     else
774     {
775         WCHAR full_name[MAX_ATOM_LEN];
776
777         len = 0;
778         SERVER_START_REQ( get_atom_name )
779         {
780             req->atom = atom;
781             req->local = local;
782             wine_server_set_reply( req, full_name, sizeof(full_name) );
783             if (!wine_server_call_err( req ))
784             {
785                 len = wine_server_reply_size(reply) / sizeof(WCHAR);
786                 if (count > len) count = len + 1;
787                 memcpy( buffer, full_name, (count-1) * sizeof(WCHAR) );
788                 buffer[count-1] = 0;
789             }
790         }
791         SERVER_END_REQ;
792         if (!len) return 0;
793     }
794     if (count <= len)
795     {
796         SetLastError( ERROR_MORE_DATA );
797         return 0;
798     }
799     TRACE( "(%s) %x -> %s\n", local ? "local" : "global", atom, debugstr_w(buffer) );
800     return len;
801 }
802
803
804 /***********************************************************************
805  *           GlobalGetAtomNameW   (KERNEL32.@)
806  */
807 UINT WINAPI GlobalGetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
808 {
809     return ATOM_GetAtomNameW( atom, buffer, count, FALSE);
810 }
811
812
813 /***********************************************************************
814  *           GetAtomNameW   (KERNEL32.@)
815  */
816 UINT WINAPI GetAtomNameW( ATOM atom, LPWSTR buffer, INT count )
817 {
818     return ATOM_GetAtomNameW( atom, buffer, count, TRUE );
819 }