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