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