Release 980601
[wine.git] / loader / resource.c
blobe4b2a2a77ad8ebb9ff877812ea19f503edffc5ff
1 /*
2 * Resources
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995 Alexandre Julliard
6 */
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include "windows.h"
16 #include "gdi.h"
17 #include "global.h"
18 #include "heap.h"
19 #include "neexe.h"
20 #include "task.h"
21 #include "process.h"
22 #include "module.h"
23 #include "resource.h"
24 #include "debug.h"
25 #include "libres.h"
26 #include "winerror.h"
28 extern WORD WINE_LanguageId;
31 /**********************************************************************
32 * FindResource32A (KERNEL32.128)
34 HANDLE32 WINAPI FindResource32A( HMODULE32 hModule, LPCSTR name, LPCSTR type)
36 return FindResourceEx32A(hModule,name,type,WINE_LanguageId);
39 /**********************************************************************
40 * FindResourceEx32A (KERNEL32.129)
42 HANDLE32 WINAPI FindResourceEx32A( HMODULE32 hModule, LPCSTR name, LPCSTR type,
43 WORD lang
44 ) {
45 LPWSTR xname,xtype;
46 HANDLE32 ret;
48 if (HIWORD((DWORD)name))
49 xname = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
50 else
51 xname = (LPWSTR)name;
52 if (HIWORD((DWORD)type))
53 xtype = HEAP_strdupAtoW( GetProcessHeap(), 0, type);
54 else
55 xtype = (LPWSTR)type;
56 ret = FindResourceEx32W( hModule, xname, xtype, lang );
57 if (HIWORD((DWORD)name)) HeapFree( GetProcessHeap(), 0, xname );
58 if (HIWORD((DWORD)type)) HeapFree( GetProcessHeap(), 0, xtype );
59 return ret;
63 /**********************************************************************
64 * FindResourceEx32W (KERNEL32.130)
66 HRSRC32 WINAPI FindResourceEx32W( HMODULE32 hModule, LPCWSTR name,
67 LPCWSTR type, WORD lang )
69 WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
70 HRSRC32 hrsrc;
72 TRACE(resource, "module=%08x "
73 "type=%s%p name=%s%p\n", wm->module,
74 (HIWORD(type))? "" : "#", type,
75 (HIWORD(name))? "" : "#", name);
76 if (__winelib) {
77 hrsrc = LIBRES_FindResource( hModule, name, type );
78 if (hrsrc)
79 return hrsrc;
81 if (wm) {
82 switch (wm->type) {
83 case MODULE32_PE:
84 return PE_FindResourceEx32W(wm,name,type,lang);
85 default:
86 ERR(module,"unknown module type %d\n",wm->type);
87 break;
90 return (HRSRC32)0;
94 /**********************************************************************
95 * FindResource32W (KERNEL32.131)
97 HRSRC32 WINAPI FindResource32W(HINSTANCE32 hModule, LPCWSTR name, LPCWSTR type)
99 return FindResourceEx32W(hModule,name,type,WINE_LanguageId);
103 /**********************************************************************
104 * LoadResource32 (KERNEL32.370)
105 * 'loads' a resource. The current implementation just returns a pointer
106 * into the already mapped image.
107 * RETURNS
108 * pointer into the mapped resource of the passed module
110 HGLOBAL32 WINAPI LoadResource32(
111 HINSTANCE32 hModule, /* [in] module handle */
112 HRSRC32 hRsrc ) /* [in] resource handle */
114 WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
116 TRACE(resource, "module=%04x res=%04x\n",
117 hModule, hRsrc );
118 if (!hRsrc) {
119 ERR(resource,"hRsrc is 0, return 0.\n");
120 return 0;
122 if (wm)
123 switch (wm->type) {
124 case MODULE32_PE:
125 return PE_LoadResource32(wm,hRsrc);
126 default:
127 ERR(resource,"unknown module type %d\n",wm->type);
128 break;
130 if (__winelib)
131 return LIBRES_LoadResource( hModule, hRsrc );
132 return 0;
136 /**********************************************************************
137 * LockResource32 (KERNEL32.384)
139 LPVOID WINAPI LockResource32( HGLOBAL32 handle )
141 return (LPVOID)handle;
145 /**********************************************************************
146 * FreeResource32 (KERNEL32.145)
148 BOOL32 WINAPI FreeResource32( HGLOBAL32 handle )
150 /* no longer used in Win32 */
151 return TRUE;
155 /**********************************************************************
156 * AccessResource32 (KERNEL32.64)
158 INT32 WINAPI AccessResource32( HMODULE32 hModule, HRSRC32 hRsrc )
160 FIXME(resource,"(module=%08x res=%08x),not implemented\n", hModule, hRsrc);
161 return 0;
165 /**********************************************************************
166 * SizeofResource32 (KERNEL32.522)
168 DWORD WINAPI SizeofResource32( HINSTANCE32 hModule, HRSRC32 hRsrc )
170 WINE_MODREF *wm = MODULE32_LookupHMODULE(PROCESS_Current(),hModule);
172 TRACE(resource, "module=%08x res=%08x\n", hModule, hRsrc );
173 if (wm)
174 switch (wm->type)
176 case MODULE32_PE:
178 DWORD ret;
179 ret = PE_SizeofResource32(hModule,hRsrc);
180 if (ret)
181 return ret;
182 break;
184 default:
185 ERR(module,"unknown module type %d\n",wm->type);
186 break;
188 if (__winelib)
189 FIXME(module,"Not implemented for WINELIB\n");
190 return 0;
194 /**********************************************************************
195 * LoadAccelerators16 [USER.177]
197 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName)
199 HRSRC16 hRsrc;
201 if (HIWORD(lpTableName))
202 TRACE(accel, "%04x '%s'\n",
203 instance, (char *)PTR_SEG_TO_LIN( lpTableName ) );
204 else
205 TRACE(accel, "%04x %04x\n",
206 instance, LOWORD(lpTableName) );
208 if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATOR16 ))) {
209 WARN(accel, "couldn't find accelerator table resource\n");
210 return 0;
213 TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
214 return LoadResource16(instance,hRsrc);
217 /**********************************************************************
218 * LoadAccelerators32W [USER.177]
219 * The image layout seems to look like this (not 100% sure):
220 * 00: BYTE type type of accelerator
221 * 01: BYTE pad (to WORD boundary)
222 * 02: WORD event
223 * 04: WORD IDval
224 * 06: WORD pad (to DWORD boundary)
226 HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName)
228 HRSRC32 hRsrc;
229 HACCEL32 hRetval;
231 if (HIWORD(lpTableName))
232 TRACE(accel, "%p '%s'\n",
233 (LPVOID)instance, (char *)( lpTableName ) );
234 else
235 TRACE(accel, "%p 0x%04x\n",
236 (LPVOID)instance, LOWORD(lpTableName) );
238 if (!(hRsrc = FindResource32W( instance, lpTableName, RT_ACCELERATOR32W )))
240 WARN(accel, "couldn't find accelerator table resource\n");
241 hRetval = 0;
243 else {
244 hRetval = LoadResource32( instance, hRsrc );
247 TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
248 return hRetval;
251 HACCEL32 WINAPI LoadAccelerators32A(HINSTANCE32 instance,LPCSTR lpTableName)
253 LPWSTR uni;
254 HACCEL32 result;
255 if (HIWORD(lpTableName))
256 uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
257 else
258 uni = (LPWSTR)lpTableName;
259 result = LoadAccelerators32W(instance,uni);
260 if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
261 return result;
264 /**********************************************************************
265 * CopyAcceleratorTable32A (USER32.58)
267 INT32 WINAPI CopyAcceleratorTable32A(HACCEL32 src, LPACCEL32 dst, INT32 entries)
269 return CopyAcceleratorTable32W(src, dst, entries);
272 /**********************************************************************
273 * CopyAcceleratorTable32W (USER32.59)
275 * By mortene@pvv.org 980321
277 INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
278 INT32 entries)
280 int i;
281 LPACCEL32 accel = (LPACCEL32)src;
282 BOOL32 done = FALSE;
284 /* Do parameter checking to avoid the explosions and the screaming
285 as far as possible. */
286 if((dst && (entries < 1)) || (src == (HACCEL32)NULL)) {
287 WARN(accel, "Application sent invalid parameters (%p %p %d).\n",
288 (LPVOID)src, (LPVOID)dst, entries);
289 return 0;
293 i=0;
294 while(!done) {
295 /* Spit out some debugging information. */
296 TRACE(accel, "accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
297 i, accel[i].fVirt, accel[i].key, accel[i].cmd);
299 /* Copy data to the destination structure array (if dst == NULL,
300 we're just supposed to count the number of entries). */
301 if(dst) {
302 memcpy(&dst[i], &accel[i], sizeof(ACCEL32));
304 /* Check if we've reached the end of the application supplied
305 accelerator table. */
306 if(i+1 == entries) {
307 /* Turn off the high order bit, just in case. */
308 dst[i].fVirt &= 0x7f;
309 done = TRUE;
313 /* The highest order bit seems to mark the end of the accelerator
314 resource table. (?) */
315 if((accel[i].fVirt & 0x80) != 0) done = TRUE;
317 i++;
320 return i;
323 /*********************************************************************
324 * CreateAcceleratorTable (USER32.64)
326 * By mortene@pvv.org 980321
328 HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
330 HACCEL32 hAccel;
332 /* Do parameter checking just in case someone's trying to be
333 funny. */
334 if(cEntries < 1) {
335 WARN(accel, "Application sent invalid parameters (%p %d).\n",
336 lpaccel, cEntries);
337 SetLastError(ERROR_INVALID_PARAMETER);
338 return (HACCEL32)NULL;
340 FIXME(accel, "should check that the accelerator descriptions are valid,"
341 " return NULL and SetLastError() if not.\n");
344 /* Allocate memory and copy the table. */
345 hAccel = (HACCEL32)HeapAlloc(GetProcessHeap(), 0,
346 cEntries * sizeof(ACCEL32));
347 TRACE(accel, "handle %p\n", (LPVOID)hAccel);
348 if(!hAccel) {
349 WARN(accel, "Out of memory.\n");
350 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
351 return (HACCEL32)NULL;
353 memcpy((LPACCEL32)hAccel, lpaccel, cEntries * sizeof(ACCEL32));
355 /* Set the end-of-table terminator. */
356 ((LPACCEL32)hAccel)[cEntries-1].fVirt |= 0x80;
358 TRACE(accel, "Allocated accelerator handle %x\n", hAccel);
359 return hAccel;
363 /******************************************************************************
364 * DestroyAcceleratorTable [USER32.130]
365 * Destroys an accelerator table
367 * NOTES
368 * By mortene@pvv.org 980321
370 * PARAMS
371 * handle [I] Handle to accelerator table
373 * RETURNS STD
375 BOOL32 WINAPI DestroyAcceleratorTable( HACCEL32 handle )
377 FIXME(accel, "(0x%x): stub\n", handle);
380 /* Weird.. I thought this should work. According to the API
381 specification, DestroyAcceleratorTable() should only be called on
382 HACCEL32's made by CreateAcceleratorTable(), but Microsoft Visual
383 Studio 97 calls this function with a series of different handle
384 values without ever calling CreateAcceleratorTable(). Something
385 is very fishy in Denmark... */
386 /* Update: looks like the calls to this function matches the calls
387 to LoadAccelerators() in M$ Visual Studio, except that the handle
388 values are off by some variable size from the HACCEL's returned
389 from LoadAccelerators(). WTH? */
391 /* Parameter checking to avoid any embarassing situations. */
392 /* if(!handle) { */
393 /* WARN(accel, "Application sent NULL ptr.\n"); */
394 /* SetLastError(ERROR_INVALID_PARAMETER); */
395 /* return FALSE; */
396 /* } */
398 /* HeapFree(GetProcessHeap(), 0, (LPACCEL32)handle); */
400 return TRUE;
403 /**********************************************************************
404 * LoadString16
406 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
407 LPSTR buffer, INT16 buflen )
409 HGLOBAL16 hmem;
410 HRSRC16 hrsrc;
411 unsigned char *p;
412 int string_num;
413 int i;
415 TRACE(resource,"inst=%04x id=%04x buff=%08x len=%d\n",
416 instance, resource_id, (int) buffer, buflen);
418 hrsrc = FindResource16( instance, (SEGPTR)((resource_id>>4)+1), RT_STRING16 );
419 if (!hrsrc) return 0;
420 hmem = LoadResource16( instance, hrsrc );
421 if (!hmem) return 0;
423 p = LockResource16(hmem);
424 string_num = resource_id & 0x000f;
425 for (i = 0; i < string_num; i++)
426 p += *p + 1;
428 TRACE(resource, "strlen = %d\n", (int)*p );
430 i = MIN(buflen - 1, *p);
431 if (buffer == NULL)
432 return i;
433 if (i > 0) {
434 memcpy(buffer, p + 1, i);
435 buffer[i] = '\0';
436 } else {
437 if (buflen > 1) {
438 buffer[0] = '\0';
439 return 0;
441 WARN(resource,"Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
443 FreeResource16( hmem );
445 TRACE(resource,"'%s' copied !\n", buffer);
446 return i;
449 /**********************************************************************
450 * LoadString32W (USER32.376)
452 INT32 WINAPI LoadString32W( HINSTANCE32 instance, UINT32 resource_id,
453 LPWSTR buffer, INT32 buflen )
455 HGLOBAL32 hmem;
456 HRSRC32 hrsrc;
457 WCHAR *p;
458 int string_num;
459 int i;
461 if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
462 resource_id = (UINT32)(-((INT32)resource_id));
463 TRACE(resource, "instance = %04x, id = %04x, buffer = %08x, "
464 "length = %d\n", instance, (int)resource_id, (int) buffer, buflen);
466 hrsrc = FindResource32W( instance, (LPCWSTR)((resource_id>>4)+1),
467 RT_STRING32W );
468 if (!hrsrc) return 0;
469 hmem = LoadResource32( instance, hrsrc );
470 if (!hmem) return 0;
472 p = LockResource32(hmem);
473 string_num = resource_id & 0x000f;
474 for (i = 0; i < string_num; i++)
475 p += *p + 1;
477 TRACE(resource, "strlen = %d\n", (int)*p );
479 i = MIN(buflen - 1, *p);
480 if (buffer == NULL)
481 return i;
482 if (i > 0) {
483 memcpy(buffer, p + 1, i * sizeof (WCHAR));
484 buffer[i] = (WCHAR) 0;
485 } else {
486 if (buflen > 1) {
487 buffer[0] = (WCHAR) 0;
488 return 0;
490 #if 0
491 WARN(resource,"Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
492 #endif
495 TRACE(resource,"'%s' copied !\n", (char *)buffer);
496 return i;
499 /**********************************************************************
500 * LoadString32A (USER32.375)
502 INT32 WINAPI LoadString32A( HINSTANCE32 instance, UINT32 resource_id,
503 LPSTR buffer, INT32 buflen )
505 INT32 retval;
506 LPWSTR buffer2 = NULL;
507 if (buffer && buflen)
508 buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen * 2 );
509 retval = LoadString32W(instance,resource_id,buffer2,buflen);
511 if (buffer2)
513 if (retval) {
514 lstrcpynWtoA( buffer, buffer2, buflen );
515 retval = lstrlen32A( buffer );
517 else
518 *buffer = 0;
519 HeapFree( GetProcessHeap(), 0, buffer2 );
521 return retval;
524 /* Messages...used by FormatMessage32* (KERNEL32.something)
526 * They can be specified either directly or using a message ID and
527 * loading them from the resource.
529 * The resourcedata has following format:
530 * start:
531 * 0: DWORD nrofentries
532 * nrofentries * subentry:
533 * 0: DWORD firstentry
534 * 4: DWORD lastentry
535 * 8: DWORD offset from start to the stringentries
537 * (lastentry-firstentry) * stringentry:
538 * 0: WORD len (0 marks end)
539 * 2: WORD unknown (flags?)
540 * 4: CHAR[len-4]
541 * (stringentry i of a subentry refers to the ID 'firstentry+i')
543 * Yes, ANSI strings in win32 resources. Go figure.
546 /**********************************************************************
547 * LoadMessage32A (internal)
549 INT32 LoadMessage32A( HMODULE32 instance, UINT32 id, WORD lang,
550 LPSTR buffer, INT32 buflen )
552 HGLOBAL32 hmem;
553 HRSRC32 hrsrc;
554 BYTE *p;
555 int nrofentries,i,slen;
556 struct _subentry {
557 DWORD firstentry;
558 DWORD lastentry;
559 DWORD offset;
560 } *se;
561 struct _stringentry {
562 WORD len;
563 WORD unknown;
564 CHAR str[1];
565 } *stre;
567 TRACE(resource, "instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
569 /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
570 hrsrc = FindResourceEx32W(instance,(LPWSTR)1,RT_MESSAGELIST32W,lang);
571 if (!hrsrc) return 0;
572 hmem = LoadResource32( instance, hrsrc );
573 if (!hmem) return 0;
575 p = LockResource32(hmem);
576 nrofentries = *(DWORD*)p;
577 stre = NULL;
578 se = (struct _subentry*)(p+4);
579 for (i=nrofentries;i--;) {
580 if ((id>=se->firstentry) && (id<=se->lastentry)) {
581 stre = (struct _stringentry*)(p+se->offset);
582 id -= se->firstentry;
583 break;
585 se++;
587 if (!stre)
588 return 0;
589 for (i=id;i--;) {
590 if (!(slen=stre->len))
591 return 0;
592 stre = (struct _stringentry*)(((char*)stre)+slen);
594 slen=stre->len;
595 TRACE(resource," - strlen=%d\n",slen);
596 i = MIN(buflen - 1, slen);
597 if (buffer == NULL)
598 return slen; /* different to LoadString */
599 if (i>0) {
600 lstrcpyn32A(buffer,stre->str,i);
601 buffer[i]=0;
602 } else {
603 if (buflen>1) {
604 buffer[0]=0;
605 return 0;
608 if (buffer)
609 TRACE(resource,"'%s' copied !\n", buffer);
610 return i;
613 /**********************************************************************
614 * LoadMessage32W (internal)
616 INT32 LoadMessage32W( HMODULE32 instance, UINT32 id, WORD lang,
617 LPWSTR buffer, INT32 buflen )
619 INT32 retval;
620 LPSTR buffer2 = NULL;
621 if (buffer && buflen)
622 buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
623 retval = LoadMessage32A(instance,id,lang,buffer2,buflen);
624 if (buffer)
626 if (retval) {
627 lstrcpynAtoW( buffer, buffer2, buflen );
628 retval = lstrlen32W( buffer );
630 HeapFree( GetProcessHeap(), 0, buffer2 );
632 return retval;
636 /**********************************************************************
637 * EnumResourceTypesA (KERNEL32.90)
639 BOOL32 WINAPI EnumResourceTypes32A( HMODULE32 hmodule,ENUMRESTYPEPROC32A lpfun,
640 LONG lParam)
642 /* FIXME: move WINE_MODREF stuff here */
643 return PE_EnumResourceTypes32A(hmodule,lpfun,lParam);
646 /**********************************************************************
647 * EnumResourceTypesW (KERNEL32.91)
649 BOOL32 WINAPI EnumResourceTypes32W( HMODULE32 hmodule,ENUMRESTYPEPROC32W lpfun,
650 LONG lParam)
652 /* FIXME: move WINE_MODREF stuff here */
653 return PE_EnumResourceTypes32W(hmodule,lpfun,lParam);
656 /**********************************************************************
657 * EnumResourceNamesA (KERNEL32.88)
659 BOOL32 WINAPI EnumResourceNames32A( HMODULE32 hmodule, LPCSTR type,
660 ENUMRESNAMEPROC32A lpfun, LONG lParam )
662 /* FIXME: move WINE_MODREF stuff here */
663 return PE_EnumResourceNames32A(hmodule,type,lpfun,lParam);
665 /**********************************************************************
666 * EnumResourceNamesW (KERNEL32.89)
668 BOOL32 WINAPI EnumResourceNames32W( HMODULE32 hmodule, LPCWSTR type,
669 ENUMRESNAMEPROC32W lpfun, LONG lParam )
671 /* FIXME: move WINE_MODREF stuff here */
672 return PE_EnumResourceNames32W(hmodule,type,lpfun,lParam);
675 /**********************************************************************
676 * EnumResourceLanguagesA (KERNEL32.86)
678 BOOL32 WINAPI EnumResourceLanguages32A( HMODULE32 hmodule, LPCSTR type,
679 LPCSTR name, ENUMRESLANGPROC32A lpfun,
680 LONG lParam)
682 /* FIXME: move WINE_MODREF stuff here */
683 return PE_EnumResourceLanguages32A(hmodule,type,name,lpfun,lParam);
685 /**********************************************************************
686 * EnumResourceLanguagesW (KERNEL32.87)
688 BOOL32 WINAPI EnumResourceLanguages32W( HMODULE32 hmodule, LPCWSTR type,
689 LPCWSTR name, ENUMRESLANGPROC32W lpfun,
690 LONG lParam)
692 /* FIXME: move WINE_MODREF stuff here */
693 return PE_EnumResourceLanguages32W(hmodule,type,name,lpfun,lParam);