Release Win16Lock during PROCESS_Create.
[wine] / loader / ne / module.c
1 /*
2  * NE modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <ctype.h>
13 #include "wine/winbase16.h"
14 #include "winerror.h"
15 #include "module.h"
16 #include "neexe.h"
17 #include "peexe.h"
18 #include "toolhelp.h"
19 #include "file.h"
20 #include "ldt.h"
21 #include "callback.h"
22 #include "heap.h"
23 #include "task.h"
24 #include "global.h"
25 #include "process.h"
26 #include "toolhelp.h"
27 #include "snoop.h"
28 #include "stackframe.h"
29 #include "debug.h"
30 #include "file.h"
31 #include "loadorder.h"
32 #include "elfdll.h"
33
34 DEFAULT_DEBUG_CHANNEL(module)
35
36 FARPROC16 (*fnSNOOP16_GetProcAddress16)(HMODULE16,DWORD,FARPROC16) = NULL;
37 void (*fnSNOOP16_RegisterDLL)(NE_MODULE*,LPCSTR) = NULL;
38
39 #define hFirstModule (pThhook->hExeHead)
40
41 static NE_MODULE *pCachedModule = 0;  /* Module cached by NE_OpenFile */
42
43 static HMODULE16 NE_LoadBuiltin(LPCSTR name,BOOL force) { return 0; }
44 HMODULE16 (*fnBUILTIN_LoadModule)(LPCSTR name,BOOL force) = NE_LoadBuiltin;
45
46
47 /***********************************************************************
48  *           NE_GetPtr
49  */
50 NE_MODULE *NE_GetPtr( HMODULE16 hModule )
51 {
52     return (NE_MODULE *)GlobalLock16( GetExePtr(hModule) );
53 }
54
55
56 /***********************************************************************
57  *           NE_DumpModule
58  */
59 void NE_DumpModule( HMODULE16 hModule )
60 {
61     int i, ordinal;
62     SEGTABLEENTRY *pSeg;
63     BYTE *pstr;
64     WORD *pword;
65     NE_MODULE *pModule;
66     ET_BUNDLE *bundle;
67     ET_ENTRY *entry;
68
69     if (!(pModule = NE_GetPtr( hModule )))
70     {
71         MSG( "**** %04x is not a module handle\n", hModule );
72         return;
73     }
74
75       /* Dump the module info */
76     DUMP( "---\n" );
77     DUMP( "Module %04x:\n", hModule );
78     DUMP( "count=%d flags=%04x heap=%d stack=%d\n",
79           pModule->count, pModule->flags,
80           pModule->heap_size, pModule->stack_size );
81     DUMP( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
82           pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
83           pModule->seg_count, pModule->modref_count );
84     DUMP( "os_flags=%d swap_area=%d version=%04x\n",
85           pModule->os_flags, pModule->min_swap_area,
86           pModule->expected_version );
87     if (pModule->flags & NE_FFLAGS_WIN32)
88         DUMP( "PE module=%08x\n", pModule->module32 );
89
90       /* Dump the file info */
91     DUMP( "---\n" );
92     DUMP( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
93
94       /* Dump the segment table */
95     DUMP( "---\n" );
96     DUMP( "Segment table:\n" );
97     pSeg = NE_SEG_TABLE( pModule );
98     for (i = 0; i < pModule->seg_count; i++, pSeg++)
99         DUMP( "%02x: pos=%d size=%d flags=%04x minsize=%d hSeg=%04x\n",
100               i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
101               pSeg->minsize, pSeg->hSeg );
102
103       /* Dump the resource table */
104     DUMP( "---\n" );
105     DUMP( "Resource table:\n" );
106     if (pModule->res_table)
107     {
108         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
109         DUMP( "Alignment: %d\n", *pword++ );
110         while (*pword)
111         {
112             struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
113             struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
114             DUMP( "id=%04x count=%d\n", ptr->type_id, ptr->count );
115             for (i = 0; i < ptr->count; i++, pname++)
116                 DUMP( "offset=%d len=%d id=%04x\n",
117                       pname->offset, pname->length, pname->id );
118             pword = (WORD *)pname;
119         }
120     }
121     else DUMP( "None\n" );
122
123       /* Dump the resident name table */
124     DUMP( "---\n" );
125     DUMP( "Resident-name table:\n" );
126     pstr = (char *)pModule + pModule->name_table;
127     while (*pstr)
128     {
129         DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
130               *(WORD *)(pstr + *pstr + 1) );
131         pstr += *pstr + 1 + sizeof(WORD);
132     }
133
134       /* Dump the module reference table */
135     DUMP( "---\n" );
136     DUMP( "Module ref table:\n" );
137     if (pModule->modref_table)
138     {
139         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
140         for (i = 0; i < pModule->modref_count; i++, pword++)
141         {
142             char name[10];
143             GetModuleName16( *pword, name, sizeof(name) );
144             DUMP( "%d: %04x -> '%s'\n", i, *pword, name );
145         }
146     }
147     else DUMP( "None\n" );
148
149       /* Dump the entry table */
150     DUMP( "---\n" );
151     DUMP( "Entry table:\n" );
152     bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->entry_table);    
153     do {
154         entry = (ET_ENTRY *)((BYTE *)bundle+6);
155         DUMP( "Bundle %d-%d: %02x\n", bundle->first, bundle->last, entry->type);
156         ordinal = bundle->first;
157         while (ordinal < bundle->last)
158         {
159             if (entry->type == 0xff)
160                 DUMP("%d: %02x:%04x (moveable)\n", ordinal++, entry->segnum, entry->offs);
161             else
162                 DUMP("%d: %02x:%04x (fixed)\n", ordinal++, entry->segnum, entry->offs);
163             entry++;
164     }
165     } while ( (bundle->next)
166            && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) );
167
168     /* Dump the non-resident names table */
169     DUMP( "---\n" );
170     DUMP( "Non-resident names table:\n" );
171     if (pModule->nrname_handle)
172     {
173         pstr = (char *)GlobalLock16( pModule->nrname_handle );
174         while (*pstr)
175         {
176             DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
177                    *(WORD *)(pstr + *pstr + 1) );
178             pstr += *pstr + 1 + sizeof(WORD);
179         }
180     }
181     DUMP( "\n" );
182 }
183
184
185 /***********************************************************************
186  *           NE_WalkModules
187  *
188  * Walk the module list and print the modules.
189  */
190 void NE_WalkModules(void)
191 {
192     HMODULE16 hModule = hFirstModule;
193     MSG( "Module Flags Name\n" );
194     while (hModule)
195     {
196         NE_MODULE *pModule = NE_GetPtr( hModule );
197         if (!pModule)
198         {
199             MSG( "Bad module %04x in list\n", hModule );
200             return;
201         }
202         MSG( " %04x  %04x  %.*s\n", hModule, pModule->flags,
203                  *((char *)pModule + pModule->name_table),
204                  (char *)pModule + pModule->name_table + 1 );
205         hModule = pModule->next;
206     }
207 }
208
209
210 /**********************************************************************
211  *           NE_RegisterModule
212  */
213 void NE_RegisterModule( NE_MODULE *pModule )
214 {
215     pModule->next = hFirstModule;
216     hFirstModule = pModule->self;
217 }
218
219
220 /***********************************************************************
221  *           NE_GetOrdinal
222  *
223  * Lookup the ordinal for a given name.
224  */
225 WORD NE_GetOrdinal( HMODULE16 hModule, const char *name )
226 {
227     unsigned char buffer[256], *cpnt;
228     BYTE len;
229     NE_MODULE *pModule;
230
231     if (!(pModule = NE_GetPtr( hModule ))) return 0;
232     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
233
234     TRACE( module, "(%04x,'%s')\n", hModule, name );
235
236       /* First handle names of the form '#xxxx' */
237
238     if (name[0] == '#') return atoi( name + 1 );
239
240       /* Now copy and uppercase the string */
241
242     strcpy( buffer, name );
243     CharUpperA( buffer );
244     len = strlen( buffer );
245
246       /* First search the resident names */
247
248     cpnt = (char *)pModule + pModule->name_table;
249
250       /* Skip the first entry (module name) */
251     cpnt += *cpnt + 1 + sizeof(WORD);
252     while (*cpnt)
253     {
254         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
255         {
256             TRACE(module, "  Found: ordinal=%d\n",
257                             *(WORD *)(cpnt + *cpnt + 1) );
258             return *(WORD *)(cpnt + *cpnt + 1);
259         }
260         cpnt += *cpnt + 1 + sizeof(WORD);
261     }
262
263       /* Now search the non-resident names table */
264
265     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
266     cpnt = (char *)GlobalLock16( pModule->nrname_handle );
267
268       /* Skip the first entry (module description string) */
269     cpnt += *cpnt + 1 + sizeof(WORD);
270     while (*cpnt)
271     {
272         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
273         {
274             TRACE(module, "  Found: ordinal=%d\n",
275                             *(WORD *)(cpnt + *cpnt + 1) );
276             return *(WORD *)(cpnt + *cpnt + 1);
277         }
278         cpnt += *cpnt + 1 + sizeof(WORD);
279     }
280     return 0;
281 }
282
283
284 /***********************************************************************
285  *           NE_GetEntryPoint   (WPROCS.27)
286  *
287  * Return the entry point for a given ordinal.
288  */
289 FARPROC16 NE_GetEntryPoint( HMODULE16 hModule, WORD ordinal )
290 {
291     return NE_GetEntryPointEx( hModule, ordinal, TRUE );
292 }
293 FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop )
294 {
295     NE_MODULE *pModule;
296     WORD sel, offset, i;
297
298     ET_ENTRY *entry;
299     ET_BUNDLE *bundle;
300
301     if (!(pModule = NE_GetPtr( hModule ))) return 0;
302     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
303
304     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
305     while ((ordinal < bundle->first + 1) || (ordinal > bundle->last))
306     {
307         if (!(bundle->next))
308             return 0;
309         bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next);
310     }
311
312     entry = (ET_ENTRY *)((BYTE *)bundle+6);
313     for (i=0; i < (ordinal - bundle->first - 1); i++)
314         entry++;
315
316     sel = entry->segnum;
317     offset = entry->offs;
318
319     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
320     else sel = GlobalHandleToSel16(NE_SEG_TABLE(pModule)[sel-1].hSeg);
321     if (sel==0xffff)
322         return (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset );
323     if (!snoop || !fnSNOOP16_GetProcAddress16)
324         return (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset );
325     else
326         return (FARPROC16)fnSNOOP16_GetProcAddress16(hModule,ordinal,(FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset ));
327 }
328
329
330 /***********************************************************************
331  *           NE_SetEntryPoint
332  *
333  * Change the value of an entry point. Use with caution!
334  * It can only change the offset value, not the selector.
335  */
336 BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset )
337 {
338     NE_MODULE *pModule;
339     ET_ENTRY *entry;
340     ET_BUNDLE *bundle;
341     int i;
342
343     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
344     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
345
346     bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->entry_table);
347     while ((ordinal < bundle->first + 1) || (ordinal > bundle->last))
348         {
349         bundle = (ET_BUNDLE *)((BYTE *)pModule + bundle->next);
350         if (!(bundle->next))
351             return 0;
352     }
353
354     entry = (ET_ENTRY *)((BYTE *)bundle+6);
355     for (i=0; i < (ordinal - bundle->first - 1); i++)
356         entry++;
357
358     entry->offs = offset;
359     return TRUE;
360 }
361
362
363 /***********************************************************************
364  *           NE_OpenFile
365  */
366 HANDLE NE_OpenFile( NE_MODULE *pModule )
367 {
368     char *name;
369
370     static HANDLE cachedfd = -1;
371
372     TRACE( module, "(%p) cache: mod=%p fd=%d\n",
373            pModule, pCachedModule, cachedfd );
374     if (pCachedModule == pModule) return cachedfd;
375     CloseHandle( cachedfd );
376     pCachedModule = pModule;
377     name = NE_MODULE_NAME( pModule );
378     if ((cachedfd = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
379                                    NULL, OPEN_EXISTING, 0, -1 )) == -1)
380         MSG( "Can't open file '%s' for module %04x\n", name, pModule->self );
381     else
382         /* FIXME: should not be necessary */
383         cachedfd = ConvertToGlobalHandle(cachedfd);
384     TRACE(module, "opened '%s' -> %d\n",
385                     name, cachedfd );
386     return cachedfd;
387 }
388
389
390 /***********************************************************************
391  *           NE_LoadExeHeader
392  */
393 static HMODULE16 NE_LoadExeHeader( HFILE16 hFile, OFSTRUCT *ofs )
394 {
395     IMAGE_DOS_HEADER mz_header;
396     IMAGE_OS2_HEADER ne_header;
397     int size;
398     HMODULE16 hModule;
399     NE_MODULE *pModule;
400     BYTE *pData, *pTempEntryTable;
401     char *buffer, *fastload = NULL;
402     int fastload_offset = 0, fastload_length = 0;
403     ET_ENTRY *entry;
404     ET_BUNDLE *bundle, *oldbundle;
405
406   /* Read a block from either the file or the fast-load area. */
407 #define READ(offset,size,buffer) \
408        ((fastload && ((offset) >= fastload_offset) && \
409          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
410         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
411         (_llseek16( hFile, (offset), SEEK_SET), \
412          _hread16( hFile, (buffer), (size) ) == (size)))
413
414     _llseek16( hFile, 0, SEEK_SET );
415     if ((_hread16(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
416         (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
417         return (HMODULE16)11;  /* invalid exe */
418
419     _llseek16( hFile, mz_header.e_lfanew, SEEK_SET );
420     if (_hread16( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
421         return (HMODULE16)11;  /* invalid exe */
422
423     if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21;  /* win32 exe */
424     if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)11;  /* invalid exe */
425
426     if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
427       MSG("Sorry, this is an OS/2 linear executable (LX) file !\n");
428       return (HMODULE16)12;
429     }
430
431     /* We now have a valid NE header */
432
433     size = sizeof(NE_MODULE) +
434              /* segment table */
435            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
436              /* resource table */
437            ne_header.rname_tab_offset - ne_header.resource_tab_offset +
438              /* resident names table */
439            ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
440              /* module ref table */
441            ne_header.n_mod_ref_tab * sizeof(WORD) + 
442              /* imported names table */
443            ne_header.entry_tab_offset - ne_header.iname_tab_offset +
444              /* entry table length */
445            ne_header.entry_tab_length +
446              /* entry table extra conversion space */
447            sizeof(ET_BUNDLE) +
448            2 * (ne_header.entry_tab_length - ne_header.n_mov_entry_points*6) +
449              /* loaded file info */
450            sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
451
452     hModule = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, size );
453     if (!hModule) return (HMODULE16)11;  /* invalid exe */
454     FarSetOwner16( hModule, hModule );
455     pModule = (NE_MODULE *)GlobalLock16( hModule );
456     memcpy( pModule, &ne_header, sizeof(ne_header) );
457     pModule->count = 0;
458     /* check *programs* for default minimal stack size */
459     if ( (!(pModule->flags & NE_FFLAGS_LIBMODULE))
460                 && (pModule->stack_size < 0x1400) )
461                 pModule->stack_size = 0x1400;
462     pModule->module32 = 0;
463     pModule->self = hModule;
464     pModule->self_loading_sel = 0;
465     pData = (BYTE *)(pModule + 1);
466
467     /* Clear internal Wine flags in case they are set in the EXE file */
468
469     pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
470
471     /* Read the fast-load area */
472
473     if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
474     {
475         fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
476         fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
477         TRACE(module, "Using fast-load area offset=%x len=%d\n",
478                         fastload_offset, fastload_length );
479         if ((fastload = HeapAlloc( SystemHeap, 0, fastload_length )) != NULL)
480         {
481             _llseek16( hFile, fastload_offset, SEEK_SET);
482             if (_hread16(hFile, fastload, fastload_length) != fastload_length)
483             {
484                 HeapFree( SystemHeap, 0, fastload );
485                 WARN( module, "Error reading fast-load area!\n");
486                 fastload = NULL;
487             }
488         }
489     }
490
491     /* Get the segment table */
492
493     pModule->seg_table = (int)pData - (int)pModule;
494     buffer = HeapAlloc( SystemHeap, 0, ne_header.n_segment_tab *
495                                       sizeof(struct ne_segment_table_entry_s));
496     if (buffer)
497     {
498         int i;
499         struct ne_segment_table_entry_s *pSeg;
500
501         if (!READ( mz_header.e_lfanew + ne_header.segment_tab_offset,
502              ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
503              buffer ))
504         {
505             HeapFree( SystemHeap, 0, buffer );
506             if (fastload)
507                 HeapFree( SystemHeap, 0, fastload );
508             GlobalFree16( hModule );
509             return (HMODULE16)11;  /* invalid exe */
510         }
511         pSeg = (struct ne_segment_table_entry_s *)buffer;
512         for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
513         {
514             memcpy( pData, pSeg, sizeof(*pSeg) );
515             pData += sizeof(SEGTABLEENTRY);
516         }
517         HeapFree( SystemHeap, 0, buffer );
518     }
519     else
520     {
521         if (fastload)
522             HeapFree( SystemHeap, 0, fastload );
523         GlobalFree16( hModule );
524         return (HMODULE16)11;  /* invalid exe */
525     }
526
527     /* Get the resource table */
528
529     if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
530     {
531         pModule->res_table = (int)pData - (int)pModule;
532         if (!READ(mz_header.e_lfanew + ne_header.resource_tab_offset,
533                   ne_header.rname_tab_offset - ne_header.resource_tab_offset,
534                   pData )) return (HMODULE16)11;  /* invalid exe */
535         pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
536         NE_InitResourceHandler( hModule );
537     }
538     else pModule->res_table = 0;  /* No resource table */
539
540     /* Get the resident names table */
541
542     pModule->name_table = (int)pData - (int)pModule;
543     if (!READ( mz_header.e_lfanew + ne_header.rname_tab_offset,
544                ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
545                pData ))
546     {
547         if (fastload)
548             HeapFree( SystemHeap, 0, fastload );
549         GlobalFree16( hModule );
550         return (HMODULE16)11;  /* invalid exe */
551     }
552     pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
553
554     /* Get the module references table */
555
556     if (ne_header.n_mod_ref_tab > 0)
557     {
558         pModule->modref_table = (int)pData - (int)pModule;
559         if (!READ( mz_header.e_lfanew + ne_header.moduleref_tab_offset,
560                   ne_header.n_mod_ref_tab * sizeof(WORD),
561                   pData ))
562         {
563             if (fastload)
564                 HeapFree( SystemHeap, 0, fastload );
565             GlobalFree16( hModule );
566             return (HMODULE16)11;  /* invalid exe */
567         }
568         pData += ne_header.n_mod_ref_tab * sizeof(WORD);
569     }
570     else pModule->modref_table = 0;  /* No module references */
571
572     /* Get the imported names table */
573
574     pModule->import_table = (int)pData - (int)pModule;
575     if (!READ( mz_header.e_lfanew + ne_header.iname_tab_offset, 
576                ne_header.entry_tab_offset - ne_header.iname_tab_offset,
577                pData ))
578     {
579         if (fastload)
580             HeapFree( SystemHeap, 0, fastload );
581         GlobalFree16( hModule );
582         return (HMODULE16)11;  /* invalid exe */
583     }
584     pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
585
586     /* Load entry table, convert it to the optimized version used by Windows */
587
588     if ((pTempEntryTable = HeapAlloc( SystemHeap, 0, ne_header.entry_tab_length)) != NULL)
589     {
590         BYTE nr_entries, type, *s;
591
592         TRACE(module, "Converting entry table.\n");
593     pModule->entry_table = (int)pData - (int)pModule;
594     if (!READ( mz_header.e_lfanew + ne_header.entry_tab_offset,
595                 ne_header.entry_tab_length, pTempEntryTable ))
596     {
597             HeapFree( SystemHeap, 0, pTempEntryTable );
598             if (fastload)
599                 HeapFree( SystemHeap, 0, fastload );
600         GlobalFree16( hModule );
601         return (HMODULE16)11;  /* invalid exe */
602     }
603
604         s = pTempEntryTable;
605         TRACE(module, "entry table: offs %04x, len %04x, entries %d\n", ne_header.entry_tab_offset, ne_header.entry_tab_length, *s);
606
607         bundle = (ET_BUNDLE *)pData;
608         TRACE(module, "first bundle: %p\n", bundle);
609         memset(bundle, 0, sizeof(ET_BUNDLE)); /* in case no entry table exists */
610         entry = (ET_ENTRY *)((BYTE *)bundle+6);
611
612         while ((nr_entries = *s++))
613         {
614             if ((type = *s++))
615             {
616                 bundle->last += nr_entries;
617                 if (type == 0xff)
618                 while (nr_entries--)
619                 {
620                     entry->type   = type;
621                     entry->flags  = *s++;
622                     s += 2;
623                     entry->segnum = *s++;
624                     entry->offs   = *(WORD *)s; s += 2;
625                     /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/
626                     entry++;
627                 }
628                 else
629                 while (nr_entries--)
630                 {
631                     entry->type   = type;
632                     entry->flags  = *s++;
633                     entry->segnum = type;
634                     entry->offs   = *(WORD *)s; s += 2;
635                     /*TRACE(module, "entry: %p, type: %d, flags: %d, segnum: %d, offs: %04x\n", entry, entry->type, entry->flags, entry->segnum, entry->offs);*/
636                     entry++;
637                 }
638             }
639             else
640             {
641                 if (bundle->first == bundle->last)
642                 {
643                     bundle->first += nr_entries;
644                     bundle->last += nr_entries;
645                 }
646                 else
647                 {
648                     oldbundle = bundle;
649                     oldbundle->next = ((int)entry - (int)pModule);
650                     bundle = (ET_BUNDLE *)entry;
651                     TRACE(module, "new bundle: %p\n", bundle);
652                     bundle->first = bundle->last =
653                         oldbundle->last + nr_entries;
654                     bundle->next = 0;
655                     (BYTE *)entry += sizeof(ET_BUNDLE);
656                 }
657             }
658         }
659         HeapFree( SystemHeap, 0, pTempEntryTable );
660     }
661     else
662     {
663         if (fastload)
664             HeapFree( SystemHeap, 0, fastload );
665         GlobalFree16( hModule );
666         return (HMODULE16)11;  /* invalid exe */
667     }
668
669     pData += ne_header.entry_tab_length + sizeof(ET_BUNDLE) +
670              2 * (ne_header.entry_tab_length - ne_header.n_mov_entry_points*6);
671
672     if ((DWORD)entry > (DWORD)pData)
673        ERR(module, "converted entry table bigger than reserved space !!!\nentry: %p, pData: %p. Please report !\n", entry, pData);
674
675     /* Store the filename information */
676
677     pModule->fileinfo = (int)pData - (int)pModule;
678     size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
679     memcpy( pData, ofs, size );
680     ((OFSTRUCT *)pData)->cBytes = size - 1;
681     pData += size;
682
683     /* Free the fast-load area */
684
685 #undef READ
686     if (fastload)
687         HeapFree( SystemHeap, 0, fastload );
688
689     /* Get the non-resident names table */
690
691     if (ne_header.nrname_tab_length)
692     {
693         pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
694                                                hModule, FALSE, FALSE, FALSE );
695         if (!pModule->nrname_handle)
696         {
697             GlobalFree16( hModule );
698             return (HMODULE16)11;  /* invalid exe */
699         }
700         buffer = GlobalLock16( pModule->nrname_handle );
701         _llseek16( hFile, ne_header.nrname_tab_offset, SEEK_SET );
702         if (_hread16( hFile, buffer, ne_header.nrname_tab_length )
703               != ne_header.nrname_tab_length)
704         {
705             GlobalFree16( pModule->nrname_handle );
706             GlobalFree16( hModule );
707             return (HMODULE16)11;  /* invalid exe */
708         }
709     }
710     else pModule->nrname_handle = 0;
711
712     /* Allocate a segment for the implicitly-loaded DLLs */
713
714     if (pModule->modref_count)
715     {
716         pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
717                                     (pModule->modref_count+1)*sizeof(HMODULE16),
718                                     hModule, FALSE, FALSE, FALSE );
719         if (!pModule->dlls_to_init)
720         {
721             if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
722             GlobalFree16( hModule );
723             return (HMODULE16)11;  /* invalid exe */
724         }
725     }
726     else pModule->dlls_to_init = 0;
727
728     NE_RegisterModule( pModule );
729     if (fnSNOOP16_RegisterDLL)
730         fnSNOOP16_RegisterDLL(pModule,ofs->szPathName);
731     return hModule;
732 }
733
734
735 /***********************************************************************
736  *           NE_LoadDLLs
737  *
738  * Load all DLLs implicitly linked to a module.
739  */
740 static BOOL NE_LoadDLLs( NE_MODULE *pModule )
741 {
742     int i;
743     WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
744     WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
745
746     for (i = 0; i < pModule->modref_count; i++, pModRef++)
747     {
748         char buffer[260];
749         BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
750         memcpy( buffer, pstr + 1, *pstr );
751        *(buffer + *pstr) = 0; /* terminate it */
752
753         TRACE(module, "Loading '%s'\n", buffer );
754         if (!(*pModRef = GetModuleHandle16( buffer )))
755         {
756             /* If the DLL is not loaded yet, load it and store */
757             /* its handle in the list of DLLs to initialize.   */
758             HMODULE16 hDLL;
759
760             if ((hDLL = MODULE_LoadModule16( buffer, TRUE )) < 32)
761             {
762                 /* FIXME: cleanup what was done */
763
764                 MSG( "Could not load '%s' required by '%.*s', error=%d\n",
765                      buffer, *((BYTE*)pModule + pModule->name_table),
766                      (char *)pModule + pModule->name_table + 1, hDLL );
767                 return FALSE;
768             }
769             *pModRef = GetExePtr( hDLL );
770             *pDLLs++ = *pModRef;
771         }
772         else  /* Increment the reference count of the DLL */
773         {
774             NE_MODULE *pOldDLL;
775
776             pOldDLL = NE_GetPtr( *pModRef );
777             if (pOldDLL) pOldDLL->count++;
778         }
779     }
780     return TRUE;
781 }
782
783
784 /**********************************************************************
785  *          NE_LoadFileModule
786  *
787  * Load first instance of NE module from file.
788  * (Note: caller is responsible for ensuring the module isn't
789  *        already loaded!)
790  */
791 static HINSTANCE16 NE_LoadFileModule( HFILE16 hFile, OFSTRUCT *ofs, 
792                                       BOOL implicit )
793 {
794     HINSTANCE16 hInstance;
795     HMODULE16 hModule;
796     NE_MODULE *pModule;
797
798     /* Create the module structure */
799
800     hModule = NE_LoadExeHeader( hFile, ofs );
801     if (hModule < 32) return hModule;
802     pModule = NE_GetPtr( hModule );
803
804     /* Allocate the segments for this module */
805
806     if (!NE_CreateSegments( pModule ) ||
807         !(hInstance = NE_CreateInstance( pModule, NULL, FALSE )))
808     {
809         GlobalFreeAll16( hModule );
810         return 8;  /* Insufficient memory */
811     }
812
813     /* Load the referenced DLLs */
814
815     if (!NE_LoadDLLs( pModule ))
816         return 2;  /* File not found (FIXME: free everything) */
817
818     /* Load the segments */
819
820     NE_LoadAllSegments( pModule );
821
822     /* Fixup the functions prologs */
823
824     NE_FixupPrologs( pModule );
825
826     /* Make sure the usage count is 1 on the first loading of  */
827     /* the module, even if it contains circular DLL references */
828
829     pModule->count = 1;
830
831     return hInstance;
832 }
833
834 /**********************************************************************
835  *          NE_LoadModule
836  *
837  * Load first instance of NE module, deciding whether to use
838  * built-in module or load module from file.
839  * (Note: caller is responsible for ensuring the module isn't
840  *        already loaded!)
841  */
842 HINSTANCE16 NE_LoadModule( LPCSTR name, BOOL implicit )
843 {
844     HINSTANCE16 hInstance;
845     HFILE16 hFile;
846     OFSTRUCT ofs;
847
848     if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
849     {
850         char    buffer[260];
851
852         if(implicit)
853         {
854             /* 4 == strlen(".dll") */
855             strncpy(buffer, name, sizeof(buffer) - 1 - 4);
856             strcat(buffer, ".dll");
857             if ((hFile = OpenFile16( buffer, &ofs, OF_READ )) == HFILE_ERROR16)
858                 return 2;  /* File not found */
859         }
860     }
861
862     hInstance = NE_LoadFileModule( hFile, &ofs, implicit );
863     _lclose16( hFile );
864
865     return hInstance;
866 }
867
868
869 /**********************************************************************
870  *          MODULE_LoadModule16
871  *
872  * Load a NE module in the order of the loadorder specification.
873  * The caller is responsible that the module is not loaded already.
874  *
875  */
876 HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit )
877 {
878         HINSTANCE16 hinst;
879         int i;
880         module_loadorder_t *plo;
881
882         plo = MODULE_GetLoadOrder(libname);
883
884         for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
885         {
886                 switch(plo->loadorder[i])
887                 {
888                 case MODULE_LOADORDER_DLL:
889                         TRACE(module, "Trying native dll '%s'\n", libname);
890                         hinst = NE_LoadModule(libname, implicit);
891                         break;
892
893                 case MODULE_LOADORDER_ELFDLL:
894                         TRACE(module, "Trying elfdll '%s'\n", libname);
895                         hinst = ELFDLL_LoadModule16(libname, implicit);
896                         break;
897
898                 case MODULE_LOADORDER_BI:
899                         TRACE(module, "Trying built-in '%s'\n", libname);
900                         hinst = fnBUILTIN_LoadModule(libname, TRUE);
901                         break;
902
903                 default:
904                         ERR(module, "Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
905                 /* Fall through */
906
907                 case MODULE_LOADORDER_SO:       /* This is not supported for NE modules */
908                 case MODULE_LOADORDER_INVALID:  /* We ignore this as it is an empty entry */
909                         hinst = 2;
910                         break;
911                 }
912
913                 if(hinst >= 32)
914                 {
915                         if(!implicit)
916                         {
917                                 HMODULE16 hModule;
918                                 NE_MODULE *pModule;
919
920                                 hModule = GetModuleHandle16(libname);
921                                 if(!hModule)
922                                 {
923                                         ERR(module, "Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get module handle\n",
924                                                 libname, hinst);
925                                         return 6;       /* ERROR_INVALID_HANDLE seems most appropriate */
926                                 }
927
928                                 pModule = NE_GetPtr(hModule);
929                                 if(!pModule)
930                                 {
931                                         ERR(module, "Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get NE_MODULE pointer\n",
932                                                 libname, hinst);
933                                         return 6;       /* ERROR_INVALID_HANDLE seems most appropriate */
934                                 }
935
936                                 TRACE(module, "Loaded module '%s' at 0x%04x, \n", libname, hinst);
937
938                                 /*
939                                  * Call initialization routines for all loaded DLLs. Note that
940                                  * when we load implicitly linked DLLs this will be done by InitTask().
941                                  */
942                                 if(pModule->flags & NE_FFLAGS_LIBMODULE)
943                                         NE_InitializeDLLs(hModule);
944                         }
945                         return hinst;
946                 }
947
948                 if(hinst != 2)
949                 {
950                         /* We quit searching when we get another error than 'File not found' */
951                         break;
952                 }
953         }
954         return hinst;   /* The last error that occured */
955 }
956
957
958 /**********************************************************************
959  *          LoadModule16    (KERNEL.45)
960  */
961 HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
962 {
963     BOOL lib_only = !paramBlock || (paramBlock == (LPVOID)-1);
964     LOADPARAMS16 *params;
965     LPSTR cmd_line, new_cmd_line;
966     LPCVOID env = NULL;
967     STARTUPINFOA startup;
968     PROCESS_INFORMATION info;
969     HINSTANCE16 hInstance, hPrevInstance = 0;
970     HMODULE16 hModule;
971     NE_MODULE *pModule;
972     PDB *pdb;
973
974     /* Load module */
975
976     if ( (hModule = GetModuleHandle16(name) ) != 0 )
977     {
978         /* Special case: second instance of an already loaded NE module */
979
980         if ( !( pModule = NE_GetPtr( hModule ) ) ) return (HINSTANCE16)11;
981         if ( pModule->module32 ) return (HINSTANCE16)21;
982
983         hInstance = NE_CreateInstance( pModule, &hPrevInstance, lib_only );
984         if ( hInstance != hPrevInstance )  /* not a library */
985             NE_LoadSegment( pModule, pModule->dgroup );
986
987         pModule->count++;
988     }
989     else
990     {
991         /* Main case: load first instance of NE module */
992
993         if ( (hInstance = MODULE_LoadModule16( name, FALSE )) < 32 )
994             return hInstance;
995
996         if ( !(pModule = NE_GetPtr( hInstance )) )
997             return (HINSTANCE16)11;
998     }
999
1000     /* If library module, we're finished */
1001
1002     if ( ( pModule->flags & NE_FFLAGS_LIBMODULE ) || lib_only )
1003         return hInstance;
1004
1005     /* Create a task for this instance */
1006
1007     pModule->flags |= NE_FFLAGS_GUI;  /* FIXME: is this necessary? */
1008
1009     params = (LOADPARAMS16 *)paramBlock;
1010     cmd_line = (LPSTR)PTR_SEG_TO_LIN( params->cmdLine );
1011     if (!cmd_line) cmd_line = "";
1012     else if (*cmd_line) cmd_line++;  /* skip the length byte */
1013
1014     if (!(new_cmd_line = HeapAlloc( GetProcessHeap(), 0,
1015                                     strlen(cmd_line)+strlen(name)+2 )))
1016         return 0;
1017     strcpy( new_cmd_line, name );
1018     strcat( new_cmd_line, " " );
1019     strcat( new_cmd_line, cmd_line );
1020
1021     if (params->hEnvironment) env = GlobalLock16( params->hEnvironment );
1022
1023     memset( &info, '\0', sizeof(info) );
1024     memset( &startup, '\0', sizeof(startup) );
1025     startup.cb = sizeof(startup);
1026     if (params->showCmd)
1027     {
1028         startup.dwFlags = STARTF_USESHOWWINDOW;
1029         startup.wShowWindow = ((UINT16 *)PTR_SEG_TO_LIN(params->showCmd))[1];
1030     }
1031
1032     SYSLEVEL_ReleaseWin16Lock();
1033     pdb = PROCESS_Create( pModule, new_cmd_line, env,
1034                           hInstance, hPrevInstance, 
1035                           NULL, NULL, TRUE, 0, &startup, &info );
1036     SYSLEVEL_RestoreWin16Lock();
1037
1038     CloseHandle( info.hThread );
1039     CloseHandle( info.hProcess );
1040
1041     if (params->hEnvironment) GlobalUnlock16( params->hEnvironment );
1042     HeapFree( GetProcessHeap(), 0, new_cmd_line );
1043     return hInstance;
1044 }
1045
1046 /**********************************************************************
1047  *          NE_CreateProcess
1048  */
1049 BOOL NE_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmd_line, LPCSTR env, 
1050                        LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
1051                        BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
1052                        LPPROCESS_INFORMATION info )
1053 {
1054     HINSTANCE16 hInstance, hPrevInstance = 0;
1055     HMODULE16 hModule;
1056     NE_MODULE *pModule;
1057     HFILE16 hFile16;
1058
1059     /* Special case: second instance of an already loaded NE module */
1060
1061     if ( ( hModule = GetModuleHandle16( ofs->szPathName ) ) != 0 )
1062     {
1063         if (   !( pModule = NE_GetPtr( hModule) )
1064             ||  ( pModule->flags & NE_FFLAGS_LIBMODULE )
1065             ||  pModule->module32 )
1066         {
1067             SetLastError( ERROR_BAD_FORMAT );
1068             return FALSE;
1069         }
1070
1071         hInstance = NE_CreateInstance( pModule, &hPrevInstance, FALSE );
1072         if ( hInstance != hPrevInstance )  /* not a library */
1073             NE_LoadSegment( pModule, pModule->dgroup );
1074
1075         pModule->count++;
1076     }
1077
1078     /* Main case: load first instance of NE module */
1079     else
1080     {
1081         /* If we didn't get a file handle, return */
1082
1083         if ( hFile == HFILE_ERROR )
1084             return FALSE;
1085
1086         /* Allocate temporary HFILE16 for NE_LoadFileModule */
1087
1088         if (!DuplicateHandle( GetCurrentProcess(), hFile,
1089                               GetCurrentProcess(), &hFile,
1090                               0, FALSE, DUPLICATE_SAME_ACCESS ))
1091         {
1092             SetLastError( ERROR_INVALID_HANDLE );
1093             return FALSE;
1094         }
1095         hFile16 = FILE_AllocDosHandle( hFile );
1096
1097         /* Load module */
1098
1099         hInstance = NE_LoadFileModule( hFile16, ofs, TRUE );
1100         _lclose16( hFile16 );
1101
1102         if ( hInstance < 32 )
1103         {
1104             SetLastError( hInstance );
1105             return FALSE;
1106         }
1107
1108         if (   !( pModule = NE_GetPtr( hInstance ) )
1109             ||  ( pModule->flags & NE_FFLAGS_LIBMODULE) )
1110         {
1111             /* FIXME: cleanup */
1112             SetLastError( ERROR_BAD_FORMAT );
1113             return FALSE;
1114         }
1115     }
1116
1117     /* Create a task for this instance */
1118
1119     pModule->flags |= NE_FFLAGS_GUI;  /* FIXME: is this necessary? */
1120
1121     if ( !PROCESS_Create( pModule, cmd_line, env,
1122                           hInstance, hPrevInstance, 
1123                           psa, tsa, inherit, flags, startup, info ) )
1124         return FALSE;
1125
1126     return TRUE;
1127 }
1128
1129 /***********************************************************************
1130  *           LoadLibrary16   (KERNEL.95)
1131  *
1132  * In Win95 LoadLibrary16("c:/junkname/user.foo") returns the HINSTANCE 
1133  * to user.exe. As GetModuleHandle as of 990425 explicitly asks _not_ 
1134  * to change its handling of extensions, we have to try a stripped down
1135  * libname here too (bon 990425)   
1136  */
1137 HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
1138 {
1139     char strippedname[256];
1140     char *dirsep1,*dirsep2;
1141     HINSTANCE16 ret;
1142
1143     dirsep1=strrchr(libname,'\\');
1144     dirsep2=strrchr(libname,'/');
1145     dirsep1=MAX(dirsep1,dirsep2);
1146     if (!dirsep1)
1147       dirsep1 =(LPSTR)libname;
1148     else
1149       dirsep1++;
1150     lstrcpynA(strippedname,dirsep1,256);
1151     dirsep1=strchr(strippedname,'.');
1152     if (dirsep1)
1153       *dirsep1=0;
1154
1155     TRACE( module, "looking for (%p) %s and %s \n", 
1156            libname, libname,strippedname );
1157
1158     /* Load library module */
1159     ret= LoadModule16( strippedname, (LPVOID)-1 );
1160     if (ret > HINSTANCE_ERROR)
1161       return ret;
1162     return LoadModule16(libname, (LPVOID)-1 );
1163 }
1164
1165
1166 /**********************************************************************
1167  *          MODULE_CallWEP
1168  *
1169  * Call a DLL's WEP, allowing it to shut down.
1170  * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
1171  */
1172 static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
1173 {
1174     FARPROC16 WEP = (FARPROC16)0;
1175     WORD ordinal = NE_GetOrdinal( hModule, "WEP" );
1176
1177     if (ordinal) WEP = NE_GetEntryPoint( hModule, ordinal );
1178     if (!WEP)
1179     {
1180         WARN(module, "module %04x doesn't have a WEP\n", hModule );
1181         return FALSE;
1182     }
1183     return Callbacks->CallWindowsExitProc( WEP, WEP_FREE_DLL );
1184 }
1185
1186
1187 /**********************************************************************
1188  *          NE_FreeModule
1189  *
1190  * Implementation of FreeModule16().
1191  */
1192 static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep )
1193 {
1194     HMODULE16 *hPrevModule;
1195     NE_MODULE *pModule;
1196     HMODULE16 *pModRef;
1197     int i;
1198
1199     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
1200     hModule = pModule->self;
1201
1202     TRACE( module, "%04x count %d\n", hModule, pModule->count );
1203
1204     if (((INT16)(--pModule->count)) > 0 ) return TRUE;
1205     else pModule->count = 0;
1206
1207     if (pModule->flags & NE_FFLAGS_BUILTIN)
1208         return FALSE;  /* Can't free built-in module */
1209
1210     if (call_wep)
1211     {
1212         if (pModule->flags & NE_FFLAGS_LIBMODULE)
1213         {
1214             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
1215             MODULE_CallWEP( hModule );
1216
1217             /* Free the objects owned by the DLL module */
1218
1219             if (pTask && pTask->userhandler)
1220                 pTask->userhandler( hModule, USIG16_DLL_UNLOAD, 0,
1221                                     pTask->hInstance, pTask->hQueue );
1222
1223             PROCESS_CallUserSignalProc( USIG_DLL_UNLOAD_WIN16, hModule );
1224         }
1225         else
1226             call_wep = FALSE;  /* We are freeing a task -> no more WEPs */
1227     }
1228     
1229
1230     /* Clear magic number just in case */
1231
1232     pModule->magic = pModule->self = 0;
1233
1234       /* Remove it from the linked list */
1235
1236     hPrevModule = &hFirstModule;
1237     while (*hPrevModule && (*hPrevModule != hModule))
1238     {
1239         hPrevModule = &(NE_GetPtr( *hPrevModule ))->next;
1240     }
1241     if (*hPrevModule) *hPrevModule = pModule->next;
1242
1243     /* Free the referenced modules */
1244
1245     pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
1246     for (i = 0; i < pModule->modref_count; i++, pModRef++)
1247     {
1248         NE_FreeModule( *pModRef, call_wep );
1249     }
1250
1251     /* Free the module storage */
1252
1253     GlobalFreeAll16( hModule );
1254
1255     /* Remove module from cache */
1256
1257     if (pCachedModule == pModule) pCachedModule = NULL;
1258     return TRUE;
1259 }
1260
1261
1262 /**********************************************************************
1263  *          FreeModule16    (KERNEL.46)
1264  */
1265 BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
1266 {
1267     return NE_FreeModule( hModule, TRUE );
1268 }
1269
1270
1271 /***********************************************************************
1272  *           FreeLibrary16   (KERNEL.96)
1273  */
1274 void WINAPI FreeLibrary16( HINSTANCE16 handle )
1275 {
1276     TRACE(module,"%04x\n", handle );
1277     FreeModule16( handle );
1278 }
1279
1280
1281 /**********************************************************************
1282  *          GetModuleName    (KERNEL.27)
1283  */
1284 BOOL16 WINAPI GetModuleName16( HINSTANCE16 hinst, LPSTR buf, INT16 count )
1285 {
1286     NE_MODULE *pModule;
1287     BYTE *p;
1288
1289     if (!(pModule = NE_GetPtr( hinst ))) return FALSE;
1290     p = (BYTE *)pModule + pModule->name_table;
1291     if (count > *p) count = *p + 1;
1292     if (count > 0)
1293     {
1294         memcpy( buf, p + 1, count - 1 );
1295         buf[count-1] = '\0';
1296     }
1297     return TRUE;
1298 }
1299
1300
1301 /**********************************************************************
1302  *          GetModuleUsage    (KERNEL.48)
1303  */
1304 INT16 WINAPI GetModuleUsage16( HINSTANCE16 hModule )
1305 {
1306     NE_MODULE *pModule = NE_GetPtr( hModule );
1307     return pModule ? pModule->count : 0;
1308 }
1309
1310
1311 /**********************************************************************
1312  *          GetExpWinVer    (KERNEL.167)
1313  */
1314 WORD WINAPI GetExpWinVer16( HMODULE16 hModule )
1315 {
1316     NE_MODULE *pModule = NE_GetPtr( hModule );
1317     return pModule ? pModule->expected_version : 0;
1318 }
1319
1320
1321 /**********************************************************************
1322  *          GetModuleFileName16    (KERNEL.49)
1323  */
1324 INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName,
1325                                   INT16 nSize )
1326 {
1327     NE_MODULE *pModule;
1328
1329     if (!hModule) hModule = GetCurrentTask();
1330     if (!(pModule = NE_GetPtr( hModule ))) return 0;
1331     lstrcpynA( lpFileName, NE_MODULE_NAME(pModule), nSize );
1332     TRACE(module, "%s\n", lpFileName );
1333     return strlen(lpFileName);
1334 }
1335
1336
1337 /**********************************************************************
1338  *          GetModuleHandle16    (KERNEL.47)
1339  *
1340  * Find a module from a module name.
1341  *
1342  * NOTE: The current implementation works the same way the Windows 95 one
1343  *       does. Do not try to 'fix' it, fix the callers.
1344  *       + It does not do ANY extension handling (except that strange .EXE bit)!
1345  *       + It does not care about paths, just about basenames. (same as Windows)
1346  *
1347  * RETURNS
1348  *   LOWORD:
1349  *      the win16 module handle if found
1350  *      0 if not
1351  *   HIWORD (undocumented, see "Undocumented Windows", chapter 5):
1352  *      Always hFirstModule
1353  */
1354 DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name )
1355 {
1356     if (HIWORD(name) == 0)
1357         return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule );
1358     return MAKELONG(GetModuleHandle16( PTR_SEG_TO_LIN(name)), hFirstModule );
1359 }
1360
1361 HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
1362 {
1363     HMODULE16   hModule = hFirstModule;
1364     LPSTR       s;
1365     BYTE        len, *name_table;
1366     char        tmpstr[128];
1367     NE_MODULE *pModule;
1368
1369     TRACE(module, "(%s)\n", name);
1370
1371     if (!HIWORD(name))
1372         return GetExePtr(LOWORD(name));
1373
1374     len = strlen(name);
1375     if (!len)
1376         return 0;
1377
1378     strncpy(tmpstr, name, sizeof(tmpstr));
1379     tmpstr[sizeof(tmpstr)-1] = '\0';
1380
1381     /* If 'name' matches exactly the module name of a module:
1382      * Return its handle.
1383      */
1384     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1385     {
1386         pModule = NE_GetPtr( hModule );
1387         if (!pModule) break;
1388
1389         name_table = (BYTE *)pModule + pModule->name_table;
1390         if ((*name_table == len) && !strncmp(name, name_table+1, len))
1391             return hModule;
1392     }
1393
1394     /* If uppercased 'name' matches exactly the module name of a module:
1395      * Return its handle
1396      */
1397     for (s = tmpstr; *s; s++)
1398         *s = toupper(*s);
1399
1400     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1401     {
1402         pModule = NE_GetPtr( hModule );
1403         if (!pModule) break;
1404
1405         name_table = (BYTE *)pModule + pModule->name_table;
1406         if ((*name_table == len) && !strncmp(tmpstr, name_table+1, len))
1407             return hModule;
1408     }
1409
1410     /* If the base filename of 'name' matches the base filename of the module
1411      * filename of some module (case-insensitive compare):
1412      * Return its handle.
1413      */
1414
1415     /* basename: search backwards in passed name to \ / or : */
1416     s = tmpstr + strlen(tmpstr);
1417     while (s > tmpstr)
1418     {
1419         if (s[-1]=='/' || s[-1]=='\\' || s[-1]==':')
1420                 break;
1421         s--;
1422     }
1423
1424     /* search this in loaded filename list */
1425     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1426     {
1427         char            *loadedfn;
1428         OFSTRUCT        *ofs;
1429
1430         pModule = NE_GetPtr( hModule );
1431         if (!pModule) break;
1432         if (!pModule->fileinfo) continue;
1433
1434         ofs = (OFSTRUCT*)((BYTE *)pModule + pModule->fileinfo);
1435         loadedfn = ((char*)ofs->szPathName) + strlen(ofs->szPathName);
1436         /* basename: search backwards in pathname to \ / or : */
1437         while (loadedfn > (char*)ofs->szPathName)
1438         {
1439             if (loadedfn[-1]=='/' || loadedfn[-1]=='\\' || loadedfn[-1]==':')
1440                     break;
1441             loadedfn--;
1442         }
1443         /* case insensitive compare ... */
1444         if (!lstrcmpiA(loadedfn, s))
1445             return hModule;
1446     }
1447
1448     /* If the extension of 'name' is '.EXE' and the base filename of 'name'
1449      * matches the base filename of the module filename of some 32-bit module:
1450      * Return the corresponding 16-bit dummy module handle. 
1451      */
1452     if (len >= 4 && !strcasecmp(name+len-4, ".EXE"))
1453     {
1454         HMODULE hModule = GetModuleHandleA( name );
1455         if ( hModule )
1456             return MapHModuleLS( hModule );
1457     }
1458
1459     if (!strcmp(tmpstr,"MSDOS"))
1460         return 1;
1461
1462     if (!strcmp(tmpstr,"TIMER"))
1463     {
1464         FIXME(module, "Eh... Should return caller's code segment, expect crash\n");
1465         return 0;
1466     }
1467
1468     return 0;
1469 }
1470
1471
1472 /**********************************************************************
1473  *          ModuleFirst    (TOOLHELP.59)
1474  */
1475 BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
1476 {
1477     lpme->wNext = hFirstModule;
1478     return ModuleNext16( lpme );
1479 }
1480
1481
1482 /**********************************************************************
1483  *          ModuleNext    (TOOLHELP.60)
1484  */
1485 BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
1486 {
1487     NE_MODULE *pModule;
1488     char *name;
1489
1490     if (!lpme->wNext) return FALSE;
1491     if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE;
1492     name = (char *)pModule + pModule->name_table;
1493     memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
1494     lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
1495     lpme->hModule = lpme->wNext;
1496     lpme->wcUsage = pModule->count;
1497     lstrcpynA( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) );
1498     lpme->wNext = pModule->next;
1499     return TRUE;
1500 }
1501
1502
1503 /**********************************************************************
1504  *          ModuleFindName    (TOOLHELP.61)
1505  */
1506 BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
1507 {
1508     lpme->wNext = GetModuleHandle16( name );
1509     return ModuleNext16( lpme );
1510 }
1511
1512
1513 /**********************************************************************
1514  *          ModuleFindHandle    (TOOLHELP.62)
1515  */
1516 BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
1517 {
1518     hModule = GetExePtr( hModule );
1519     lpme->wNext = hModule;
1520     return ModuleNext16( lpme );
1521 }
1522
1523
1524 /***************************************************************************
1525  *              MapHModuleLS                    (KERNEL32.520)
1526  */
1527 HMODULE16 WINAPI MapHModuleLS(HMODULE hmod) {
1528         NE_MODULE       *pModule;
1529
1530         if (!hmod)
1531                 return ((TDB*)GlobalLock16(GetCurrentTask()))->hInstance;
1532         if (!HIWORD(hmod))
1533                 return hmod; /* we already have a 16 bit module handle */
1534         pModule = (NE_MODULE*)GlobalLock16(hFirstModule);
1535         while (pModule)  {
1536                 if (pModule->module32 == hmod)
1537                         return pModule->self;
1538                 pModule = (NE_MODULE*)GlobalLock16(pModule->next);
1539         }
1540         return 0;
1541 }
1542
1543 /***************************************************************************
1544  *              MapHModuleSL                    (KERNEL32.521)
1545  */
1546 HMODULE WINAPI MapHModuleSL(HMODULE16 hmod) {
1547         NE_MODULE       *pModule;
1548
1549         if (!hmod) {
1550                 TDB *pTask = (TDB*)GlobalLock16(GetCurrentTask());
1551
1552                 hmod = pTask->hModule;
1553         }
1554         pModule = (NE_MODULE*)GlobalLock16(hmod);
1555         if (    (pModule->magic!=IMAGE_OS2_SIGNATURE)   ||
1556                 !(pModule->flags & NE_FFLAGS_WIN32)
1557         )
1558                 return 0;
1559         return pModule->module32;
1560 }
1561
1562 /***************************************************************************
1563  *              MapHInstLS                      (KERNEL32.516)
1564  */
1565 void WINAPI REGS_FUNC(MapHInstLS)( CONTEXT *context )
1566 {
1567         EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1568 }
1569
1570 /***************************************************************************
1571  *              MapHInstSL                      (KERNEL32.518)
1572  */
1573 void WINAPI REGS_FUNC(MapHInstSL)( CONTEXT *context )
1574 {
1575         EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1576 }
1577
1578 /***************************************************************************
1579  *              MapHInstLS_PN                   (KERNEL32.517)
1580  */
1581 void WINAPI REGS_FUNC(MapHInstLS_PN)( CONTEXT *context )
1582 {
1583         if (EAX_reg(context))
1584             EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1585 }
1586
1587 /***************************************************************************
1588  *              MapHInstSL_PN                   (KERNEL32.519)
1589  */
1590 void WINAPI REGS_FUNC(MapHInstSL_PN)( CONTEXT *context )
1591 {
1592         if (EAX_reg(context))
1593             EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1594 }
1595
1596 /***************************************************************************
1597  *              WIN16_MapHInstLS                (KERNEL.472)
1598  */
1599 VOID WINAPI WIN16_MapHInstLS( CONTEXT *context ) {
1600         EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1601 }
1602
1603 /***************************************************************************
1604  *              WIN16_MapHInstSL                (KERNEL.473)
1605  */
1606 VOID WINAPI WIN16_MapHInstSL( CONTEXT *context ) {
1607         EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1608 }