Implemented SHCreateStdEnumFmtEtc.
[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 "windef.h"
23 #include "winbase.h"
24 #include "winerror.h"
25 #include "winnls.h"
26 #include "wine/winbase16.h"
27 #include "wine/winuser16.h"
28 #include "user.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(resource);
32 WINE_DECLARE_DEBUG_CHANNEL(accel);
33
34 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
35 typedef struct
36 {
37     BYTE   fVirt;
38     BYTE   pad0;
39     WORD   key;
40     WORD   cmd;
41     WORD   pad1;
42 } PE_ACCEL, *LPPE_ACCEL;
43
44 /**********************************************************************
45  *                      LoadAccelerators        [USER.177]
46  */
47 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, LPCSTR lpTableName)
48 {
49     HRSRC16     hRsrc;
50
51     TRACE_(accel)("%04x %s\n", instance, debugstr_a(lpTableName) );
52
53     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATORA ))) {
54       WARN_(accel)("couldn't find accelerator table resource\n");
55       return 0;
56     }
57
58     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
59     return LoadResource16(instance,hRsrc);
60 }
61
62 /**********************************************************************
63  *                      LoadAcceleratorsW       (USER32.@)
64  * The image layout seems to look like this (not 100% sure):
65  * 00:  BYTE    type            type of accelerator
66  * 01:  BYTE    pad             (to WORD boundary)
67  * 02:  WORD    event
68  * 04:  WORD    IDval
69  * 06:  WORD    pad             (to DWORD boundary)
70  */
71 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE instance,LPCWSTR lpTableName)
72 {
73     HRSRC hRsrc;
74     HACCEL hMem;
75     HACCEL16 hRetval=0;
76     DWORD size;
77
78     if (HIWORD(lpTableName))
79         TRACE_(accel)("%p '%s'\n",
80                       (LPVOID)instance, (char *)( lpTableName ) );
81     else
82         TRACE_(accel)("%p 0x%04x\n",
83                        (LPVOID)instance, LOWORD(lpTableName) );
84
85     if (!(hRsrc = FindResourceW( instance, lpTableName, RT_ACCELERATORW )))
86     {
87       WARN_(accel)("couldn't find accelerator table resource\n");
88     } else {
89       hMem = LoadResource( instance, hRsrc );
90       size = SizeofResource( instance, hRsrc );
91       if(size>=sizeof(PE_ACCEL))
92       {
93         LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
94         LPACCEL16 accel16;
95         int i,nrofaccells = size/sizeof(PE_ACCEL);
96
97         hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells);
98         accel16 = (LPACCEL16)GlobalLock16(hRetval);
99         for (i=0;i<nrofaccells;i++) {
100                 accel16[i].fVirt = accel_table[i].fVirt;
101                 accel16[i].key = accel_table[i].key;
102                 accel16[i].cmd = accel_table[i].cmd;
103         }
104         accel16[i-1].fVirt |= 0x80;
105       }
106     }
107     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
108     return HACCEL_32(hRetval);
109 }
110
111 /***********************************************************************
112  *              LoadAcceleratorsA   (USER32.@)
113  */
114 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE instance,LPCSTR lpTableName)
115 {
116     INT len;
117     LPWSTR uni;
118     HACCEL result = 0;
119
120     if (!HIWORD(lpTableName)) return LoadAcceleratorsW( instance, (LPCWSTR)lpTableName );
121
122     len = MultiByteToWideChar( CP_ACP, 0, lpTableName, -1, NULL, 0 );
123     if ((uni = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
124     {
125         MultiByteToWideChar( CP_ACP, 0, lpTableName, -1, uni, len );
126         result = LoadAcceleratorsW(instance,uni);
127         HeapFree( GetProcessHeap(), 0, uni);
128     }
129     return result;
130 }
131
132 /**********************************************************************
133  *             CopyAcceleratorTableA   (USER32.@)
134  */
135 INT WINAPI CopyAcceleratorTableA(HACCEL src, LPACCEL dst, INT entries)
136 {
137   return CopyAcceleratorTableW(src, dst, entries);
138 }
139
140 /**********************************************************************
141  *             CopyAcceleratorTableW   (USER32.@)
142  *
143  * By mortene@pvv.org 980321
144  */
145 INT WINAPI CopyAcceleratorTableW(HACCEL src, LPACCEL dst,
146                                      INT entries)
147 {
148   int i,xsize;
149   LPACCEL16 accel = (LPACCEL16)GlobalLock16(HACCEL_16(src));
150   BOOL done = FALSE;
151
152   /* Do parameter checking to avoid the explosions and the screaming
153      as far as possible. */
154   if((dst && (entries < 1)) || (src == (HACCEL)NULL) || !accel) {
155     WARN_(accel)("Application sent invalid parameters (%p %p %d).\n",
156          (LPVOID)src, (LPVOID)dst, entries);
157     return 0;
158   }
159   xsize = GlobalSize16(HACCEL_16(src))/sizeof(ACCEL16);
160   if (xsize>entries) entries=xsize;
161
162   i=0;
163   while(!done) {
164     /* Spit out some debugging information. */
165     TRACE_(accel)("accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
166           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
167
168     /* Copy data to the destination structure array (if dst == NULL,
169        we're just supposed to count the number of entries). */
170     if(dst) {
171       dst[i].fVirt = accel[i].fVirt;
172       dst[i].key = accel[i].key;
173       dst[i].cmd = accel[i].cmd;
174
175       /* Check if we've reached the end of the application supplied
176          accelerator table. */
177       if(i+1 == entries) {
178         /* Turn off the high order bit, just in case. */
179         dst[i].fVirt &= 0x7f;
180         done = TRUE;
181       }
182     }
183
184     /* The highest order bit seems to mark the end of the accelerator
185        resource table, but not always. Use GlobalSize() check too. */
186     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
187
188     i++;
189   }
190
191   return i;
192 }
193
194 /*********************************************************************
195  *                    CreateAcceleratorTableA   (USER32.@)
196  *
197  * By mortene@pvv.org 980321
198  */
199 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccel, INT cEntries)
200 {
201   HACCEL        hAccel;
202   LPACCEL16     accel;
203   int           i;
204
205   /* Do parameter checking just in case someone's trying to be
206      funny. */
207   if(cEntries < 1) {
208     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
209          lpaccel, cEntries);
210     SetLastError(ERROR_INVALID_PARAMETER);
211     return (HACCEL)NULL;
212   }
213   FIXME_(accel)("should check that the accelerator descriptions are valid,"
214         " return NULL and SetLastError() if not.\n");
215
216
217   /* Allocate memory and copy the table. */
218   hAccel = HACCEL_32(GlobalAlloc16(0,cEntries*sizeof(ACCEL16)));
219
220   TRACE_(accel)("handle %x\n", hAccel);
221   if(!hAccel) {
222     ERR_(accel)("Out of memory.\n");
223     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
224     return (HACCEL)NULL;
225   }
226   accel = GlobalLock16(HACCEL_16(hAccel));
227   for (i=0;i<cEntries;i++) {
228         accel[i].fVirt = lpaccel[i].fVirt;
229         accel[i].key = lpaccel[i].key;
230         accel[i].cmd = lpaccel[i].cmd;
231   }
232   /* Set the end-of-table terminator. */
233   accel[cEntries-1].fVirt |= 0x80;
234
235   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
236   return hAccel;
237 }
238
239 /*********************************************************************
240  *                    CreateAcceleratorTableW   (USER32.@)
241  *
242  *
243  */
244 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccel, INT cEntries)
245 {
246   HACCEL        hAccel;
247   LPACCEL16     accel;
248   int           i;
249   char          ckey;
250
251   /* Do parameter checking just in case someone's trying to be
252      funny. */
253   if(cEntries < 1) {
254     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
255          lpaccel, cEntries);
256     SetLastError(ERROR_INVALID_PARAMETER);
257     return (HACCEL)NULL;
258   }
259   FIXME_(accel)("should check that the accelerator descriptions are valid,"
260         " return NULL and SetLastError() if not.\n");
261
262
263   /* Allocate memory and copy the table. */
264   hAccel = HACCEL_32(GlobalAlloc16(0,cEntries*sizeof(ACCEL16)));
265
266   TRACE_(accel)("handle %x\n", hAccel);
267   if(!hAccel) {
268     ERR_(accel)("Out of memory.\n");
269     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
270     return (HACCEL)NULL;
271   }
272   accel = GlobalLock16(HACCEL_16(hAccel));
273
274
275   for (i=0;i<cEntries;i++) {
276        accel[i].fVirt = lpaccel[i].fVirt;
277        if( !(accel[i].fVirt & FVIRTKEY) ) {
278           ckey = (char) lpaccel[i].key;
279          if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &ckey, 1, &accel[i].key, 1))
280             WARN_(accel)("Error converting ASCII accelerator table to Unicode");
281        }
282        else
283          accel[i].key = lpaccel[i].key;
284        accel[i].cmd = lpaccel[i].cmd;
285   }
286
287   /* Set the end-of-table terminator. */
288   accel[cEntries-1].fVirt |= 0x80;
289
290   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
291   return hAccel;
292 }
293
294 /******************************************************************************
295  * DestroyAcceleratorTable [USER32.@]
296  * Destroys an accelerator table
297  *
298  * NOTES
299  *    By mortene@pvv.org 980321
300  *
301  * PARAMS
302  *    handle [I] Handle to accelerator table
303  *
304  * RETURNS STD
305  */
306 BOOL WINAPI DestroyAcceleratorTable( HACCEL handle )
307 {
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), RT_STRINGA );
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("Dont know why caller give 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 = %04x, 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                              RT_STRINGW );
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("Dont know why caller give 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 = %04x, 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 }