Release 980413
[wine] / loader / resource.c
1 /*
2  * Resources
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include <stdio.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 "module.h"
22 #include "resource.h"
23 #include "debug.h"
24 #include "libres.h"
25 #include "winerror.h"
26
27 extern WORD WINE_LanguageId;
28
29 /* error message when 16-bit resource function is called for Win32 module */
30 static const char* NEWin32FailureString = "fails with Win32 module\n";
31 /* error message when 32-bit resource function is called for Win16 module */
32 static const char* PEWin16FailureString = "fails with Win16 module\n";
33
34 /**********************************************************************
35  *          FindResource16    (KERNEL.60)
36  */
37 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, SEGPTR name, SEGPTR type )
38 {
39     NE_MODULE *pModule;
40
41     hModule = MODULE_HANDLEtoHMODULE16( hModule ); 
42
43     if (HIWORD(name))  /* Check for '#xxx' name */
44     {
45         char *ptr = PTR_SEG_TO_LIN( name );
46         if (ptr[0] == '#')
47             if (!(name = (SEGPTR)atoi( ptr + 1 ))) {
48               WARN(resource, "Incorrect resource name: %s\n", ptr);
49               return 0;
50             }
51     }
52
53     if (HIWORD(type))  /* Check for '#xxx' type */
54     {
55         char *ptr = PTR_SEG_TO_LIN( type );
56         if (ptr[0] == '#')
57           if (!(type = (SEGPTR)atoi( ptr + 1 ))){
58             WARN(resource, "Incorrect resource type: %s\n", ptr);
59             return 0;
60           }
61     }
62
63     TRACE(resource, "module=%04x name=%s type=%s\n", 
64                  hModule, debugres_a(PTR_SEG_TO_LIN(name)), 
65                  debugres_a(PTR_SEG_TO_LIN(type)) );
66
67     if ((pModule = MODULE_GetPtr( hModule )))
68     {
69         if (!__winelib)
70         {
71             if (pModule->flags & NE_FFLAGS_WIN32)
72                 fprintf(stderr,"FindResource16: %s", NEWin32FailureString);
73             else
74                 return NE_FindResource( hModule, type, name );
75         }
76         else return LIBRES_FindResource16( hModule,
77                                            (LPCSTR)PTR_SEG_TO_LIN(name),
78                                            (LPCSTR)PTR_SEG_TO_LIN(type) );
79     }
80     return 0;
81 }
82
83
84 /**********************************************************************
85  *          FindResource32A    (KERNEL32.128)
86  */
87 HANDLE32 WINAPI FindResource32A( HINSTANCE32 hModule, LPCSTR name, LPCSTR type)
88 {
89     return FindResourceEx32A(hModule,name,type,WINE_LanguageId);
90 }
91
92 /**********************************************************************
93  *          FindResourceEx32A    (KERNEL32.129)
94  */
95 HANDLE32 WINAPI FindResourceEx32A( HINSTANCE32 hModule, LPCSTR name,
96                                    LPCSTR type, WORD lang )
97 {
98     LPWSTR xname,xtype;
99     HANDLE32 ret;
100
101     if (HIWORD((DWORD)name))
102         xname = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
103     else
104         xname = (LPWSTR)name;
105     if (HIWORD((DWORD)type))
106         xtype = HEAP_strdupAtoW( GetProcessHeap(), 0, type);
107     else
108         xtype = (LPWSTR)type;
109     ret = FindResourceEx32W( hModule, xname, xtype, lang );
110     if (HIWORD((DWORD)name)) HeapFree( GetProcessHeap(), 0, xname );
111     if (HIWORD((DWORD)type)) HeapFree( GetProcessHeap(), 0, xtype );
112     return ret;
113 }
114
115
116 /**********************************************************************
117  *          FindResourceEx32W    (KERNEL32.130)
118  */
119 HRSRC32 WINAPI FindResourceEx32W( HINSTANCE32 hModule, LPCWSTR name,
120                                   LPCWSTR type, WORD lang )
121 {
122     if (!__winelib)
123     {
124         NE_MODULE *pModule;
125
126         if (!hModule) hModule = GetTaskDS();
127         hModule = MODULE_HANDLEtoHMODULE32( hModule );
128         TRACE(resource, "module=%08x "
129                          "type=%s%p name=%s%p\n", hModule,
130                          (HIWORD(type))? "" : "#", type, 
131                          (HIWORD(name))? "" : "#", name);
132
133         if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
134         if (!(pModule->flags & NE_FFLAGS_WIN32)) return 0;
135         return PE_FindResourceEx32W(hModule,name,type,lang);
136     }
137     else return LIBRES_FindResource32( hModule, name, type );
138 }
139
140 /**********************************************************************
141  *          FindResource32W    (KERNEL32.131)
142  */
143 HRSRC32 WINAPI FindResource32W(HINSTANCE32 hModule, LPCWSTR name, LPCWSTR type)
144 {
145     return FindResourceEx32W(hModule,name,type,WINE_LanguageId);
146 }
147
148
149 /**********************************************************************
150  *          LoadResource16    (KERNEL.61)
151  */
152 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
153 {
154     NE_MODULE *pModule;
155
156     hModule = MODULE_HANDLEtoHMODULE16( hModule );
157     TRACE(resource, "module=%04x res=%04x\n",
158                      hModule, hRsrc );
159     if (!hRsrc) return 0;
160     if ((pModule = MODULE_GetPtr( hModule )))
161     {
162         if (!__winelib)
163         {
164             if (pModule->flags & NE_FFLAGS_WIN32)
165                 fprintf(stderr,"LoadResource16: %s", NEWin32FailureString);
166             else
167                 return NE_LoadResource( hModule, hRsrc );
168         }
169         else return LIBRES_LoadResource( hModule, hRsrc );
170     }
171     return 0;
172 }
173
174 /**********************************************************************
175  *          LoadResource32    (KERNEL32.370)
176  */
177 HGLOBAL32 WINAPI LoadResource32( HINSTANCE32 hModule, HRSRC32 hRsrc )
178 {
179     if (!__winelib)
180     {
181         NE_MODULE *pModule;
182
183         if (!hModule) hModule = GetTaskDS(); /* FIXME: see FindResource32W */
184         hModule = MODULE_HANDLEtoHMODULE32( hModule );
185         TRACE(resource, "module=%04x res=%04x\n",
186                          hModule, hRsrc );
187         if (!hRsrc) return 0;
188
189         if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
190         if (!(pModule->flags & NE_FFLAGS_WIN32))
191         {
192             fprintf(stderr,"LoadResource32: %s", PEWin16FailureString );
193             return 0;  /* FIXME? */
194         }
195         return PE_LoadResource32(hModule,hRsrc);
196     }
197     else return LIBRES_LoadResource( hModule, hRsrc );
198 }
199
200
201 /**********************************************************************
202  *          LockResource    (KERNEL.62)
203  */
204 /* 16-bit version */
205 SEGPTR WINAPI WIN16_LockResource16(HGLOBAL16 handle)
206 {
207     HMODULE16 hModule;
208     NE_MODULE *pModule;
209
210     TRACE(resource, "handle=%04x\n", handle );
211     if (!handle) return (SEGPTR)0;
212     hModule = MODULE_HANDLEtoHMODULE16( handle );
213     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
214     if (pModule->flags & NE_FFLAGS_WIN32)
215     {
216         fprintf(stderr,"LockResource16: %s", NEWin32FailureString);
217         return 0;
218     }
219     return NE_LockResource( hModule, handle );
220 }
221
222 /* Winelib 16-bit version */
223 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
224 {
225     if (!__winelib)
226     {
227         HMODULE16 hModule;
228         NE_MODULE *pModule;
229
230         TRACE(resource, "handle=%04x\n", handle );
231         if (!handle) return NULL;
232         hModule = MODULE_HANDLEtoHMODULE16( handle );
233         if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
234         if (pModule->flags & NE_FFLAGS_WIN32)
235         {
236             fprintf(stderr,"LockResource16: %s", NEWin32FailureString);
237             return 0;
238         }
239         return (LPSTR)PTR_SEG_TO_LIN( NE_LockResource( hModule, handle ) );
240     }
241     else return LIBRES_LockResource( handle );
242 }
243
244
245 /**********************************************************************
246  *          LockResource32    (KERNEL32.384)
247  */
248 LPVOID WINAPI LockResource32( HGLOBAL32 handle )
249 {
250     return (LPVOID)handle;
251 }
252
253
254 /**********************************************************************
255  *          FreeResource16    (KERNEL.63)
256  */
257 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
258 {
259     if (!__winelib)
260     {
261         HMODULE16 hModule;
262         NE_MODULE *pModule;
263
264         TRACE(resource, "handle=%04x\n", handle );
265         if (!handle) return FALSE;
266         hModule = MODULE_HANDLEtoHMODULE16( handle );
267         if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
268         if (pModule->flags & NE_FFLAGS_WIN32)
269         {
270             fprintf(stderr,"FreeResource16: %s", NEWin32FailureString);
271             return 0;
272         }
273         return NE_FreeResource( hModule, handle );
274     }
275     else return LIBRES_FreeResource( handle );
276 }
277
278 /**********************************************************************
279  *          FreeResource32    (KERNEL32.145)
280  */
281 BOOL32 WINAPI FreeResource32( HGLOBAL32 handle )
282 {
283     /* no longer used in Win32 */
284     return TRUE;
285 }
286
287
288 /**********************************************************************
289  *          AccessResource16    (KERNEL.64)
290  */
291 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
292 {
293     NE_MODULE *pModule;
294
295     hModule = MODULE_HANDLEtoHMODULE16( hModule );
296     TRACE(resource, "module=%04x res=%04x\n",
297                      hModule, hRsrc );
298     if (!hRsrc) return 0;
299     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
300     if (!__winelib)
301     {
302         if (pModule->flags & NE_FFLAGS_WIN32)
303         {
304             fprintf(stderr,"AccessResource16: %s", NEWin32FailureString);
305             return 0;
306         }
307         return NE_AccessResource( hModule, hRsrc );
308     }
309     else return LIBRES_AccessResource( hModule, hRsrc );
310 }
311
312
313 /**********************************************************************
314  *          AccessResource32    (KERNEL32.64)
315  */
316 INT32 WINAPI AccessResource32( HINSTANCE32 hModule, HRSRC32 hRsrc )
317 {
318     hModule = MODULE_HANDLEtoHMODULE32( hModule );
319     TRACE(resource, "module=%04x res=%04x\n",
320                      hModule, hRsrc );
321     if (!hRsrc) return 0;
322     fprintf(stderr,"AccessResource32: not implemented\n");
323     return 0;
324 }
325
326
327 /**********************************************************************
328  *          SizeofResource16    (KERNEL.65)
329  */
330 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
331 {
332     NE_MODULE *pModule;
333
334     hModule = MODULE_HANDLEtoHMODULE16( hModule );
335     TRACE(resource, "module=%04x res=%04x\n",
336                      hModule, hRsrc );
337     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
338     if (!__winelib)
339     {
340         if (pModule->flags & NE_FFLAGS_WIN32)
341         {
342             fprintf(stderr,"SizeOfResource16: %s", NEWin32FailureString);
343             return 0;
344         }
345         return NE_SizeofResource( hModule, hRsrc );
346     }
347     else return LIBRES_SizeofResource( hModule, hRsrc );
348 }
349
350
351 /**********************************************************************
352  *          SizeofResource32    (KERNEL32.522)
353  */
354 DWORD WINAPI SizeofResource32( HINSTANCE32 hModule, HRSRC32 hRsrc )
355 {
356     hModule = MODULE_HANDLEtoHMODULE32( hModule );
357     TRACE(resource, "module=%04x res=%04x\n",
358                      hModule, hRsrc );
359     if (!__winelib) return PE_SizeofResource32(hModule,hRsrc);
360     else
361     {
362         fprintf(stderr,"SizeofResource32: not implemented\n");
363         return 0;
364     }
365 }
366
367
368 /**********************************************************************
369  *          AllocResource16    (KERNEL.66)
370  */
371 HGLOBAL16 WINAPI AllocResource16( HMODULE16 hModule, HRSRC16 hRsrc, DWORD size)
372 {
373     NE_MODULE *pModule;
374
375     hModule = MODULE_HANDLEtoHMODULE16( hModule );
376     TRACE(resource, "module=%04x res=%04x size=%ld\n",
377                      hModule, hRsrc, size );
378     if (!hRsrc) return 0;
379     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
380     if (!__winelib)
381     {
382         if (pModule->flags & NE_FFLAGS_WIN32)
383         {
384             fprintf(stderr,"AllocResource16: %s", NEWin32FailureString);
385             return 0;
386         }
387         return NE_AllocResource( hModule, hRsrc, size );
388     }
389     else return LIBRES_AllocResource( hModule, hRsrc, size );
390 }
391
392 /**********************************************************************
393  *      DirectResAlloc    (KERNEL.168)
394  *
395  * Check Schulman, p. 232 for details
396  */
397 HGLOBAL16 WINAPI DirectResAlloc( HINSTANCE16 hInstance, WORD wType,
398                                  UINT16 wSize )
399 {
400     TRACE(resource,"(%04x,%04x,%04x)\n",
401                      hInstance, wType, wSize );
402     hInstance = MODULE_HANDLEtoHMODULE16(hInstance);
403     if(!hInstance)return 0;
404     if(wType != 0x10)   /* 0x10 is the only observed value, passed from
405                            CreateCursorIndirect. */
406         fprintf(stderr, "DirectResAlloc: wType = %x\n", wType);
407     return GLOBAL_Alloc(GMEM_MOVEABLE, wSize, hInstance, FALSE, FALSE, FALSE);
408 }
409
410
411 /**********************************************************************
412  *                      LoadAccelerators16      [USER.177]
413  */
414 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName)
415 {
416     HRSRC16     hRsrc;
417
418     if (HIWORD(lpTableName))
419         TRACE(accel, "%04x '%s'\n",
420                       instance, (char *)PTR_SEG_TO_LIN( lpTableName ) );
421     else
422         TRACE(accel, "%04x %04x\n",
423                        instance, LOWORD(lpTableName) );
424
425     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATOR16 ))) {
426       WARN(accel, "couldn't find accelerator table resource\n");
427       return 0;
428     }
429
430     TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
431     return LoadResource16(instance,hRsrc);
432 }
433
434 /**********************************************************************
435  *                      LoadAccelerators32W     [USER.177]
436  * The image layout seems to look like this (not 100% sure):
437  * 00:  BYTE    type            type of accelerator
438  * 01:  BYTE    pad             (to WORD boundary)
439  * 02:  WORD    event
440  * 04:  WORD    IDval           
441  * 06:  WORD    pad             (to DWORD boundary)
442  */
443 HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName)
444 {
445     HRSRC32 hRsrc;
446     HACCEL32 hRetval;
447
448     if (HIWORD(lpTableName))
449         TRACE(accel, "%p '%s'\n",
450                       (LPVOID)instance, (char *)( lpTableName ) );
451     else
452         TRACE(accel, "%p 0x%04x\n",
453                        (LPVOID)instance, LOWORD(lpTableName) );
454
455     if (!(hRsrc = FindResource32W( instance, lpTableName, RT_ACCELERATOR32W )))
456     {
457       WARN(accel, "couldn't find accelerator table resource\n");
458       hRetval = 0;
459     }
460     else {
461       hRetval = LoadResource32( instance, hRsrc );
462     }
463
464     TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
465     return hRetval;
466 }
467
468 HACCEL32 WINAPI LoadAccelerators32A(HINSTANCE32 instance,LPCSTR lpTableName)
469 {
470         LPWSTR   uni;
471         HACCEL32 result;
472         if (HIWORD(lpTableName))
473                 uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
474         else
475                 uni = (LPWSTR)lpTableName;
476         result = LoadAccelerators32W(instance,uni);
477         if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
478         return result;
479 }
480
481 /**********************************************************************
482  *             CopyAcceleratorTable32A   (USER32.58)
483  */
484 INT32 WINAPI CopyAcceleratorTable32A(HACCEL32 src, LPACCEL32 dst, INT32 entries)
485 {
486   return CopyAcceleratorTable32W(src, dst, entries);
487 }
488
489 /**********************************************************************
490  *             CopyAcceleratorTable32W   (USER32.59)
491  *
492  * By mortene@pvv.org 980321
493  */
494 INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
495                                      INT32 entries)
496 {
497   int i;
498   LPACCEL32 accel = (LPACCEL32)src;
499   BOOL32 done = FALSE;
500
501   /* Do parameter checking to avoid the explosions and the screaming
502      as far as possible. */
503   if((dst && (entries < 1)) || (src == (HACCEL32)NULL)) {
504     WARN(accel, "Application sent invalid parameters (%p %p %d).\n",
505          (LPVOID)src, (LPVOID)dst, entries);
506     return 0;
507   }
508
509
510   i=0;
511   while(!done) {
512     /* Spit out some debugging information. */
513     TRACE(accel, "accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
514           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
515
516     /* Copy data to the destination structure array (if dst == NULL,
517        we're just supposed to count the number of entries). */
518     if(dst) {
519       memcpy(&dst[i], &accel[i], sizeof(ACCEL32));
520
521       /* Check if we've reached the end of the application supplied
522          accelerator table. */
523       if(i+1 == entries) {
524         /* Turn off the high order bit, just in case. */
525         dst[i].fVirt &= 0x7f;
526         done = TRUE;
527       }
528     }
529
530     /* The highest order bit seems to mark the end of the accelerator
531        resource table. (?) */
532     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
533
534     i++;
535   }
536
537   return i;
538 }
539
540 /*********************************************************************
541  *                    CreateAcceleratorTable   (USER32.64)
542  *
543  * By mortene@pvv.org 980321
544  */
545 HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
546 {
547   HACCEL32 hAccel;
548
549   /* Do parameter checking just in case someone's trying to be
550      funny. */
551   if(cEntries < 1) {
552     WARN(accel, "Application sent invalid parameters (%p %d).\n",
553          lpaccel, cEntries);
554     SetLastError(ERROR_INVALID_PARAMETER);
555     return (HACCEL32)NULL;
556   }
557   FIXME(accel, "should check that the accelerator descriptions are valid,"
558         " return NULL and SetLastError() if not.\n");
559
560
561   /* Allocate memory and copy the table. */
562   hAccel = (HACCEL32)HeapAlloc(GetProcessHeap(), 0,
563                                cEntries * sizeof(ACCEL32));
564   TRACE(accel, "handle %p\n", (LPVOID)hAccel);
565   if(!hAccel) {
566     WARN(accel, "Out of memory.\n");
567     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
568     return (HACCEL32)NULL;
569   }
570   memcpy((LPACCEL32)hAccel, lpaccel, cEntries * sizeof(ACCEL32));
571
572   /* Set the end-of-table terminator. */
573   ((LPACCEL32)hAccel)[cEntries-1].fVirt |= 0x80;
574
575   TRACE(accel, "Allocated accelerator handle %x\n", hAccel);
576   return hAccel;
577 }
578
579 /**********************************************************************
580  *             DestroyAcceleratorTable   (USER32.130)
581  *
582  * By mortene@pvv.org 980321
583  */
584 BOOL32 WINAPI DestroyAcceleratorTable( HACCEL32 handle )
585 {
586   FIXME(accel, "stub (handle 0x%x)\n", handle);
587
588
589   /* Weird.. I thought this should work. According to the API
590      specification, DestroyAcceleratorTable() should only be called on
591      HACCEL32's made by CreateAcceleratorTable(), but Microsoft Visual
592      Studio 97 calls this function with a series of different handle
593      values without ever calling CreateAcceleratorTable(). Something
594      is very fishy in Denmark... */
595   /* Update: looks like the calls to this function matches the calls
596      to LoadAccelerators() in M$ Visual Studio, except that the handle
597      values are off by some variable size from the HACCEL's returned
598      from LoadAccelerators(). WTH? */
599   
600   /* Parameter checking to avoid any embarassing situations. */
601 /*   if(!handle) { */
602 /*     WARN(accel, "Application sent NULL ptr.\n"); */
603 /*     SetLastError(ERROR_INVALID_PARAMETER); */
604 /*     return FALSE; */
605 /*   } */
606   
607 /*   HeapFree(GetProcessHeap(), 0, (LPACCEL32)handle); */
608
609   return TRUE;
610 }
611   
612 /**********************************************************************
613  *                                      LoadString16
614  */
615 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
616                            LPSTR buffer, INT16 buflen )
617 {
618     HGLOBAL16 hmem;
619     HRSRC16 hrsrc;
620     unsigned char *p;
621     int string_num;
622     int i;
623
624     TRACE(resource,"inst=%04x id=%04x buff=%08x len=%d\n",
625                      instance, resource_id, (int) buffer, buflen);
626
627     hrsrc = FindResource16( instance, (SEGPTR)((resource_id>>4)+1), RT_STRING16 );
628     if (!hrsrc) return 0;
629     hmem = LoadResource16( instance, hrsrc );
630     if (!hmem) return 0;
631     
632     p = LockResource16(hmem);
633     string_num = resource_id & 0x000f;
634     for (i = 0; i < string_num; i++)
635         p += *p + 1;
636     
637     TRACE(resource, "strlen = %d\n", (int)*p );
638     
639     i = MIN(buflen - 1, *p);
640     if (buffer == NULL)
641         return i;
642     if (i > 0) {
643         memcpy(buffer, p + 1, i);
644         buffer[i] = '\0';
645     } else {
646         if (buflen > 1) {
647             buffer[0] = '\0';
648             return 0;
649         }
650         fprintf(stderr,"LoadString // I dont know why , but caller give buflen=%d *p=%d !\n", buflen, *p);
651         fprintf(stderr,"LoadString // and try to obtain string '%s'\n", p + 1);
652     }
653     FreeResource16( hmem );
654
655     TRACE(resource,"'%s' copied !\n", buffer);
656     return i;
657 }
658
659 /**********************************************************************
660  *      LoadString32W           (USER32.376)
661  */
662 INT32 WINAPI LoadString32W( HINSTANCE32 instance, UINT32 resource_id,
663                             LPWSTR buffer, INT32 buflen )
664 {
665     HGLOBAL32 hmem;
666     HRSRC32 hrsrc;
667     WCHAR *p;
668     int string_num;
669     int i;
670
671     if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
672         resource_id = (UINT32)(-((INT32)resource_id));
673     TRACE(resource, "instance = %04x, id = %04x, buffer = %08x, "
674            "length = %d\n", instance, (int)resource_id, (int) buffer, buflen);
675
676     hrsrc = FindResource32W( instance, (LPCWSTR)((resource_id>>4)+1),
677                              RT_STRING32W );
678     if (!hrsrc) return 0;
679     hmem = LoadResource32( instance, hrsrc );
680     if (!hmem) return 0;
681     
682     p = LockResource32(hmem);
683     string_num = resource_id & 0x000f;
684     for (i = 0; i < string_num; i++)
685         p += *p + 1;
686     
687     TRACE(resource, "strlen = %d\n", (int)*p );
688     
689     i = MIN(buflen - 1, *p);
690     if (buffer == NULL)
691         return i;
692     if (i > 0) {
693         memcpy(buffer, p + 1, i * sizeof (WCHAR));
694         buffer[i] = (WCHAR) 0;
695     } else {
696         if (buflen > 1) {
697             buffer[0] = (WCHAR) 0;
698             return 0;
699         }
700 #if 0
701         fprintf(stderr,"LoadString // I dont know why , but caller give buflen=%d *p=%d !\n", buflen, *p);
702         fprintf(stderr,"LoadString // and try to obtain string '%s'\n", p + 1);
703 #endif
704     }
705
706     TRACE(resource,"'%s' copied !\n", (char *)buffer);
707     return i;
708 }
709
710 /**********************************************************************
711  *      LoadString32A   (USER32.375)
712  */
713 INT32 WINAPI LoadString32A( HINSTANCE32 instance, UINT32 resource_id,
714                             LPSTR buffer, INT32 buflen )
715 {
716     INT32 retval;
717     LPWSTR buffer2 = NULL;
718     if (buffer && buflen)
719         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen * 2 );
720     retval = LoadString32W(instance,resource_id,buffer2,buflen);
721
722     if (buffer2)
723     {
724         if (retval) {
725             lstrcpynWtoA( buffer, buffer2, buflen );
726             retval = lstrlen32A( buffer );
727         }
728         else
729             *buffer = 0;
730         HeapFree( GetProcessHeap(), 0, buffer2 );
731     }
732     return retval;
733 }
734
735 /* Messages...used by FormatMessage32* (KERNEL32.something)
736  * 
737  * They can be specified either directly or using a message ID and
738  * loading them from the resource.
739  * 
740  * The resourcedata has following format:
741  * start:
742  * 0: DWORD nrofentries
743  * nrofentries * subentry:
744  *      0: DWORD firstentry
745  *      4: DWORD lastentry
746  *      8: DWORD offset from start to the stringentries
747  *
748  * (lastentry-firstentry) * stringentry:
749  * 0: WORD len (0 marks end)
750  * 2: WORD unknown (flags?)
751  * 4: CHAR[len-4]
752  *      (stringentry i of a subentry refers to the ID 'firstentry+i')
753  *
754  * Yes, ANSI strings in win32 resources. Go figure.
755  */
756
757 /**********************************************************************
758  *      LoadMessage32A          (internal)
759  */
760 INT32 LoadMessage32A( HINSTANCE32 instance, UINT32 id, WORD lang,
761                       LPSTR buffer, INT32 buflen )
762 {
763     HGLOBAL32   hmem;
764     HRSRC32     hrsrc;
765     BYTE        *p;
766     int         nrofentries,i,slen;
767     struct      _subentry {
768         DWORD   firstentry;
769         DWORD   lastentry;
770         DWORD   offset;
771     } *se;
772     struct      _stringentry {
773         WORD    len;
774         WORD    unknown;
775         CHAR    str[1];
776     } *stre;
777
778     TRACE(resource, "instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
779
780     /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
781     hrsrc = FindResourceEx32W(instance,(LPWSTR)1,RT_MESSAGELIST32W,lang);
782     if (!hrsrc) return 0;
783     hmem = LoadResource32( instance, hrsrc );
784     if (!hmem) return 0;
785     
786     p = LockResource32(hmem);
787     nrofentries = *(DWORD*)p;
788     stre = NULL;
789     se = (struct _subentry*)(p+4);
790     for (i=nrofentries;i--;) {
791         if ((id>=se->firstentry) && (id<=se->lastentry)) {
792             stre = (struct _stringentry*)(p+se->offset);
793             id  -= se->firstentry;
794             break;
795         }
796         se++;
797     }
798     if (!stre)
799         return 0;
800     for (i=id;i--;) {
801         if (!(slen=stre->len))
802                 return 0;
803         stre = (struct _stringentry*)(((char*)stre)+slen);
804     }
805     slen=stre->len;
806     TRACE(resource,"    - strlen=%d\n",slen);
807     i = MIN(buflen - 1, slen);
808     if (buffer == NULL)
809         return slen; /* different to LoadString */
810     if (i>0) {
811         lstrcpyn32A(buffer,stre->str,i);
812         buffer[i]=0;
813     } else {
814         if (buflen>1) {
815             buffer[0]=0;
816             return 0;
817         }
818     }
819     if (buffer)
820             TRACE(resource,"'%s' copied !\n", buffer);
821     return i;
822 }
823
824 /**********************************************************************
825  *      LoadMessage32W  (internal)
826  */
827 INT32 LoadMessage32W( HINSTANCE32 instance, UINT32 id, WORD lang,
828                       LPWSTR buffer, INT32 buflen )
829 {
830     INT32 retval;
831     LPSTR buffer2 = NULL;
832     if (buffer && buflen)
833         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
834     retval = LoadMessage32A(instance,id,lang,buffer2,buflen);
835     if (buffer)
836     {
837         if (retval) {
838             lstrcpynAtoW( buffer, buffer2, buflen );
839             retval = lstrlen32W( buffer );
840         }
841         HeapFree( GetProcessHeap(), 0, buffer2 );
842     }
843     return retval;
844 }
845
846
847 /**********************************************************************
848  *      SetResourceHandler      (KERNEL.43)
849  */
850 FARPROC16 WINAPI SetResourceHandler( HMODULE16 hModule, SEGPTR s,
851                                      FARPROC16 resourceHandler )
852 {
853     NE_MODULE *pModule;
854
855     hModule = GetExePtr( hModule );
856
857     TRACE(resource, "module=%04x type=%s\n", 
858                  hModule, debugres_a(PTR_SEG_TO_LIN(s)) );
859
860     if ((pModule = MODULE_GetPtr( hModule )))
861     {
862         if (pModule->flags & NE_FFLAGS_WIN32)
863             fprintf(stderr,"SetResourceHandler: %s\n", NEWin32FailureString);
864         else if (pModule->res_table)
865             return NE_SetResourceHandler( hModule, s, resourceHandler );
866     }
867     return NULL;
868 }
869
870
871 /**********************************************************************
872  *      EnumResourceTypesA      (KERNEL32.90)
873  */
874 BOOL32 WINAPI EnumResourceTypes32A( HMODULE32 hmodule,ENUMRESTYPEPROC32A lpfun,
875                                     LONG lParam)
876 {
877     return PE_EnumResourceTypes32A(hmodule,lpfun,lParam);
878 }
879
880 /**********************************************************************
881  *      EnumResourceTypesW      (KERNEL32.91)
882  */
883 BOOL32 WINAPI EnumResourceTypes32W( HMODULE32 hmodule,ENUMRESTYPEPROC32W lpfun,
884                                     LONG lParam)
885 {
886     return PE_EnumResourceTypes32W(hmodule,lpfun,lParam);
887 }
888
889 /**********************************************************************
890  *      EnumResourceNamesA      (KERNEL32.88)
891  */
892 BOOL32 WINAPI EnumResourceNames32A( HMODULE32 hmodule, LPCSTR type,
893                                     ENUMRESNAMEPROC32A lpfun, LONG lParam )
894 {
895     return PE_EnumResourceNames32A(hmodule,type,lpfun,lParam);
896 }
897 /**********************************************************************
898  *      EnumResourceNamesW      (KERNEL32.89)
899  */
900 BOOL32 WINAPI EnumResourceNames32W( HMODULE32 hmodule, LPCWSTR type,
901                                     ENUMRESNAMEPROC32W lpfun, LONG lParam )
902 {
903     return PE_EnumResourceNames32W(hmodule,type,lpfun,lParam);
904 }
905
906 /**********************************************************************
907  *      EnumResourceLanguagesA  (KERNEL32.86)
908  */
909 BOOL32 WINAPI EnumResourceLanguages32A( HMODULE32 hmodule, LPCSTR type,
910                                         LPCSTR name, ENUMRESLANGPROC32A lpfun,
911                                         LONG lParam)
912 {
913     return PE_EnumResourceLanguages32A(hmodule,type,name,lpfun,lParam);
914 }
915 /**********************************************************************
916  *      EnumResourceLanguagesW  (KERNEL32.87)
917  */
918 BOOL32 WINAPI EnumResourceLanguages32W( HMODULE32 hmodule, LPCWSTR type,
919                                         LPCWSTR name, ENUMRESLANGPROC32W lpfun,
920                                         LONG lParam)
921 {
922     return PE_EnumResourceLanguages32W(hmodule,type,name,lpfun,lParam);
923 }