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