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