Solaris make doesn't like unnecessary \.
[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 "winbase.h"
16 #include "windef.h"
17 #include "winuser.h"
18 #include "wine/winbase16.h"
19 #include "wine/winuser16.h"
20 #include "ldt.h"
21 #include "global.h"
22 #include "heap.h"
23 #include "callback.h"
24 #include "cursoricon.h"
25 #include "neexe.h"
26 #include "task.h"
27 #include "process.h"
28 #include "module.h"
29 #include "file.h"
30 #include "debugtools.h"
31 #include "libres.h"
32 #include "winerror.h"
33 #include "debugstr.h"
34 #include "winnls.h"
35
36 DECLARE_DEBUG_CHANNEL(accel)
37 DECLARE_DEBUG_CHANNEL(resource)
38
39 extern WORD WINE_LanguageId;
40
41 #define HRSRC_MAP_BLOCKSIZE 16
42
43 typedef struct _HRSRC_ELEM
44 {
45     HANDLE hRsrc;
46     WORD     type;
47 } HRSRC_ELEM;
48
49 typedef struct _HRSRC_MAP
50 {
51     int nAlloc;
52     int nUsed;
53     HRSRC_ELEM *elem;
54 } HRSRC_MAP;
55
56 /**********************************************************************
57  *          MapHRsrc32To16
58  */
59 static HRSRC16 MapHRsrc32To16( NE_MODULE *pModule, HANDLE hRsrc32, WORD type )
60 {
61     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
62     HRSRC_ELEM *newElem;
63     int i;
64
65     /* On first call, initialize HRSRC map */
66     if ( !map )
67     {
68         if ( !(map = (HRSRC_MAP *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
69                                              sizeof(HRSRC_MAP) ) ) )
70         {
71             ERR_(resource)("Cannot allocate HRSRC map\n" );
72             return 0;
73         }
74         pModule->hRsrcMap = (LPVOID)map;
75     }
76
77     /* Check whether HRSRC32 already in map */
78     for ( i = 0; i < map->nUsed; i++ )
79         if ( map->elem[i].hRsrc == hRsrc32 )
80             return (HRSRC16)(i + 1);
81
82     /* If no space left, grow table */
83     if ( map->nUsed == map->nAlloc )
84     {
85         if ( !(newElem = (HRSRC_ELEM *)HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
86                                                     map->elem, 
87                                                     (map->nAlloc + HRSRC_MAP_BLOCKSIZE) 
88                                                     * sizeof(HRSRC_ELEM) ) ))
89         {
90             ERR_(resource)("Cannot grow HRSRC map\n" );
91             return 0;
92         }
93         map->elem = newElem;
94         map->nAlloc += HRSRC_MAP_BLOCKSIZE;
95     }
96
97     /* Add HRSRC32 to table */
98     map->elem[map->nUsed].hRsrc = hRsrc32;
99     map->elem[map->nUsed].type  = type;
100     map->nUsed++;
101
102     return (HRSRC16)map->nUsed;
103 }
104
105 /**********************************************************************
106  *          MapHRsrc16To32
107  */
108 static HANDLE MapHRsrc16To32( NE_MODULE *pModule, HRSRC16 hRsrc16 )
109 {
110     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
111     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
112
113     return map->elem[(int)hRsrc16-1].hRsrc;
114 }
115
116 /**********************************************************************
117  *          MapHRsrc16ToType
118  */
119 static WORD MapHRsrc16ToType( NE_MODULE *pModule, HRSRC16 hRsrc16 )
120 {
121     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
122     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
123
124     return map->elem[(int)hRsrc16-1].type;
125 }
126
127
128 /**********************************************************************
129  *          RES_FindResource
130  */
131 static HRSRC RES_FindResource( HMODULE hModule, LPCSTR type,
132                                LPCSTR name, WORD lang, 
133                                BOOL bUnicode, BOOL bRet16 )
134 {
135     HRSRC hRsrc = 0;
136
137     HMODULE16 hMod16   = MapHModuleLS( hModule );
138     NE_MODULE *pModule = NE_GetPtr( hMod16 );
139     WINE_MODREF *wm    = pModule && pModule->module32? 
140                          MODULE32_LookupHMODULE( pModule->module32 ) : NULL;
141
142     TRACE_(resource)("(%08x %s, %08x%s, %08x%s, %04x, %s, %s)\n",
143            hModule, pModule ? (char *)NE_MODULE_NAME(pModule) : "NULL dereference",
144            (UINT)type, HIWORD(type)? (bUnicode? debugstr_w((LPWSTR)type) : debugstr_a(type)) : "",
145            (UINT)name, HIWORD(name)? (bUnicode? debugstr_w((LPWSTR)name) : debugstr_a(name)) : "",
146            lang,
147            bUnicode? "W"  : "A",
148            bRet16?   "NE" : "PE" );
149
150     if ( !pModule ) return 0;
151
152     if ( wm )
153     {
154         /* 32-bit PE/ELF module */
155         LPWSTR typeStr, nameStr;
156
157         if ( HIWORD( type ) && !bUnicode )
158             typeStr = HEAP_strdupAtoW( GetProcessHeap(), 0, type );
159         else
160             typeStr = (LPWSTR)type;
161         if ( HIWORD( name ) && !bUnicode )
162             nameStr = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
163         else
164             nameStr = (LPWSTR)name;
165
166         switch ( wm->type ) 
167         {
168         case MODULE32_PE:
169             hRsrc = PE_FindResourceExW( wm, nameStr, typeStr, lang );
170             break;
171
172         case MODULE32_ELF:
173             hRsrc = LIBRES_FindResource( hModule, nameStr, typeStr );
174             break;
175         
176         default:
177             ERR_(resource)("unknown module type %d\n", wm->type );
178             break;
179         }
180
181         if ( HIWORD( type ) && !bUnicode ) 
182             HeapFree( GetProcessHeap(), 0, typeStr );
183         if ( HIWORD( name ) && !bUnicode ) 
184             HeapFree( GetProcessHeap(), 0, nameStr );
185
186
187         /* If we need to return 16-bit HRSRC, perform conversion */
188         if ( bRet16 )
189             hRsrc = MapHRsrc32To16( pModule, hRsrc, 
190                                     HIWORD( type )? 0 : LOWORD( type ) );
191     }
192     else
193     {
194         /* 16-bit NE module */
195         LPSTR typeStr, nameStr;
196
197         if ( HIWORD( type ) && bUnicode )
198             typeStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)type );
199         else
200             typeStr = (LPSTR)type;
201         if ( HIWORD( name ) && bUnicode )
202             nameStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)name );
203         else
204             nameStr = (LPSTR)name;
205
206         hRsrc = NE_FindResource( pModule, nameStr, typeStr );
207
208         if ( HIWORD( type ) && bUnicode ) 
209             HeapFree( GetProcessHeap(), 0, typeStr );
210         if ( HIWORD( name ) && bUnicode ) 
211             HeapFree( GetProcessHeap(), 0, nameStr );
212
213
214         /* If we need to return 32-bit HRSRC, no conversion is necessary,
215            we simply use the 16-bit HRSRC as 32-bit HRSRC */
216     }
217
218     return hRsrc;
219 }
220
221 /**********************************************************************
222  *          RES_SizeofResource
223  */
224 static DWORD RES_SizeofResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
225 {
226     DWORD size = 0;
227
228     HMODULE16 hMod16   = MapHModuleLS( hModule );
229     NE_MODULE *pModule = NE_GetPtr( hMod16 );
230     WINE_MODREF *wm    = pModule && pModule->module32? 
231                          MODULE32_LookupHMODULE( pModule->module32 ) : NULL;
232
233     TRACE_(resource)("(%08x %s, %08x, %s)\n",
234            hModule, NE_MODULE_NAME(pModule), hRsrc, bRet16? "NE" : "PE" );
235
236     if ( !pModule || !hRsrc ) return 0;
237
238     if ( wm )
239     {
240         /* 32-bit PE/ELF module */
241
242         /* If we got a 16-bit hRsrc, convert it */
243         HRSRC hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc );
244
245         switch ( wm->type ) 
246         {
247         case MODULE32_PE:
248             size = PE_SizeofResource( hModule, hRsrc32 );
249             break;
250
251         case MODULE32_ELF:
252             size = LIBRES_SizeofResource( hModule, hRsrc32 );
253             break;
254
255         default:
256             ERR_(resource)("unknown module type %d\n", wm->type );
257             break;
258         }
259     }
260     else
261     {
262         /* 16-bit NE module */
263
264         /* If we got a 32-bit hRsrc, we don't need to convert it */
265
266         size = NE_SizeofResource( pModule, hRsrc );
267     }
268
269     return size;
270 }
271
272 /**********************************************************************
273  *          RES_AccessResource
274  */
275 static HFILE RES_AccessResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
276 {
277     HFILE hFile = HFILE_ERROR;
278
279     HMODULE16 hMod16   = MapHModuleLS( hModule );
280     NE_MODULE *pModule = NE_GetPtr( hMod16 );
281     WINE_MODREF *wm    = pModule && pModule->module32? 
282                          MODULE32_LookupHMODULE( pModule->module32 ) : NULL;
283
284     TRACE_(resource)("(%08x %s, %08x, %s)\n",
285            hModule, NE_MODULE_NAME(pModule), hRsrc, bRet16? "NE" : "PE" );
286
287     if ( !pModule || !hRsrc ) return HFILE_ERROR;
288
289     if ( wm )
290     {
291         /* 32-bit PE/ELF module */
292 #if 0
293         /* If we got a 16-bit hRsrc, convert it */
294         HRSRC hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc );
295 #endif
296
297         FIXME_(resource)("32-bit modules not yet supported.\n" );
298         hFile = HFILE_ERROR;
299
300         /* If we need to return a 16-bit file handle, convert it */
301         if ( bRet16 )
302             hFile = FILE_AllocDosHandle( hFile );
303     }
304     else
305     {
306         /* 16-bit NE module */
307
308         /* If we got a 32-bit hRsrc, we don't need to convert it */
309
310         hFile = NE_AccessResource( pModule, hRsrc );
311
312         /* If we are to return a 32-bit file handle, convert it */
313         if ( !bRet16 )
314             hFile = FILE_GetHandle( hFile );
315     }
316
317     return hFile;
318 }
319
320 /**********************************************************************
321  *          RES_LoadResource
322  */
323 static HGLOBAL RES_LoadResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
324 {
325     HGLOBAL hMem = 0;
326
327     HMODULE16 hMod16   = MapHModuleLS( hModule );
328     NE_MODULE *pModule = NE_GetPtr( hMod16 );
329     WINE_MODREF *wm    = pModule && pModule->module32? 
330                          MODULE32_LookupHMODULE( pModule->module32 ) : NULL;
331
332     TRACE_(resource)("(%08x %s, %08x, %s)\n",
333            hModule, NE_MODULE_NAME(pModule), hRsrc, bRet16? "NE" : "PE" );
334
335     if ( !pModule || !hRsrc ) return 0;
336
337     if ( wm )
338     {
339         /* 32-bit PE/ELF module */
340
341         /* If we got a 16-bit hRsrc, convert it */
342         HRSRC hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc );
343
344         switch ( wm->type ) 
345         {
346         case MODULE32_PE:
347             hMem = PE_LoadResource( wm, hRsrc32 );
348             break;
349
350         case MODULE32_ELF:
351             hMem = LIBRES_LoadResource( hModule, hRsrc32 );
352             break;
353
354         default:
355             ERR_(resource)("unknown module type %d\n", wm->type );
356             break;
357         }
358
359         /* If we need to return a 16-bit resource, convert it */
360         if ( bRet16 )
361         {
362             WORD type   = MapHRsrc16ToType( pModule, hRsrc );
363             DWORD size  = SizeofResource( hModule, hRsrc );
364             LPVOID bits = LockResource( hMem );
365
366             hMem = NE_LoadPEResource( pModule, type, bits, size );
367         }
368     }
369     else
370     {
371         /* 16-bit NE module */
372
373         /* If we got a 32-bit hRsrc, we don't need to convert it */
374
375         hMem = NE_LoadResource( pModule, hRsrc );
376
377         /* If we are to return a 32-bit resource, we should probably
378            convert it but we don't for now.  FIXME !!! */
379     }
380
381     return hMem;
382 }
383
384 /**********************************************************************
385  *          RES_LockResource
386  */
387 static LPVOID RES_LockResource( HGLOBAL handle, BOOL bRet16 )
388 {
389     LPVOID bits = NULL;
390
391     TRACE_(resource)("(%08x, %s)\n", handle, bRet16? "NE" : "PE" );
392
393     if ( HIWORD( handle ) )
394     {
395         /* 32-bit memory handle */
396
397         if ( bRet16 )
398             FIXME_(resource)("can't return SEGPTR to 32-bit resource %08x.\n", handle );
399         else
400             bits = (LPVOID)handle;
401     }
402     else
403     {
404         /* 16-bit memory handle */
405
406         /* May need to reload the resource if discarded */
407         SEGPTR segPtr = WIN16_GlobalLock16( handle );
408         
409         if ( bRet16 )
410             bits = (LPVOID)segPtr;
411         else
412             bits = PTR_SEG_TO_LIN( segPtr );
413     }
414
415     return bits;
416 }
417
418 /**********************************************************************
419  *          RES_FreeResource
420  */
421 static BOOL RES_FreeResource( HGLOBAL handle )
422 {
423     HGLOBAL retv = handle;
424
425     TRACE_(resource)("(%08x)\n", handle );
426
427     if ( HIWORD( handle ) )
428     {
429         /* 32-bit memory handle: nothing to do */
430     }
431     else
432     {
433         /* 16-bit memory handle */
434         NE_MODULE *pModule = NE_GetPtr( FarGetOwner16( handle ) );
435
436         /* Try NE resource first */
437         retv = NE_FreeResource( pModule, handle );
438
439         /* If this failed, call USER.DestroyIcon32; this will check
440            whether it is a shared cursor/icon; if not it will call
441            GlobalFree16() */
442         if ( retv ) {
443             if ( Callout.DestroyIcon32 )
444                 retv = Callout.DestroyIcon32( handle, CID_RESOURCE );
445             else
446                 retv = GlobalFree16( handle );
447         }
448     }
449
450     return (BOOL)retv;
451 }
452
453
454 /**********************************************************************
455  *          FindResource16   (KERNEL.60)
456  */
457 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, SEGPTR name, SEGPTR type )
458 {
459     LPCSTR nameStr = HIWORD(name)? PTR_SEG_TO_LIN(name) : (LPCSTR)name;
460     LPCSTR typeStr = HIWORD(type)? PTR_SEG_TO_LIN(type) : (LPCSTR)type;
461
462     return RES_FindResource( hModule, typeStr, nameStr, 
463                              WINE_LanguageId, FALSE, TRUE );
464 }
465
466 /**********************************************************************
467  *          FindResourceA    (KERNEL32.128)
468  */
469 HANDLE WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
470 {
471     return RES_FindResource( hModule, type, name, 
472                              WINE_LanguageId, FALSE, FALSE );
473 }
474
475 /**********************************************************************
476  *          FindResourceExA  (KERNEL32.129)
477  */
478 HANDLE WINAPI FindResourceExA( HMODULE hModule, 
479                                LPCSTR type, LPCSTR name, WORD lang )
480 {
481     return RES_FindResource( hModule, type, name, 
482                              lang, FALSE, FALSE );
483 }
484
485 /**********************************************************************
486  *          FindResourceExW  (KERNEL32.130)
487  */
488 HRSRC WINAPI FindResourceExW( HMODULE hModule, 
489                               LPCWSTR type, LPCWSTR name, WORD lang )
490 {
491     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, 
492                              lang, TRUE, FALSE );
493 }
494
495 /**********************************************************************
496  *          FindResourceW    (KERNEL32.131)
497  */
498 HRSRC WINAPI FindResourceW(HINSTANCE hModule, LPCWSTR name, LPCWSTR type)
499 {
500     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name, 
501                              WINE_LanguageId, TRUE, FALSE );
502 }
503
504 /**********************************************************************
505  *          LoadResource16   (KERNEL.61)
506  */
507 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
508 {
509     return RES_LoadResource( hModule, hRsrc, TRUE );
510 }
511
512 /**********************************************************************
513  *          LoadResource     (KERNEL32.370)
514  */
515 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
516 {
517     return RES_LoadResource( hModule, hRsrc, FALSE );
518 }
519
520 /**********************************************************************
521  *          LockResource16   (KERNEL.62)
522  */
523 SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
524 {
525     return (SEGPTR)RES_LockResource( handle, TRUE );
526 }
527 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
528 {
529     return RES_LockResource( handle, FALSE );
530 }
531
532 /**********************************************************************
533  *          LockResource     (KERNEL32.384)
534  */
535 LPVOID WINAPI LockResource( HGLOBAL handle )
536 {
537     return RES_LockResource( handle, FALSE );
538 }
539
540 /**********************************************************************
541  *          FreeResource16   (KERNEL.63)
542  */
543 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
544 {
545     return RES_FreeResource( handle );
546 }
547
548 /**********************************************************************
549  *          FreeResource     (KERNEL32.145)
550  */
551 BOOL WINAPI FreeResource( HGLOBAL handle )
552 {
553     return RES_FreeResource( handle );
554 }
555
556 /**********************************************************************
557  *          AccessResource16 (KERNEL.64)
558  */
559 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
560 {
561     return RES_AccessResource( hModule, hRsrc, TRUE );
562 }
563
564 /**********************************************************************
565  *          AccessResource   (KERNEL32.64)
566  */
567 INT WINAPI AccessResource( HMODULE hModule, HRSRC hRsrc )
568 {
569     return RES_AccessResource( hModule, hRsrc, FALSE );
570 }
571
572 /**********************************************************************
573  *          SizeofResource16 (KERNEL.65)
574  */
575 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
576 {
577     return RES_SizeofResource( hModule, hRsrc, TRUE );
578 }
579
580 /**********************************************************************
581  *          SizeofResource   (KERNEL32.522)
582  */
583 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
584 {
585     return RES_SizeofResource( hModule, hRsrc, FALSE );
586 }
587
588
589
590 /**********************************************************************
591  *                      LoadAccelerators16      [USER.177]
592  */
593 HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName)
594 {
595     HRSRC16     hRsrc;
596
597     if (HIWORD(lpTableName))
598         TRACE_(accel)("%04x '%s'\n",
599                       instance, (char *)PTR_SEG_TO_LIN( lpTableName ) );
600     else
601         TRACE_(accel)("%04x %04x\n",
602                        instance, LOWORD(lpTableName) );
603
604     if (!(hRsrc = FindResource16( instance, lpTableName, RT_ACCELERATOR16 ))) {
605       WARN_(accel)("couldn't find accelerator table resource\n");
606       return 0;
607     }
608
609     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
610     return LoadResource16(instance,hRsrc);
611 }
612
613 /**********************************************************************
614  *                      LoadAccelerators32W     [USER.177]
615  * The image layout seems to look like this (not 100% sure):
616  * 00:  BYTE    type            type of accelerator
617  * 01:  BYTE    pad             (to WORD boundary)
618  * 02:  WORD    event
619  * 04:  WORD    IDval           
620  * 06:  WORD    pad             (to DWORD boundary)
621  */
622 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE instance,LPCWSTR lpTableName)
623 {
624     HRSRC hRsrc;
625     HACCEL hMem,hRetval=0;
626     DWORD size;
627
628     if (HIWORD(lpTableName))
629         TRACE_(accel)("%p '%s'\n",
630                       (LPVOID)instance, (char *)( lpTableName ) );
631     else
632         TRACE_(accel)("%p 0x%04x\n",
633                        (LPVOID)instance, LOWORD(lpTableName) );
634
635     if (!(hRsrc = FindResourceW( instance, lpTableName, RT_ACCELERATORW )))
636     {
637       WARN_(accel)("couldn't find accelerator table resource\n");
638     } else {
639       hMem = LoadResource( instance, hRsrc );
640       size = SizeofResource( instance, hRsrc );
641       if(size>=sizeof(PE_ACCEL))
642       {
643         LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
644         LPACCEL16 accel16;
645         int i,nrofaccells = size/sizeof(PE_ACCEL);
646
647         hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells);
648         accel16 = (LPACCEL16)GlobalLock16(hRetval);
649         for (i=0;i<nrofaccells;i++) {
650                 accel16[i].fVirt = accel_table[i].fVirt;
651                 accel16[i].key = accel_table[i].key;
652                 accel16[i].cmd = accel_table[i].cmd;
653         }
654         accel16[i-1].fVirt |= 0x80;
655       }
656     }
657     TRACE_(accel)("returning HACCEL 0x%x\n", hRsrc);
658     return hRetval;
659 }
660
661 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE instance,LPCSTR lpTableName)
662 {
663         LPWSTR   uni;
664         HACCEL result;
665         if (HIWORD(lpTableName))
666                 uni = HEAP_strdupAtoW( GetProcessHeap(), 0, lpTableName );
667         else
668                 uni = (LPWSTR)lpTableName;
669         result = LoadAcceleratorsW(instance,uni);
670         if (HIWORD(uni)) HeapFree( GetProcessHeap(), 0, uni);
671         return result;
672 }
673
674 /**********************************************************************
675  *             CopyAcceleratorTable32A   (USER32.58)
676  */
677 INT WINAPI CopyAcceleratorTableA(HACCEL src, LPACCEL dst, INT entries)
678 {
679   return CopyAcceleratorTableW(src, dst, entries);
680 }
681
682 /**********************************************************************
683  *             CopyAcceleratorTable32W   (USER32.59)
684  *
685  * By mortene@pvv.org 980321
686  */
687 INT WINAPI CopyAcceleratorTableW(HACCEL src, LPACCEL dst,
688                                      INT entries)
689 {
690   int i,xsize;
691   LPACCEL16 accel = (LPACCEL16)GlobalLock16(src);
692   BOOL done = FALSE;
693
694   /* Do parameter checking to avoid the explosions and the screaming
695      as far as possible. */
696   if((dst && (entries < 1)) || (src == (HACCEL)NULL) || !accel) {
697     WARN_(accel)("Application sent invalid parameters (%p %p %d).\n",
698          (LPVOID)src, (LPVOID)dst, entries);
699     return 0;
700   }
701   xsize = GlobalSize16(src)/sizeof(ACCEL16);
702   if (xsize>entries) entries=xsize;
703
704   i=0;
705   while(!done) {
706     /* Spit out some debugging information. */
707     TRACE_(accel)("accel %d: type 0x%02x, event '%c', IDval 0x%04x.\n",
708           i, accel[i].fVirt, accel[i].key, accel[i].cmd);
709
710     /* Copy data to the destination structure array (if dst == NULL,
711        we're just supposed to count the number of entries). */
712     if(dst) {
713       dst[i].fVirt = accel[i].fVirt;
714       dst[i].key = accel[i].key;
715       dst[i].cmd = accel[i].cmd;
716
717       /* Check if we've reached the end of the application supplied
718          accelerator table. */
719       if(i+1 == entries) {
720         /* Turn off the high order bit, just in case. */
721         dst[i].fVirt &= 0x7f;
722         done = TRUE;
723       }
724     }
725
726     /* The highest order bit seems to mark the end of the accelerator
727        resource table, but not always. Use GlobalSize() check too. */
728     if((accel[i].fVirt & 0x80) != 0) done = TRUE;
729
730     i++;
731   }
732
733   return i;
734 }
735
736 /*********************************************************************
737  *                    CreateAcceleratorTable   (USER32.64)
738  *
739  * By mortene@pvv.org 980321
740  */
741 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccel, INT cEntries)
742 {
743   HACCEL        hAccel;
744   LPACCEL16     accel;
745   int           i;
746
747   /* Do parameter checking just in case someone's trying to be
748      funny. */
749   if(cEntries < 1) {
750     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
751          lpaccel, cEntries);
752     SetLastError(ERROR_INVALID_PARAMETER);
753     return (HACCEL)NULL;
754   }
755   FIXME_(accel)("should check that the accelerator descriptions are valid,"
756         " return NULL and SetLastError() if not.\n");
757
758
759   /* Allocate memory and copy the table. */
760   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
761
762   TRACE_(accel)("handle %x\n", hAccel);
763   if(!hAccel) {
764     ERR_(accel)("Out of memory.\n");
765     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
766     return (HACCEL)NULL;
767   }
768   accel = GlobalLock16(hAccel);
769   for (i=0;i<cEntries;i++) {
770         accel[i].fVirt = lpaccel[i].fVirt;
771         accel[i].key = lpaccel[i].key;
772         accel[i].cmd = lpaccel[i].cmd;
773   }
774   /* Set the end-of-table terminator. */
775   accel[cEntries-1].fVirt |= 0x80;
776
777   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
778   return hAccel;
779 }
780
781 /*********************************************************************
782  *                    CreateAcceleratorTableW   (USER32.64)
783  *
784  * 
785  */
786 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccel, INT cEntries)
787 {
788   HACCEL        hAccel;
789   LPACCEL16     accel;
790   int           i;
791   char          ckey;  
792
793   /* Do parameter checking just in case someone's trying to be
794      funny. */
795   if(cEntries < 1) {
796     WARN_(accel)("Application sent invalid parameters (%p %d).\n",
797          lpaccel, cEntries);
798     SetLastError(ERROR_INVALID_PARAMETER);
799     return (HACCEL)NULL;
800   }
801   FIXME_(accel)("should check that the accelerator descriptions are valid,"
802         " return NULL and SetLastError() if not.\n");
803
804
805   /* Allocate memory and copy the table. */
806   hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
807
808   TRACE_(accel)("handle %x\n", hAccel);
809   if(!hAccel) {
810     ERR_(accel)("Out of memory.\n");
811     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
812     return (HACCEL)NULL;
813   }
814   accel = GlobalLock16(hAccel);
815
816
817   for (i=0;i<cEntries;i++) {
818        accel[i].fVirt = lpaccel[i].fVirt;
819        if( !(accel[i].fVirt & FVIRTKEY) ) {
820           ckey = (char) lpaccel[i].key;
821          if(!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, &ckey, 1, &accel[i].key, 1))
822             WARN_(accel)("Error converting ASCII accelerator table to Unicode");
823        }
824        else 
825          accel[i].key = lpaccel[i].key; 
826        accel[i].cmd = lpaccel[i].cmd;
827   }
828
829   /* Set the end-of-table terminator. */
830   accel[cEntries-1].fVirt |= 0x80;
831
832   TRACE_(accel)("Allocated accelerator handle %x\n", hAccel);
833   return hAccel;
834 }
835
836 /******************************************************************************
837  * DestroyAcceleratorTable [USER32.130]
838  * Destroys an accelerator table
839  *
840  * NOTES
841  *    By mortene@pvv.org 980321
842  *
843  * PARAMS
844  *    handle [I] Handle to accelerator table
845  *
846  * RETURNS STD
847  */
848 BOOL WINAPI DestroyAcceleratorTable( HACCEL handle )
849 {
850     return GlobalFree16(handle); 
851 }
852   
853 /**********************************************************************
854  *                                      LoadString16
855  */
856 INT16 WINAPI LoadString16( HINSTANCE16 instance, UINT16 resource_id,
857                            LPSTR buffer, INT16 buflen )
858 {
859     HGLOBAL16 hmem;
860     HRSRC16 hrsrc;
861     unsigned char *p;
862     int string_num;
863     int i;
864
865     TRACE_(resource)("inst=%04x id=%04x buff=%08x len=%d\n",
866                      instance, resource_id, (int) buffer, buflen);
867
868     hrsrc = FindResource16( instance, (SEGPTR)((resource_id>>4)+1), RT_STRING16 );
869     if (!hrsrc) return 0;
870     hmem = LoadResource16( instance, hrsrc );
871     if (!hmem) return 0;
872     
873     p = LockResource16(hmem);
874     string_num = resource_id & 0x000f;
875     for (i = 0; i < string_num; i++)
876         p += *p + 1;
877     
878     TRACE_(resource)("strlen = %d\n", (int)*p );
879     
880     if (buffer == NULL) return *p;
881     i = MIN(buflen - 1, *p);
882     if (i > 0) {
883         memcpy(buffer, p + 1, i);
884         buffer[i] = '\0';
885     } else {
886         if (buflen > 1) {
887             buffer[0] = '\0';
888             return 0;
889         }
890         WARN_(resource)("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
891     }
892     FreeResource16( hmem );
893
894     TRACE_(resource)("'%s' loaded !\n", buffer);
895     return i;
896 }
897
898 /**********************************************************************
899  *      LoadString32W           (USER32.376)
900  */
901 INT WINAPI LoadStringW( HINSTANCE instance, UINT resource_id,
902                             LPWSTR buffer, INT buflen )
903 {
904     HGLOBAL hmem;
905     HRSRC hrsrc;
906     WCHAR *p;
907     int string_num;
908     int i;
909
910     if (HIWORD(resource_id)==0xFFFF) /* netscape 3 passes this */
911         resource_id = (UINT)(-((INT)resource_id));
912     TRACE_(resource)("instance = %04x, id = %04x, buffer = %08x, "
913            "length = %d\n", instance, (int)resource_id, (int) buffer, buflen);
914
915     /* Use bits 4 - 19 (incremented by 1) as resourceid, mask out 
916      * 20 - 31. */
917     hrsrc = FindResourceW( instance, (LPCWSTR)(((resource_id>>4)&0xffff)+1),
918                              RT_STRINGW );
919     if (!hrsrc) return 0;
920     hmem = LoadResource( instance, hrsrc );
921     if (!hmem) return 0;
922     
923     p = LockResource(hmem);
924     string_num = resource_id & 0x000f;
925     for (i = 0; i < string_num; i++)
926         p += *p + 1;
927     
928     TRACE_(resource)("strlen = %d\n", (int)*p );
929     
930     if (buffer == NULL) return *p;
931     i = MIN(buflen - 1, *p);
932     if (i > 0) {
933         memcpy(buffer, p + 1, i * sizeof (WCHAR));
934         buffer[i] = (WCHAR) 0;
935     } else {
936         if (buflen > 1) {
937             buffer[0] = (WCHAR) 0;
938             return 0;
939         }
940 #if 0
941         WARN_(resource)("Dont know why caller give buflen=%d *p=%d trying to obtain string '%s'\n", buflen, *p, p + 1);
942 #endif
943     }
944
945     TRACE_(resource)("%s loaded !\n", debugstr_w(buffer));
946     return i;
947 }
948
949 /**********************************************************************
950  *      LoadString32A   (USER32.375)
951  */
952 INT WINAPI LoadStringA( HINSTANCE instance, UINT resource_id,
953                             LPSTR buffer, INT buflen )
954 {
955     INT retval;
956     LPWSTR buffer2 = NULL;
957     if (buffer && buflen)
958         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen * 2 );
959     retval = LoadStringW(instance,resource_id,buffer2,buflen);
960
961     if (buffer2)
962     {
963         if (retval) {
964             lstrcpynWtoA( buffer, buffer2, buflen );
965             retval = lstrlenA( buffer );
966         }
967         else
968             *buffer = 0;
969         HeapFree( GetProcessHeap(), 0, buffer2 );
970     }
971     return retval;
972 }
973
974 /* Messages...used by FormatMessage32* (KERNEL32.something)
975  * 
976  * They can be specified either directly or using a message ID and
977  * loading them from the resource.
978  * 
979  * The resourcedata has following format:
980  * start:
981  * 0: DWORD nrofentries
982  * nrofentries * subentry:
983  *      0: DWORD firstentry
984  *      4: DWORD lastentry
985  *      8: DWORD offset from start to the stringentries
986  *
987  * (lastentry-firstentry) * stringentry:
988  * 0: WORD len (0 marks end)
989  * 2: WORD flags
990  * 4: CHAR[len-4]
991  *      (stringentry i of a subentry refers to the ID 'firstentry+i')
992  *
993  * Yes, ANSI strings in win32 resources. Go figure.
994  */
995
996 /**********************************************************************
997  *      LoadMessage32A          (internal)
998  */
999 INT WINAPI LoadMessageA( HMODULE instance, UINT id, WORD lang,
1000                       LPSTR buffer, INT buflen )
1001 {
1002     HGLOBAL     hmem;
1003     HRSRC       hrsrc;
1004     PMESSAGE_RESOURCE_DATA      mrd;
1005     PMESSAGE_RESOURCE_BLOCK     mrb;
1006     PMESSAGE_RESOURCE_ENTRY     mre;
1007     int         i,slen;
1008
1009     TRACE_(resource)("instance = %08lx, id = %08lx, buffer = %p, length = %ld\n", (DWORD)instance, (DWORD)id, buffer, (DWORD)buflen);
1010
1011     /*FIXME: I am not sure about the '1' ... But I've only seen those entries*/
1012     hrsrc = FindResourceExW(instance,RT_MESSAGELISTW,(LPWSTR)1,lang);
1013     if (!hrsrc) return 0;
1014     hmem = LoadResource( instance, hrsrc );
1015     if (!hmem) return 0;
1016     
1017     mrd = (PMESSAGE_RESOURCE_DATA)LockResource(hmem);
1018     mre = NULL;
1019     mrb = &(mrd->Blocks[0]);
1020     for (i=mrd->NumberOfBlocks;i--;) {
1021         if ((id>=mrb->LowId) && (id<=mrb->HighId)) {
1022             mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mrd)+mrb->OffsetToEntries);
1023             id  -= mrb->LowId;
1024             break;
1025         }
1026         mrb++;
1027     }
1028     if (!mre)
1029         return 0;
1030     for (i=id;i--;) {
1031         if (!mre->Length)
1032                 return 0;
1033         mre = (PMESSAGE_RESOURCE_ENTRY)(((char*)mre)+(mre->Length));
1034     }
1035     slen=mre->Length;
1036     TRACE_(resource)("  - strlen=%d\n",slen);
1037     i = MIN(buflen - 1, slen);
1038     if (buffer == NULL)
1039         return slen;
1040     if (i>0) {
1041         lstrcpynA(buffer,(char*)mre->Text,i);
1042         buffer[i]=0;
1043     } else {
1044         if (buflen>1) {
1045             buffer[0]=0;
1046             return 0;
1047         }
1048     }
1049     if (buffer)
1050             TRACE_(resource)("'%s' copied !\n", buffer);
1051     return i;
1052 }
1053
1054 /**********************************************************************
1055  *      LoadMessage32W  (internal)
1056  */
1057 INT WINAPI LoadMessageW( HMODULE instance, UINT id, WORD lang,
1058                       LPWSTR buffer, INT buflen )
1059 {
1060     INT retval;
1061     LPSTR buffer2 = NULL;
1062     if (buffer && buflen)
1063         buffer2 = HeapAlloc( GetProcessHeap(), 0, buflen );
1064     retval = LoadMessageA(instance,id,lang,buffer2,buflen);
1065     if (buffer)
1066     {
1067         if (retval) {
1068             lstrcpynAtoW( buffer, buffer2, buflen );
1069             retval = lstrlenW( buffer );
1070         }
1071         HeapFree( GetProcessHeap(), 0, buffer2 );
1072     }
1073     return retval;
1074 }
1075
1076
1077 /**********************************************************************
1078  *      EnumResourceTypesA      (KERNEL32.90)
1079  */
1080 BOOL WINAPI EnumResourceTypesA( HMODULE hmodule,ENUMRESTYPEPROCA lpfun,
1081                                     LONG lParam)
1082 {
1083         /* FIXME: move WINE_MODREF stuff here */
1084     return PE_EnumResourceTypesA(hmodule,lpfun,lParam);
1085 }
1086
1087 /**********************************************************************
1088  *      EnumResourceTypesW      (KERNEL32.91)
1089  */
1090 BOOL WINAPI EnumResourceTypesW( HMODULE hmodule,ENUMRESTYPEPROCW lpfun,
1091                                     LONG lParam)
1092 {
1093         /* FIXME: move WINE_MODREF stuff here */
1094     return PE_EnumResourceTypesW(hmodule,lpfun,lParam);
1095 }
1096
1097 /**********************************************************************
1098  *      EnumResourceNamesA      (KERNEL32.88)
1099  */
1100 BOOL WINAPI EnumResourceNamesA( HMODULE hmodule, LPCSTR type,
1101                                     ENUMRESNAMEPROCA lpfun, LONG lParam )
1102 {
1103         /* FIXME: move WINE_MODREF stuff here */
1104     return PE_EnumResourceNamesA(hmodule,type,lpfun,lParam);
1105 }
1106 /**********************************************************************
1107  *      EnumResourceNamesW      (KERNEL32.89)
1108  */
1109 BOOL WINAPI EnumResourceNamesW( HMODULE hmodule, LPCWSTR type,
1110                                     ENUMRESNAMEPROCW lpfun, LONG lParam )
1111 {
1112         /* FIXME: move WINE_MODREF stuff here */
1113     return PE_EnumResourceNamesW(hmodule,type,lpfun,lParam);
1114 }
1115
1116 /**********************************************************************
1117  *      EnumResourceLanguagesA  (KERNEL32.86)
1118  */
1119 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmodule, LPCSTR type,
1120                                         LPCSTR name, ENUMRESLANGPROCA lpfun,
1121                                         LONG lParam)
1122 {
1123         /* FIXME: move WINE_MODREF stuff here */
1124     return PE_EnumResourceLanguagesA(hmodule,type,name,lpfun,lParam);
1125 }
1126 /**********************************************************************
1127  *      EnumResourceLanguagesW  (KERNEL32.87)
1128  */
1129 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmodule, LPCWSTR type,
1130                                         LPCWSTR name, ENUMRESLANGPROCW lpfun,
1131                                         LONG lParam)
1132 {
1133         /* FIXME: move WINE_MODREF stuff here */
1134     return PE_EnumResourceLanguagesW(hmodule,type,name,lpfun,lParam);
1135 }