Moved MAKEINTATOM to winbase.h and added Unicode version.
[wine] / dlls / user / resource.c
1 /*
2  * USER resource functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include "windef.h"
9 #include "winbase.h"
10 #include "winerror.h"
11 #include "winnls.h"
12 #include "wine/winbase16.h"
13 #include "wine/winuser16.h"
14
15 #include "heap.h"
16 #include "debugtools.h"
17
18 DEFAULT_DEBUG_CHANNEL(resource);
19 DECLARE_DEBUG_CHANNEL(accel);
20
21 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
22 typedef struct
23 {
24     BYTE   fVirt;
25     BYTE   pad0;
26     WORD   key;
27     WORD   cmd;
28     WORD   pad1;
29 } PE_ACCEL, *LPPE_ACCEL;
30
31 /**********************************************************************
32  *                      LoadAccelerators        [USER.177]
33  */
34 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, LPCSTR lpTableName)
35 {
36     HRSRC16     hRsrc;
37
38     TRACE_(accel)("%04x %s\n", instance, debugres_a(lpTableName) );
39
40     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATORA ))) {
41       WARN_(accel)("couldn't find accelerator table resource\n");
42       return 0;
43     }
44
45     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
46     return LoadResource16(instance,hRsrc);
47 }
48
49 /**********************************************************************
50  *                      LoadAcceleratorsW       (USER32.@)
51  * The image layout seems to look like this (not 100% sure):
52  * 00:  BYTE    type            type of accelerator
53  * 01:  BYTE    pad             (to WORD boundary)
54  * 02:  WORD    event
55  * 04:  WORD    IDval           
56  * 06:  WORD    pad             (to DWORD boundary)
57  */
58 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE instance,LPCWSTR lpTableName)
59 {
60     HRSRC hRsrc;
61     HACCEL hMem,hRetval=0;
62     DWORD size;
63
64     if (HIWORD(lpTableName))
65         TRACE_(accel)("%p '%s'\n",
66                       (LPVOID)instance, (char *)( lpTableName ) );
67     else
68         TRACE_(accel)("%p 0x%04x\n",
69                        (LPVOID)instance, LOWORD(lpTableName) );
70
71     if (!(hRsrc = FindResourceW( instance, lpTableName, RT_ACCELERATORW )))
72     {
73       WARN_(accel)("couldn't find accelerator table resource\n");
74     } else {
75       hMem = LoadResource( instance, hRsrc );
76       size = SizeofResource( instance, hRsrc );
77       if(size>=sizeof(PE_ACCEL))
78       {
79         LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
80         LPACCEL16 accel16;
81         int i,nrofaccells = size/sizeof(PE_ACCEL);
82
83         hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells);
84         accel16 = (LPACCEL16)GlobalLock16(hRetval);
85         for (i=0;i<nrofaccells;i++) {
86                 accel16[i].fVirt = accel_table[i].fVirt;
87                 accel16[i].key = accel_table[i].key;
88                 accel16[i].cmd = accel_table[i].cmd;
89         }
90         accel16[i-1].fVirt |= 0x80;
91       }
92     }
93     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
94     return hRetval;
95 }
96
97 /***********************************************************************
98  *              LoadAcceleratorsA   (USER32.@)
99  */
100 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE instance,LPCSTR lpTableName)
101 {
102         LPWSTR   uni;
103         HACCEL result;
104         if (HIWORD(lpTableName))
105                 uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
106         else
107                 uni = (LPWSTR)lpTableName;
108         result = LoadAcceleratorsW(instance,uni);
109         if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
110         return result;
111 }
112
113 /**********************************************************************
114  *             CopyAcceleratorTableA   (USER32.@)
115  */
116 INT WINAPI CopyAcceleratorTableA(HACCEL src, LPACCEL dst, INT entries)
117 {
118   return CopyAcceleratorTableW(src, dst, entries);
119 }
120
121 /**********************************************************************
122  *             CopyAcceleratorTableW   (USER32.@)
123  *
124  * By mortene@pvv.org 980321
125  */
126 INT WINAPI CopyAcceleratorTableW(HACCEL src, LPACCEL dst,
127                                      INT entries)
128 {
129   int i,xsize;
130   LPACCEL16 accel = (LPACCEL16)GlobalLock16(src);
131   BOOL done = FALSE;
132
133   /* Do parameter checking to avoid the explosions and the screaming
134      as far as possible. */
135   if((dst && (entries < 1)) || (src == (HACCEL)NULL) || !accel) {
136     WARN_(accel)("Application sent invalid parameters (%p %p %d).\n",
137          (LPVOID)src, (LPVOID)dst, entries);
138     return 0;
139   }
140   xsize = GlobalSize16(src)/sizeof(ACCEL16);
141   if (xsize>entries) entries=xsize;
142
143   i=0;
144   while(!done) {
145     /* Spit out some debugging information. */
146     TRACE_(accel)("accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
147           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
148
149     /* Copy data to the destination structure array (if dst == NULL,
150        we're just supposed to count the number of entries). */
151     if(dst) {
152       dst[i].fVirt = accel[i].fVirt;
153       dst[i].key = accel[i].key;
154       dst[i].cmd = accel[i].cmd;
155
156       /* Check if we've reached the end of the application supplied
157          accelerator table. */
158       if(i+1 == entries) {
159         /* Turn off the high order bit, just in case. */
160         dst[i].fVirt &= 0x7f;
161         done = TRUE;
162       }
163     }
164
165     /* The highest order bit seems to mark the end of the accelerator
166        resource table, but not always. Use GlobalSize() check too. */
167     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
168
169     i++;
170   }
171
172   return i;
173 }
174
175 /*********************************************************************
176  *                    CreateAcceleratorTableA   (USER32.@)
177  *
178  * By mortene@pvv.org 980321
179  */
180 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccel, INT cEntries)
181 {
182   HACCEL        hAccel;
183   LPACCEL16     accel;
184   int           i;
185
186   /* Do parameter checking just in case someone's trying to be
187      funny. */
188   if(cEntries < 1) {
189     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
190          lpaccel, cEntries);
191     SetLastError(ERROR_INVALID_PARAMETER);
192     return (HACCEL)NULL;
193   }
194   FIXME_(accel)("should check that the accelerator descriptions are valid,"
195         " return NULL and SetLastError() if not.\n");
196
197
198   /* Allocate memory and copy the table. */
199   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
200
201   TRACE_(accel)("handle %x\n", hAccel);
202   if(!hAccel) {
203     ERR_(accel)("Out of memory.\n");
204     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
205     return (HACCEL)NULL;
206   }
207   accel = GlobalLock16(hAccel);
208   for (i=0;i<cEntries;i++) {
209         accel[i].fVirt = lpaccel[i].fVirt;
210         accel[i].key = lpaccel[i].key;
211         accel[i].cmd = lpaccel[i].cmd;
212   }
213   /* Set the end-of-table terminator. */
214   accel[cEntries-1].fVirt |= 0x80;
215
216   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
217   return hAccel;
218 }
219
220 /*********************************************************************
221  *                    CreateAcceleratorTableW   (USER32.@)
222  *
223  * 
224  */
225 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccel, INT cEntries)
226 {
227   HACCEL        hAccel;
228   LPACCEL16     accel;
229   int           i;
230   char          ckey;  
231
232   /* Do parameter checking just in case someone's trying to be
233      funny. */
234   if(cEntries < 1) {
235     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
236          lpaccel, cEntries);
237     SetLastError(ERROR_INVALID_PARAMETER);
238     return (HACCEL)NULL;
239   }
240   FIXME_(accel)("should check that the accelerator descriptions are valid,"
241         " return NULL and SetLastError() if not.\n");
242
243
244   /* Allocate memory and copy the table. */
245   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
246
247   TRACE_(accel)("handle %x\n", hAccel);
248   if(!hAccel) {
249     ERR_(accel)("Out of memory.\n");
250     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
251     return (HACCEL)NULL;
252   }
253   accel = GlobalLock16(hAccel);
254
255
256   for (i=0;i<cEntries;i++) {
257        accel[i].fVirt = lpaccel[i].fVirt;
258        if( !(accel[i].fVirt & FVIRTKEY) ) {
259           ckey = (char) lpaccel[i].key;
260          if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &ckey, 1, &accel[i].key, 1))
261             WARN_(accel)("Error converting ASCII accelerator table to Unicode");
262        }
263        else 
264          accel[i].key = lpaccel[i].key; 
265        accel[i].cmd = lpaccel[i].cmd;
266   }
267
268   /* Set the end-of-table terminator. */
269   accel[cEntries-1].fVirt |= 0x80;
270
271   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
272   return hAccel;
273 }
274
275 /******************************************************************************
276  * DestroyAcceleratorTable [USER32.@]
277  * Destroys an accelerator table
278  *
279  * NOTES
280  *    By mortene@pvv.org 980321
281  *
282  * PARAMS
283  *    handle [I] Handle to accelerator table
284  *
285  * RETURNS STD
286  */
287 BOOL WINAPI DestroyAcceleratorTable( HACCEL handle )
288 {
289     return !GlobalFree16(handle); 
290 }
291   
292 /**********************************************************************
293  *     LoadString   (USER.176)
294  */
295 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
296                            LPSTR buffer, INT16 buflen )
297 {
298     HGLOBAL16 hmem;
299     HRSRC16 hrsrc;
300     unsigned char *p;
301     int string_num;
302     int i;
303
304     TRACE("inst=%04x id=%04x buff=%08x len=%d\n",
305           instance, resource_id, (int) buffer, buflen);
306
307     hrsrc = FindResource16( instance, (LPCSTR)((resource_id>>4)+1), RT_STRINGA );
308     if (!hrsrc) return 0;
309     hmem = LoadResource16( instance, hrsrc );
310     if (!hmem) return 0;
311     
312     p = LockResource16(hmem);
313     string_num = resource_id & 0x000f;
314     for (i = 0; i < string_num; i++)
315         p += *p + 1;
316     
317     TRACE("strlen = %d\n", (int)*p );
318     
319     if (buffer == NULL) return *p;
320     i = min(buflen - 1, *p);
321     if (i > 0) {
322         memcpy(buffer, p + 1, i);
323         buffer[i] = '\0';
324     } else {
325         if (buflen > 1) {
326             buffer[0] = '\0';
327             return 0;
328         }
329         WARN("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
330     }
331     FreeResource16( hmem );
332
333     TRACE("'%s' loaded !\n", buffer);
334     return i;
335 }
336
337 /**********************************************************************
338  *      LoadStringW             (USER32.@)
339  */
340 INT WINAPI LoadStringW( HINSTANCE instance, UINT resource_id,
341                             LPWSTR buffer, INT buflen )
342 {
343     HGLOBAL hmem;
344     HRSRC hrsrc;
345     WCHAR *p;
346     int string_num;
347     int i;
348
349     if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
350         resource_id = (UINT)(-((INT)resource_id));
351     TRACE("instance = %04x, id = %04x, buffer = %08x, length = %d\n",
352           instance, (int)resource_id, (int) buffer, buflen);
353
354     /* Use bits 4 - 19 (incremented by 1) as resourceid, mask out 
355      * 20 - 31. */
356     hrsrc = FindResourceW( instance, (LPCWSTR)(((resource_id>>4)&0xffff)+1),
357                              RT_STRINGW );
358     if (!hrsrc) return 0;
359     hmem = LoadResource( instance, hrsrc );
360     if (!hmem) return 0;
361     
362     p = LockResource(hmem);
363     string_num = resource_id & 0x000f;
364     for (i = 0; i < string_num; i++)
365         p += *p + 1;
366     
367     TRACE("strlen = %d\n", (int)*p );
368     
369     if (buffer == NULL) return *p;
370     i = min(buflen - 1, *p);
371     if (i > 0) {
372         memcpy(buffer, p + 1, i * sizeof (WCHAR));
373         buffer[i] = (WCHAR) 0;
374     } else {
375         if (buflen > 1) {
376             buffer[0] = (WCHAR) 0;
377             return 0;
378         }
379 #if 0
380         WARN("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
381 #endif
382     }
383
384     TRACE("%s loaded !\n", debugstr_w(buffer));
385     return i;
386 }
387
388 /**********************************************************************
389  *      LoadStringA     (USER32.@)
390  */
391 INT WINAPI LoadStringA( HINSTANCE instance, UINT resource_id,
392                             LPSTR buffer, INT buflen )
393 {
394     INT    retval;
395     LPWSTR wbuf;
396
397     TRACE("instance = %04x, id = %04x, buffer = %08x, length = %d\n",
398           instance, (int)resource_id, (int) buffer, buflen);
399
400     if(buffer == NULL) /* asked size of string */
401         return LoadStringW(instance, resource_id, NULL, 0);
402     
403     wbuf = HeapAlloc(GetProcessHeap(), 0, buflen * sizeof(WCHAR));
404     if(!wbuf)
405         return 0;
406
407     retval = LoadStringW(instance, resource_id, wbuf, buflen);
408     if(retval != 0)
409     {
410         retval = WideCharToMultiByte(CP_ACP, 0, wbuf, retval, buffer, buflen - 1, NULL, NULL);
411         buffer[retval] = 0;
412         TRACE("%s loaded !\n", debugstr_a(buffer));
413     }
414     else buffer[0] = 0;    /* no check of buflen here */
415     HeapFree( GetProcessHeap(), 0, wbuf );
416
417     return retval;
418 }