Fixed loading of native NE dlls.
[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         /* 4 == strlen(".dll") */
853         strncpy(buffer, name, sizeof(buffer) - 1 - 4);
854         strcat(buffer, ".dll");
855         if ((hFile = OpenFile16( buffer, &ofs, OF_READ )) == HFILE_ERROR16) {
856             return 2;  /* File not found */
857         }
858     }
859
860     hInstance = NE_LoadFileModule( hFile, &ofs, implicit );
861     _lclose16( hFile );
862
863     return hInstance;
864 }
865
866
867 /**********************************************************************
868  *          MODULE_LoadModule16
869  *
870  * Load a NE module in the order of the loadorder specification.
871  * The caller is responsible that the module is not loaded already.
872  *
873  */
874 HINSTANCE16 MODULE_LoadModule16( LPCSTR libname, BOOL implicit )
875 {
876         HINSTANCE16 hinst;
877         int i;
878         module_loadorder_t *plo;
879
880         plo = MODULE_GetLoadOrder(libname);
881
882         for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
883         {
884                 switch(plo->loadorder[i])
885                 {
886                 case MODULE_LOADORDER_DLL:
887                         TRACE(module, "Trying native dll '%s'\n", libname);
888                         hinst = NE_LoadModule(libname, implicit);
889                         break;
890
891                 case MODULE_LOADORDER_ELFDLL:
892                         TRACE(module, "Trying elfdll '%s'\n", libname);
893                         hinst = ELFDLL_LoadModule16(libname, implicit);
894                         break;
895
896                 case MODULE_LOADORDER_BI:
897                         TRACE(module, "Trying built-in '%s'\n", libname);
898                         hinst = fnBUILTIN_LoadModule(libname, TRUE);
899                         break;
900
901                 default:
902                         ERR(module, "Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
903                 /* Fall through */
904
905                 case MODULE_LOADORDER_SO:       /* This is not supported for NE modules */
906                 case MODULE_LOADORDER_INVALID:  /* We ignore this as it is an empty entry */
907                         hinst = 2;
908                         break;
909                 }
910
911                 if(hinst >= 32)
912                 {
913                         if(!implicit)
914                         {
915                                 HMODULE16 hModule;
916                                 NE_MODULE *pModule;
917
918                                 hModule = GetModuleHandle16(libname);
919                                 if(!hModule)
920                                 {
921                                         ERR(module, "Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get module handle\n",
922                                                 libname, hinst);
923                                         return 6;       /* ERROR_INVALID_HANDLE seems most appropriate */
924                                 }
925
926                                 pModule = NE_GetPtr(hModule);
927                                 if(!pModule)
928                                 {
929                                         ERR(module, "Serious trouble. Just loaded module '%s' (hinst=0x%04x), but can't get NE_MODULE pointer\n",
930                                                 libname, hinst);
931                                         return 6;       /* ERROR_INVALID_HANDLE seems most appropriate */
932                                 }
933
934                                 TRACE(module, "Loaded module '%s' at 0x%04x, \n", libname, hinst);
935
936                                 /*
937                                  * Call initialization routines for all loaded DLLs. Note that
938                                  * when we load implicitly linked DLLs this will be done by InitTask().
939                                  */
940                                 if(pModule->flags & NE_FFLAGS_LIBMODULE)
941                                         NE_InitializeDLLs(hModule);
942                         }
943                         return hinst;
944                 }
945
946                 if(hinst != 2)
947                 {
948                         /* We quit searching when we get another error than 'File not found' */
949                         break;
950                 }
951         }
952         return hinst;   /* The last error that occured */
953 }
954
955
956 /**********************************************************************
957  *          LoadModule16    (KERNEL.45)
958  */
959 HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
960 {
961     BOOL lib_only = !paramBlock || (paramBlock == (LPVOID)-1);
962     LOADPARAMS16 *params;
963     LPSTR cmd_line, new_cmd_line;
964     LPCVOID env = NULL;
965     STARTUPINFOA startup;
966     PROCESS_INFORMATION info;
967     HINSTANCE16 hInstance, hPrevInstance = 0;
968     HMODULE16 hModule;
969     NE_MODULE *pModule;
970     PDB *pdb;
971
972     /* Load module */
973
974     if ( (hModule = GetModuleHandle16(name) ) != 0 )
975     {
976         /* Special case: second instance of an already loaded NE module */
977
978         if ( !( pModule = NE_GetPtr( hModule ) ) ) return (HINSTANCE16)11;
979         if ( pModule->module32 ) return (HINSTANCE16)21;
980
981         hInstance = NE_CreateInstance( pModule, &hPrevInstance, lib_only );
982         if ( hInstance != hPrevInstance )  /* not a library */
983             NE_LoadSegment( pModule, pModule->dgroup );
984
985         pModule->count++;
986     }
987     else
988     {
989         /* Main case: load first instance of NE module */
990
991         if ( (hInstance = MODULE_LoadModule16( name, FALSE )) < 32 )
992             return hInstance;
993
994         if ( !(pModule = NE_GetPtr( hInstance )) )
995             return (HINSTANCE16)11;
996     }
997
998     /* If library module, we're finished */
999
1000     if ( ( pModule->flags & NE_FFLAGS_LIBMODULE ) || lib_only )
1001         return hInstance;
1002
1003     /* Create a task for this instance */
1004
1005     pModule->flags |= NE_FFLAGS_GUI;  /* FIXME: is this necessary? */
1006
1007     params = (LOADPARAMS16 *)paramBlock;
1008     cmd_line = (LPSTR)PTR_SEG_TO_LIN( params->cmdLine );
1009     if (!cmd_line) cmd_line = "";
1010     else if (*cmd_line) cmd_line++;  /* skip the length byte */
1011
1012     if (!(new_cmd_line = HeapAlloc( GetProcessHeap(), 0,
1013                                     strlen(cmd_line)+strlen(name)+2 )))
1014         return 0;
1015     strcpy( new_cmd_line, name );
1016     strcat( new_cmd_line, " " );
1017     strcat( new_cmd_line, cmd_line );
1018
1019     if (params->hEnvironment) env = GlobalLock16( params->hEnvironment );
1020
1021     memset( &info, '\0', sizeof(info) );
1022     memset( &startup, '\0', sizeof(startup) );
1023     startup.cb = sizeof(startup);
1024     if (params->showCmd)
1025     {
1026         startup.dwFlags = STARTF_USESHOWWINDOW;
1027         startup.wShowWindow = ((UINT16 *)PTR_SEG_TO_LIN(params->showCmd))[1];
1028     }
1029
1030     pdb = PROCESS_Create( pModule, new_cmd_line, env,
1031                           hInstance, hPrevInstance, 
1032                           NULL, NULL, TRUE, &startup, &info );
1033
1034     CloseHandle( info.hThread );
1035     CloseHandle( info.hProcess );
1036
1037     if (params->hEnvironment) GlobalUnlock16( params->hEnvironment );
1038     HeapFree( GetProcessHeap(), 0, new_cmd_line );
1039     return hInstance;
1040 }
1041
1042 /**********************************************************************
1043  *          NE_CreateProcess
1044  */
1045 BOOL NE_CreateProcess( HFILE hFile, OFSTRUCT *ofs, LPCSTR cmd_line, LPCSTR env, 
1046                        LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
1047                        BOOL inherit, LPSTARTUPINFOA startup,
1048                        LPPROCESS_INFORMATION info )
1049 {
1050     HINSTANCE16 hInstance, hPrevInstance = 0;
1051     HMODULE16 hModule;
1052     NE_MODULE *pModule;
1053     HFILE16 hFile16;
1054
1055     /* Special case: second instance of an already loaded NE module */
1056
1057     if ( ( hModule = GetModuleHandle16( ofs->szPathName ) ) != 0 )
1058     {
1059         if (   !( pModule = NE_GetPtr( hModule) )
1060             ||  ( pModule->flags & NE_FFLAGS_LIBMODULE )
1061             ||  pModule->module32 )
1062         {
1063             SetLastError( ERROR_BAD_FORMAT );
1064             return FALSE;
1065         }
1066
1067         hInstance = NE_CreateInstance( pModule, &hPrevInstance, FALSE );
1068         if ( hInstance != hPrevInstance )  /* not a library */
1069             NE_LoadSegment( pModule, pModule->dgroup );
1070
1071         pModule->count++;
1072     }
1073
1074     /* Main case: load first instance of NE module */
1075     else
1076     {
1077         /* If we didn't get a file handle, return */
1078
1079         if ( hFile == HFILE_ERROR )
1080             return FALSE;
1081
1082         /* Allocate temporary HFILE16 for NE_LoadFileModule */
1083
1084         if (!DuplicateHandle( GetCurrentProcess(), hFile,
1085                               GetCurrentProcess(), &hFile,
1086                               0, FALSE, DUPLICATE_SAME_ACCESS ))
1087         {
1088             SetLastError( ERROR_INVALID_HANDLE );
1089             return FALSE;
1090         }
1091         hFile16 = FILE_AllocDosHandle( hFile );
1092
1093         /* Load module */
1094
1095         hInstance = NE_LoadFileModule( hFile16, ofs, TRUE );
1096         _lclose16( hFile16 );
1097
1098         if ( hInstance < 32 )
1099         {
1100             SetLastError( hInstance );
1101             return FALSE;
1102         }
1103
1104         if (   !( pModule = NE_GetPtr( hInstance ) )
1105             ||  ( pModule->flags & NE_FFLAGS_LIBMODULE) )
1106         {
1107             /* FIXME: cleanup */
1108             SetLastError( ERROR_BAD_FORMAT );
1109             return FALSE;
1110         }
1111     }
1112
1113     /* Create a task for this instance */
1114
1115     pModule->flags |= NE_FFLAGS_GUI;  /* FIXME: is this necessary? */
1116
1117     if ( !PROCESS_Create( pModule, cmd_line, env,
1118                           hInstance, hPrevInstance, 
1119                           psa, tsa, inherit, startup, info ) )
1120         return FALSE;
1121
1122     return TRUE;
1123 }
1124
1125 /***********************************************************************
1126  *           LoadLibrary16   (KERNEL.95)
1127  */
1128 HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
1129 {
1130     TRACE( module, "(%p) %s\n", libname, libname );
1131
1132     /* Load library module */
1133     return LoadModule16( libname, (LPVOID)-1 );
1134 }
1135
1136
1137 /**********************************************************************
1138  *          MODULE_CallWEP
1139  *
1140  * Call a DLL's WEP, allowing it to shut down.
1141  * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
1142  */
1143 static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
1144 {
1145     FARPROC16 WEP = (FARPROC16)0;
1146     WORD ordinal = NE_GetOrdinal( hModule, "WEP" );
1147
1148     if (ordinal) WEP = NE_GetEntryPoint( hModule, ordinal );
1149     if (!WEP)
1150     {
1151         WARN(module, "module %04x doesn't have a WEP\n", hModule );
1152         return FALSE;
1153     }
1154     return Callbacks->CallWindowsExitProc( WEP, WEP_FREE_DLL );
1155 }
1156
1157
1158 /**********************************************************************
1159  *          NE_FreeModule
1160  *
1161  * Implementation of FreeModule16().
1162  */
1163 static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL call_wep )
1164 {
1165     HMODULE16 *hPrevModule;
1166     NE_MODULE *pModule;
1167     HMODULE16 *pModRef;
1168     int i;
1169
1170     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
1171     hModule = pModule->self;
1172
1173     TRACE( module, "%04x count %d\n", hModule, pModule->count );
1174
1175     if (((INT16)(--pModule->count)) > 0 ) return TRUE;
1176     else pModule->count = 0;
1177
1178     if (pModule->flags & NE_FFLAGS_BUILTIN)
1179         return FALSE;  /* Can't free built-in module */
1180
1181     if (call_wep)
1182     {
1183         if (pModule->flags & NE_FFLAGS_LIBMODULE)
1184         {
1185             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
1186             MODULE_CallWEP( hModule );
1187
1188             /* Free the objects owned by the DLL module */
1189
1190             if (pTask && pTask->userhandler)
1191                 pTask->userhandler( hModule, USIG16_DLL_UNLOAD, 0,
1192                                     pTask->hInstance, pTask->hQueue );
1193
1194             PROCESS_CallUserSignalProc( USIG_DLL_UNLOAD_WIN16, 0, hModule );
1195         }
1196         else
1197             call_wep = FALSE;  /* We are freeing a task -> no more WEPs */
1198     }
1199     
1200
1201     /* Clear magic number just in case */
1202
1203     pModule->magic = pModule->self = 0;
1204
1205       /* Remove it from the linked list */
1206
1207     hPrevModule = &hFirstModule;
1208     while (*hPrevModule && (*hPrevModule != hModule))
1209     {
1210         hPrevModule = &(NE_GetPtr( *hPrevModule ))->next;
1211     }
1212     if (*hPrevModule) *hPrevModule = pModule->next;
1213
1214     /* Free the referenced modules */
1215
1216     pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
1217     for (i = 0; i < pModule->modref_count; i++, pModRef++)
1218     {
1219         NE_FreeModule( *pModRef, call_wep );
1220     }
1221
1222     /* Free the module storage */
1223
1224     GlobalFreeAll16( hModule );
1225
1226     /* Remove module from cache */
1227
1228     if (pCachedModule == pModule) pCachedModule = NULL;
1229     return TRUE;
1230 }
1231
1232
1233 /**********************************************************************
1234  *          FreeModule16    (KERNEL.46)
1235  */
1236 BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
1237 {
1238     return NE_FreeModule( hModule, TRUE );
1239 }
1240
1241
1242 /***********************************************************************
1243  *           FreeLibrary16   (KERNEL.96)
1244  */
1245 void WINAPI FreeLibrary16( HINSTANCE16 handle )
1246 {
1247     TRACE(module,"%04x\n", handle );
1248     FreeModule16( handle );
1249 }
1250
1251
1252 /**********************************************************************
1253  *          GetModuleName    (KERNEL.27)
1254  */
1255 BOOL16 WINAPI GetModuleName16( HINSTANCE16 hinst, LPSTR buf, INT16 count )
1256 {
1257     NE_MODULE *pModule;
1258     BYTE *p;
1259
1260     if (!(pModule = NE_GetPtr( hinst ))) return FALSE;
1261     p = (BYTE *)pModule + pModule->name_table;
1262     if (count > *p) count = *p + 1;
1263     if (count > 0)
1264     {
1265         memcpy( buf, p + 1, count - 1 );
1266         buf[count-1] = '\0';
1267     }
1268     return TRUE;
1269 }
1270
1271
1272 /**********************************************************************
1273  *          GetModuleUsage    (KERNEL.48)
1274  */
1275 INT16 WINAPI GetModuleUsage16( HINSTANCE16 hModule )
1276 {
1277     NE_MODULE *pModule = NE_GetPtr( hModule );
1278     return pModule ? pModule->count : 0;
1279 }
1280
1281
1282 /**********************************************************************
1283  *          GetExpWinVer    (KERNEL.167)
1284  */
1285 WORD WINAPI GetExpWinVer16( HMODULE16 hModule )
1286 {
1287     NE_MODULE *pModule = NE_GetPtr( hModule );
1288     return pModule ? pModule->expected_version : 0;
1289 }
1290
1291
1292 /**********************************************************************
1293  *          GetModuleFileName16    (KERNEL.49)
1294  */
1295 INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName,
1296                                   INT16 nSize )
1297 {
1298     NE_MODULE *pModule;
1299
1300     if (!hModule) hModule = GetCurrentTask();
1301     if (!(pModule = NE_GetPtr( hModule ))) return 0;
1302     lstrcpynA( lpFileName, NE_MODULE_NAME(pModule), nSize );
1303     TRACE(module, "%s\n", lpFileName );
1304     return strlen(lpFileName);
1305 }
1306
1307
1308 /**********************************************************************
1309  *          GetModuleHandle16    (KERNEL.47)
1310  *
1311  * Find a module from a module name.
1312  *
1313  * NOTE: The current implementation works the same way the Windows 95 one
1314  *       does. Do not try to 'fix' it, fix the callers.
1315  *       + It does not do ANY extension handling (except that strange .EXE bit)!
1316  *       + It does not care about paths, just about basenames. (same as Windows)
1317  *
1318  * RETURNS
1319  *   LOWORD:
1320  *      the win16 module handle if found
1321  *      0 if not
1322  *   HIWORD (undocumented, see "Undocumented Windows", chapter 5):
1323  *      Always hFirstModule
1324  */
1325 DWORD WINAPI WIN16_GetModuleHandle( SEGPTR name )
1326 {
1327     if (HIWORD(name) == 0)
1328         return MAKELONG(GetExePtr( (HINSTANCE16)name), hFirstModule );
1329     return MAKELONG(GetModuleHandle16( PTR_SEG_TO_LIN(name)), hFirstModule );
1330 }
1331
1332 HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
1333 {
1334     HMODULE16   hModule = hFirstModule;
1335     LPSTR       s;
1336     BYTE        len, *name_table;
1337     char        tmpstr[128];
1338     NE_MODULE *pModule;
1339
1340     TRACE(module, "(%s)\n", name);
1341
1342     if (!HIWORD(name))
1343         return GetExePtr(LOWORD(name));
1344
1345     len = strlen(name);
1346     if (!len)
1347         return 0;
1348
1349     strncpy(tmpstr, name, sizeof(tmpstr));
1350     tmpstr[sizeof(tmpstr)-1] = '\0';
1351
1352     /* If 'name' matches exactly the module name of a module:
1353      * Return its handle.
1354      */
1355     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1356     {
1357         pModule = NE_GetPtr( hModule );
1358         if (!pModule) break;
1359
1360         name_table = (BYTE *)pModule + pModule->name_table;
1361         if ((*name_table == len) && !strncmp(name, name_table+1, len))
1362             return hModule;
1363     }
1364
1365     /* If uppercased 'name' matches exactly the module name of a module:
1366      * Return its handle
1367      */
1368     for (s = tmpstr; *s; s++)
1369         *s = toupper(*s);
1370
1371     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1372     {
1373         pModule = NE_GetPtr( hModule );
1374         if (!pModule) break;
1375
1376         name_table = (BYTE *)pModule + pModule->name_table;
1377         if ((*name_table == len) && !strncmp(tmpstr, name_table+1, len))
1378             return hModule;
1379     }
1380
1381     /* If the base filename of 'name' matches the base filename of the module
1382      * filename of some module (case-insensitive compare):
1383      * Return its handle.
1384      */
1385
1386     /* basename: search backwards in passed name to \ / or : */
1387     s = tmpstr + strlen(tmpstr);
1388     while (s > tmpstr)
1389     {
1390         if (s[-1]=='/' || s[-1]=='\\' || s[-1]==':')
1391                 break;
1392         s--;
1393     }
1394
1395     /* search this in loaded filename list */
1396     for (hModule = hFirstModule; hModule ; hModule = pModule->next)
1397     {
1398         char            *loadedfn;
1399         OFSTRUCT        *ofs;
1400
1401         pModule = NE_GetPtr( hModule );
1402         if (!pModule) break;
1403         if (!pModule->fileinfo) continue;
1404
1405         ofs = (OFSTRUCT*)((BYTE *)pModule + pModule->fileinfo);
1406         loadedfn = ((char*)ofs->szPathName) + strlen(ofs->szPathName);
1407         /* basename: search backwards in pathname to \ / or : */
1408         while (loadedfn > (char*)ofs->szPathName)
1409         {
1410             if (loadedfn[-1]=='/' || loadedfn[-1]=='\\' || loadedfn[-1]==':')
1411                     break;
1412             loadedfn--;
1413         }
1414         /* case insensitive compare ... */
1415         if (!lstrcmpiA(loadedfn, s))
1416             return hModule;
1417     }
1418
1419     /* If the extension of 'name' is '.EXE' and the base filename of 'name'
1420      * matches the base filename of the module filename of some 32-bit module:
1421      * Return the corresponding 16-bit dummy module handle. 
1422      */
1423     if (len >= 4 && !strcasecmp(name+len-4, ".EXE"))
1424     {
1425         HMODULE hModule = GetModuleHandleA( name );
1426         if ( hModule )
1427             return MapHModuleLS( hModule );
1428     }
1429
1430     if (!strcmp(tmpstr,"MSDOS"))
1431         return 1;
1432
1433     if (!strcmp(tmpstr,"TIMER"))
1434     {
1435         FIXME(module, "Eh... Should return caller's code segment, expect crash\n");
1436         return 0;
1437     }
1438
1439     return 0;
1440 }
1441
1442
1443 /**********************************************************************
1444  *          ModuleFirst    (TOOLHELP.59)
1445  */
1446 BOOL16 WINAPI ModuleFirst16( MODULEENTRY *lpme )
1447 {
1448     lpme->wNext = hFirstModule;
1449     return ModuleNext16( lpme );
1450 }
1451
1452
1453 /**********************************************************************
1454  *          ModuleNext    (TOOLHELP.60)
1455  */
1456 BOOL16 WINAPI ModuleNext16( MODULEENTRY *lpme )
1457 {
1458     NE_MODULE *pModule;
1459     char *name;
1460
1461     if (!lpme->wNext) return FALSE;
1462     if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE;
1463     name = (char *)pModule + pModule->name_table;
1464     memcpy( lpme->szModule, name + 1, min(*name, MAX_MODULE_NAME) );
1465     lpme->szModule[min(*name, MAX_MODULE_NAME)] = '\0';
1466     lpme->hModule = lpme->wNext;
1467     lpme->wcUsage = pModule->count;
1468     lstrcpynA( lpme->szExePath, NE_MODULE_NAME(pModule), sizeof(lpme->szExePath) );
1469     lpme->wNext = pModule->next;
1470     return TRUE;
1471 }
1472
1473
1474 /**********************************************************************
1475  *          ModuleFindName    (TOOLHELP.61)
1476  */
1477 BOOL16 WINAPI ModuleFindName16( MODULEENTRY *lpme, LPCSTR name )
1478 {
1479     lpme->wNext = GetModuleHandle16( name );
1480     return ModuleNext16( lpme );
1481 }
1482
1483
1484 /**********************************************************************
1485  *          ModuleFindHandle    (TOOLHELP.62)
1486  */
1487 BOOL16 WINAPI ModuleFindHandle16( MODULEENTRY *lpme, HMODULE16 hModule )
1488 {
1489     hModule = GetExePtr( hModule );
1490     lpme->wNext = hModule;
1491     return ModuleNext16( lpme );
1492 }
1493
1494
1495 /***************************************************************************
1496  *              MapHModuleLS                    (KERNEL32.520)
1497  */
1498 HMODULE16 WINAPI MapHModuleLS(HMODULE hmod) {
1499         NE_MODULE       *pModule;
1500
1501         if (!hmod)
1502                 return ((TDB*)GlobalLock16(GetCurrentTask()))->hInstance;
1503         if (!HIWORD(hmod))
1504                 return hmod; /* we already have a 16 bit module handle */
1505         pModule = (NE_MODULE*)GlobalLock16(hFirstModule);
1506         while (pModule)  {
1507                 if (pModule->module32 == hmod)
1508                         return pModule->self;
1509                 pModule = (NE_MODULE*)GlobalLock16(pModule->next);
1510         }
1511         return 0;
1512 }
1513
1514 /***************************************************************************
1515  *              MapHModuleSL                    (KERNEL32.521)
1516  */
1517 HMODULE WINAPI MapHModuleSL(HMODULE16 hmod) {
1518         NE_MODULE       *pModule;
1519
1520         if (!hmod) {
1521                 TDB *pTask = (TDB*)GlobalLock16(GetCurrentTask());
1522
1523                 hmod = pTask->hModule;
1524         }
1525         pModule = (NE_MODULE*)GlobalLock16(hmod);
1526         if (    (pModule->magic!=IMAGE_OS2_SIGNATURE)   ||
1527                 !(pModule->flags & NE_FFLAGS_WIN32)
1528         )
1529                 return 0;
1530         return pModule->module32;
1531 }
1532
1533 /***************************************************************************
1534  *              MapHInstLS                      (KERNEL32.516)
1535  */
1536 REGS_ENTRYPOINT(MapHInstLS) {
1537         EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1538 }
1539
1540 /***************************************************************************
1541  *              MapHInstSL                      (KERNEL32.518)
1542  */
1543 REGS_ENTRYPOINT(MapHInstSL) {
1544         EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1545 }
1546
1547 /***************************************************************************
1548  *              MapHInstLS_PN                   (KERNEL32.517)
1549  */
1550 REGS_ENTRYPOINT(MapHInstLS_PN) {
1551         if (EAX_reg(context))
1552             EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1553 }
1554
1555 /***************************************************************************
1556  *              MapHInstSL_PN                   (KERNEL32.519)
1557  */
1558 REGS_ENTRYPOINT(MapHInstSL_PN) {
1559         if (EAX_reg(context))
1560             EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1561 }
1562
1563 /***************************************************************************
1564  *              WIN16_MapHInstLS                (KERNEL.472)
1565  */
1566 VOID WINAPI WIN16_MapHInstLS( CONTEXT *context ) {
1567         EAX_reg(context) = MapHModuleLS(EAX_reg(context));
1568 }
1569
1570 /***************************************************************************
1571  *              WIN16_MapHInstSL                (KERNEL.473)
1572  */
1573 VOID WINAPI WIN16_MapHInstSL( CONTEXT *context ) {
1574         EAX_reg(context) = MapHModuleSL(EAX_reg(context));
1575 }