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