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