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