Use a memory mapping instead of file I/O to load 16-bit modules.
[wine] / dlls / kernel / resource16.c
1 /*
2  * 16-bit resource functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1997 Alex Korobka
6  * Copyright 1998 Ulrich Weigand
7  * Copyright 1995, 2003 Alexandre Julliard
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wownt32.h"
36 #include "wine/winbase16.h"
37 #include "wine/winuser16.h"
38 #include "wine/unicode.h"
39 #include "kernel16_private.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(resource);
43
44 /* handle conversions */
45 #define HRSRC_32(h16)   ((HRSRC)(ULONG_PTR)(h16))
46 #define HGLOBAL_32(h16) ((HGLOBAL)(ULONG_PTR)(h16))
47
48 static inline NE_MODULE *get_module( HMODULE16 mod )
49 {
50     if (!mod) mod = TASK_GetCurrent()->hModule;
51     return NE_GetPtr( mod );
52 }
53
54 #define HRSRC_MAP_BLOCKSIZE 16
55
56 typedef struct _HRSRC_ELEM
57 {
58     HRSRC hRsrc;
59     WORD  type;
60 } HRSRC_ELEM;
61
62 typedef struct _HRSRC_MAP
63 {
64     int nAlloc;
65     int nUsed;
66     HRSRC_ELEM *elem;
67 } HRSRC_MAP;
68
69
70 /**********************************************************************
71  *          MapHRsrc32To16
72  */
73 static HRSRC16 MapHRsrc32To16( NE_MODULE *pModule, HRSRC hRsrc32, WORD type )
74 {
75     HRSRC_MAP *map = pModule->rsrc32_map;
76     HRSRC_ELEM *newElem;
77     int i;
78
79     /* On first call, initialize HRSRC map */
80     if ( !map )
81     {
82         if ( !(map = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HRSRC_MAP) ) ) )
83         {
84             ERR("Cannot allocate HRSRC map\n" );
85             return 0;
86         }
87         pModule->rsrc32_map = map;
88     }
89
90     /* Check whether HRSRC32 already in map */
91     for ( i = 0; i < map->nUsed; i++ )
92         if ( map->elem[i].hRsrc == hRsrc32 )
93             return (HRSRC16)(i + 1);
94
95     /* If no space left, grow table */
96     if ( map->nUsed == map->nAlloc )
97     {
98
99         if (map->elem)
100             newElem = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
101                     map->elem, (map->nAlloc + HRSRC_MAP_BLOCKSIZE) * sizeof(HRSRC_ELEM) );
102         else
103             newElem = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
104                     (map->nAlloc + HRSRC_MAP_BLOCKSIZE) * sizeof(HRSRC_ELEM) );
105
106         if ( !newElem )
107         {
108             ERR("Cannot grow HRSRC map\n" );
109             return 0;
110         }
111         map->elem = newElem;
112         map->nAlloc += HRSRC_MAP_BLOCKSIZE;
113     }
114
115     /* Add HRSRC32 to table */
116     map->elem[map->nUsed].hRsrc = hRsrc32;
117     map->elem[map->nUsed].type  = type;
118     map->nUsed++;
119
120     return (HRSRC16)map->nUsed;
121 }
122
123 /**********************************************************************
124  *          MapHRsrc16To32
125  */
126 static HRSRC MapHRsrc16To32( NE_MODULE *pModule, HRSRC16 hRsrc16 )
127 {
128     HRSRC_MAP *map = pModule->rsrc32_map;
129     if ( !map || !hRsrc16 || hRsrc16 > map->nUsed ) return 0;
130
131     return map->elem[hRsrc16-1].hRsrc;
132 }
133
134 /**********************************************************************
135  *          MapHRsrc16ToType
136  */
137 static WORD MapHRsrc16ToType( NE_MODULE *pModule, HRSRC16 hRsrc16 )
138 {
139     HRSRC_MAP *map = pModule->rsrc32_map;
140     if ( !map || !hRsrc16 || hRsrc16 > map->nUsed ) return 0;
141
142     return map->elem[hRsrc16-1].type;
143 }
144
145
146 /**********************************************************************
147  *          get_res_name
148  *
149  * Convert a resource name from '#xxx' form to numerical id.
150  */
151 static inline LPCSTR get_res_name( LPCSTR name )
152 {
153     if (HIWORD(name) && name[0] == '#') name = (LPCSTR)atoi( name + 1 );
154     return name;
155 }
156
157
158 /**********************************************************************
159  *          next_typeinfo
160  */
161 static inline NE_TYPEINFO *next_typeinfo( NE_TYPEINFO *info )
162 {
163     return (NE_TYPEINFO *)((char*)(info + 1) + info->count * sizeof(NE_NAMEINFO));
164 }
165
166
167 /**********************************************************************
168  *          get_default_res_handler
169  */
170 static inline FARPROC16 get_default_res_handler(void)
171 {
172     static FARPROC16 handler;
173
174     if (!handler) handler = GetProcAddress16( GetModuleHandle16("KERNEL"), "DefResourceHandler" );
175     return handler;
176 }
177
178
179 /***********************************************************************
180  *           NE_FindNameTableId
181  *
182  * Find the type and resource id from their names.
183  * Return value is MAKELONG( typeId, resId ), or 0 if not found.
184  */
185 static DWORD NE_FindNameTableId( NE_MODULE *pModule, LPCSTR typeId, LPCSTR resId )
186 {
187     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->ne_rsrctab + 2);
188     NE_NAMEINFO *pNameInfo;
189     HGLOBAL16 handle;
190     WORD *p;
191     DWORD ret = 0;
192     int count;
193
194     for (; pTypeInfo->type_id != 0;
195            pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo+1) +
196                                         pTypeInfo->count * sizeof(NE_NAMEINFO)))
197     {
198         if (pTypeInfo->type_id != 0x800f) continue;
199         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
200         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
201         {
202             TRACE("NameTable entry: type=%04x id=%04x\n",
203                               pTypeInfo->type_id, pNameInfo->id );
204             handle = LoadResource16( pModule->self,
205                                      (HRSRC16)((int)pNameInfo - (int)pModule) );
206             for(p = (WORD*)LockResource16(handle); p && *p; p = (WORD *)((char*)p+*p))
207             {
208                 TRACE("  type=%04x '%s' id=%04x '%s'\n",
209                                   p[1], (char *)(p+3), p[2],
210                                   (char *)(p+3)+strlen((char *)(p+3))+1 );
211                 /* Check for correct type */
212
213                 if (p[1] & 0x8000)
214                 {
215                     if (!HIWORD(typeId)) continue;
216                     if (strcasecmp( typeId, (char *)(p + 3) )) continue;
217                 }
218                 else if (HIWORD(typeId) || (((DWORD)typeId & ~0x8000)!= p[1]))
219                   continue;
220
221                 /* Now check for the id */
222
223                 if (p[2] & 0x8000)
224                 {
225                     if (!HIWORD(resId)) continue;
226                     if (strcasecmp( resId, (char*)(p+3)+strlen((char*)(p+3))+1 )) continue;
227
228                 }
229                 else if (HIWORD(resId) || (((DWORD)resId & ~0x8000) != p[2]))
230                   continue;
231
232                 /* If we get here, we've found the entry */
233
234                 TRACE("  Found!\n" );
235                 ret = MAKELONG( p[1], p[2] );
236                 break;
237             }
238             FreeResource16( handle );
239             if (ret) return ret;
240         }
241     }
242     return 0;
243 }
244
245
246 /***********************************************************************
247  *           NE_FindTypeSection
248  *
249  * Find header struct for a particular resource type.
250  */
251 static NE_TYPEINFO *NE_FindTypeSection( LPBYTE pResTab, NE_TYPEINFO *pTypeInfo, LPCSTR typeId )
252 {
253     /* start from pTypeInfo */
254
255     if (HIWORD(typeId) != 0)  /* Named type */
256     {
257         LPCSTR str = typeId;
258         BYTE len = strlen( str );
259         while (pTypeInfo->type_id)
260         {
261             if (!(pTypeInfo->type_id & 0x8000))
262             {
263                 BYTE *p = pResTab + pTypeInfo->type_id;
264                 if ((*p == len) && !strncasecmp( p+1, str, len ))
265                 {
266                     TRACE("  Found type '%s'\n", str );
267                     return pTypeInfo;
268                 }
269             }
270             TRACE("  Skipping type %04x\n", pTypeInfo->type_id );
271             pTypeInfo = next_typeinfo(pTypeInfo);
272         }
273     }
274     else  /* Numeric type id */
275     {
276         WORD id = LOWORD(typeId) | 0x8000;
277         while (pTypeInfo->type_id)
278         {
279             if (pTypeInfo->type_id == id)
280             {
281                 TRACE("  Found type %04x\n", id );
282                 return pTypeInfo;
283             }
284             TRACE("  Skipping type %04x\n", pTypeInfo->type_id );
285             pTypeInfo = next_typeinfo(pTypeInfo);
286         }
287     }
288     return NULL;
289 }
290
291
292 /***********************************************************************
293  *           NE_FindResourceFromType
294  *
295  * Find a resource once the type info structure has been found.
296  */
297 static NE_NAMEINFO *NE_FindResourceFromType( LPBYTE pResTab, NE_TYPEINFO *pTypeInfo, LPCSTR resId )
298 {
299     BYTE *p;
300     int count;
301     NE_NAMEINFO *pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
302
303     if (HIWORD(resId) != 0)  /* Named resource */
304     {
305         LPCSTR str = resId;
306         BYTE len = strlen( str );
307         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
308         {
309             if (pNameInfo->id & 0x8000) continue;
310             p = pResTab + pNameInfo->id;
311             if ((*p == len) && !strncasecmp( p+1, str, len ))
312                 return pNameInfo;
313         }
314     }
315     else  /* Numeric resource id */
316     {
317         WORD id = LOWORD(resId) | 0x8000;
318         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
319             if (pNameInfo->id == id) return pNameInfo;
320     }
321     return NULL;
322 }
323
324
325 /***********************************************************************
326  *           DefResourceHandler (KERNEL.456)
327  *
328  * This is the default LoadProc() function.
329  */
330 HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
331                                         HRSRC16 hRsrc )
332 {
333     HGLOBAL16 handle;
334     WORD sizeShift;
335     NE_NAMEINFO* pNameInfo;
336     NE_MODULE* pModule = NE_GetPtr( hModule );
337
338     if (!pModule) return 0;
339
340     sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
341     pNameInfo = (NE_NAMEINFO *)((char *)pModule + hRsrc);
342
343     if ( hMemObj )
344         handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
345     else
346         handle = AllocResource16( hModule, hRsrc, 0 );
347
348     if (handle)
349     {
350         if (pModule->ne_flags & NE_FFLAGS_BUILTIN)
351         {
352             /* NOTE: hRsrcMap points to start of built-in resource data */
353             memcpy( GlobalLock16( handle ),
354                     (char *)pModule->rsrc32_map + (pNameInfo->offset << sizeShift),
355                     pNameInfo->length << sizeShift );
356         }
357         else
358         {
359             if (!NE_READ_DATA( pModule, GlobalLock16( handle ),
360                                (int)pNameInfo->offset << sizeShift,
361                                (int)pNameInfo->length << sizeShift ))
362             {
363                 GlobalFree16( handle );
364                 handle = 0;
365             }
366         }
367     }
368     return handle;
369 }
370
371
372 /**********************************************************************
373  *      SetResourceHandler      (KERNEL.67)
374  */
375 FARPROC16 WINAPI SetResourceHandler16( HMODULE16 hModule, LPCSTR typeId, FARPROC16 resourceHandler )
376 {
377     LPBYTE pResTab;
378     NE_TYPEINFO *pTypeInfo;
379     FARPROC16 prevHandler = NULL;
380     NE_MODULE *pModule = NE_GetPtr( hModule );
381
382     if (!pModule || !pModule->ne_rsrctab) return NULL;
383
384     pResTab = (LPBYTE)pModule + pModule->ne_rsrctab;
385     pTypeInfo = (NE_TYPEINFO *)(pResTab + 2);
386
387     TRACE("module=%04x type=%s\n", hModule, debugstr_a(typeId) );
388
389     for (;;)
390     {
391         if (!(pTypeInfo = NE_FindTypeSection( pResTab, pTypeInfo, typeId )))
392             break;
393         memcpy_unaligned( &prevHandler, &pTypeInfo->resloader, sizeof(FARPROC16) );
394         memcpy_unaligned( &pTypeInfo->resloader, &resourceHandler, sizeof(FARPROC16) );
395         pTypeInfo = next_typeinfo(pTypeInfo);
396     }
397     if (!prevHandler) prevHandler = get_default_res_handler();
398     return prevHandler;
399 }
400
401 static inline DWORD get_dword(LPVOID *p)
402 {
403     DWORD ret = *(DWORD*)*p;
404     *p = (DWORD *)*p + 1;
405     return ret;
406 }
407
408 static inline void put_dword(LPVOID *p, DWORD d)
409 {
410     *(DWORD*)*p = d;
411     *p = (DWORD *)*p + 1;
412 }
413
414 static inline WORD get_word(LPVOID *p)
415 {
416     WORD ret = *(WORD*)*p;
417     *p = (WORD *)*p + 1;
418     return ret;
419 }
420
421 static inline void put_word(LPVOID *p, WORD w)
422 {
423     *(WORD*)*p = w;
424     *p = (WORD *)*p + 1;
425 }
426
427 static inline BYTE get_byte(LPVOID *p)
428 {
429     BYTE ret = *(BYTE *)*p;
430     *p = (BYTE *)*p + 1;
431     return ret;
432 }
433
434 static inline void put_byte(LPVOID *p, BYTE b)
435 {
436     *(BYTE *)*p = b;
437     *p = (BYTE *)*p + 1;
438 }
439
440 /* convert a resource name */
441 static void convert_name( LPVOID *dst, LPVOID *src )
442 {
443     int len;
444     switch (*((WORD *)*src))
445     {
446     case 0x0000:
447         get_word( src );
448         put_byte( dst, 0 );
449         break;
450     case 0xffff:
451         get_word( src );
452         put_byte( dst, 0xff );
453         put_word( dst, get_word(src) );
454         break;
455     default:
456         len = WideCharToMultiByte( CP_ACP, 0, *src, -1, *dst, 0x7fffffff, NULL,NULL );
457         *dst = (char *)*dst + len;
458         *src = (WCHAR *)*src + strlenW( (WCHAR *)*src ) + 1;
459         break;
460     }
461 }
462
463 /**********************************************************************
464  *          ConvertDialog32To16   (KERNEL.615)
465  */
466 VOID WINAPI ConvertDialog32To16( LPVOID dialog32, DWORD size, LPVOID dialog16 )
467 {
468     WORD nbItems, data, dialogEx;
469     DWORD style;
470
471     style = get_dword( &dialog32 );
472     put_dword( &dialog16, style );
473     dialogEx = (style == 0xffff0001);  /* DIALOGEX resource */
474     if (dialogEx)
475     {
476         put_dword( &dialog16, get_dword( &dialog32 ) );  /* helpID */
477         put_dword( &dialog16, get_dword( &dialog32 ) );  /* exStyle */
478         style = get_dword( &dialog32 );
479         put_dword( &dialog16, style );                   /* style */
480     }
481     else
482         dialog32 = (DWORD *)dialog32 + 1; /* exStyle ignored in 16-bit standard dialog */
483
484     nbItems = get_word( &dialog32 );
485     put_byte( &dialog16, nbItems );
486     put_word( &dialog16, get_word( &dialog32 ) ); /* x */
487     put_word( &dialog16, get_word( &dialog32 ) ); /* y */
488     put_word( &dialog16, get_word( &dialog32 ) ); /* cx */
489     put_word( &dialog16, get_word( &dialog32 ) ); /* cy */
490
491     /* Transfer menu name */
492     convert_name( &dialog16, &dialog32 );
493
494     /* Transfer class name */
495     convert_name( &dialog16, &dialog32 );
496
497     /* Transfer window caption */
498     WideCharToMultiByte( CP_ACP, 0, dialog32, -1, dialog16, 0x7fffffff, NULL, NULL );
499     dialog16 = (LPSTR)dialog16 + strlen( (LPSTR)dialog16 ) + 1;
500     dialog32 = (LPWSTR)dialog32 + strlenW( (LPWSTR)dialog32 ) + 1;
501
502     /* Transfer font info */
503     if (style & DS_SETFONT)
504     {
505         put_word( &dialog16, get_word( &dialog32 ) );  /* pointSize */
506         if (dialogEx)
507         {
508             put_word( &dialog16, get_word( &dialog32 ) ); /* weight */
509             put_word( &dialog16, get_word( &dialog32 ) ); /* italic */
510         }
511         WideCharToMultiByte( CP_ACP, 0, (LPWSTR)dialog32, -1, (LPSTR)dialog16, 0x7fffffff, NULL, NULL );  /* faceName */
512         dialog16 = (LPSTR)dialog16 + strlen( (LPSTR)dialog16 ) + 1;
513         dialog32 = (LPWSTR)dialog32 + strlenW( (LPWSTR)dialog32 ) + 1;
514     }
515
516     /* Transfer dialog items */
517     while (nbItems)
518     {
519         /* align on DWORD boundary (32-bit only) */
520         dialog32 = (LPVOID)((((int)dialog32) + 3) & ~3);
521
522         if (dialogEx)
523         {
524             put_dword( &dialog16, get_dword( &dialog32 ) ); /* helpID */
525             put_dword( &dialog16, get_dword( &dialog32 ) ); /* exStyle */
526             put_dword( &dialog16, get_dword( &dialog32 ) ); /* style */
527         }
528         else
529         {
530             style = get_dword( &dialog32 );    /* save style */
531             dialog32 = (DWORD *)dialog32 + 1;  /* ignore exStyle */
532         }
533
534         put_word( &dialog16, get_word( &dialog32 ) ); /* x */
535         put_word( &dialog16, get_word( &dialog32 ) ); /* y */
536         put_word( &dialog16, get_word( &dialog32 ) ); /* cx */
537         put_word( &dialog16, get_word( &dialog32 ) ); /* cy */
538
539         if (dialogEx)
540             put_dword( &dialog16, get_dword( &dialog32 ) ); /* ID */
541         else
542         {
543             put_word( &dialog16, get_word( &dialog32 ) ); /* ID */
544             put_dword( &dialog16, style );  /* style from above */
545         }
546
547         /* Transfer class name */
548         switch (*(WORD *)dialog32)
549         {
550         case 0x0000:
551             get_word( &dialog32 );
552             put_byte( &dialog16, 0 );
553             break;
554         case 0xffff:
555             get_word( &dialog32 );
556             put_byte( &dialog16, get_word( &dialog32 ) );
557             break;
558         default:
559             WideCharToMultiByte( CP_ACP, 0, (LPWSTR)dialog32, -1, (LPSTR)dialog16, 0x7fffffff, NULL, NULL );
560             dialog16 = (LPSTR)dialog16 + strlen( (LPSTR)dialog16 ) + 1;
561             dialog32 = (LPWSTR)dialog32 + strlenW( (LPWSTR)dialog32 ) + 1;
562             break;
563         }
564
565         /* Transfer window name */
566         convert_name( &dialog16, &dialog32 );
567
568         /* Transfer data */
569         data = get_word( &dialog32 );
570         if (dialogEx)
571             put_word(&dialog16, data);
572         else
573             put_byte(&dialog16,(BYTE)data);
574
575         if (data)
576         {
577             memcpy( dialog16, dialog32, data );
578             dialog16 = (BYTE *)dialog16 + data;
579             dialog32 = (BYTE *)dialog32 + data;
580         }
581
582         /* Next item */
583         nbItems--;
584     }
585 }
586
587
588 /**********************************************************************
589  *          GetDialog32Size   (KERNEL.618)
590  */
591 WORD WINAPI GetDialog32Size16( LPVOID dialog32 )
592 {
593     LPVOID p = dialog32;
594     WORD nbItems, data, dialogEx;
595     DWORD style;
596
597     style = get_dword(&p);
598     dialogEx = (style == 0xffff0001);  /* DIALOGEX resource */
599     if (dialogEx)
600     {
601         p = (DWORD *)p + 1; /* helpID */
602         p = (DWORD *)p + 1; /* exStyle */
603         style = get_dword(&p); /* style */
604     }
605     else
606         p = (DWORD *)p + 1; /* exStyle */
607
608     nbItems = get_word(&p);
609     p = (WORD *)p + 1; /* x */
610     p = (WORD *)p + 1; /* y */
611     p = (WORD *)p + 1; /* cx */
612     p = (WORD *)p + 1; /* cy */
613
614     /* Skip menu name */
615     switch (*((WORD *)p))
616     {
617     case 0x0000:  p = (WORD *)p + 1; break;
618     case 0xffff:  p = (WORD *)p + 2; break;
619     default:      p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1; break;
620     }
621
622     /* Skip class name */
623     switch (*((WORD *)p))
624     {
625     case 0x0000:  p = (WORD *)p + 1; break;
626     case 0xffff:  p = (WORD *)p + 2; break;
627     default:      p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1; break;
628     }
629
630     /* Skip window caption */
631     p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1;
632
633     /* Skip font info */
634     if (style & DS_SETFONT)
635     {
636         p = (WORD *)p + 1;  /* pointSize */
637         if (dialogEx)
638         {
639             p = (WORD *)p + 1; /* weight */
640             p = (WORD *)p + 1; /* italic */
641         }
642         p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1;  /* faceName */
643     }
644
645     /* Skip dialog items */
646     while (nbItems)
647     {
648         /* align on DWORD boundary */
649         p = (LPVOID)((((int)p) + 3) & ~3);
650
651         if (dialogEx)
652         {
653             p = (DWORD *)p + 1; /* helpID */
654             p = (DWORD *)p + 1; /* exStyle */
655             p = (DWORD *)p + 1; /* style */
656         }
657         else
658         {
659             p = (DWORD *)p + 1; /* style */
660             p = (DWORD *)p + 1; /* exStyle */
661         }
662
663         p = (WORD *)p + 1; /* x */
664         p = (WORD *)p + 1; /* y */
665         p = (WORD *)p + 1; /* cx */
666         p = (WORD *)p + 1; /* cy */
667
668         if (dialogEx)
669             p = (DWORD *)p + 1; /* ID */
670         else
671             p = (WORD *)p + 1; /* ID */
672
673         /* Skip class name */
674         switch (*((WORD *)p))
675         {
676         case 0x0000:  p = (WORD *)p + 1; break;
677         case 0xffff:  p = (WORD *)p + 2; break;
678         default:      p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1; break;
679         }
680
681         /* Skip window name */
682         switch (*((WORD *)p))
683         {
684         case 0x0000:  p = (WORD *)p + 1; break;
685         case 0xffff:  p = (WORD *)p + 2; break;
686         default:      p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1; break;
687         }
688
689         /* Skip data */
690         data = get_word(&p);
691         p = (BYTE *)p + data;
692
693         /* Next item */
694         nbItems--;
695     }
696
697     return (WORD)((LPSTR)p - (LPSTR)dialog32);
698 }
699
700
701 /**********************************************************************
702  *          ConvertMenu32To16   (KERNEL.616)
703  */
704 VOID WINAPI ConvertMenu32To16( LPVOID menu32, DWORD size, LPVOID menu16 )
705 {
706     WORD version, headersize, flags, level = 1;
707
708     version = get_word( &menu32 );
709     headersize = get_word( &menu32 );
710     put_word( &menu16, version );
711     put_word( &menu16, headersize );
712     if ( headersize )
713     {
714         memcpy( menu16, menu32, headersize );
715         menu16 = (BYTE *)menu16 + headersize;
716         menu32 = (BYTE *)menu32 + headersize;
717     }
718
719     while ( level )
720         if ( version == 0 )  /* standard */
721         {
722             flags = get_word( &menu32 );
723             put_word( &menu16, flags );
724             if ( !(flags & MF_POPUP) )
725                 put_word( &menu16, get_word( &menu32 ) );  /* ID */
726             else
727                 level++;
728
729             WideCharToMultiByte( CP_ACP, 0, (LPWSTR)menu32, -1, (LPSTR)menu16, 0x7fffffff, NULL, NULL );
730             menu16 = (LPSTR)menu16 + strlen( (LPSTR)menu16 ) + 1;
731             menu32 = (LPWSTR)menu32 + strlenW( (LPWSTR)menu32 ) + 1;
732
733             if ( flags & MF_END )
734                 level--;
735         }
736         else  /* extended */
737         {
738             put_dword( &menu16, get_dword( &menu32 ) );  /* fType */
739             put_dword( &menu16, get_dword( &menu32 ) );  /* fState */
740             put_word( &menu16, get_dword( &menu32 ) );   /* ID */
741             flags = get_word( &menu32 );
742             put_byte(&menu16,flags);
743
744             WideCharToMultiByte( CP_ACP, 0, (LPWSTR)menu32, -1, (LPSTR)menu16, 0x7fffffff, NULL, NULL );
745             menu16 = (LPSTR)menu16 + strlen( (LPSTR)menu16 ) + 1;
746             menu32 = (LPWSTR)menu32 + strlenW( (LPWSTR)menu32 ) + 1;
747
748             /* align on DWORD boundary (32-bit only) */
749             menu32 = (LPVOID)((((int)menu32) + 3) & ~3);
750
751             /* If popup, transfer helpid */
752             if ( flags & 1)
753             {
754                 put_dword( &menu16, get_dword( &menu32 ) );
755                 level++;
756             }
757
758             if ( flags & MF_END )
759                 level--;
760         }
761 }
762
763
764 /**********************************************************************
765  *          GetMenu32Size   (KERNEL.617)
766  */
767 WORD WINAPI GetMenu32Size16( LPVOID menu32 )
768 {
769     LPVOID p = menu32;
770     WORD version, headersize, flags, level = 1;
771
772     version = get_word(&p);
773     headersize = get_word(&p);
774     p = (BYTE *)p + headersize;
775
776     while ( level )
777         if ( version == 0 )  /* standard */
778         {
779             flags = get_word(&p);
780             if ( !(flags & MF_POPUP) )
781                 p = (WORD *)p + 1;  /* ID */
782             else
783                 level++;
784
785             p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1;
786
787             if ( flags & MF_END )
788                 level--;
789         }
790         else  /* extended */
791         {
792             p = (DWORD *)p + 1; /* fType */
793             p = (DWORD *)p + 1; /* fState */
794             p = (DWORD *)p + 1; /* ID */
795             flags = get_word(&p);
796
797             p = (LPWSTR)p + strlenW( (LPWSTR)p ) + 1;
798
799             /* align on DWORD boundary (32-bit only) */
800             p = (LPVOID)((((int)p) + 3) & ~3);
801
802             /* If popup, skip helpid */
803             if ( flags & 1)
804             {
805                 p = (DWORD *)p + 1;
806                 level++;
807             }
808
809             if ( flags & MF_END )
810                 level--;
811         }
812
813     return (WORD)((LPSTR)p - (LPSTR)menu32);
814 }
815
816
817 /**********************************************************************
818  *          ConvertAccelerator32To16
819  */
820 static void ConvertAccelerator32To16( LPVOID acc32, DWORD size, LPVOID acc16 )
821 {
822     BYTE type;
823
824     do
825     {
826         /* Copy type */
827         type = get_byte(&acc32);
828         put_byte(&acc16, type);
829         /* Skip padding */
830         get_byte(&acc32);
831         /* Copy event and IDval */
832         put_word(&acc16, get_word(&acc32));
833         put_word(&acc16, get_word(&acc32));
834         /* Skip padding */
835         get_word(&acc32);
836
837     } while ( !( type & 0x80 ) );
838 }
839
840
841 /**********************************************************************
842  *          NE_LoadPEResource
843  */
844 static HGLOBAL16 NE_LoadPEResource( NE_MODULE *pModule, WORD type, LPVOID bits, DWORD size )
845 {
846     HGLOBAL16 handle;
847
848     TRACE("module=%04x type=%04x\n", pModule->self, type );
849
850     handle = GlobalAlloc16( 0, size );
851
852     switch (type)
853     {
854     case RT_MENU:
855         ConvertMenu32To16( bits, size, GlobalLock16( handle ) );
856         break;
857     case RT_DIALOG:
858         ConvertDialog32To16( bits, size, GlobalLock16( handle ) );
859         break;
860     case RT_ACCELERATOR:
861         ConvertAccelerator32To16( bits, size, GlobalLock16( handle ) );
862         break;
863     case RT_STRING:
864         FIXME("not yet implemented!\n" );
865         /* fall through */
866     default:
867         memcpy( GlobalLock16( handle ), bits, size );
868         break;
869     }
870     return handle;
871 }
872
873
874 /**********************************************************************
875  *          AllocResource    (KERNEL.66)
876  */
877 HGLOBAL16 WINAPI AllocResource16( HMODULE16 hModule, HRSRC16 hRsrc, DWORD size)
878 {
879     NE_NAMEINFO *pNameInfo=NULL;
880     WORD sizeShift;
881     HGLOBAL16 ret;
882
883     NE_MODULE *pModule = NE_GetPtr( hModule );
884     if (!pModule || !pModule->ne_rsrctab || !hRsrc) return 0;
885
886     TRACE("module=%04x res=%04x size=%ld\n", hModule, hRsrc, size );
887
888     sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
889     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
890     if (size < (DWORD)pNameInfo->length << sizeShift)
891         size = (DWORD)pNameInfo->length << sizeShift;
892     ret = GlobalAlloc16( GMEM_FIXED, size );
893     if (ret) FarSetOwner16( ret, hModule );
894     return ret;
895 }
896
897
898 /**********************************************************************
899  *      DirectResAlloc    (KERNEL.168)
900  *
901  * Check Schulman, p. 232 for details
902  */
903 HGLOBAL16 WINAPI DirectResAlloc16( HINSTANCE16 hInstance, WORD wType,
904                                  UINT16 wSize )
905 {
906     HGLOBAL16 ret;
907     TRACE("(%04x,%04x,%04x)\n", hInstance, wType, wSize );
908     if (!(hInstance = GetExePtr( hInstance ))) return 0;
909     if(wType != 0x10)   /* 0x10 is the only observed value, passed from
910                            CreateCursorIndirect. */
911         TRACE("(wType=%x)\n", wType);
912     ret = GlobalAlloc16( GMEM_MOVEABLE, wSize );
913     if (ret) FarSetOwner16( ret, hInstance );
914     return ret;
915 }
916
917
918 /**********************************************************************
919  *          AccessResource (KERNEL.64)
920  */
921 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
922 {
923     HFILE16 fd;
924     NE_MODULE *pModule = NE_GetPtr( hModule );
925
926     if (!pModule || !pModule->ne_rsrctab || !hRsrc) return -1;
927
928     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
929
930     if ((fd = _lopen16( NE_MODULE_NAME(pModule), OF_READ )) != HFILE_ERROR16)
931     {
932         WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
933         NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
934         _llseek16( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
935     }
936     return fd;
937 }
938
939
940 /**********************************************************************
941  *          FindResource     (KERNEL.60)
942  */
943 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, LPCSTR name, LPCSTR type )
944 {
945     NE_TYPEINFO *pTypeInfo;
946     NE_NAMEINFO *pNameInfo;
947     LPBYTE pResTab;
948     NE_MODULE *pModule = get_module( hModule );
949
950     if (!pModule) return 0;
951
952     if (pModule->module32)
953     {
954         /* 32-bit PE module */
955         HRSRC hRsrc32 = FindResourceA( pModule->module32, name, type );
956         return MapHRsrc32To16( pModule, hRsrc32, HIWORD(type) ? 0 : LOWORD(type) );
957     }
958
959     TRACE("module=%04x name=%s type=%s\n", pModule->self, debugstr_a(name), debugstr_a(type) );
960
961     if (!pModule->ne_rsrctab) return 0;
962
963     type = get_res_name( type );
964     name = get_res_name( name );
965
966     if (HIWORD(type) || HIWORD(name))
967     {
968         DWORD id = NE_FindNameTableId( pModule, type, name );
969         if (id)  /* found */
970         {
971             type = (LPCSTR)(ULONG_PTR)LOWORD(id);
972             name = (LPCSTR)(ULONG_PTR)HIWORD(id);
973         }
974     }
975     pResTab = (LPBYTE)pModule + pModule->ne_rsrctab;
976     pTypeInfo = (NE_TYPEINFO *)( pResTab + 2 );
977
978     for (;;)
979     {
980         if (!(pTypeInfo = NE_FindTypeSection( pResTab, pTypeInfo, type ))) break;
981         if ((pNameInfo = NE_FindResourceFromType( pResTab, pTypeInfo, name )))
982         {
983             TRACE("    Found id %08lx\n", (DWORD)name );
984             return (HRSRC16)( (char *)pNameInfo - (char *)pModule );
985         }
986         pTypeInfo = next_typeinfo(pTypeInfo);
987     }
988     return 0;
989 }
990
991
992 /**********************************************************************
993  *          LoadResource     (KERNEL.61)
994  */
995 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
996 {
997     NE_TYPEINFO *pTypeInfo;
998     NE_NAMEINFO *pNameInfo = NULL;
999     NE_MODULE *pModule = get_module( hModule );
1000     int d;
1001
1002     if (!hRsrc || !pModule) return 0;
1003
1004     if (pModule->module32)
1005     {
1006         /* load 32-bit resource and convert it */
1007         HRSRC hRsrc32 = MapHRsrc16To32( pModule, hRsrc );
1008         WORD type     = MapHRsrc16ToType( pModule, hRsrc );
1009         HGLOBAL hMem  = LoadResource( pModule->module32, hRsrc32 );
1010         DWORD size    = SizeofResource( pModule->module32, hRsrc32 );
1011         if (!hMem) return 0;
1012         return NE_LoadPEResource( pModule, type, LockResource( hMem ), size );
1013     }
1014
1015     /* first, verify hRsrc (just an offset from pModule to the needed pNameInfo) */
1016
1017     d = pModule->ne_rsrctab + 2;
1018     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
1019     while( hRsrc > d )
1020     {
1021         if (pTypeInfo->type_id == 0) break; /* terminal entry */
1022         d += sizeof(NE_TYPEINFO) + pTypeInfo->count * sizeof(NE_NAMEINFO);
1023         if (hRsrc < d)
1024         {
1025             if( ((d - hRsrc)%sizeof(NE_NAMEINFO)) == 0 )
1026             {
1027                 pNameInfo = (NE_NAMEINFO *)((char *)pModule + hRsrc);
1028                 break;
1029             }
1030             else break; /* NE_NAMEINFO boundary mismatch */
1031         }
1032         pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
1033     }
1034
1035     if (pNameInfo)
1036     {
1037         if (pNameInfo->handle && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED))
1038         {
1039             pNameInfo->usage++;
1040             TRACE("  Already loaded, new count=%d\n", pNameInfo->usage );
1041         }
1042         else
1043         {
1044             FARPROC16 resloader;
1045             memcpy_unaligned( &resloader, &pTypeInfo->resloader, sizeof(FARPROC16) );
1046             if (resloader && resloader != get_default_res_handler())
1047             {
1048                 WORD args[3];
1049                 DWORD ret;
1050
1051                 args[2] = pNameInfo->handle;
1052                 args[1] = pModule->self;
1053                 args[0] = hRsrc;
1054                 WOWCallback16Ex( (DWORD)resloader, WCB16_PASCAL, sizeof(args), args, &ret );
1055                 pNameInfo->handle = LOWORD(ret);
1056             }
1057             else
1058                 pNameInfo->handle = NE_DefResourceHandler( pNameInfo->handle, pModule->self, hRsrc );
1059
1060             if (pNameInfo->handle)
1061             {
1062                 pNameInfo->usage++;
1063                 pNameInfo->flags |= NE_SEGFLAGS_LOADED;
1064             }
1065         }
1066         return pNameInfo->handle;
1067     }
1068     return 0;
1069 }
1070
1071
1072 /**********************************************************************
1073  *          LockResource   (KERNEL.62)
1074  */
1075 SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
1076 {
1077     TRACE("(%04x)\n", handle );
1078     /* May need to reload the resource if discarded */
1079     return K32WOWGlobalLock16( handle );
1080 }
1081
1082
1083 /**********************************************************************
1084  *          LockResource16 (KERNEL32.@)
1085  */
1086 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
1087 {
1088     return MapSL( WIN16_LockResource16(handle) );
1089 }
1090
1091
1092 /**********************************************************************
1093  *          SizeofResource   (KERNEL.65)
1094  */
1095 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
1096 {
1097     NE_MODULE *pModule = NE_GetPtr( hModule );
1098
1099     TRACE("(%x, %x)\n", hModule, hRsrc );
1100
1101     if (!hRsrc) return 0;
1102     if (!(pModule = get_module( hModule ))) return 0;
1103     if (pModule->ne_rsrctab)
1104     {
1105         WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
1106         NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
1107         return (DWORD)pNameInfo->length << sizeShift;
1108     }
1109     if (pModule->module32)
1110     {
1111         /* 32-bit PE module */
1112         return SizeofResource( pModule->module32, MapHRsrc16To32( pModule, hRsrc ) );
1113     }
1114     return 0;
1115 }
1116
1117
1118 typedef WORD (WINAPI *pDestroyIcon32Proc)( HGLOBAL16 handle, UINT16 flags );
1119
1120 /**********************************************************************
1121  *          FreeResource     (KERNEL.63)
1122  */
1123 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
1124 {
1125     pDestroyIcon32Proc proc;
1126     HMODULE user;
1127     NE_MODULE *pModule = NE_GetPtr( FarGetOwner16( handle ) );
1128
1129     TRACE("(%04x)\n", handle );
1130
1131     /* Try NE resource first */
1132
1133     if (pModule && pModule->ne_rsrctab)
1134     {
1135         NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->ne_rsrctab + 2);
1136         while (pTypeInfo->type_id)
1137         {
1138             WORD count;
1139             NE_NAMEINFO *pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
1140             for (count = pTypeInfo->count; count > 0; count--)
1141             {
1142                 if (pNameInfo->handle == handle)
1143                 {
1144                     if (pNameInfo->usage > 0) pNameInfo->usage--;
1145                     if (pNameInfo->usage == 0)
1146                     {
1147                         GlobalFree16( pNameInfo->handle );
1148                         pNameInfo->handle = 0;
1149                         pNameInfo->flags &= ~NE_SEGFLAGS_LOADED;
1150                     }
1151                     return 0;
1152                 }
1153                 pNameInfo++;
1154             }
1155             pTypeInfo = (NE_TYPEINFO *)pNameInfo;
1156         }
1157     }
1158
1159     /* If this failed, call USER.DestroyIcon32; this will check
1160        whether it is a shared cursor/icon; if not it will call
1161        GlobalFree16() */
1162     user = GetModuleHandleA( "user32.dll" );
1163     if (user && (proc = (pDestroyIcon32Proc)GetProcAddress( user, "DestroyIcon32" )))
1164         return proc( handle, 1 /*CID_RESOURCE*/ );
1165     else
1166         return GlobalFree16( handle );
1167 }