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