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