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