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