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