Fix another error under Win9x (hopefully).
[wine] / dlls / kernel / ne_module.c
1 /*
2  * NE modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include <ctype.h>
34
35 #include "ntstatus.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "wine/winbase16.h"
39 #include "winerror.h"
40 #include "wownt32.h"
41 #include "wine/library.h"
42 #include "module.h"
43 #include "toolhelp.h"
44 #include "global.h"
45 #include "file.h"
46 #include "task.h"
47 #include "snoop.h"
48 #include "builtin16.h"
49 #include "stackframe.h"
50 #include "excpt.h"
51 #include "wine/exception.h"
52 #include "wine/debug.h"
53
54 WINE_DEFAULT_DEBUG_CHANNEL(module);
55 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
56
57 #include "pshpack1.h"
58 typedef struct _GPHANDLERDEF
59 {
60     WORD selector;
61     WORD rangeStart;
62     WORD rangeEnd;
63     WORD handler;
64 } GPHANDLERDEF;
65 #include "poppack.h"
66
67 /*
68  * Segment table entry
69  */
70 struct ne_segment_table_entry_s
71 {
72     WORD seg_data_offset;   /* Sector offset of segment data    */
73     WORD seg_data_length;   /* Length of segment data           */
74     WORD seg_flags;         /* Flags associated with this segment       */
75     WORD min_alloc;         /* Minimum allocation size for this */
76 };
77
78 #define hFirstModule (pThhook->hExeHead)
79
80 static NE_MODULE *pCachedModule = 0;  /* Module cached by NE_OpenFile */
81
82 typedef struct
83 {
84     void       *module_start;      /* 32-bit address of the module data */
85     int         module_size;       /* Size of the module data */
86     void       *code_start;        /* 32-bit address of DLL code */
87     void       *data_start;        /* 32-bit address of DLL data */
88     const char *owner;             /* 32-bit dll that contains this dll */
89     const void *rsrc;              /* resources data */
90 } BUILTIN16_DESCRIPTOR;
91
92 /* Table of all built-in DLLs */
93
94 #define MAX_DLLS 50
95
96 static const BUILTIN16_DESCRIPTOR *builtin_dlls[MAX_DLLS];
97
98
99 static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only );
100 static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep );
101
102 static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only );
103
104 static HMODULE16 NE_GetModuleByFilename( LPCSTR name );
105
106
107 static WINE_EXCEPTION_FILTER(page_fault)
108 {
109     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
110         GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
111         return EXCEPTION_EXECUTE_HANDLER;
112     return EXCEPTION_CONTINUE_SEARCH;
113 }
114
115
116 /* patch all the flat cs references of the code segment if necessary */
117 inline static void patch_code_segment( void *code_segment )
118 {
119 #ifdef __i386__
120     CALLFROM16 *call = code_segment;
121     if (call->flatcs == wine_get_cs()) return;  /* nothing to patch */
122     while (call->pushl == 0x68)
123     {
124         call->flatcs = wine_get_cs();
125         call++;
126     }
127 #endif
128 }
129
130
131 /***********************************************************************
132  *           find_dll_descr
133  *
134  * Find a descriptor in the list
135  */
136 static const BUILTIN16_DESCRIPTOR *find_dll_descr( const char *dllname )
137 {
138     int i;
139     for (i = 0; i < MAX_DLLS; i++)
140     {
141         const BUILTIN16_DESCRIPTOR *descr = builtin_dlls[i];
142         if (descr)
143         {
144             NE_MODULE *pModule = (NE_MODULE *)descr->module_start;
145             OFSTRUCT *pOfs = (OFSTRUCT *)((LPBYTE)pModule + pModule->fileinfo);
146             BYTE *name_table = (BYTE *)pModule + pModule->name_table;
147
148             /* check the dll file name */
149             if (!FILE_strcasecmp( pOfs->szPathName, dllname )) return descr;
150             /* check the dll module name (without extension) */
151             if (!FILE_strncasecmp( dllname, name_table+1, *name_table ) &&
152                 !strcmp( dllname + *name_table, ".dll" ))
153                 return descr;
154         }
155     }
156     return NULL;
157 }
158
159
160 /***********************************************************************
161  *           is_builtin_present
162  *
163  * Check if a builtin dll descriptor is present (because we loaded its 32-bit counterpart).
164  */
165 static BOOL is_builtin_present( LPCSTR name )
166 {
167     char dllname[20], *p;
168
169     if (strlen(name) >= sizeof(dllname)-4) return FALSE;
170     strcpy( dllname, name );
171     p = strrchr( dllname, '.' );
172     if (!p) strcat( dllname, ".dll" );
173     for (p = dllname; *p; p++) *p = FILE_tolower(*p);
174
175     return (find_dll_descr( dllname ) != NULL);
176 }
177
178
179 /***********************************************************************
180  *           __wine_register_dll_16 (KERNEL32.@)
181  *
182  * Register a built-in DLL descriptor.
183  */
184 void __wine_register_dll_16( const BUILTIN16_DESCRIPTOR *descr )
185 {
186     int i;
187
188     for (i = 0; i < MAX_DLLS; i++)
189     {
190         if (builtin_dlls[i]) continue;
191         builtin_dlls[i] = descr;
192         break;
193     }
194     assert( i < MAX_DLLS );
195 }
196
197
198 /***********************************************************************
199  *           __wine_unregister_dll_16 (KERNEL32.@)
200  *
201  * Unregister a built-in DLL descriptor.
202  */
203 void __wine_unregister_dll_16( const BUILTIN16_DESCRIPTOR *descr )
204 {
205     int i;
206
207     for (i = 0; i < MAX_DLLS; i++)
208     {
209         if (builtin_dlls[i] != descr) continue;
210         builtin_dlls[i] = NULL;
211         break;
212     }
213 }
214
215
216 /**********************************************************************
217  *           NE_RegisterModule
218  */
219 void NE_RegisterModule( NE_MODULE *pModule )
220 {
221     pModule->next = hFirstModule;
222     hFirstModule = pModule->self;
223 }
224
225
226 /***********************************************************************
227  *           NE_DumpModule
228  */
229 void NE_DumpModule( HMODULE16 hModule )
230 {
231     int i, ordinal;
232     SEGTABLEENTRY *pSeg;
233     BYTE *pstr;
234     WORD *pword;
235     NE_MODULE *pModule;
236     ET_BUNDLE *bundle;
237     ET_ENTRY *entry;
238
239     if (!(pModule = NE_GetPtr( hModule )))
240     {
241         MESSAGE( "**** %04x is not a module handle\n", hModule );
242         return;
243     }
244
245       /* Dump the module info */
246     DPRINTF( "---\n" );
247     DPRINTF( "Module %04x:\n", hModule );
248     DPRINTF( "count=%d flags=%04x heap=%d stack=%d\n",
249              pModule->count, pModule->flags,
250              pModule->heap_size, pModule->stack_size );
251     DPRINTF( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
252              pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
253              pModule->seg_count, pModule->modref_count );
254     DPRINTF( "os_flags=%d swap_area=%d version=%04x\n",
255              pModule->os_flags, pModule->min_swap_area,
256              pModule->expected_version );
257     if (pModule->flags & NE_FFLAGS_WIN32)
258         DPRINTF( "PE module=%p\n", pModule->module32 );
259
260       /* Dump the file info */
261     DPRINTF( "---\n" );
262     DPRINTF( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
263
264       /* Dump the segment table */
265     DPRINTF( "---\n" );
266     DPRINTF( "Segment table:\n" );
267     pSeg = NE_SEG_TABLE( pModule );
268     for (i = 0; i < pModule->seg_count; i++, pSeg++)
269         DPRINTF( "%02x: pos=%d size=%d flags=%04x minsize=%d hSeg=%04x\n",
270                  i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
271                  pSeg->minsize, pSeg->hSeg );
272
273       /* Dump the resource table */
274     DPRINTF( "---\n" );
275     DPRINTF( "Resource table:\n" );
276     if (pModule->res_table)
277     {
278         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
279         DPRINTF( "Alignment: %d\n", *pword++ );
280         while (*pword)
281         {
282             NE_TYPEINFO *ptr = (NE_TYPEINFO *)pword;
283             NE_NAMEINFO *pname = (NE_NAMEINFO *)(ptr + 1);
284             DPRINTF( "id=%04x count=%d\n", ptr->type_id, ptr->count );
285             for (i = 0; i < ptr->count; i++, pname++)
286                 DPRINTF( "offset=%d len=%d id=%04x\n",
287                       pname->offset, pname->length, pname->id );
288             pword = (WORD *)pname;
289         }
290     }
291     else DPRINTF( "None\n" );
292
293       /* Dump the resident name table */
294     DPRINTF( "---\n" );
295     DPRINTF( "Resident-name table:\n" );
296     pstr = (char *)pModule + pModule->name_table;
297     while (*pstr)
298     {
299         DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
300                  *(WORD *)(pstr + *pstr + 1) );
301         pstr += *pstr + 1 + sizeof(WORD);
302     }
303
304       /* Dump the module reference table */
305     DPRINTF( "---\n" );
306     DPRINTF( "Module ref table:\n" );
307     if (pModule->modref_table)
308     {
309         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
310         for (i = 0; i < pModule->modref_count; i++, pword++)
311         {
312             char name[10];
313             GetModuleName16( *pword, name, sizeof(name) );
314             DPRINTF( "%d: %04x -> '%s'\n", i, *pword, name );
315         }
316     }
317     else DPRINTF( "None\n" );
318
319       /* Dump the entry table */
320     DPRINTF( "---\n" );
321     DPRINTF( "Entry table:\n" );
322     bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);
323     do {
324         entry = (ET_ENTRY *)((BYTE *)bundle+6);
325         DPRINTF( "Bundle %d-%d: %02x\n", bundle->first, bundle->last, entry->type);
326         ordinal = bundle->first;
327         while (ordinal < bundle->last)
328         {
329             if (entry->type == 0xff)
330                 DPRINTF("%d: %02x:%04x (moveable)\n", ordinal++, entry->segnum, entry->offs);
331             else
332                 DPRINTF("%d: %02x:%04x (fixed)\n", ordinal++, entry->segnum, entry->offs);
333             entry++;
334         }
335     } while ( (bundle->next) && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
336
337     /* Dump the non-resident names table */
338     DPRINTF( "---\n" );
339     DPRINTF( "Non-resident names table:\n" );
340     if (pModule->nrname_handle)
341     {
342         pstr = (char *)GlobalLock16( pModule->nrname_handle );
343         while (*pstr)
344         {
345             DPRINTF( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
346                    *(WORD *)(pstr + *pstr + 1) );
347             pstr += *pstr + 1 + sizeof(WORD);
348         }
349     }
350     DPRINTF( "\n" );
351 }
352
353
354 /***********************************************************************
355  *           NE_WalkModules
356  *
357  * Walk the module list and print the modules.
358  */
359 void NE_WalkModules(void)
360 {
361     HMODULE16 hModule = hFirstModule;
362     MESSAGE( "Module Flags Name\n" );
363     while (hModule)
364     {
365         NE_MODULE *pModule = NE_GetPtr( hModule );
366         if (!pModule)
367         {
368             MESSAGE( "Bad module %04x in list\n", hModule );
369             return;
370         }
371         MESSAGE( " %04x  %04x  %.*s\n", hModule, pModule->flags,
372                  *((char *)pModule + pModule->name_table),
373                  (char *)pModule + pModule->name_table + 1 );
374         hModule = pModule->next;
375     }
376 }
377
378
379 /***********************************************************************
380  *           NE_InitResourceHandler
381  *
382  * Fill in 'resloader' fields in the resource table.
383  */
384 void NE_InitResourceHandler( NE_MODULE *pModule )
385 {
386     static FARPROC16 proc;
387
388     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
389
390     TRACE("InitResourceHandler[%04x]\n", pModule->self );
391
392     if (!proc) proc = GetProcAddress16( GetModuleHandle16("KERNEL"), "DefResourceHandler" );
393
394     while(pTypeInfo->type_id)
395     {
396         memcpy_unaligned( &pTypeInfo->resloader, &proc, sizeof(FARPROC16) );
397         pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo + 1) + pTypeInfo->count * sizeof(NE_NAMEINFO));
398     }
399 }
400
401
402 /***********************************************************************
403  *           NE_GetOrdinal
404  *
405  * Lookup the ordinal for a given name.
406  */
407 WORD NE_GetOrdinal( HMODULE16 hModule, const char *name )
408 {
409     unsigned char buffer[256], *cpnt;
410     BYTE len;
411     NE_MODULE *pModule;
412
413     if (!(pModule = NE_GetPtr( hModule ))) return 0;
414     if (pModule->flags & NE_FFLAGS_WIN32) return 0;
415
416     TRACE("(%04x,'%s')\n", hModule, name );
417
418       /* First handle names of the form '#xxxx' */
419
420     if (name[0] == '#') return atoi( name + 1 );
421
422       /* Now copy and uppercase the string */
423
424     strcpy( buffer, name );
425     for (cpnt = buffer; *cpnt; cpnt++) *cpnt = FILE_toupper(*cpnt);
426     len = cpnt - buffer;
427
428       /* First search the resident names */
429
430     cpnt = (char *)pModule + pModule->name_table;
431
432       /* Skip the first entry (module name) */
433     cpnt += *cpnt + 1 + sizeof(WORD);
434     while (*cpnt)
435     {
436         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
437         {
438             WORD ordinal;
439             memcpy( &ordinal, cpnt + *cpnt + 1, sizeof(ordinal) );
440             TRACE("  Found: ordinal=%d\n", ordinal );
441             return ordinal;
442         }
443         cpnt += *cpnt + 1 + sizeof(WORD);
444     }
445
446       /* Now search the non-resident names table */
447
448     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
449     cpnt = (char *)GlobalLock16( pModule->nrname_handle );
450
451       /* Skip the first entry (module description string) */
452     cpnt += *cpnt + 1 + sizeof(WORD);
453     while (*cpnt)
454     {
455         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
456         {
457             WORD ordinal;
458             memcpy( &ordinal, cpnt + *cpnt + 1, sizeof(ordinal) );
459             TRACE("  Found: ordinal=%d\n", ordinal );
460             return ordinal;
461         }
462         cpnt += *cpnt + 1 + sizeof(WORD);
463     }
464     return 0;
465 }
466
467
468 /***********************************************************************
469  *              NE_GetEntryPoint
470  */
471 FARPROC16 WINAPI NE_GetEntryPoint( HMODULE16 hModule, WORD ordinal )
472 {
473     return NE_GetEntryPointEx( hModule, ordinal, TRUE );
474 }
475
476 /***********************************************************************
477  *              NE_GetEntryPointEx
478  */
479 FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop )
480 {
481     NE_MODULE *pModule;
482     WORD sel, offset, i;
483
484     ET_ENTRY *entry;
485     ET_BUNDLE *bundle;
486
487     if (!(pModule = NE_GetPtr( hModule ))) return 0;
488     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
489
490     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
491     while ((ordinal < bundle->first + 1) || (ordinal > bundle->last))
492     {
493         if (!(bundle->next))
494             return 0;
495         bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next);
496     }
497
498     entry = (ET_ENTRY *)((BYTE *)bundle+6);
499     for (i=0; i < (ordinal - bundle->first - 1); i++)
500         entry++;
501
502     sel = entry->segnum;
503     memcpy( &offset, &entry->offs, sizeof(WORD) );
504
505     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
506     else sel = GlobalHandleToSel16(NE_SEG_TABLE(pModule)[sel-1].hSeg);
507     if (sel==0xffff)
508         return (FARPROC16)MAKESEGPTR( sel, offset );
509     if (!snoop)
510         return (FARPROC16)MAKESEGPTR( sel, offset );
511     else
512         return (FARPROC16)SNOOP16_GetProcAddress16(hModule,ordinal,(FARPROC16)MAKESEGPTR( sel, offset ));
513 }
514
515
516 /***********************************************************************
517  *              EntryAddrProc (KERNEL.667) Wine-specific export
518  *
519  * Return the entry point for a given ordinal.
520  */
521 FARPROC16 WINAPI EntryAddrProc16( HMODULE16 hModule, WORD ordinal )
522 {
523     FARPROC16 ret = NE_GetEntryPointEx( hModule, ordinal, TRUE );
524     CURRENT_STACK16->ecx = hModule; /* FIXME: might be incorrect value */
525     return ret;
526 }
527
528 /***********************************************************************
529  *           NE_SetEntryPoint
530  *
531  * Change the value of an entry point. Use with caution!
532  * It can only change the offset value, not the selector.
533  */
534 BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset )
535 {
536     NE_MODULE *pModule;
537     ET_ENTRY *entry;
538     ET_BUNDLE *bundle;
539     int i;
540
541     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
542     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
543
544     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
545     while ((ordinal < bundle->first + 1) || (ordinal > bundle->last))
546     {
547         bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next);
548         if (!(bundle->next)) return 0;
549     }
550
551     entry = (ET_ENTRY *)((BYTE *)bundle+6);
552     for (i=0; i < (ordinal - bundle->first - 1); i++)
553         entry++;
554
555     memcpy( &entry->offs, &offset, sizeof(WORD) );
556     return TRUE;
557 }
558
559
560 /***********************************************************************
561  *           NE_OpenFile
562  */
563 HANDLE NE_OpenFile( NE_MODULE *pModule )
564 {
565     HANDLE handle;
566     char *name;
567
568     TRACE("(%p)\n", pModule );
569     /* mjm - removed module caching because it keeps open file handles
570              thus preventing CDROMs from being ejected */
571     name = NE_MODULE_NAME( pModule );
572     if ((handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
573                                    NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
574         MESSAGE( "Can't open file '%s' for module %04x\n", name, pModule->self );
575     TRACE("opened '%s' -> %p\n", name, handle);
576     return handle;
577 }
578
579
580 /* wrapper for SetFilePointer and ReadFile */
581 static BOOL read_data( HANDLE handle, LONG offset, void *buffer, DWORD size )
582 {
583     DWORD result;
584
585     if (SetFilePointer( handle, offset, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) return FALSE;
586     if (!ReadFile( handle, buffer, size, &result, NULL )) return FALSE;
587     return (result == size);
588 }
589
590 /***********************************************************************
591  *           NE_LoadExeHeader
592  */
593 static HMODULE16 NE_LoadExeHeader( HANDLE handle, LPCSTR path )
594 {
595     IMAGE_DOS_HEADER mz_header;
596     IMAGE_OS2_HEADER ne_header;
597     int size;
598     HMODULE16 hModule;
599     NE_MODULE *pModule;
600     BYTE *pData, *pTempEntryTable;
601     char *buffer, *fastload = NULL;
602     int fastload_offset = 0, fastload_length = 0;
603     ET_ENTRY *entry;
604     ET_BUNDLE *bundle, *oldbundle;
605     OFSTRUCT *ofs;
606
607   /* Read a block from either the file or the fast-load area. */
608 #define READ(offset,size,buffer) \
609        ((fastload && ((offset) >= fastload_offset) && \
610          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
611         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
612          read_data( handle, (offset), (buffer), (size)))
613
614     if (!read_data( handle, 0, &mz_header, sizeof(mz_header)) ||
615         (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
616         return (HMODULE16)11;  /* invalid exe */
617
618     if (!read_data( handle, mz_header.e_lfanew, &ne_header, sizeof(ne_header) ))
619         return (HMODULE16)11;  /* invalid exe */
620
621     if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21;  /* win32 exe */
622     if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
623         MESSAGE("Sorry, this is an OS/2 linear executable (LX) file !\n");
624         return (HMODULE16)12;
625     }
626     if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)11;  /* invalid exe */
627
628     /* We now have a valid NE header */
629
630     size = sizeof(NE_MODULE) +
631              /* segment table */
632            ne_header.ne_cseg * sizeof(SEGTABLEENTRY) +
633              /* resource table */
634            ne_header.ne_restab - ne_header.ne_rsrctab +
635              /* resident names table */
636            ne_header.ne_modtab - ne_header.ne_restab +
637              /* module ref table */
638            ne_header.ne_cmod * sizeof(WORD) +
639              /* imported names table */
640            ne_header.ne_enttab - ne_header.ne_imptab +
641              /* entry table length */
642            ne_header.ne_cbenttab +
643              /* entry table extra conversion space */
644            sizeof(ET_BUNDLE) +
645            2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6) +
646              /* loaded file info */
647            sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1;
648
649     hModule = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, size );
650     if (!hModule) return (HMODULE16)11;  /* invalid exe */
651
652     FarSetOwner16( hModule, hModule );
653     pModule = (NE_MODULE *)GlobalLock16( hModule );
654     memcpy( pModule, &ne_header, sizeof(ne_header) );
655     pModule->count = 0;
656     /* check *programs* for default minimal stack size */
657     if ( (!(pModule->flags & NE_FFLAGS_LIBMODULE))
658          && (pModule->stack_size < 0x1400) )
659         pModule->stack_size = 0x1400;
660     pModule->module32 = 0;
661     pModule->self = hModule;
662     pModule->self_loading_sel = 0;
663     pData = (BYTE *)(pModule + 1);
664
665     /* Clear internal Wine flags in case they are set in the EXE file */
666
667     pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
668
669     /* Read the fast-load area */
670
671     if (ne_header.ne_flagsothers & NE_AFLAGS_FASTLOAD)
672     {
673         fastload_offset=ne_header.ne_pretthunks << ne_header.ne_align;
674         fastload_length=ne_header.ne_psegrefbytes << ne_header.ne_align;
675         TRACE("Using fast-load area offset=%x len=%d\n",
676                         fastload_offset, fastload_length );
677         if ((fastload = HeapAlloc( GetProcessHeap(), 0, fastload_length )) != NULL)
678         {
679             if (!read_data( handle, fastload_offset, fastload, fastload_length))
680             {
681                 HeapFree( GetProcessHeap(), 0, fastload );
682                 WARN("Error reading fast-load area!\n");
683                 fastload = NULL;
684             }
685         }
686     }
687
688     /* Get the segment table */
689
690     pModule->seg_table = pData - (BYTE *)pModule;
691     buffer = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cseg *
692                                       sizeof(struct ne_segment_table_entry_s));
693     if (buffer)
694     {
695         int i;
696         struct ne_segment_table_entry_s *pSeg;
697
698         if (!READ( mz_header.e_lfanew + ne_header.ne_segtab,
699              ne_header.ne_cseg * sizeof(struct ne_segment_table_entry_s),
700              buffer ))
701         {
702             HeapFree( GetProcessHeap(), 0, buffer );
703             if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
704             GlobalFree16( hModule );
705             return (HMODULE16)11;  /* invalid exe */
706         }
707         pSeg = (struct ne_segment_table_entry_s *)buffer;
708         for (i = ne_header.ne_cseg; i > 0; i--, pSeg++)
709         {
710             memcpy( pData, pSeg, sizeof(*pSeg) );
711             pData += sizeof(SEGTABLEENTRY);
712         }
713         HeapFree( GetProcessHeap(), 0, buffer );
714     }
715     else
716     {
717         if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
718         GlobalFree16( hModule );
719         return (HMODULE16)11;  /* invalid exe */
720     }
721
722     /* Get the resource table */
723
724     if (ne_header.ne_rsrctab < ne_header.ne_restab)
725     {
726         pModule->res_table = pData - (BYTE *)pModule;
727         if (!READ(mz_header.e_lfanew + ne_header.ne_rsrctab,
728                   ne_header.ne_restab - ne_header.ne_rsrctab,
729                   pData ))
730             return (HMODULE16)11;  /* invalid exe */
731         pData += ne_header.ne_restab - ne_header.ne_rsrctab;
732         NE_InitResourceHandler( pModule );
733     }
734     else pModule->res_table = 0;  /* No resource table */
735
736     /* Get the resident names table */
737
738     pModule->name_table = pData - (BYTE *)pModule;
739     if (!READ( mz_header.e_lfanew + ne_header.ne_restab,
740                ne_header.ne_modtab - ne_header.ne_restab,
741                pData ))
742     {
743         if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
744         GlobalFree16( hModule );
745         return (HMODULE16)11;  /* invalid exe */
746     }
747     pData += ne_header.ne_modtab - ne_header.ne_restab;
748
749     /* Get the module references table */
750
751     if (ne_header.ne_cmod > 0)
752     {
753         pModule->modref_table = pData - (BYTE *)pModule;
754         if (!READ( mz_header.e_lfanew + ne_header.ne_modtab,
755                   ne_header.ne_cmod * sizeof(WORD),
756                   pData ))
757         {
758             if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
759             GlobalFree16( hModule );
760             return (HMODULE16)11;  /* invalid exe */
761         }
762         pData += ne_header.ne_cmod * sizeof(WORD);
763     }
764     else pModule->modref_table = 0;  /* No module references */
765
766     /* Get the imported names table */
767
768     pModule->import_table = pData - (BYTE *)pModule;
769     if (!READ( mz_header.e_lfanew + ne_header.ne_imptab,
770                ne_header.ne_enttab - ne_header.ne_imptab,
771                pData ))
772     {
773         if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
774         GlobalFree16( hModule );
775         return (HMODULE16)11;  /* invalid exe */
776     }
777     pData += ne_header.ne_enttab - ne_header.ne_imptab;
778
779     /* Load entry table, convert it to the optimized version used by Windows */
780
781     if ((pTempEntryTable = HeapAlloc( GetProcessHeap(), 0, ne_header.ne_cbenttab)) != NULL)
782     {
783         BYTE nr_entries, type, *s;
784
785         TRACE("Converting entry table.\n");
786         pModule->entry_table = pData - (BYTE *)pModule;
787         if (!READ( mz_header.e_lfanew + ne_header.ne_enttab,
788                    ne_header.ne_cbenttab, pTempEntryTable ))
789         {
790             HeapFree( GetProcessHeap(), 0, pTempEntryTable );
791             if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
792             GlobalFree16( hModule );
793             return (HMODULE16)11;  /* invalid exe */
794         }
795
796         s = pTempEntryTable;
797         TRACE("entry table: offs %04x, len %04x, entries %d\n", ne_header.ne_enttab, ne_header.ne_cbenttab, *s);
798
799         bundle = (ET_BUNDLE *)pData;
800         TRACE("first bundle: %p\n", bundle);
801         memset(bundle, 0, sizeof(ET_BUNDLE)); /* in case no entry table exists */
802         entry = (ET_ENTRY *)((BYTE *)bundle+6);
803
804         while ((nr_entries = *s++))
805         {
806             if ((type = *s++))
807             {
808                 bundle->last += nr_entries;
809                 if (type == 0xff)
810                 while (nr_entries--)
811                 {
812                     entry->type   = type;
813                     entry->flags  = *s++;
814                     s += 2;
815                     entry->segnum = *s++;
816                     entry->offs   = *(WORD *)s; s += 2;
817                     /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/
818                     entry++;
819                 }
820                 else
821                 while (nr_entries--)
822                 {
823                     entry->type   = type;
824                     entry->flags  = *s++;
825                     entry->segnum = type;
826                     entry->offs   = *(WORD *)s; s += 2;
827                     /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/
828                     entry++;
829                 }
830             }
831             else
832             {
833                 if (bundle->first == bundle->last)
834                 {
835                     bundle->first += nr_entries;
836                     bundle->last += nr_entries;
837                 }
838                 else
839                 {
840                     oldbundle = bundle;
841                     oldbundle->next = ((int)entry - (int)pModule);
842                     bundle = (ET_BUNDLE *)entry;
843                     TRACE("new bundle: %p\n", bundle);
844                     bundle->first = bundle->last =
845                         oldbundle->last + nr_entries;
846                     bundle->next = 0;
847                     (BYTE *)entry += sizeof(ET_BUNDLE);
848                 }
849             }
850         }
851         HeapFree( GetProcessHeap(), 0, pTempEntryTable );
852     }
853     else
854     {
855         if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
856         GlobalFree16( hModule );
857         return (HMODULE16)11;  /* invalid exe */
858     }
859
860     pData += ne_header.ne_cbenttab + sizeof(ET_BUNDLE) +
861         2 * (ne_header.ne_cbenttab - ne_header.ne_cmovent*6);
862
863     if ((DWORD)entry > (DWORD)pData)
864        ERR("converted entry table bigger than reserved space !!!\nentry: %p, pData: %p. Please report !\n", entry, pData);
865
866     /* Store the filename information */
867
868     pModule->fileinfo = pData - (BYTE *)pModule;
869     size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(path) + 1;
870     ofs = (OFSTRUCT *)pData;
871     ofs->cBytes = size - 1;
872     ofs->fFixedDisk = 1;
873     strcpy( ofs->szPathName, path );
874     pData += size;
875
876     /* Free the fast-load area */
877
878 #undef READ
879     if (fastload) HeapFree( GetProcessHeap(), 0, fastload );
880
881     /* Get the non-resident names table */
882
883     if (ne_header.ne_cbnrestab)
884     {
885         pModule->nrname_handle = GlobalAlloc16( 0, ne_header.ne_cbnrestab );
886         if (!pModule->nrname_handle)
887         {
888             GlobalFree16( hModule );
889             return (HMODULE16)11;  /* invalid exe */
890         }
891         FarSetOwner16( pModule->nrname_handle, hModule );
892         buffer = GlobalLock16( pModule->nrname_handle );
893         if (!read_data( handle, ne_header.ne_nrestab, buffer, ne_header.ne_cbnrestab ))
894         {
895             GlobalFree16( pModule->nrname_handle );
896             GlobalFree16( hModule );
897             return (HMODULE16)11;  /* invalid exe */
898         }
899     }
900     else pModule->nrname_handle = 0;
901
902     /* Allocate a segment for the implicitly-loaded DLLs */
903
904     if (pModule->modref_count)
905     {
906         pModule->dlls_to_init = GlobalAlloc16( GMEM_ZEROINIT,
907                                                (pModule->modref_count+1)*sizeof(HMODULE16) );
908         if (!pModule->dlls_to_init)
909         {
910             if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
911             GlobalFree16( hModule );
912             return (HMODULE16)11;  /* invalid exe */
913         }
914         FarSetOwner16( pModule->dlls_to_init, hModule );
915     }
916     else pModule->dlls_to_init = 0;
917
918     NE_RegisterModule( pModule );
919     SNOOP16_RegisterDLL(pModule,path);
920     return hModule;
921 }
922
923
924 /***********************************************************************
925  *           NE_LoadDLLs
926  *
927  * Load all DLLs implicitly linked to a module.
928  */
929 static BOOL NE_LoadDLLs( NE_MODULE *pModule )
930 {
931     int i;
932     WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
933     WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
934
935     for (i = 0; i < pModule->modref_count; i++, pModRef++)
936     {
937         char buffer[260], *p;
938         BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
939         memcpy( buffer, pstr + 1, *pstr );
940         *(buffer + *pstr) = 0; /* terminate it */
941
942         TRACE("Loading '%s'\n", buffer );
943         if (!(*pModRef = GetModuleHandle16( buffer )))
944         {
945             /* If the DLL is not loaded yet, load it and store */
946             /* its handle in the list of DLLs to initialize.   */
947             HMODULE16 hDLL;
948
949             /* Append .DLL to name if no extension present */
950             if (!(p = strrchr( buffer, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
951                     strcat( buffer, ".DLL" );
952
953             if ((hDLL = MODULE_LoadModule16( buffer, TRUE, TRUE )) < 32)
954             {
955                 /* FIXME: cleanup what was done */
956
957                 MESSAGE( "Could not load '%s' required by '%.*s', error=%d\n",
958                      buffer, *((BYTE*)pModule + pModule->name_table),
959                      (char *)pModule + pModule->name_table + 1, hDLL );
960                 return FALSE;
961             }
962             *pModRef = GetExePtr( hDLL );
963             *pDLLs++ = *pModRef;
964         }
965         else  /* Increment the reference count of the DLL */
966         {
967             NE_MODULE *pOldDLL = NE_GetPtr( *pModRef );
968             if (pOldDLL) pOldDLL->count++;
969         }
970     }
971     return TRUE;
972 }
973
974
975 /**********************************************************************
976  *          NE_DoLoadModule
977  *
978  * Load first instance of NE module from file.
979  *
980  * pModule must point to a module structure prepared by NE_LoadExeHeader.
981  * This routine must never be called twice on a module.
982  *
983  */
984 static HINSTANCE16 NE_DoLoadModule( NE_MODULE *pModule )
985 {
986     /* Allocate the segments for this module */
987
988     if (!NE_CreateAllSegments( pModule ))
989         return ERROR_NOT_ENOUGH_MEMORY; /* 8 */
990
991     /* Load the referenced DLLs */
992
993     if (!NE_LoadDLLs( pModule ))
994         return ERROR_FILE_NOT_FOUND; /* 2 */
995
996     /* Load the segments */
997
998     NE_LoadAllSegments( pModule );
999
1000     /* Make sure the usage count is 1 on the first loading of  */
1001     /* the module, even if it contains circular DLL references */
1002
1003     pModule->count = 1;
1004
1005     return NE_GetInstance( pModule );
1006 }
1007
1008 /**********************************************************************
1009  *          NE_LoadModule
1010  *
1011  * Load first instance of NE module. (Note: caller is responsible for
1012  * ensuring the module isn't already loaded!)
1013  *
1014  * If the module turns out to be an executable module, only a
1015  * handle to a module stub is returned; this needs to be initialized
1016  * by calling NE_DoLoadModule later, in the context of the newly
1017  * created process.
1018  *
1019  * If lib_only is TRUE, however, the module is perforce treated
1020  * like a DLL module, even if it is an executable module.
1021  *
1022  */
1023 static HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL lib_only )
1024 {
1025     NE_MODULE *pModule;
1026     HMODULE16 hModule;
1027     HINSTANCE16 hInstance;
1028     HFILE16 hFile;
1029     OFSTRUCT ofs;
1030
1031     /* Open file */
1032     if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
1033         return (HMODULE16)2;  /* File not found */
1034
1035     hModule = NE_LoadExeHeader( DosFileHandleToWin32Handle(hFile), ofs.szPathName );
1036     _lclose16( hFile );
1037     if (hModule < 32) return hModule;
1038
1039     pModule = NE_GetPtr( hModule );
1040     if ( !pModule ) return hModule;
1041
1042     if ( !lib_only && !( pModule->flags & NE_FFLAGS_LIBMODULE ) )
1043         return hModule;
1044
1045     hInstance = NE_DoLoadModule( pModule );
1046     if ( hInstance < 32 )
1047     {
1048         /* cleanup ... */
1049         NE_FreeModule( hModule, 0 );
1050     }
1051
1052     return hInstance;
1053 }
1054
1055
1056 /***********************************************************************
1057  *           NE_DoLoadBuiltinModule
1058  *
1059  * Load a built-in Win16 module. Helper function for NE_LoadBuiltinModule.
1060  */
1061 static HMODULE16 NE_DoLoadBuiltinModule( const BUILTIN16_DESCRIPTOR *descr )
1062 {
1063     NE_MODULE *pModule;
1064     int minsize;
1065     SEGTABLEENTRY *pSegTable;
1066     HMODULE16 hModule;
1067
1068     hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, descr->module_start,
1069                                   descr->module_size, 0, WINE_LDT_FLAGS_DATA );
1070     if (!hModule) return 0;
1071     FarSetOwner16( hModule, hModule );
1072
1073     pModule = (NE_MODULE *)GlobalLock16( hModule );
1074     pModule->self = hModule;
1075     /* NOTE: (Ab)use the hRsrcMap parameter for resource data pointer */
1076     pModule->hRsrcMap = (void *)descr->rsrc;
1077
1078     /* Allocate the code segment */
1079
1080     pSegTable = NE_SEG_TABLE( pModule );
1081     pSegTable->hSeg = GLOBAL_CreateBlock( GMEM_FIXED, descr->code_start,
1082                                           pSegTable->minsize, hModule,
1083                                           WINE_LDT_FLAGS_CODE|WINE_LDT_FLAGS_32BIT );
1084     if (!pSegTable->hSeg) return 0;
1085     patch_code_segment( descr->code_start );
1086     pSegTable++;
1087
1088     /* Allocate the data segment */
1089
1090     minsize = pSegTable->minsize ? pSegTable->minsize : 0x10000;
1091     minsize += pModule->heap_size;
1092     if (minsize > 0x10000) minsize = 0x10000;
1093     pSegTable->hSeg = GlobalAlloc16( GMEM_FIXED, minsize );
1094     if (!pSegTable->hSeg) return 0;
1095     FarSetOwner16( pSegTable->hSeg, hModule );
1096     if (pSegTable->minsize) memcpy( GlobalLock16( pSegTable->hSeg ),
1097                                     descr->data_start, pSegTable->minsize);
1098     if (pModule->heap_size)
1099         LocalInit16( GlobalHandleToSel16(pSegTable->hSeg), pSegTable->minsize, minsize );
1100
1101     if (descr->rsrc) NE_InitResourceHandler(pModule);
1102
1103     NE_RegisterModule( pModule );
1104
1105     /* make sure the 32-bit library containing this one is loaded too */
1106     LoadLibraryA( descr->owner );
1107
1108     return hModule;
1109 }
1110
1111
1112 /***********************************************************************
1113  *           NE_LoadBuiltinModule
1114  *
1115  * Load a built-in module.
1116  */
1117 static HMODULE16 NE_LoadBuiltinModule( LPCSTR name )
1118 {
1119     const BUILTIN16_DESCRIPTOR *descr;
1120     char error[256], dllname[20], *p;
1121     int file_exists;
1122     void *handle;
1123
1124     /* Fix the name in case we have a full path and extension */
1125
1126     if ((p = strrchr( name, '\\' ))) name = p + 1;
1127     if ((p = strrchr( name, '/' ))) name = p + 1;
1128
1129     if (strlen(name) >= sizeof(dllname)-4) return (HMODULE16)2;
1130
1131     strcpy( dllname, name );
1132     p = strrchr( dllname, '.' );
1133     if (!p) strcat( dllname, ".dll" );
1134     for (p = dllname; *p; p++) *p = FILE_tolower(*p);
1135
1136     if ((descr = find_dll_descr( dllname )))
1137         return NE_DoLoadBuiltinModule( descr );
1138
1139     if ((handle = wine_dll_load( dllname, error, sizeof(error), &file_exists )))
1140     {
1141         if ((descr = find_dll_descr( dllname )))
1142             return NE_DoLoadBuiltinModule( descr );
1143
1144         ERR( "loaded .so but dll %s still not found\n", dllname );
1145     }
1146     else
1147     {
1148         if (!file_exists) WARN("cannot open .so lib for 16-bit builtin %s: %s\n", name, error);
1149         else ERR("failed to load .so lib for 16-bit builtin %s: %s\n", name, error );
1150     }
1151     return (HMODULE16)2;
1152 }
1153
1154
1155 /**********************************************************************
1156  *          MODULE_LoadModule16
1157  *
1158  * Load a NE module in the order of the loadorder specification.
1159  * The caller is responsible that the module is not loaded already.
1160  *
1161  */
1162 static HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit, BOOL lib_only )
1163 {
1164     HINSTANCE16 hinst = 2;
1165     enum loadorder_type loadorder[LOADORDER_NTYPES];
1166     int i;
1167     const char *filetype = "";
1168     const char *ptr, *basename;
1169
1170     /* strip path information */
1171
1172     basename = libname;
1173     if (basename[0] && basename[1] == ':') basename += 2;  /* strip drive specification */
1174     if ((ptr = strrchr( basename, '\\' ))) basename = ptr + 1;
1175     if ((ptr = strrchr( basename, '/' ))) basename = ptr + 1;
1176
1177     if (is_builtin_present(basename))
1178     {
1179         TRACE( "forcing loadorder to builtin for %s\n", debugstr_a(basename) );
1180         /* force builtin loadorder since the dll is already in memory */
1181         loadorder[0] = LOADORDER_BI;
1182         loadorder[1] = LOADORDER_INVALID;
1183     }
1184     else MODULE_GetLoadOrder(loadorder, basename, FALSE);
1185
1186     for(i = 0; i < LOADORDER_NTYPES; i++)
1187     {
1188         if (loadorder[i] == LOADORDER_INVALID) break;
1189
1190         switch(loadorder[i])
1191         {
1192         case LOADORDER_DLL:
1193             TRACE("Trying native dll '%s'\n", libname);
1194             hinst = NE_LoadModule(libname, lib_only);
1195             filetype = "native";
1196             break;
1197
1198         case LOADORDER_BI:
1199             TRACE("Trying built-in '%s'\n", libname);
1200             hinst = NE_LoadBuiltinModule(libname);
1201             filetype = "builtin";
1202             break;
1203
1204         default:
1205             hinst = 2;
1206             break;
1207         }
1208
1209         if(hinst >= 32)
1210         {
1211             TRACE_(loaddll)("Loaded module '%s' : %s\n", libname, filetype);
1212             if(!implicit)
1213             {
1214                 HMODULE16 hModule;
1215                 NE_MODULE *pModule;
1216
1217                 hModule = GetModuleHandle16(libname);
1218                 if(!hModule)
1219                 {
1220                     ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get module handle. Filename too long ?\n",
1221                         libname, hinst);
1222                     return 6;   /* ERROR_INVALID_HANDLE seems most appropriate */
1223                 }
1224
1225                 pModule = NE_GetPtr(hModule);
1226                 if(!pModule)
1227                 {
1228                     ERR("Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get NE_MODULE pointer\n",
1229                         libname, hinst);
1230                     return 6;   /* ERROR_INVALID_HANDLE seems most appropriate */
1231                 }
1232
1233                 TRACE("Loaded module '%s' at 0x%04x.\n", libname, hinst);
1234
1235                 /*
1236                  * Call initialization routines for all loaded DLLs. Note that
1237                  * when we load implicitly linked DLLs this will be done by InitTask().
1238                  */
1239                 if(pModule->flags & NE_FFLAGS_LIBMODULE)
1240                 {
1241                     NE_InitializeDLLs(hModule);
1242                     NE_DllProcessAttach(hModule);
1243                 }
1244             }
1245             return hinst;
1246         }
1247
1248         if(hinst != 2)
1249         {
1250             /* We quit searching when we get another error than 'File not found' */
1251             break;
1252         }
1253     }
1254     return hinst;       /* The last error that occurred */
1255 }
1256
1257
1258 /**********************************************************************
1259  *          NE_CreateThread
1260  *
1261  * Create the thread for a 16-bit module.
1262  */
1263 static HINSTANCE16 NE_CreateThread( NE_MODULE *pModule, WORD cmdShow, LPCSTR cmdline )
1264 {
1265     HANDLE hThread;
1266     TDB *pTask;
1267     HTASK16 hTask;
1268     HINSTANCE16 instance = 0;
1269
1270     if (!(hTask = TASK_SpawnTask( pModule, cmdShow, cmdline + 1, *cmdline, &hThread )))
1271         return 0;
1272
1273     /* Post event to start the task */
1274     PostEvent16( hTask );
1275
1276     /* Wait until we get the instance handle */
1277     do
1278     {
1279         DirectedYield16( hTask );
1280         if (!IsTask16( hTask ))  /* thread has died */
1281         {
1282             DWORD exit_code;
1283             WaitForSingleObject( hThread, INFINITE );
1284             GetExitCodeThread( hThread, &exit_code );
1285             CloseHandle( hThread );
1286             return exit_code;
1287         }
1288         if (!(pTask = GlobalLock16( hTask ))) break;
1289         instance = pTask->hInstance;
1290         GlobalUnlock16( hTask );
1291     } while (!instance);
1292
1293     CloseHandle( hThread );
1294     return instance;
1295 }
1296
1297
1298 /**********************************************************************
1299  *          LoadModule      (KERNEL.45)
1300  */
1301 HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
1302 {
1303     BOOL lib_only = !paramBlock || (paramBlock == (LPVOID)-1);
1304     LOADPARAMS16 *params;
1305     HMODULE16 hModule;
1306     NE_MODULE *pModule;
1307     LPSTR cmdline;
1308     WORD cmdShow;
1309
1310     /* Load module */
1311
1312     if ( (hModule = NE_GetModuleByFilename(name) ) != 0 )
1313     {
1314         /* Special case: second instance of an already loaded NE module */
1315
1316         if ( !( pModule = NE_GetPtr( hModule ) ) ) return (HINSTANCE16)11;
1317         if ( pModule->module32 ) return (HINSTANCE16)21;
1318
1319         /* Increment refcount */
1320
1321         pModule->count++;
1322     }
1323     else
1324     {
1325         /* Main case: load first instance of NE module */
1326
1327         if ( (hModule = MODULE_LoadModule16( name, FALSE, lib_only )) < 32 )
1328             return hModule;
1329
1330         if ( !(pModule = NE_GetPtr( hModule )) )
1331             return (HINSTANCE16)11;
1332     }
1333
1334     /* If library module, we just retrieve the instance handle */
1335
1336     if ( ( pModule->flags & NE_FFLAGS_LIBMODULE ) || lib_only )
1337         return NE_GetInstance( pModule );
1338
1339     /*
1340      *  At this point, we need to create a new process.
1341      *
1342      *  pModule points either to an already loaded module, whose refcount
1343      *  has already been incremented (to avoid having the module vanish
1344      *  in the meantime), or else to a stub module which contains only header
1345      *  information.
1346      */
1347     params = (LOADPARAMS16 *)paramBlock;
1348     cmdShow = ((WORD *)MapSL(params->showCmd))[1];
1349     cmdline = MapSL( params->cmdLine );
1350     return NE_CreateThread( pModule, cmdShow, cmdline );
1351 }
1352
1353
1354 /**********************************************************************
1355  *          NE_StartTask
1356  *
1357  * Startup code for a new 16-bit task.
1358  */
1359 DWORD NE_StartTask(void)
1360 {
1361     TDB *pTask = TASK_GetCurrent();
1362     NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
1363     HINSTANCE16 hInstance, hPrevInstance;
1364     SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
1365     WORD sp;
1366
1367     if ( pModule->count > 0 )
1368     {
1369         /* Second instance of an already loaded NE module */
1370         /* Note that the refcount was already incremented by the parent */
1371
1372         hPrevInstance = NE_GetInstance( pModule );
1373
1374         if ( pModule->dgroup )
1375             if ( NE_CreateSegment( pModule, pModule->dgroup ) )
1376                 NE_LoadSegment( pModule, pModule->dgroup );
1377
1378         hInstance = NE_GetInstance( pModule );
1379         TRACE("created second instance %04x[%d] of instance %04x.\n", hInstance, pModule->dgroup, hPrevInstance);
1380
1381     }
1382     else
1383     {
1384         /* Load first instance of NE module */
1385
1386         pModule->flags |= NE_FFLAGS_GUI;  /* FIXME: is this necessary? */
1387
1388         hInstance = NE_DoLoadModule( pModule );
1389         hPrevInstance = 0;
1390     }
1391
1392     if ( hInstance >= 32 )
1393     {
1394         CONTEXT86 context;
1395
1396         /* Enter instance handles into task struct */
1397
1398         pTask->hInstance = hInstance;
1399         pTask->hPrevInstance = hPrevInstance;
1400
1401         /* Use DGROUP for 16-bit stack */
1402
1403         if (!(sp = pModule->sp))
1404             sp = pSegTable[pModule->ss-1].minsize + pModule->stack_size;
1405         sp &= ~1;
1406         sp -= sizeof(STACK16FRAME);
1407         NtCurrentTeb()->cur_stack = MAKESEGPTR( GlobalHandleToSel16(hInstance), sp );
1408
1409         /* Registers at initialization must be:
1410          * ax   zero
1411          * bx   stack size in bytes
1412          * cx   heap size in bytes
1413          * si   previous app instance
1414          * di   current app instance
1415          * bp   zero
1416          * es   selector to the PSP
1417          * ds   dgroup of the application
1418          * ss   stack selector
1419          * sp   top of the stack
1420          */
1421         memset( &context, 0, sizeof(context) );
1422         context.SegCs  = GlobalHandleToSel16(pSegTable[pModule->cs - 1].hSeg);
1423         context.SegDs  = GlobalHandleToSel16(pTask->hInstance);
1424         context.SegEs  = pTask->hPDB;
1425         context.Eip    = pModule->ip;
1426         context.Ebx    = pModule->stack_size;
1427         context.Ecx    = pModule->heap_size;
1428         context.Edi    = pTask->hInstance;
1429         context.Esi    = pTask->hPrevInstance;
1430
1431         /* Now call 16-bit entry point */
1432
1433         TRACE("Starting main program: cs:ip=%04lx:%04lx ds=%04lx ss:sp=%04x:%04x\n",
1434               context.SegCs, context.Eip, context.SegDs,
1435               SELECTOROF(NtCurrentTeb()->cur_stack),
1436               OFFSETOF(NtCurrentTeb()->cur_stack) );
1437
1438         WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context );
1439         ExitThread( LOWORD(context.Eax) );
1440     }
1441     return hInstance;  /* error code */
1442 }
1443
1444 /***********************************************************************
1445  *           LoadLibrary     (KERNEL.95)
1446  *           LoadLibrary16   (KERNEL32.35)
1447  */
1448 HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
1449 {
1450     return LoadModule16(libname, (LPVOID)-1 );
1451 }
1452
1453
1454 /**********************************************************************
1455  *          MODULE_CallWEP
1456  *
1457  * Call a DLL's WEP, allowing it to shut down.
1458  * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
1459  */
1460 static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
1461 {
1462     BOOL16 ret;
1463     FARPROC16 WEP = GetProcAddress16( hModule, "WEP" );
1464     if (!WEP) return FALSE;
1465
1466     __TRY
1467     {
1468         WORD args[1];
1469         DWORD dwRet;
1470
1471         args[0] = WEP_FREE_DLL;
1472         WOWCallback16Ex( (DWORD)WEP, WCB16_PASCAL, sizeof(args), args, &dwRet );
1473         ret = LOWORD(dwRet);
1474     }
1475     __EXCEPT(page_fault)
1476     {
1477         WARN("Page fault\n");
1478         ret = 0;
1479     }
1480     __ENDTRY
1481
1482     return ret;
1483 }
1484
1485
1486 /**********************************************************************
1487  *          NE_FreeModule
1488  *
1489  * Implementation of FreeModule16().
1490  */
1491 static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep )
1492 {
1493     HMODULE16 *hPrevModule;
1494     NE_MODULE *pModule;
1495     HMODULE16 *pModRef;
1496     int i;
1497
1498     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
1499     hModule = pModule->self;
1500
1501     TRACE("%04x count %d\n", hModule, pModule->count );
1502
1503     if (((INT16)(--pModule->count)) > 0 ) return TRUE;
1504     else pModule->count = 0;
1505
1506     if (pModule->flags & NE_FFLAGS_BUILTIN)
1507         return FALSE;  /* Can't free built-in module */
1508
1509     if (call_wep && !(pModule->flags & NE_FFLAGS_WIN32))
1510     {
1511         /* Free the objects owned by the DLL module */
1512         NE_CallUserSignalProc( hModule, USIG16_DLL_UNLOAD );
1513
1514         if (pModule->flags & NE_FFLAGS_LIBMODULE)
1515             MODULE_CallWEP( hModule );
1516         else
1517             call_wep = FALSE;  /* We are freeing a task -> no more WEPs */
1518     }
1519
1520
1521     /* Clear magic number just in case */
1522
1523     pModule->magic = pModule->self = 0;
1524
1525       /* Remove it from the linked list */
1526
1527     hPrevModule = &hFirstModule;
1528     while (*hPrevModule && (*hPrevModule != hModule))
1529     {
1530         hPrevModule = &(NE_GetPtr( *hPrevModule ))->next;
1531     }
1532     if (*hPrevModule) *hPrevModule = pModule->next;
1533
1534     /* Free the referenced modules */
1535
1536     pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
1537     for (i = 0; i < pModule->modref_count; i++, pModRef++)
1538     {
1539         NE_FreeModule( *pModRef, call_wep );
1540     }
1541
1542     /* Free the module storage */
1543
1544     GlobalFreeAll16( hModule );
1545
1546     /* Remove module from cache */
1547
1548     if (pCachedModule == pModule) pCachedModule = NULL;
1549     return TRUE;
1550 }
1551
1552
1553 /**********************************************************************
1554  *          FreeModule    (KERNEL.46)
1555  */
1556 BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
1557 {
1558     return NE_FreeModule( hModule, TRUE );
1559 }
1560
1561
1562 /***********************************************************************
1563  *           FreeLibrary     (KERNEL.96)
1564  *           FreeLibrary16   (KERNEL32.36)
1565  */
1566 void WINAPI FreeLibrary16( HINSTANCE16 handle )
1567 {
1568     TRACE("%04x\n", handle );
1569     FreeModule16( handle );
1570 }
1571
1572
1573 /**********************************************************************
1574  *          GetModuleName    (KERNEL.27)
1575  */
1576 BOOL16 WINAPI GetModuleName16( HINSTANCE16 hinst, LPSTR buf, INT16 count )
1577 {
1578     NE_MODULE *pModule;
1579     BYTE *p;
1580
1581     if (!(pModule = NE_GetPtr( hinst ))) return FALSE;
1582     p = (BYTE *)pModule + pModule->name_table;
1583     if (count > *p) count = *p + 1;
1584     if (count > 0)
1585     {
1586         memcpy( buf, p + 1, count - 1 );
1587         buf[count-1] = '\0';
1588     }
1589     return TRUE;
1590 }
1591
1592
1593 /**********************************************************************
1594  *          GetModuleUsage    (KERNEL.48)
1595  */
1596 INT16 WINAPI GetModuleUsage16( HINSTANCE16 hModule )
1597 {
1598     NE_MODULE *pModule = NE_GetPtr( hModule );
1599     return pModule ? pModule->count : 0;
1600 }
1601
1602
1603 /**********************************************************************
1604  *          GetExpWinVer    (KERNEL.167)
1605  */
1606 WORD WINAPI GetExpWinVer16( HMODULE16 hModule )
1607 {
1608     NE_MODULE *pModule = NE_GetPtr( hModule );
1609     if ( !pModule ) return 0;
1610
1611     /*
1612      * For built-in modules, fake the expected version the module should
1613      * have according to the Windows version emulated by Wine
1614      */
1615     if ( !pModule->expected_version )
1616     {
1617         OSVERSIONINFOA versionInfo;
1618         versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
1619
1620         if ( GetVersionExA( &versionInfo ) )
1621             pModule->expected_version =
1622                      (versionInfo.dwMajorVersion & 0xff) << 8
1623                    | (versionInfo.dwMinorVersion & 0xff);
1624     }
1625
1626     return pModule->expected_version;
1627 }
1628
1629
1630 /***********************************************************************
1631  *           WinExec     (KERNEL.166)
1632  */
1633 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
1634 {
1635     LPCSTR p, args = NULL;
1636     LPCSTR name_beg, name_end;
1637     LPSTR name, cmdline;
1638     int arglen;
1639     HINSTANCE16 ret;
1640     char buffer[MAX_PATH];
1641
1642     if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */
1643     {
1644         name_beg = lpCmdLine+1;
1645         p = strchr ( lpCmdLine+1, '"' );
1646         if (p)
1647         {
1648             name_end = p;
1649             args = strchr ( p, ' ' );
1650         }
1651         else /* yes, even valid with trailing '"' missing */
1652             name_end = lpCmdLine+strlen(lpCmdLine);
1653     }
1654     else
1655     {
1656         name_beg = lpCmdLine;
1657         args = strchr( lpCmdLine, ' ' );
1658         name_end = args ? args : lpCmdLine+strlen(lpCmdLine);
1659     }
1660
1661     if ((name_beg == lpCmdLine) && (!args))
1662     { /* just use the original cmdline string as file name */
1663         name = (LPSTR)lpCmdLine;
1664     }
1665     else
1666     {
1667         if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 )))
1668             return ERROR_NOT_ENOUGH_MEMORY;
1669         memcpy( name, name_beg, name_end - name_beg );
1670         name[name_end - name_beg] = '\0';
1671     }
1672
1673     if (args)
1674     {
1675         args++;
1676         arglen = strlen(args);
1677         cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen );
1678         cmdline[0] = (BYTE)arglen;
1679         strcpy( cmdline + 1, args );
1680     }
1681     else
1682     {
1683         cmdline = HeapAlloc( GetProcessHeap(), 0, 2 );
1684         cmdline[0] = cmdline[1] = 0;
1685     }
1686
1687     TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]);
1688
1689     if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
1690     {
1691         LOADPARAMS16 params;
1692         WORD showCmd[2];
1693         showCmd[0] = 2;
1694         showCmd[1] = nCmdShow;
1695
1696         params.hEnvironment = 0;
1697         params.cmdLine = MapLS( cmdline );
1698         params.showCmd = MapLS( showCmd );
1699         params.reserved = 0;
1700
1701         ret = LoadModule16( buffer, &params );
1702         UnMapLS( params.cmdLine );
1703         UnMapLS( params.showCmd );
1704     }
1705     else ret = GetLastError();
1706
1707     HeapFree( GetProcessHeap(), 0, cmdline );
1708     if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
1709
1710     if (ret == 21)  /* 32-bit module */
1711     {
1712         DWORD count;
1713         ReleaseThunkLock( &count );
1714         ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) );
1715         RestoreThunkLock( count );
1716     }
1717     return ret;
1718 }
1719
1720 /***********************************************************************
1721  *           GetProcAddress   (KERNEL.50)
1722  */
1723 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name )
1724 {
1725     WORD ordinal;
1726     FARPROC16 ret;
1727
1728     if (!hModule) hModule = GetCurrentTask();
1729     hModule = GetExePtr( hModule );
1730
1731     if (HIWORD(name) != 0)
1732     {
1733         ordinal = NE_GetOrdinal( hModule, name );
1734         TRACE("%04x '%s'\n", hModule, name );
1735     }
1736     else
1737     {
1738         ordinal = LOWORD(name);
1739         TRACE("%04x %04x\n", hModule, ordinal );
1740     }
1741     if (!ordinal) return (FARPROC16)0;
1742
1743     ret = NE_GetEntryPoint( hModule, ordinal );
1744
1745     TRACE("returning %08x\n", (UINT)ret );
1746     return ret;
1747 }
1748
1749
1750 /***************************************************************************
1751  *              HasGPHandler                    (KERNEL.338)
1752  */
1753 SEGPTR WINAPI HasGPHandler16( SEGPTR address )
1754 {
1755     HMODULE16 hModule;
1756     int gpOrdinal;
1757     SEGPTR gpPtr;
1758     GPHANDLERDEF *gpHandler;
1759
1760     if (    (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1761          && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
1762          && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
1763          && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1764          && (gpHandler = MapSL( gpPtr )) != NULL )
1765     {
1766         while (gpHandler->selector)
1767         {
1768             if (    SELECTOROF(address) == gpHandler->selector
1769                  && OFFSETOF(address)   >= gpHandler->rangeStart
1770                  && OFFSETOF(address)   <  gpHandler->rangeEnd  )
1771                 return MAKESEGPTR( gpHandler->selector, gpHandler->handler );
1772             gpHandler++;
1773         }
1774     }
1775
1776     return 0;
1777 }
1778
1779
1780 /**********************************************************************
1781  *          GetModuleHandle    (KERNEL.47)
1782  *
1783  * Find a module from a module name.
1784  *
1785  * NOTE: The current implementation works the same way the Windows 95 one
1786  *       does. Do not try to 'fix' it, fix the callers.
1787  *       + It does not do ANY extension handling (except that strange .EXE bit)!
1788  *       + It does not care about paths, just about basenames. (same as Windows)
1789  *
1790  * RETURNS
1791  *   LOWORD:
1792  *      the win16 module handle if found
1793  *      0 if not
1794  *   HIWORD (undocumented, see "Undocumented Windows", chapter 5):
1795  *      Always hFirstModule
1796  */
1797 DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name )
1798 {
1799     if (HIWORD(name) == 0)
1800         return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule );
1801     return MAKELONG(GetModuleHandle16( MapSL(name)), hFirstModule );
1802 }
1803
1804 /**********************************************************************
1805  *          NE_GetModuleByFilename
1806  */
1807 static HMODULE16 NE_GetModuleByFilename( LPCSTR name )
1808 {
1809     HMODULE16   hModule;
1810     LPSTR       s, p;
1811     BYTE        len, *name_table;
1812     char        tmpstr[MAX_PATH];
1813     NE_MODULE *pModule;
1814
1815     lstrcpynA(tmpstr, name, sizeof(tmpstr));
1816
1817     /* If the base filename of 'name' matches the base filename of the module
1818      * filename of some module (case-insensitive compare):
1819      * Return its handle.
1820      */
1821
1822     /* basename: search backwards in passed name to \ / or : */
1823     s = tmpstr + strlen(tmpstr);
1824     while (s > tmpstr)
1825     {
1826         if (s[-1]=='/' || s[-1]=='\\' || s[-1]==':')
1827                 break;
1828         s--;
1829     }
1830
1831     /* search this in loaded filename list */
1832     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1833     {
1834         char            *loadedfn;
1835         OFSTRUCT        *ofs;
1836
1837         pModule = NE_GetPtr( hModule );
1838         if (!pModule) break;
1839         if (!pModule->fileinfo) continue;
1840         if (pModule->flags & NE_FFLAGS_WIN32) continue;
1841
1842         ofs = (OFSTRUCT*)((BYTE *)pModule + pModule->fileinfo);
1843         loadedfn = ((char*)ofs->szPathName) + strlen(ofs->szPathName);
1844         /* basename: search backwards in pathname to \ / or : */
1845         while (loadedfn > (char*)ofs->szPathName)
1846         {
1847             if (loadedfn[-1]=='/' || loadedfn[-1]=='\\' || loadedfn[-1]==':')
1848                     break;
1849             loadedfn--;
1850         }
1851         /* case insensitive compare ... */
1852         if (!FILE_strcasecmp(loadedfn, s))
1853             return hModule;
1854     }
1855     /* If basename (without ext) matches the module name of a module:
1856      * Return its handle.
1857      */
1858
1859     if ( (p = strrchr( s, '.' )) != NULL ) *p = '\0';
1860     len = strlen(s);
1861
1862     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1863     {
1864         pModule = NE_GetPtr( hModule );
1865         if (!pModule) break;
1866         if (pModule->flags & NE_FFLAGS_WIN32) continue;
1867
1868         name_table = (BYTE *)pModule + pModule->name_table;
1869         if ((*name_table == len) && !FILE_strncasecmp(s, name_table+1, len))
1870             return hModule;
1871     }
1872
1873     return 0;
1874 }
1875
1876 /***********************************************************************
1877  *           GetProcAddress16   (KERNEL32.37)
1878  * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1879  */
1880 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
1881 {
1882     if (!hModule) return 0;
1883     if (HIWORD(hModule))
1884     {
1885         WARN("hModule is Win32 handle (%p)\n", hModule );
1886         return 0;
1887     }
1888     return GetProcAddress16( LOWORD(hModule), name );
1889 }
1890
1891 /**********************************************************************
1892  *          ModuleFirst    (TOOLHELP.59)
1893  */
1894 BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
1895 {
1896     lpme->wNext = hFirstModule;
1897     return ModuleNext16( lpme );
1898 }
1899
1900
1901 /**********************************************************************
1902  *          ModuleNext    (TOOLHELP.60)
1903  */
1904 BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
1905 {
1906     NE_MODULE *pModule;
1907     char *name;
1908
1909     if (!lpme->wNext) return FALSE;
1910     if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE;
1911     name = (char *)pModule + pModule->name_table;
1912     memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
1913     lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
1914     lpme->hModule = lpme->wNext;
1915     lpme->wcUsage = pModule->count;
1916     lstrcpynA( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) );
1917     lpme->wNext = pModule->next;
1918     return TRUE;
1919 }
1920
1921
1922 /**********************************************************************
1923  *          ModuleFindName    (TOOLHELP.61)
1924  */
1925 BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
1926 {
1927     lpme->wNext = GetModuleHandle16( name );
1928     return ModuleNext16( lpme );
1929 }
1930
1931
1932 /**********************************************************************
1933  *          ModuleFindHandle    (TOOLHELP.62)
1934  */
1935 BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
1936 {
1937     hModule = GetExePtr( hModule );
1938     lpme->wNext = hModule;
1939     return ModuleNext16( lpme );
1940 }
1941
1942
1943 /***************************************************************************
1944  *          IsRomModule    (KERNEL.323)
1945  */
1946 BOOL16 WINAPI IsRomModule16( HMODULE16 unused )
1947 {
1948     return FALSE;
1949 }
1950
1951 /***************************************************************************
1952  *          IsRomFile    (KERNEL.326)
1953  */
1954 BOOL16 WINAPI IsRomFile16( HFILE16 unused )
1955 {
1956     return FALSE;
1957 }
1958
1959 /***********************************************************************
1960  *           create_dummy_module
1961  *
1962  * Create a dummy NE module for Win32 or Winelib.
1963  */
1964 static HMODULE16 create_dummy_module( HMODULE module32 )
1965 {
1966     HMODULE16 hModule;
1967     NE_MODULE *pModule;
1968     SEGTABLEENTRY *pSegment;
1969     char *pStr,*s;
1970     unsigned int len;
1971     const char* basename;
1972     OFSTRUCT *ofs;
1973     int of_size, size;
1974     char filename[MAX_PATH];
1975     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 );
1976
1977     if (!nt) return (HMODULE16)11;  /* invalid exe */
1978
1979     /* Extract base filename */
1980     GetModuleFileNameA( module32, filename, sizeof(filename) );
1981     basename = strrchr(filename, '\\');
1982     if (!basename) basename = filename;
1983     else basename++;
1984     len = strlen(basename);
1985     if ((s = strchr(basename, '.'))) len = s - basename;
1986
1987     /* Allocate module */
1988     of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
1989                     + strlen(filename) + 1;
1990     size = sizeof(NE_MODULE) +
1991                  /* loaded file info */
1992                  ((of_size + 3) & ~3) +
1993                  /* segment table: DS,CS */
1994                  2 * sizeof(SEGTABLEENTRY) +
1995                  /* name table */
1996                  len + 2 +
1997                  /* several empty tables */
1998                  8;
1999
2000     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
2001     if (!hModule) return (HMODULE16)11;  /* invalid exe */
2002
2003     FarSetOwner16( hModule, hModule );
2004     pModule = (NE_MODULE *)GlobalLock16( hModule );
2005
2006     /* Set all used entries */
2007     pModule->magic            = IMAGE_OS2_SIGNATURE;
2008     pModule->count            = 1;
2009     pModule->next             = 0;
2010     pModule->flags            = NE_FFLAGS_WIN32;
2011     pModule->dgroup           = 0;
2012     pModule->ss               = 1;
2013     pModule->cs               = 2;
2014     pModule->heap_size        = 0;
2015     pModule->stack_size       = 0;
2016     pModule->seg_count        = 2;
2017     pModule->modref_count     = 0;
2018     pModule->nrname_size      = 0;
2019     pModule->fileinfo         = sizeof(NE_MODULE);
2020     pModule->os_flags         = NE_OSFLAGS_WINDOWS;
2021     pModule->self             = hModule;
2022     pModule->module32         = module32;
2023
2024     /* Set version and flags */
2025     pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
2026                                 (nt->OptionalHeader.MinorSubsystemVersion & 0xff);
2027     if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
2028         pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
2029
2030     /* Set loaded file information */
2031     ofs = (OFSTRUCT *)(pModule + 1);
2032     memset( ofs, 0, of_size );
2033     ofs->cBytes = of_size < 256 ? of_size : 255;   /* FIXME */
2034     strcpy( ofs->szPathName, filename );
2035
2036     pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3));
2037     pModule->seg_table = (int)pSegment - (int)pModule;
2038     /* Data segment */
2039     pSegment->size    = 0;
2040     pSegment->flags   = NE_SEGFLAGS_DATA;
2041     pSegment->minsize = 0x1000;
2042     pSegment++;
2043     /* Code segment */
2044     pSegment->flags   = 0;
2045     pSegment++;
2046
2047     /* Module name */
2048     pStr = (char *)pSegment;
2049     pModule->name_table = (int)pStr - (int)pModule;
2050     assert(len<256);
2051     *pStr = len;
2052     lstrcpynA( pStr+1, basename, len+1 );
2053     pStr += len+2;
2054
2055     /* All tables zero terminated */
2056     pModule->res_table = pModule->import_table = pModule->entry_table = (int)pStr - (int)pModule;
2057
2058     NE_RegisterModule( pModule );
2059     LoadLibraryA( filename );  /* increment the ref count of the 32-bit module */
2060     return hModule;
2061 }
2062
2063 /***********************************************************************
2064  *           PrivateLoadLibrary       (KERNEL32.@)
2065  *
2066  * FIXME: rough guesswork, don't know what "Private" means
2067  */
2068 HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname)
2069 {
2070     return LoadLibrary16(libname);
2071 }
2072
2073 /***********************************************************************
2074  *           PrivateFreeLibrary       (KERNEL32.@)
2075  *
2076  * FIXME: rough guesswork, don't know what "Private" means
2077  */
2078 void WINAPI PrivateFreeLibrary(HINSTANCE16 handle)
2079 {
2080     FreeLibrary16(handle);
2081 }
2082
2083 /***************************************************************************
2084  *              MapHModuleLS                    (KERNEL32.@)
2085  */
2086 HMODULE16 WINAPI MapHModuleLS(HMODULE hmod)
2087 {
2088     HMODULE16 ret;
2089     NE_MODULE *pModule;
2090
2091     if (!hmod)
2092         return TASK_GetCurrent()->hInstance;
2093     if (!HIWORD(hmod))
2094         return LOWORD(hmod); /* we already have a 16 bit module handle */
2095     pModule = (NE_MODULE*)GlobalLock16(hFirstModule);
2096     while (pModule)  {
2097         if (pModule->module32 == hmod)
2098             return pModule->self;
2099         pModule = (NE_MODULE*)GlobalLock16(pModule->next);
2100     }
2101     if ((ret = create_dummy_module( hmod )) < 32)
2102     {
2103         SetLastError(ret);
2104         ret = 0;
2105     }
2106     return ret;
2107 }
2108
2109 /***************************************************************************
2110  *              MapHModuleSL                    (KERNEL32.@)
2111  */
2112 HMODULE WINAPI MapHModuleSL(HMODULE16 hmod)
2113 {
2114     NE_MODULE *pModule;
2115
2116     if (!hmod) {
2117         TDB *pTask = TASK_GetCurrent();
2118         hmod = pTask->hModule;
2119     }
2120     pModule = (NE_MODULE*)GlobalLock16(hmod);
2121     if ((pModule->magic!=IMAGE_OS2_SIGNATURE) || !(pModule->flags & NE_FFLAGS_WIN32))
2122         return 0;
2123     return pModule->module32;
2124 }
2125
2126 /***************************************************************************
2127  *              MapHInstLS                      (KERNEL32.@)
2128  *              MapHInstLS                      (KERNEL.472)
2129  */
2130 void WINAPI MapHInstLS( CONTEXT86 *context )
2131 {
2132     context->Eax = MapHModuleLS( (HMODULE)context->Eax );
2133 }
2134
2135 /***************************************************************************
2136  *              MapHInstSL                      (KERNEL32.@)
2137  *              MapHInstSL                      (KERNEL.473)
2138  */
2139 void WINAPI MapHInstSL( CONTEXT86 *context )
2140 {
2141     context->Eax = (DWORD)MapHModuleSL( context->Eax );
2142 }
2143
2144 /***************************************************************************
2145  *              MapHInstLS_PN                   (KERNEL32.@)
2146  */
2147 void WINAPI MapHInstLS_PN( CONTEXT86 *context )
2148 {
2149     if (context->Eax) context->Eax = MapHModuleLS( (HMODULE)context->Eax );
2150 }
2151
2152 /***************************************************************************
2153  *              MapHInstSL_PN                   (KERNEL32.@)
2154  */
2155 void WINAPI MapHInstSL_PN( CONTEXT86 *context )
2156 {
2157     if (context->Eax) context->Eax = (DWORD)MapHModuleSL( context->Eax );
2158 }