Release 980628
[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 "module.h"
13 #include "file.h"
14 #include "ldt.h"
15 #include "callback.h"
16 #include "heap.h"
17 #include "task.h"
18 #include "global.h"
19 #include "process.h"
20 #include "toolhelp.h"
21 #include "snoop.h"
22 #include "debug.h"
23
24 static HMODULE16 hFirstModule = 0;
25 static NE_MODULE *pCachedModule = 0;  /* Module cached by NE_OpenFile */
26
27 static HMODULE16 NE_LoadBuiltin(LPCSTR name,BOOL32 force) { return 0; }
28 HMODULE16 (*fnBUILTIN_LoadModule)(LPCSTR name,BOOL32 force) = NE_LoadBuiltin;
29
30
31 /***********************************************************************
32  *           NE_GetPtr
33  */
34 NE_MODULE *NE_GetPtr( HMODULE16 hModule )
35 {
36     return (NE_MODULE *)GlobalLock16( GetExePtr(hModule) );
37 }
38
39
40 /***********************************************************************
41  *           NE_DumpModule
42  */
43 void NE_DumpModule( HMODULE16 hModule )
44 {
45     int i, ordinal;
46     SEGTABLEENTRY *pSeg;
47     BYTE *pstr;
48     WORD *pword;
49     NE_MODULE *pModule;
50
51     if (!(pModule = NE_GetPtr( hModule )))
52     {
53         MSG( "**** %04x is not a module handle\n", hModule );
54         return;
55     }
56
57       /* Dump the module info */
58     DUMP( "---\n" );
59     DUMP( "Module %04x:\n", hModule );
60     DUMP( "count=%d flags=%04x heap=%d stack=%d\n",
61           pModule->count, pModule->flags,
62           pModule->heap_size, pModule->stack_size );
63     DUMP( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
64           pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
65           pModule->seg_count, pModule->modref_count );
66     DUMP( "os_flags=%d swap_area=%d version=%04x\n",
67           pModule->os_flags, pModule->min_swap_area,
68           pModule->expected_version );
69     if (pModule->flags & NE_FFLAGS_WIN32)
70         DUMP( "PE module=%08x\n", pModule->module32 );
71
72       /* Dump the file info */
73     DUMP( "---\n" );
74     DUMP( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
75
76       /* Dump the segment table */
77     DUMP( "---\n" );
78     DUMP( "Segment table:\n" );
79     pSeg = NE_SEG_TABLE( pModule );
80     for (i = 0; i < pModule->seg_count; i++, pSeg++)
81         DUMP( "%02x: pos=%d size=%d flags=%04x minsize=%d sel=%04x\n",
82               i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
83               pSeg->minsize, pSeg->selector );
84
85       /* Dump the resource table */
86     DUMP( "---\n" );
87     DUMP( "Resource table:\n" );
88     if (pModule->res_table)
89     {
90         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
91         DUMP( "Alignment: %d\n", *pword++ );
92         while (*pword)
93         {
94             struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
95             struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
96             DUMP( "id=%04x count=%d\n", ptr->type_id, ptr->count );
97             for (i = 0; i < ptr->count; i++, pname++)
98                 DUMP( "offset=%d len=%d id=%04x\n",
99                       pname->offset, pname->length, pname->id );
100             pword = (WORD *)pname;
101         }
102     }
103     else DUMP( "None\n" );
104
105       /* Dump the resident name table */
106     DUMP( "---\n" );
107     DUMP( "Resident-name table:\n" );
108     pstr = (char *)pModule + pModule->name_table;
109     while (*pstr)
110     {
111         DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
112               *(WORD *)(pstr + *pstr + 1) );
113         pstr += *pstr + 1 + sizeof(WORD);
114     }
115
116       /* Dump the module reference table */
117     DUMP( "---\n" );
118     DUMP( "Module ref table:\n" );
119     if (pModule->modref_table)
120     {
121         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
122         for (i = 0; i < pModule->modref_count; i++, pword++)
123         {
124             char name[10];
125             GetModuleName( *pword, name, sizeof(name) );
126             DUMP( "%d: %04x -> '%s'\n", i, *pword, name );
127         }
128     }
129     else DUMP( "None\n" );
130
131       /* Dump the entry table */
132     DUMP( "---\n" );
133     DUMP( "Entry table:\n" );
134     pstr = (char *)pModule + pModule->entry_table;
135     ordinal = 1;
136     while (*pstr)
137     {
138         DUMP( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
139         if (!pstr[1])
140         {
141             ordinal += *pstr;
142             pstr += 2;
143         }
144         else if ((BYTE)pstr[1] == 0xff)  /* moveable */
145         {
146             i = *pstr;
147             pstr += 2;
148             while (i--)
149             {
150                 DUMP( "%d: %02x:%04x (moveable)\n",
151                       ordinal++, pstr[3], *(WORD *)(pstr + 4) );
152                 pstr += 6;
153             }
154         }
155         else  /* fixed */
156         {
157             i = *pstr;
158             pstr += 2;
159             while (i--)
160             {
161                 DUMP( "%d: %04x (fixed)\n",
162                       ordinal++, *(WORD *)(pstr + 1) );
163                 pstr += 3;
164             }
165         }
166     }
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     CharUpper32A( 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     NE_MODULE *pModule;
292     WORD curOrdinal = 1;
293     BYTE *p;
294     WORD sel, offset;
295
296     if (!(pModule = NE_GetPtr( hModule ))) return 0;
297     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
298
299     p = (BYTE *)pModule + pModule->entry_table;
300     while (*p && (curOrdinal + *p <= ordinal))
301     {
302           /* Skipping this bundle */
303         curOrdinal += *p;
304         switch(p[1])
305         {
306             case 0:    p += 2; break;  /* unused */
307             case 0xff: p += 2 + *p * 6; break;  /* moveable */
308             default:   p += 2 + *p * 3; break;  /* fixed */
309         }
310     }
311     if (!*p) return 0;
312
313     switch(p[1])
314     {
315         case 0:  /* unused */
316             return 0;
317         case 0xff:  /* moveable */
318             p += 2 + 6 * (ordinal - curOrdinal);
319             sel = p[3];
320             offset = *(WORD *)(p + 4);
321             break;
322         default:  /* fixed */
323             sel = p[1];
324             p += 2 + 3 * (ordinal - curOrdinal);
325             offset = *(WORD *)(p + 1);
326             break;
327     }
328
329     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
330     else sel = (WORD)(DWORD)NE_SEG_TABLE(pModule)[sel-1].selector;
331     if (sel==0xffff)
332         return (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset );
333     else
334         return (FARPROC16)SNOOP16_GetProcAddress16(hModule,ordinal,(FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset ));
335 }
336
337
338 /***********************************************************************
339  *           NE_SetEntryPoint
340  *
341  * Change the value of an entry point. Use with caution!
342  * It can only change the offset value, not the selector.
343  */
344 BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset )
345 {
346     NE_MODULE *pModule;
347     WORD curOrdinal = 1;
348     BYTE *p;
349
350     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
351     assert( !(pModule->flags & NE_FFLAGS_WIN32) );
352
353     p = (BYTE *)pModule + pModule->entry_table;
354     while (*p && (curOrdinal + *p <= ordinal))
355     {
356           /* Skipping this bundle */
357         curOrdinal += *p;
358         switch(p[1])
359         {
360             case 0:    p += 2; break;  /* unused */
361             case 0xff: p += 2 + *p * 6; break;  /* moveable */
362             default:   p += 2 + *p * 3; break;  /* fixed */
363         }
364     }
365     if (!*p) return FALSE;
366
367     switch(p[1])
368     {
369         case 0:  /* unused */
370             return FALSE;
371         case 0xff:  /* moveable */
372             p += 2 + 6 * (ordinal - curOrdinal);
373             *(WORD *)(p + 4) = offset;
374             break;
375         default:  /* fixed */
376             p += 2 + 3 * (ordinal - curOrdinal);
377             *(WORD *)(p + 1) = offset;
378             break;
379     }
380     return TRUE;
381 }
382
383
384 /***********************************************************************
385  *           NE_OpenFile
386  */
387 int NE_OpenFile( NE_MODULE *pModule )
388 {
389     DOS_FULL_NAME full_name;
390     char *name;
391
392     static int cachedfd = -1;
393
394     TRACE( module, "(%p) cache: mod=%p fd=%d\n",
395            pModule, pCachedModule, cachedfd );
396     if (pCachedModule == pModule) return cachedfd;
397     close( cachedfd );
398     pCachedModule = pModule;
399     name = NE_MODULE_NAME( pModule );
400     if (!DOSFS_GetFullName( name, TRUE, &full_name ) ||
401         (cachedfd = open( full_name.long_name, O_RDONLY )) == -1)
402         MSG( "Can't open file '%s' for module %04x\n", name, pModule->self );
403     TRACE(module, "opened '%s' -> %d\n",
404                     name, cachedfd );
405     return cachedfd;
406 }
407
408
409 /***********************************************************************
410  *           NE_LoadExeHeader
411  */
412 static HMODULE16 NE_LoadExeHeader( HFILE16 hFile, OFSTRUCT *ofs )
413 {
414     IMAGE_DOS_HEADER mz_header;
415     IMAGE_OS2_HEADER ne_header;
416     int size;
417     HMODULE16 hModule;
418     NE_MODULE *pModule;
419     BYTE *pData;
420     char *buffer, *fastload = NULL;
421     int fastload_offset = 0, fastload_length = 0;
422
423   /* Read a block from either the file or the fast-load area. */
424 #define READ(offset,size,buffer) \
425        ((fastload && ((offset) >= fastload_offset) && \
426          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
427         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
428         (_llseek16( hFile, (offset), SEEK_SET), \
429          _hread16( hFile, (buffer), (size) ) == (size)))
430
431     _llseek16( hFile, 0, SEEK_SET );
432     if ((_hread16(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
433         (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
434         return (HMODULE16)11;  /* invalid exe */
435
436     _llseek16( hFile, mz_header.e_lfanew, SEEK_SET );
437     if (_hread16( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
438         return (HMODULE16)11;  /* invalid exe */
439
440     if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21;  /* win32 exe */
441     if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)11;  /* invalid exe */
442
443     if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
444       MSG("Sorry, this is an OS/2 linear executable (LX) file !\n");
445       return (HMODULE16)12;
446     }
447
448     /* We now have a valid NE header */
449
450     size = sizeof(NE_MODULE) +
451              /* segment table */
452            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
453              /* resource table */
454            ne_header.rname_tab_offset - ne_header.resource_tab_offset +
455              /* resident names table */
456            ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
457              /* module ref table */
458            ne_header.n_mod_ref_tab * sizeof(WORD) + 
459              /* imported names table */
460            ne_header.entry_tab_offset - ne_header.iname_tab_offset +
461              /* entry table length */
462            ne_header.entry_tab_length +
463              /* loaded file info */
464            sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
465
466     hModule = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, size );
467     if (!hModule) return (HMODULE16)11;  /* invalid exe */
468     FarSetOwner( hModule, hModule );
469     pModule = (NE_MODULE *)GlobalLock16( hModule );
470     memcpy( pModule, &ne_header, sizeof(ne_header) );
471     pModule->count = 0;
472     pModule->module32 = 0;
473     pModule->self = hModule;
474     pModule->self_loading_sel = 0;
475     pData = (BYTE *)(pModule + 1);
476
477     /* Clear internal Wine flags in case they are set in the EXE file */
478
479     pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
480
481     /* Read the fast-load area */
482
483     if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
484     {
485         fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
486         fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
487         TRACE(module, "Using fast-load area offset=%x len=%d\n",
488                         fastload_offset, fastload_length );
489         if ((fastload = HeapAlloc( SystemHeap, 0, fastload_length )) != NULL)
490         {
491             _llseek16( hFile, fastload_offset, SEEK_SET);
492             if (_hread16(hFile, fastload, fastload_length) != fastload_length)
493             {
494                 HeapFree( SystemHeap, 0, fastload );
495                 WARN( module, "Error reading fast-load area!\n");
496                 fastload = NULL;
497             }
498         }
499     }
500
501     /* Get the segment table */
502
503     pModule->seg_table = (int)pData - (int)pModule;
504     buffer = HeapAlloc( SystemHeap, 0, ne_header.n_segment_tab *
505                                       sizeof(struct ne_segment_table_entry_s));
506     if (buffer)
507     {
508         int i;
509         struct ne_segment_table_entry_s *pSeg;
510
511         if (!READ( mz_header.e_lfanew + ne_header.segment_tab_offset,
512              ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
513              buffer ))
514         {
515             HeapFree( SystemHeap, 0, buffer );
516             if (fastload) HeapFree( SystemHeap, 0, fastload );
517             GlobalFree16( hModule );
518             return (HMODULE16)11;  /* invalid exe */
519         }
520         pSeg = (struct ne_segment_table_entry_s *)buffer;
521         for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
522         {
523             memcpy( pData, pSeg, sizeof(*pSeg) );
524             pData += sizeof(SEGTABLEENTRY);
525         }
526         HeapFree( SystemHeap, 0, buffer );
527     }
528     else
529     {
530         if (fastload) HeapFree( SystemHeap, 0, fastload );
531         GlobalFree16( hModule );
532         return (HMODULE16)11;  /* invalid exe */
533     }
534
535     /* Get the resource table */
536
537     if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
538     {
539         pModule->res_table = (int)pData - (int)pModule;
540         if (!READ(mz_header.e_lfanew + ne_header.resource_tab_offset,
541                   ne_header.rname_tab_offset - ne_header.resource_tab_offset,
542                   pData )) return (HMODULE16)11;  /* invalid exe */
543         pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
544         NE_InitResourceHandler( hModule );
545     }
546     else pModule->res_table = 0;  /* No resource table */
547
548     /* Get the resident names table */
549
550     pModule->name_table = (int)pData - (int)pModule;
551     if (!READ( mz_header.e_lfanew + ne_header.rname_tab_offset,
552                ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
553                pData ))
554     {
555         if (fastload) HeapFree( SystemHeap, 0, fastload );
556         GlobalFree16( hModule );
557         return (HMODULE16)11;  /* invalid exe */
558     }
559     pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
560
561     /* Get the module references table */
562
563     if (ne_header.n_mod_ref_tab > 0)
564     {
565         pModule->modref_table = (int)pData - (int)pModule;
566         if (!READ( mz_header.e_lfanew + ne_header.moduleref_tab_offset,
567                   ne_header.n_mod_ref_tab * sizeof(WORD),
568                   pData ))
569         {
570             if (fastload) HeapFree( SystemHeap, 0, fastload );
571             GlobalFree16( hModule );
572             return (HMODULE16)11;  /* invalid exe */
573         }
574         pData += ne_header.n_mod_ref_tab * sizeof(WORD);
575     }
576     else pModule->modref_table = 0;  /* No module references */
577
578     /* Get the imported names table */
579
580     pModule->import_table = (int)pData - (int)pModule;
581     if (!READ( mz_header.e_lfanew + ne_header.iname_tab_offset, 
582                ne_header.entry_tab_offset - ne_header.iname_tab_offset,
583                pData ))
584     {
585         if (fastload) HeapFree( SystemHeap, 0, fastload );
586         GlobalFree16( hModule );
587         return (HMODULE16)11;  /* invalid exe */
588     }
589     pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
590
591     /* Get the entry table */
592
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,
596                pData ))
597     {
598         if (fastload) HeapFree( SystemHeap, 0, fastload );
599         GlobalFree16( hModule );
600         return (HMODULE16)11;  /* invalid exe */
601     }
602     pData += ne_header.entry_tab_length;
603
604     /* Store the filename information */
605
606     pModule->fileinfo = (int)pData - (int)pModule;
607     size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
608     memcpy( pData, ofs, size );
609     ((OFSTRUCT *)pData)->cBytes = size - 1;
610     pData += size;
611
612     /* Free the fast-load area */
613
614 #undef READ
615     if (fastload) HeapFree( SystemHeap, 0, fastload );
616
617     /* Get the non-resident names table */
618
619     if (ne_header.nrname_tab_length)
620     {
621         pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
622                                                hModule, FALSE, FALSE, FALSE );
623         if (!pModule->nrname_handle)
624         {
625             GlobalFree16( hModule );
626             return (HMODULE16)11;  /* invalid exe */
627         }
628         buffer = GlobalLock16( pModule->nrname_handle );
629         _llseek16( hFile, ne_header.nrname_tab_offset, SEEK_SET );
630         if (_hread16( hFile, buffer, ne_header.nrname_tab_length )
631               != ne_header.nrname_tab_length)
632         {
633             GlobalFree16( pModule->nrname_handle );
634             GlobalFree16( hModule );
635             return (HMODULE16)11;  /* invalid exe */
636         }
637     }
638     else pModule->nrname_handle = 0;
639
640     /* Allocate a segment for the implicitly-loaded DLLs */
641
642     if (pModule->modref_count)
643     {
644         pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
645                                     (pModule->modref_count+1)*sizeof(HMODULE16),
646                                     hModule, FALSE, FALSE, FALSE );
647         if (!pModule->dlls_to_init)
648         {
649             if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
650             GlobalFree16( hModule );
651             return (HMODULE16)11;  /* invalid exe */
652         }
653     }
654     else pModule->dlls_to_init = 0;
655
656     NE_RegisterModule( pModule );
657     SNOOP16_RegisterDLL(pModule,ofs->szPathName);
658     return hModule;
659 }
660
661
662 /***********************************************************************
663  *           NE_LoadDLLs
664  *
665  * Load all DLLs implicitly linked to a module.
666  */
667 static BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
668 {
669     int i;
670     WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
671     WORD *pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
672
673     for (i = 0; i < pModule->modref_count; i++, pModRef++)
674     {
675         char buffer[260];
676         BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
677         memcpy( buffer, pstr + 1, *pstr );
678         strcpy( buffer + *pstr, ".dll" );
679         TRACE(module, "Loading '%s'\n", buffer );
680         if (!(*pModRef = GetModuleHandle16( buffer )))
681         {
682             /* If the DLL is not loaded yet, load it and store */
683             /* its handle in the list of DLLs to initialize.   */
684             HMODULE16 hDLL;
685
686             if ((hDLL = NE_LoadModule( buffer, NULL, TRUE, TRUE )) == 2)
687             {
688                 /* file not found */
689                 char *p;
690
691                 /* Try with prepending the path of the current module */
692                 GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
693                 if (!(p = strrchr( buffer, '\\' ))) p = buffer;
694                 memcpy( p + 1, pstr + 1, *pstr );
695                 strcpy( p + 1 + *pstr, ".dll" );
696                 hDLL = NE_LoadModule( buffer, NULL, TRUE, TRUE );
697             }
698             if (hDLL < 32)
699             {
700                 /* FIXME: cleanup what was done */
701
702                 MSG( "Could not load '%s' required by '%.*s', error=%d\n",
703                      buffer, *((BYTE*)pModule + pModule->name_table),
704                      (char *)pModule + pModule->name_table + 1, hDLL );
705                 return FALSE;
706             }
707             *pModRef = GetExePtr( hDLL );
708             *pDLLs++ = *pModRef;
709         }
710         else  /* Increment the reference count of the DLL */
711         {
712             NE_MODULE *pOldDLL = NE_GetPtr( *pModRef );
713             if (pOldDLL) pOldDLL->count++;
714         }
715     }
716     return TRUE;
717 }
718
719
720 /**********************************************************************
721  *          NE_LoadModule
722  *
723  * Implementation of LoadModule16().
724  */
725 HINSTANCE16 NE_LoadModule( LPCSTR name, HINSTANCE16 *hPrevInstance,
726                            BOOL32 implicit, BOOL32 lib_only )
727 {
728     HMODULE16 hModule;
729     HINSTANCE16 hInstance;
730     NE_MODULE *pModule;
731     HFILE16 hFile;
732     OFSTRUCT ofs;
733
734     /* Check if the module is already loaded */
735
736     if ((hModule = GetModuleHandle16( name )) != 0)
737     {
738         HINSTANCE16 prev;
739         pModule = NE_GetPtr( hModule );
740         hInstance = NE_CreateInstance( pModule, &prev, lib_only );
741         if (hInstance != prev)  /* not a library */
742             NE_LoadSegment( pModule, pModule->dgroup );
743         pModule->count++;
744         if (hPrevInstance) *hPrevInstance = prev;
745         return hInstance;
746     }
747     if (hPrevInstance) *hPrevInstance = 0;
748
749     /* Try to load the built-in first if not disabled */
750
751     if ((hModule = fnBUILTIN_LoadModule( name, FALSE ))) return hModule;
752
753     if ((hFile = OpenFile16( name, &ofs, OF_READ )) == HFILE_ERROR16)
754     {
755         /* Now try the built-in even if disabled */
756         if ((hModule = fnBUILTIN_LoadModule( name, TRUE )))
757         {
758             MSG( "Could not load Windows DLL '%s', using built-in module.\n",
759                  name );
760             return hModule;
761         }
762         return 2;  /* File not found */
763     }
764
765     /* Create the module structure */
766
767     hModule = NE_LoadExeHeader( hFile, &ofs );
768     _lclose16( hFile );
769     if (hModule < 32) return hModule;
770     pModule = NE_GetPtr( hModule );
771
772     /* Allocate the segments for this module */
773
774     if (!NE_CreateSegments( pModule ) ||
775         !(hInstance = NE_CreateInstance( pModule, NULL, lib_only )))
776     {
777         GlobalFreeAll( hModule );
778         return 8;  /* Insufficient memory */
779     }
780
781     /* Load the referenced DLLs */
782
783     if (!NE_LoadDLLs( pModule ))
784         return 2;  /* File not found (FIXME: free everything) */
785
786     /* Load the segments */
787
788     NE_LoadAllSegments( pModule );
789
790     /* Fixup the functions prologs */
791
792     NE_FixupPrologs( pModule );
793
794     /* Make sure the usage count is 1 on the first loading of  */
795     /* the module, even if it contains circular DLL references */
796
797     pModule->count = 1;
798
799     /* Call initialization rountines for all loaded DLLs. Note that
800      * when we load implicitly linked DLLs this will be done by InitTask().
801      */
802
803     if (!implicit && (pModule->flags & NE_FFLAGS_LIBMODULE))
804         NE_InitializeDLLs( hModule );
805
806     return hInstance;
807 }
808
809
810 /***********************************************************************
811  *           LoadLibrary   (KERNEL.95)
812  */
813 HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
814 {
815     HINSTANCE16 handle;
816     LPCSTR p;
817     char *new_name;
818
819     TRACE(module, "(%08x) %s\n", (int)libname, libname);
820
821     /* Check for an extension */
822
823     if ((p = strrchr( libname, '.')) && !strchr( p, '/' ) && !strchr( p, '\\'))
824     {
825         /* An extension is present -> use the name as is */
826         return NE_LoadModule( libname, NULL, FALSE, TRUE );
827     }
828
829     /* Now append .dll before loading */
830
831     if (!(new_name = HeapAlloc( GetProcessHeap(), 0, strlen(libname) + 4 )))
832         return 0;
833     strcpy( new_name, libname );
834     strcat( new_name, ".dll" );
835     handle = NE_LoadModule( new_name, NULL, FALSE, TRUE );
836     HeapFree( GetProcessHeap(), 0, new_name );
837     return handle;
838 }
839
840
841 /**********************************************************************
842  *          MODULE_CallWEP
843  *
844  * Call a DLL's WEP, allowing it to shut down.
845  * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
846  */
847 static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
848 {
849     FARPROC16 WEP = (FARPROC16)0;
850     WORD ordinal = NE_GetOrdinal( hModule, "WEP" );
851
852     if (ordinal) WEP = NE_GetEntryPoint( hModule, ordinal );
853     if (!WEP)
854     {
855         WARN(module, "module %04x doesn't have a WEP\n", hModule );
856         return FALSE;
857     }
858     return Callbacks->CallWindowsExitProc( WEP, WEP_FREE_DLL );
859 }
860
861
862 /**********************************************************************
863  *          NE_FreeModule
864  *
865  * Implementation of FreeModule16().
866  */
867 static BOOL16 NE_FreeModule( HMODULE16 hModule, BOOL32 call_wep )
868 {
869     HMODULE16 *hPrevModule;
870     NE_MODULE *pModule;
871     HMODULE16 *pModRef;
872     int i;
873
874     if (!(pModule = NE_GetPtr( hModule ))) return FALSE;
875     hModule = pModule->self;
876
877     TRACE( module, "%04x count %d\n", hModule, pModule->count );
878
879     if (((INT16)(--pModule->count)) > 0 ) return TRUE;
880     else pModule->count = 0;
881
882     if (pModule->flags & NE_FFLAGS_BUILTIN)
883         return FALSE;  /* Can't free built-in module */
884
885     if (call_wep)
886     {
887         if (pModule->flags & NE_FFLAGS_LIBMODULE)
888         {
889             TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
890             MODULE_CallWEP( hModule );
891
892             /* Free the objects owned by the DLL module */
893
894             if (pTask && pTask->userhandler)
895                 pTask->userhandler( hModule, USIG_DLL_UNLOAD, 0,
896                                     pTask->hInstance, pTask->hQueue );
897         }
898         else
899             call_wep = FALSE;  /* We are freeing a task -> no more WEPs */
900     }
901     
902
903     /* Clear magic number just in case */
904
905     pModule->magic = pModule->self = 0;
906
907       /* Remove it from the linked list */
908
909     hPrevModule = &hFirstModule;
910     while (*hPrevModule && (*hPrevModule != hModule))
911     {
912         hPrevModule = &(NE_GetPtr( *hPrevModule ))->next;
913     }
914     if (*hPrevModule) *hPrevModule = pModule->next;
915
916     /* Free the referenced modules */
917
918     pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
919     for (i = 0; i < pModule->modref_count; i++, pModRef++)
920     {
921         NE_FreeModule( *pModRef, call_wep );
922     }
923
924     /* Free the module storage */
925
926     GlobalFreeAll( hModule );
927
928     /* Remove module from cache */
929
930     if (pCachedModule == pModule) pCachedModule = NULL;
931     return TRUE;
932 }
933
934
935 /**********************************************************************
936  *          FreeModule16    (KERNEL.46)
937  */
938 BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
939 {
940     return NE_FreeModule( hModule, TRUE );
941 }
942
943
944 /***********************************************************************
945  *           FreeLibrary16   (KERNEL.96)
946  */
947 void WINAPI FreeLibrary16( HINSTANCE16 handle )
948 {
949     TRACE(module,"%04x\n", handle );
950     FreeModule16( handle );
951 }
952
953
954 /**********************************************************************
955  *          GetModuleName    (KERNEL.27)
956  */
957 BOOL16 WINAPI GetModuleName( HINSTANCE16 hinst, LPSTR buf, INT16 count )
958 {
959     NE_MODULE *pModule;
960     BYTE *p;
961
962     if (!(pModule = NE_GetPtr( hinst ))) return FALSE;
963     p = (BYTE *)pModule + pModule->name_table;
964     if (count > *p) count = *p + 1;
965     if (count > 0)
966     {
967         memcpy( buf, p + 1, count - 1 );
968         buf[count-1] = '\0';
969     }
970     return TRUE;
971 }
972
973
974 /**********************************************************************
975  *          GetModuleUsage    (KERNEL.48)
976  */
977 INT16 WINAPI GetModuleUsage( HINSTANCE16 hModule )
978 {
979     NE_MODULE *pModule = NE_GetPtr( hModule );
980     return pModule ? pModule->count : 0;
981 }
982
983
984 /**********************************************************************
985  *          GetExpWinVer    (KERNEL.167)
986  */
987 WORD WINAPI GetExpWinVer( HMODULE16 hModule )
988 {
989     NE_MODULE *pModule = NE_GetPtr( hModule );
990     return pModule ? pModule->expected_version : 0;
991 }
992
993
994 /**********************************************************************
995  *          GetModuleFileName16    (KERNEL.49)
996  */
997 INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName,
998                                   INT16 nSize )
999 {
1000     NE_MODULE *pModule;
1001
1002     if (!hModule) hModule = GetCurrentTask();
1003     if (!(pModule = NE_GetPtr( hModule ))) return 0;
1004     lstrcpyn32A( lpFileName, NE_MODULE_NAME(pModule), nSize );
1005     TRACE(module, "%s\n", lpFileName );
1006     return strlen(lpFileName);
1007 }
1008
1009
1010 /**********************************************************************
1011  *          GetModuleHandle16    (KERNEL.47)
1012  *
1013  * Find a module from a path name.
1014  *
1015  * RETURNS
1016  *      the win16 module handle if found
1017  *      0 if not
1018  */
1019 HMODULE16 WINAPI WIN16_GetModuleHandle( SEGPTR name )
1020 {
1021     if (HIWORD(name) == 0) return GetExePtr( (HINSTANCE16)name );
1022     return GetModuleHandle16( PTR_SEG_TO_LIN(name) );
1023 }
1024
1025 HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
1026 {
1027     HMODULE16 hModule = hFirstModule;
1028     LPCSTR filename, dotptr, modulepath, modulename;
1029     BYTE len, *name_table;
1030
1031     if (!(filename = strrchr( name, '\\' ))) filename = name;
1032     else filename++;
1033     if ((dotptr = strrchr( filename, '.' )) != NULL)
1034         len = (BYTE)(dotptr - filename);
1035     else len = strlen( filename );
1036
1037     while (hModule)
1038     {
1039         NE_MODULE *pModule = NE_GetPtr( hModule );
1040         if (!pModule) break;
1041         modulepath = NE_MODULE_NAME(pModule);
1042         if (!(modulename = strrchr( modulepath, '\\' )))
1043             modulename = modulepath;
1044         else modulename++;
1045         if (!lstrcmpi32A( modulename, filename )) return hModule;
1046
1047         name_table = (BYTE *)pModule + pModule->name_table;
1048         if ((*name_table == len) && !lstrncmpi32A(filename, name_table+1, len))
1049             return hModule;
1050         hModule = pModule->next;
1051     }
1052     return 0;
1053 }
1054
1055
1056 /**********************************************************************
1057  *          ModuleFirst    (TOOLHELP.59)
1058  */
1059 BOOL16 WINAPI ModuleFirst( MODULEENTRY *lpme )
1060 {
1061     lpme->wNext = hFirstModule;
1062     return ModuleNext( lpme );
1063 }
1064
1065
1066 /**********************************************************************
1067  *          ModuleNext    (TOOLHELP.60)
1068  */
1069 BOOL16 WINAPI ModuleNext( MODULEENTRY *lpme )
1070 {
1071     NE_MODULE *pModule;
1072     char *name;
1073
1074     if (!lpme->wNext) return FALSE;
1075     if (!(pModule = NE_GetPtr( lpme->wNext ))) return FALSE;
1076     name = (char *)pModule + pModule->name_table;
1077     memcpy( lpme->szModule, name + 1, *name );
1078     lpme->szModule[(BYTE)*name] = '\0';
1079     lpme->hModule = lpme->wNext;
1080     lpme->wcUsage = pModule->count;
1081     strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
1082     lpme->szExePath[MAX_PATH] = '\0';
1083     lpme->wNext = pModule->next;
1084     return TRUE;
1085 }
1086
1087
1088 /**********************************************************************
1089  *          ModuleFindName    (TOOLHELP.61)
1090  */
1091 BOOL16 WINAPI ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1092 {
1093     lpme->wNext = GetModuleHandle16( name );
1094     return ModuleNext( lpme );
1095 }
1096
1097
1098 /**********************************************************************
1099  *          ModuleFindHandle    (TOOLHELP.62)
1100  */
1101 BOOL16 WINAPI ModuleFindHandle( MODULEENTRY *lpme, HMODULE16 hModule )
1102 {
1103     hModule = GetExePtr( hModule );
1104     lpme->wNext = hModule;
1105     return ModuleNext( lpme );
1106 }