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