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