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