Release 950727
[wine] / loader / module.c
1 /*
2  * Modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include "windows.h"
14 #include "dlls.h"
15 #include "dos_fs.h"
16 #include "global.h"
17 #include "ldt.h"
18 #include "module.h"
19 #include "neexe.h"
20 #include "stackframe.h"
21 #include "task.h"
22 #include "toolhelp.h"
23 #include "stddebug.h"
24 #include "debug.h"
25
26
27 static HMODULE hFirstModule = 0;
28 static HMODULE hCachedModule = 0;  /* Module cached by MODULE_OpenFile */
29
30
31 /***********************************************************************
32  *           MODULE_Init
33  *
34  * Create the built-in modules.
35  */
36 BOOL MODULE_Init(void)
37 {
38     extern void load_entrypoints( HMODULE );
39
40     HMODULE hModule;
41     NE_MODULE *pModule;
42     SEGTABLEENTRY *pSegTable;
43     struct dll_table_s *table;
44     char *dosmem;
45     int i;
46
47       /* Create the built-in modules */
48
49     for (i = 0, table = dll_builtin_table; i < N_BUILTINS; i++, table++)
50     {
51         if (!table->used) continue;
52
53         hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->module_start,
54                                       table->module_end - table->module_start,
55                                       0, FALSE, FALSE, FALSE, NULL );
56         if (!hModule) return FALSE;
57         FarSetOwner( hModule, hModule );
58
59         table->hModule = hModule;
60
61         dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
62                         table->name, hModule );
63
64           /* Allocate the code segment */
65
66         pModule = (NE_MODULE *)GlobalLock( hModule );
67         pSegTable = NE_SEG_TABLE( pModule );
68
69         pSegTable->selector = GLOBAL_CreateBlock(GMEM_FIXED, table->code_start,
70                                                  pSegTable->minsize, hModule,
71                                                  TRUE, TRUE, FALSE, NULL );
72         if (!pSegTable->selector) return FALSE;
73         pSegTable++;
74
75           /* Allocate the data segment */
76
77         pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, pSegTable->minsize,
78                                             hModule, FALSE, FALSE, FALSE );
79         if (!pSegTable->selector) return FALSE;
80         memcpy( GlobalLock( pSegTable->selector ), table->data_start,
81                 pSegTable->minsize );
82
83         pModule->next = hFirstModule;
84         hFirstModule = hModule;
85         load_entrypoints( hModule );
86     }
87
88       /* Initialize some KERNEL exported values */
89
90     if (!(hModule = GetModuleHandle( "KERNEL" ))) return TRUE;
91
92       /* KERNEL.178: __WINFLAGS */
93     MODULE_SetEntryPoint( hModule, 178, GetWinFlags() );
94
95     /* Allocate 7 64k segments for 0000, A000, B000, C000, D000, E000, F000. */
96
97     dosmem = malloc( 0x70000 );
98
99     MODULE_SetEntryPoint( hModule, 183,  /* KERNEL.183: __0000H */
100                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem,
101                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
102     MODULE_SetEntryPoint( hModule, 193,  /* KERNEL.193: __0040H */
103                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x400,
104                                   0x100, hModule, FALSE, FALSE, FALSE, NULL ));
105     MODULE_SetEntryPoint( hModule, 174,  /* KERNEL.174: __A000H */
106                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x10000,
107                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
108     MODULE_SetEntryPoint( hModule, 181,  /* KERNEL.181: __B000H */
109                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x20000,
110                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
111     MODULE_SetEntryPoint( hModule, 182,  /* KERNEL.182: __B800H */
112                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x28000,
113                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
114     MODULE_SetEntryPoint( hModule, 195,  /* KERNEL.195: __C000H */
115                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x30000,
116                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
117     MODULE_SetEntryPoint( hModule, 179,  /* KERNEL.179: __D000H */
118                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x40000,
119                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
120     MODULE_SetEntryPoint( hModule, 190,  /* KERNEL.190: __E000H */
121                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x50000,
122                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
123     MODULE_SetEntryPoint( hModule, 173,  /* KERNEL.173: __ROMBIOS */
124                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
125                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
126     MODULE_SetEntryPoint( hModule, 194,  /* KERNEL.194: __F000H */
127                           GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
128                                 0x10000, hModule, FALSE, FALSE, FALSE, NULL ));
129     return TRUE;
130 }
131
132
133 /***********************************************************************
134  *           MODULE_PrintModule
135  */
136 void MODULE_PrintModule( HMODULE hmodule )
137 {
138     int i, ordinal;
139     SEGTABLEENTRY *pSeg;
140     BYTE *pstr;
141     WORD *pword;
142     NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hmodule );
143
144       /* Dump the module info */
145
146     printf( "Module %04x:\n", hmodule );
147     printf( "count=%d flags=%04x heap=%d stack=%d\n",
148             pModule->count, pModule->flags,
149             pModule->heap_size, pModule->stack_size );
150     printf( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
151            pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
152            pModule->seg_count, pModule->modref_count );
153     printf( "os_flags=%d swap_area=%d version=%04x\n",
154             pModule->os_flags, pModule->min_swap_area,
155             pModule->expected_version );
156
157       /* Dump the file info */
158
159     printf( "Filename: '%s'\n",
160          ((LOADEDFILEINFO *)((BYTE *)pModule + pModule->fileinfo))->filename );
161
162       /* Dump the segment table */
163
164     printf( "\nSegment table:\n" );
165     pSeg = NE_SEG_TABLE( pModule );
166     for (i = 0; i < pModule->seg_count; i++, pSeg++)
167         printf( "%02x: pos=%d size=%d flags=%04x minsize=%d sel=%04x\n",
168                 i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
169                 pSeg->minsize, pSeg->selector );
170
171       /* Dump the resource table */
172
173     printf( "\nResource table:\n" );
174     if (pModule->res_table)
175     {
176         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
177         printf( "Alignment: %d\n", *pword++ );
178         while (*pword)
179         {
180             struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
181             struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
182             printf( "id=%04x count=%d\n", ptr->type_id, ptr->count );
183             for (i = 0; i < ptr->count; i++, pname++)
184                 printf( "offset=%d len=%d id=%04x\n",
185                        pname->offset, pname->length, pname->id );
186             pword = (WORD *)pname;
187         }
188     }
189     else printf( "None\n" );
190
191       /* Dump the resident name table */
192
193     printf( "\nResident-name table:\n" );
194     pstr = (char *)pModule + pModule->name_table;
195     while (*pstr)
196     {
197         printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
198                 *(WORD *)(pstr + *pstr + 1) );
199         pstr += *pstr + 1 + sizeof(WORD);
200     }
201
202       /* Dump the module reference table */
203
204     printf( "\nModule ref table:\n" );
205     if (pModule->modref_table)
206     {
207         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
208         for (i = 0; i < pModule->modref_count; i++, pword++)
209         {
210             char *name = (char *)pModule + pModule->import_table + *pword;
211             printf( "%d: %04x -> '%*.*s'\n",
212                     i, *pword, *name, *name, name + 1 );
213         }
214     }
215     else printf( "None\n" );
216
217       /* Dump the entry table */
218
219     printf( "\nEntry table:\n" );
220     pstr = (char *)pModule + pModule->entry_table;
221     ordinal = 1;
222     while (*pstr)
223     {
224         printf( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
225         if (!pstr[1])
226         {
227             ordinal += *pstr;
228             pstr += 2;
229         }
230         else if ((BYTE)pstr[1] == 0xff)  /* moveable */
231         {
232             struct entry_tab_movable_s *pe = (struct entry_tab_movable_s*)(pstr+2);
233             for (i = 0; i < *pstr; i++, pe++)
234                 printf( "%d: %02x:%04x (moveable)\n",
235                         ordinal++, pe->seg_number, pe->offset );
236             pstr = (char *)pe;
237         }
238         else  /* fixed */
239         {
240             struct entry_tab_fixed_s *pe = (struct entry_tab_fixed_s*)(pstr+2);
241             for (i = 0; i < *pstr; i++, pe++)
242                 printf( "%d: %04x (fixed)\n",
243                         ordinal++, pe->offset[0] + (pe->offset[1] << 8) );
244             pstr = (char *)pe;
245         }
246     }
247
248     /* Dump the non-resident names table */
249
250     printf( "\nNon-resident names table:\n" );
251     if (pModule->nrname_handle)
252     {
253         pstr = (char *)GlobalLock( pModule->nrname_handle );
254         while (*pstr)
255         {
256             printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
257                    *(WORD *)(pstr + *pstr + 1) );
258             pstr += *pstr + 1 + sizeof(WORD);
259         }
260     }
261     printf( "\n" );
262 }
263
264
265 /***********************************************************************
266  *           MODULE_OpenFile
267  */
268 int MODULE_OpenFile( HMODULE hModule )
269 {
270     NE_MODULE *pModule;
271     char *name;
272
273     static int cachedfd = -1;
274
275     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
276     dprintf_module( stddeb, "MODULE_OpenFile(%04x) cache: mod=%04x fd=%d\n",
277                     hModule, hCachedModule, cachedfd );
278     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return -1;
279     if (hCachedModule == hModule) return cachedfd;
280     close( cachedfd );
281     hCachedModule = hModule;
282     name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
283     cachedfd = open( DOS_GetUnixFileName( name ), O_RDONLY );
284     dprintf_module( stddeb, "MODULE_OpenFile: opened '%s' -> %d\n",
285                     name, cachedfd );
286     return cachedfd;
287 }
288
289
290 /***********************************************************************
291  *           MODULE_CreateSegments
292  */
293 static BOOL MODULE_CreateSegments( HMODULE hModule )
294 {
295     SEGTABLEENTRY *pSegment;
296     NE_MODULE *pModule;
297     int i, minsize;
298
299     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
300     pSegment = NE_SEG_TABLE( pModule );
301     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
302     {
303         minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
304         if (i == pModule->ss) minsize += pModule->stack_size;
305         /* The DGROUP is allocated by MODULE_CreateInstance */
306         if (i == pModule->dgroup) continue;
307         pSegment->selector = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
308                                       minsize, hModule,
309                                       !(pSegment->flags & NE_SEGFLAGS_DATA),
310                                       FALSE,
311                             FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
312         if (!pSegment->selector) return FALSE;
313     }
314
315     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
316                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
317     return TRUE;
318 }
319
320
321 /***********************************************************************
322  *           MODULE_GetInstance
323  */
324 static HINSTANCE MODULE_GetInstance( HMODULE hModule )
325 {
326     SEGTABLEENTRY *pSegment;
327     NE_MODULE *pModule;
328     
329     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
330     if (pModule->dgroup == 0) return hModule;
331
332     pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
333     
334     return pSegment->selector;
335 }
336
337
338 /***********************************************************************
339  *           MODULE_CreateInstance
340  */
341 static HINSTANCE MODULE_CreateInstance( HMODULE hModule, LOADPARAMS *params )
342 {
343     SEGTABLEENTRY *pSegment;
344     NE_MODULE *pModule;
345     int minsize;
346     HINSTANCE hNewInstance, hPrevInstance;
347
348     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
349     if (pModule->dgroup == 0) return hModule;
350
351     pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
352     hPrevInstance = pSegment->selector;
353
354       /* if it's a library, create a new instance only the first time */
355     if (hPrevInstance)
356     {
357         if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
358         if (params == (LOADPARAMS*)-1) return hPrevInstance;
359     }
360
361     minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
362     if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
363     minsize += pModule->heap_size;
364     hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
365                                  minsize, hModule, FALSE, FALSE, FALSE );
366     if (!hNewInstance) return 0;
367     pSegment->selector = hNewInstance;
368     return hNewInstance;
369 }
370
371
372 /***********************************************************************
373  *           MODULE_LoadExeHeader
374  */
375 HMODULE MODULE_LoadExeHeader( int fd, OFSTRUCT *ofs )
376 {
377     struct mz_header_s mz_header;
378     struct ne_header_s ne_header;
379     int size;
380     HMODULE hModule;
381     NE_MODULE *pModule;
382     BYTE *pData;
383     char *buffer, *fastload = NULL;
384     int fastload_offset = 0, fastload_length = 0;
385
386   /* Read a block from either the file or the fast-load area. */
387 #define READ(offset,size,buffer) \
388        ((fastload && ((offset) >= fastload_offset) && \
389          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
390         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
391         (lseek( fd, mz_header.ne_offset+(offset), SEEK_SET), \
392          read( fd, (buffer), (size) ) == (size)))
393
394     lseek( fd, 0, SEEK_SET );
395     if ((read( fd, &mz_header, sizeof(mz_header) ) != sizeof(mz_header)) ||
396         (mz_header.mz_magic != MZ_SIGNATURE)) return 11;  /* invalid exe */
397
398     lseek( fd, mz_header.ne_offset, SEEK_SET );
399     if (read( fd, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
400         return 11;  /* invalid exe */
401
402     if (ne_header.ne_magic == PE_SIGNATURE) return 21;  /* win32 exe */
403     if (ne_header.ne_magic != NE_SIGNATURE) return 11;  /* invalid exe */
404
405     /* We now have a valid NE header */
406
407     size = sizeof(NE_MODULE) +
408              /* loaded file info */
409            sizeof(LOADEDFILEINFO) + strlen(ofs->szPathName) +
410              /* segment table */
411            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
412              /* resource table */
413            ne_header.rname_tab_offset - ne_header.resource_tab_offset +
414              /* resident names table */
415            ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
416              /* module ref table */
417            ne_header.n_mod_ref_tab * sizeof(WORD) + 
418              /* imported names table */
419            ne_header.entry_tab_offset - ne_header.iname_tab_offset +
420              /* entry table length */
421            ne_header.entry_tab_length;
422
423     hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
424     if (!hModule) return 11;  /* invalid exe */
425     FarSetOwner( hModule, hModule );
426     pModule = (NE_MODULE *)GlobalLock( hModule );
427     memcpy( pModule, &ne_header, sizeof(NE_MODULE) );
428     pModule->count = 0;
429     pData = (BYTE *)(pModule + 1);
430
431     /* Read the fast-load area */
432
433     if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
434     {
435         fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
436         fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
437         dprintf_module( stddeb, "Using fast-load area offset=%x len=%d\n",
438                         fastload_offset, fastload_length );
439         if ((fastload = (char *)malloc( fastload_length )) != NULL)
440         {
441             lseek( fd, mz_header.ne_offset + fastload_offset, SEEK_SET );
442             if (read( fd, fastload, fastload_length ) != fastload_length)
443             {
444                 free( fastload );
445                 fastload = NULL;
446             }
447         }
448     }
449
450     /* Store the filename information */
451
452     pModule->fileinfo = (int)pData - (int)pModule;
453     ((LOADEDFILEINFO*)pData)->length = sizeof(LOADEDFILEINFO)+strlen(ofs->szPathName);
454     ((LOADEDFILEINFO*)pData)->fixed_media = TRUE;
455     ((LOADEDFILEINFO*)pData)->error = 0;
456     ((LOADEDFILEINFO*)pData)->date = 0;
457     ((LOADEDFILEINFO*)pData)->time = 0;
458     strcpy( ((LOADEDFILEINFO*)pData)->filename, ofs->szPathName );
459     pData += ((LOADEDFILEINFO*)pData)->length--;
460
461     /* Get the segment table */
462
463     pModule->seg_table = (int)pData - (int)pModule;
464     buffer = malloc( ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s) );
465     if (buffer)
466     {
467         int i;
468         struct ne_segment_table_entry_s *pSeg;
469
470         if (!READ( ne_header.segment_tab_offset,
471              ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
472              buffer )) return 11;  /* invalid exe */
473         pSeg = (struct ne_segment_table_entry_s *)buffer;
474         for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
475         {
476             memcpy( pData, pSeg, sizeof(*pSeg) );
477             pData += sizeof(SEGTABLEENTRY);
478         }
479         free( buffer );
480     }
481     else return 11;  /* invalid exe */
482
483     /* Get the resource table */
484
485     if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
486     {
487         pModule->res_table = (int)pData - (int)pModule;
488         if (!READ(ne_header.resource_tab_offset,
489                   ne_header.rname_tab_offset - ne_header.resource_tab_offset,
490                   pData )) return 11;  /* invalid exe */
491         pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
492     }
493     else pModule->res_table = 0;  /* No resource table */
494
495     /* Get the resident names table */
496
497     pModule->name_table = (int)pData - (int)pModule;
498     if (!READ( ne_header.rname_tab_offset,
499                ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
500                pData )) return 11;  /* invalid exe */
501     pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
502
503     /* Get the module references table */
504
505     if (ne_header.n_mod_ref_tab > 0)
506     {
507         pModule->modref_table = (int)pData - (int)pModule;
508         if (!READ( ne_header.moduleref_tab_offset,
509                   ne_header.n_mod_ref_tab * sizeof(WORD),
510                   pData )) return 11;  /* invalid exe */
511         pData += ne_header.n_mod_ref_tab * sizeof(WORD);
512     }
513     else pModule->modref_table = 0;  /* No module references */
514
515     /* Get the imported names table */
516
517     pModule->import_table = (int)pData - (int)pModule;
518     if (!READ( ne_header.iname_tab_offset, 
519                ne_header.entry_tab_offset - ne_header.iname_tab_offset,
520                pData )) return 11;  /* invalid exe */
521     pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
522
523     /* Get the entry table */
524
525     pModule->entry_table = (int)pData - (int)pModule;
526     if (!READ( ne_header.entry_tab_offset,
527                ne_header.entry_tab_length,
528                pData )) return 11;  /* invalid exe */
529     pData += ne_header.entry_tab_length;
530
531     /* Get the non-resident names table */
532
533     if (ne_header.nrname_tab_length)
534     {
535         pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
536                                                hModule, FALSE, FALSE, FALSE );
537         if (!pModule->nrname_handle) return 11;  /* invalid exe */
538         buffer = GlobalLock( pModule->nrname_handle );
539         lseek( fd, ne_header.nrname_tab_offset, SEEK_SET );
540         if (read( fd, buffer, ne_header.nrname_tab_length )
541               != ne_header.nrname_tab_length) return 11;  /* invalid exe */
542     }
543     else pModule->nrname_handle = 0;
544
545     /* Allocate a segment for the implicitly-loaded DLLs */
546
547     if (pModule->modref_count)
548     {
549         pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
550                                     (pModule->modref_count+1)*sizeof(HMODULE),
551                                     hModule, FALSE, FALSE, FALSE );
552         if (!pModule->dlls_to_init) return 11;  /* invalid exe */
553     }
554     else pModule->dlls_to_init = 0;
555
556     if (debugging_module) MODULE_PrintModule( hModule );
557     pModule->next = hFirstModule;
558     hFirstModule = hModule;
559     return hModule;
560 }
561
562
563 /***********************************************************************
564  *           MODULE_GetOrdinal
565  *
566  * Lookup the ordinal for a given name.
567  */
568 WORD MODULE_GetOrdinal( HMODULE hModule, char *name )
569 {
570     char buffer[256], *cpnt;
571     BYTE len;
572     NE_MODULE *pModule;
573
574     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
575
576     dprintf_module( stddeb, "MODULE_GetOrdinal(%04x,'%s')\n",
577                     hModule, name );
578
579       /* First handle names of the form '#xxxx' */
580
581     if (name[0] == '#') return atoi( name + 1 );
582
583       /* Now copy and uppercase the string */
584
585     strcpy( buffer, name );
586     AnsiUpper( buffer );
587     len = strlen( buffer );
588
589       /* First search the resident names */
590
591     cpnt = (char *)pModule + pModule->name_table;
592
593       /* Skip the first entry (module name) */
594     cpnt += *cpnt + 1 + sizeof(WORD);
595     while (*cpnt)
596     {
597         dprintf_module( stddeb, "  Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
598         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
599         {
600             dprintf_module( stddeb, "  Found: ordinal=%d\n",
601                             *(WORD *)(cpnt + *cpnt + 1) );
602             return *(WORD *)(cpnt + *cpnt + 1);
603         }
604         cpnt += *cpnt + 1 + sizeof(WORD);
605     }
606
607       /* Now search the non-resident names table */
608
609     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
610     cpnt = (char *)GlobalLock( pModule->nrname_handle );
611
612       /* Skip the first entry (module description string) */
613     cpnt += *cpnt + 1 + sizeof(WORD);
614     while (*cpnt)
615     {
616         dprintf_module( stddeb, "  Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
617         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
618         {
619             dprintf_module( stddeb, "  Found: ordinal=%d\n",
620                             *(WORD *)(cpnt + *cpnt + 1) );
621             return *(WORD *)(cpnt + *cpnt + 1);
622         }
623         cpnt += *cpnt + 1 + sizeof(WORD);
624     }
625     return 0;
626 }
627
628
629 /***********************************************************************
630  *           MODULE_GetEntryPoint
631  *
632  * Return the entry point for a given ordinal.
633  */
634 DWORD MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal )
635 {
636     NE_MODULE *pModule;
637     WORD curOrdinal = 1;
638     BYTE *p;
639     WORD sel, offset;
640
641     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
642
643     p = (BYTE *)pModule + pModule->entry_table;
644     while (*p && (curOrdinal + *p <= ordinal))
645     {
646           /* Skipping this bundle */
647         curOrdinal += *p;
648         switch(p[1])
649         {
650             case 0:    p += 2; break;  /* unused */
651             case 0xff: p += 2 + *p * 6; break;  /* moveable */
652             default:   p += 2 + *p * 3; break;  /* fixed */
653         }
654     }
655     if (!*p) return 0;
656
657     switch(p[1])
658     {
659         case 0:  /* unused */
660             return 0;
661         case 0xff:  /* moveable */
662             p += 2 + 6 * (ordinal - curOrdinal);
663             sel = p[3];
664             offset = *(WORD *)(p + 4);
665             break;
666         default:  /* fixed */
667             sel = p[1];
668             p += 2 + 3 * (ordinal - curOrdinal);
669             offset = *(WORD *)(p + 1);
670             break;
671     }
672
673     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
674     else sel = NE_SEG_TABLE(pModule)[sel-1].selector;
675     return MAKELONG( offset, sel );
676 }
677
678
679 /***********************************************************************
680  *           MODULE_SetEntryPoint
681  *
682  * Change the value of an entry point. Use with caution!
683  * It can only change the offset value, not the selector.
684  */
685 BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset )
686 {
687     NE_MODULE *pModule;
688     WORD curOrdinal = 1;
689     BYTE *p;
690
691     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
692
693     p = (BYTE *)pModule + pModule->entry_table;
694     while (*p && (curOrdinal + *p <= ordinal))
695     {
696           /* Skipping this bundle */
697         curOrdinal += *p;
698         switch(p[1])
699         {
700             case 0:    p += 2; break;  /* unused */
701             case 0xff: p += 2 + *p * 6; break;  /* moveable */
702             default:   p += 2 + *p * 3; break;  /* fixed */
703         }
704     }
705     if (!*p) return FALSE;
706
707     switch(p[1])
708     {
709         case 0:  /* unused */
710             return FALSE;
711         case 0xff:  /* moveable */
712             p += 2 + 6 * (ordinal - curOrdinal);
713             *(WORD *)(p + 4) = offset;
714             break;
715         default:  /* fixed */
716             p += 2 + 3 * (ordinal - curOrdinal);
717             *(WORD *)(p + 1) = offset;
718             break;
719     }
720     return TRUE;
721 }
722
723
724 /***********************************************************************
725  *           MODULE_GetEntryPointName
726  *
727  * Return the entry point name for a given ordinal.
728  * Used only by relay debugging.
729  * Warning: returned pointer is to a Pascal-type string.
730  */
731 LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal )
732 {
733     register char *cpnt;
734     NE_MODULE *pModule;
735
736     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
737
738       /* First search the resident names */
739
740     cpnt = (char *)pModule + pModule->name_table;
741     while (*cpnt)
742     {
743         cpnt += *cpnt + 1 + sizeof(WORD);
744         if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
745     }
746
747       /* Now search the non-resident names table */
748
749     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
750     cpnt = (char *)GlobalLock( pModule->nrname_handle );
751     while (*cpnt)
752     {
753         cpnt += *cpnt + 1 + sizeof(WORD);
754         if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
755     }
756     return NULL;
757 }
758
759
760 /***********************************************************************
761  *           MODULE_GetModuleName
762  */
763 LPSTR MODULE_GetModuleName( HMODULE hModule )
764 {
765     NE_MODULE *pModule;
766     BYTE *p, len;
767     static char buffer[10];
768
769     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return NULL;
770     p = (BYTE *)pModule + pModule->name_table;
771     len = min( *p, 8 );
772     memcpy( buffer, p + 1, len );
773     buffer[len] = '\0';
774     return buffer;
775 }
776
777
778 /**********************************************************************
779  *          MODULE_FindModule
780  *
781  * Find a module from a path name.
782  */
783 HMODULE MODULE_FindModule( LPCSTR path )
784 {
785     HMODULE hModule = hFirstModule;
786     LPCSTR filename, dotptr, modulepath, modulename;
787     BYTE len, *name_table;
788
789     if (!(filename = strrchr( path, '\\' ))) filename = path;
790     else filename++;
791     if ((dotptr = strrchr( filename, '.' )) != NULL)
792         len = (BYTE)(dotptr - filename);
793     else len = strlen( filename );
794
795     while(hModule)
796     {
797         NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
798         if (!pModule) break;
799         modulepath = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
800         if (!(modulename = strrchr( modulepath, '\\' )))
801             modulename = modulepath;
802         else modulename++;
803         if (!strcasecmp( modulename, filename )) return hModule;
804
805         name_table = (BYTE *)pModule + pModule->name_table;
806         if ((*name_table == len) && !strncasecmp(filename, name_table+1, len))
807             return hModule;
808         hModule = pModule->next;
809     }
810     return 0;
811 }
812
813
814 /**********************************************************************
815  *          MODULE_FreeModule
816  *
817  * Remove a module from memory.
818  */
819 static void MODULE_FreeModule( HMODULE hModule )
820 {
821     HMODULE *hPrevModule;
822     NE_MODULE *pModule;
823     SEGTABLEENTRY *pSegment;
824     WORD *pModRef;
825     int i;
826
827     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return;
828
829     /* FIXME: should call the exit code for the library here */
830
831       /* Remove it from the linked list */
832
833     hPrevModule = &hFirstModule;
834     while (*hPrevModule && (*hPrevModule != hModule))
835     {
836         hPrevModule = &((NE_MODULE *)GlobalLock( *hPrevModule ))->next;
837     }
838     if (*hPrevModule) *hPrevModule = pModule->next;
839
840       /* Free all the segments */
841
842     pSegment = NE_SEG_TABLE( pModule );
843     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
844     {
845         GlobalFree( pSegment->selector );
846     }
847
848       /* Free the referenced modules */
849
850     pModRef = NE_MODULE_TABLE( pModule );
851     for (i = 0; i < pModule->modref_count; i++, pModRef++)
852     {
853         FreeModule( *pModRef );
854     }
855
856       /* Free the module storage */
857
858     if (pModule->nrname_handle) GlobalFree( pModule->nrname_handle );
859     if (pModule->dlls_to_init) GlobalFree( pModule->dlls_to_init );
860     GlobalFree( hModule );
861
862       /* Remove module from cache */
863
864     if (hCachedModule == hModule) hCachedModule = 0;
865 }
866
867
868 /**********************************************************************
869  *          LoadModule    (KERNEL.45)
870  */
871 HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
872 {
873     HMODULE hModule;
874     HANDLE hInstance, hPrevInstance;
875     NE_MODULE *pModule;
876     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
877     WORD *pModRef, *pDLLs;
878     int i, fd;
879
880     hModule = MODULE_FindModule( name );
881     if (!hModule)  /* We have to load the module */
882     {
883         OFSTRUCT ofs;
884         if (strchr( name, '/' )) name = DOS_GetDosFileName( name );
885         if ((fd = OpenFile( name, &ofs, OF_READ )) == -1)
886             return 2;  /* File not found */
887
888           /* Create the module structure */
889
890         if ((hModule = MODULE_LoadExeHeader( fd, &ofs )) < 32)
891         {
892             close( fd );
893             fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
894                      name, hModule );
895             return hModule;
896         }
897         pModule = (NE_MODULE *)GlobalLock( hModule );
898
899           /* Allocate the segments for this module */
900
901         MODULE_CreateSegments( hModule );
902
903         hPrevInstance = 0;
904         hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
905
906           /* Load the referenced DLLs */
907
908         pModRef = (WORD *)((char *)pModule + pModule->modref_table);
909         pDLLs = (WORD *)GlobalLock( pModule->dlls_to_init );
910         for (i = 0; i < pModule->modref_count; i++, pModRef++)
911         {
912             char buffer[256];
913             BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
914             memcpy( buffer, pstr + 1, *pstr );
915             strcpy( buffer + *pstr, ".dll" );
916             dprintf_module( stddeb, "Loading '%s'\n", buffer );
917             if (!(*pModRef = MODULE_FindModule( buffer )))
918             {
919                 /* If the DLL is not loaded yet, load it and store */
920                 /* its handle in the list of DLLs to initialize.   */
921                 HMODULE hDLL;
922
923                 if ((hDLL = LoadModule( buffer, (LPVOID)-1 )) == 2)  /* file not found */
924                 {
925                     char *p;
926
927                     /* Try with prepending the path of the current module */
928                     GetModuleFileName( hModule, buffer, 256 );
929                     if (!(p = strrchr( buffer, '\\' ))) p = buffer;
930                     memcpy( p + 1, pstr + 1, *pstr );
931                     strcpy( p + 1 + *pstr, ".dll" );
932                     hDLL = LoadModule( buffer, (LPVOID)-1 );
933                 }
934                 if (hDLL < 32)
935                 {
936                     fprintf( stderr, "Could not load '%s' required by '%s', error = %d\n",
937                              buffer, name, hDLL );
938                     return 2;  /* file not found */
939                 }
940                 *pModRef = GetExePtr( hDLL );
941                 *pDLLs++ = *pModRef;
942             }
943             else  /* Increment the reference count of the DLL */
944             {
945                 NE_MODULE *pOldDLL = (NE_MODULE *)GlobalLock( *pModRef );
946                 if (pOldDLL) pOldDLL->count++;
947             }
948         }
949
950           /* Load the segments */
951
952         for (i = 1; i <= pModule->seg_count; i++) NE_LoadSegment( hModule, i );
953
954           /* Fixup the functions prologs */
955
956         NE_FixupPrologs( hModule );
957
958           /* Make sure the usage count is 1 on the first loading of  */
959           /* the module, even if it contains circular DLL references */
960
961         pModule->count = 1;
962     }
963     else
964     {
965         pModule = (NE_MODULE *)GlobalLock( hModule );
966         hPrevInstance = MODULE_GetInstance( hModule );
967         hInstance = MODULE_CreateInstance( hModule, params );
968         if (hInstance != hPrevInstance)  /* not a library */
969             NE_LoadSegment( hModule, pModule->dgroup );
970         pModule->count++;
971     }
972
973       /* Create a task for this instance */
974
975     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
976     {
977         TASK_CreateTask( hModule, hInstance, hPrevInstance,
978                          params->hEnvironment,
979                          (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
980                          *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1) );
981     }
982
983     return hInstance;
984 }
985
986
987 /**********************************************************************
988  *          FreeModule    (KERNEL.46)
989  */
990 BOOL FreeModule( HANDLE hModule )
991 {
992     NE_MODULE *pModule;
993
994     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
995     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
996
997     dprintf_module( stddeb, "FreeModule: %s count %d\n", 
998                     MODULE_GetModuleName(hModule), pModule->count );
999     if (--pModule->count == 0) MODULE_FreeModule( hModule );
1000     return TRUE;
1001 }
1002
1003
1004 /**********************************************************************
1005  *          GetModuleHandle    (KERNEL.47)
1006  */
1007 HMODULE WIN16_GetModuleHandle( SEGPTR name )
1008 {
1009     if (HIWORD(name) == 0) return GetExePtr( LOWORD(name) );
1010     return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
1011 }
1012
1013 HMODULE GetModuleHandle( LPCSTR name )
1014 {
1015     return MODULE_FindModule( name );
1016 }
1017
1018
1019 /**********************************************************************
1020  *          GetModuleUsage    (KERNEL.48)
1021  */
1022 int GetModuleUsage( HANDLE hModule )
1023 {
1024     NE_MODULE *pModule;
1025
1026     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1027     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
1028     dprintf_module( stddeb, "GetModuleUsage(%04x): returning %d\n",
1029                     hModule, pModule->count );
1030     return pModule->count;
1031 }
1032
1033
1034 /**********************************************************************
1035  *          GetModuleFileName    (KERNEL.49)
1036  */
1037 int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
1038 {
1039     NE_MODULE *pModule;
1040     char *name;
1041
1042     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1043     if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
1044     name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
1045     strncpy( lpFileName, name, nSize );
1046     lpFileName[nSize-1] = '\0';
1047     dprintf_module( stddeb, "GetModuleFilename: %s\n", lpFileName );
1048     return strlen(lpFileName);
1049 }
1050
1051
1052 /***********************************************************************
1053  *           LoadLibrary   (KERNEL.95)
1054  */
1055 HANDLE LoadLibrary( LPCSTR libname )
1056 {
1057     HANDLE handle;
1058
1059     dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
1060     /* This does not increment the module reference count, and will
1061      * therefore cause crashes on FreeLibrary calls.
1062     if ((handle = MODULE_FindModule( libname )) != 0) return handle;
1063      */
1064     handle = LoadModule( libname, (LPVOID)-1 );
1065     if (handle == 2)  /* file not found */
1066     {
1067         char buffer[256];
1068         strcpy( buffer, libname );
1069         strcat( buffer, ".dll" );
1070         handle = LoadModule( buffer, (LPVOID)-1 );
1071     }
1072     if (handle >= 32) NE_InitializeDLLs( GetExePtr(handle) );
1073     return handle;
1074 }
1075
1076
1077 /***********************************************************************
1078  *           FreeLibrary   (KERNEL.96)
1079  */
1080 void FreeLibrary( HANDLE handle )
1081 {
1082     dprintf_module( stddeb,"FreeLibrary: %04x\n", handle );
1083     FreeModule( handle );
1084 }
1085
1086
1087 /***********************************************************************
1088  *           WinExec   (KERNEL.166)
1089  */
1090 HANDLE WinExec( LPSTR lpCmdLine, WORD nCmdShow )
1091 {
1092     LOADPARAMS params;
1093     HLOCAL cmdShowHandle, cmdLineHandle;
1094     HANDLE handle;
1095     WORD *cmdShowPtr;
1096     char *p, *cmdline, filename[256];
1097
1098     if (!(cmdShowHandle = GlobalAlloc( 0, 2 * sizeof(WORD) ))) return 0;
1099     if (!(cmdLineHandle = GlobalAlloc( 0, 256 ))) return 0;
1100
1101       /* Store nCmdShow */
1102
1103     cmdShowPtr = (WORD *)GlobalLock( cmdShowHandle );
1104     cmdShowPtr[0] = 2;
1105     cmdShowPtr[1] = nCmdShow;
1106
1107       /* Build the filename and command-line */
1108
1109     cmdline = (char *)GlobalLock( cmdLineHandle );
1110     strncpy( filename, lpCmdLine, 256 );
1111     filename[255] = '\0';
1112     for (p = filename; *p && (*p != ' ') && (*p != '\t'); p++);
1113     if (*p)
1114     {
1115         strncpy( cmdline, p + 1, 128 );
1116         cmdline[127] = '\0';
1117     }
1118     else cmdline[0] = '\0';
1119     *p = '\0';
1120
1121       /* Now load the executable file */
1122
1123     params.hEnvironment = SELECTOROF( GetDOSEnvironment() );
1124     params.cmdLine  = WIN16_GlobalLock( cmdLineHandle );
1125     params.showCmd  = WIN16_GlobalLock( cmdShowHandle );
1126     params.reserved = 0;
1127     handle = LoadModule( filename, &params );
1128     if (handle == 2)  /* file not found */
1129     {
1130         strcat( filename, ".exe" );
1131         handle = LoadModule( filename, &params );
1132     }
1133
1134     GlobalFree( cmdShowHandle );
1135     GlobalFree( cmdLineHandle );
1136     return handle;
1137 }
1138
1139
1140 /***********************************************************************
1141  *           GetProcAddress   (KERNEL.50)
1142  */
1143 FARPROC GetProcAddress( HANDLE hModule, SEGPTR name )
1144 {
1145     WORD ordinal;
1146     SEGPTR ret;
1147
1148     if (!hModule) hModule = GetCurrentTask();
1149     hModule = GetExePtr( hModule );
1150
1151     if (HIWORD(name) != 0)
1152     {
1153         ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1154         dprintf_module( stddeb, "GetProcAddress: %04x '%s'\n",
1155                         hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1156     }
1157     else
1158     {
1159         ordinal = LOWORD(name);
1160         dprintf_module( stddeb, "GetProcAddress: %04x %04x\n",
1161                         hModule, ordinal );
1162     }
1163     if (!ordinal) return (FARPROC)0;
1164
1165     ret = MODULE_GetEntryPoint( hModule, ordinal );
1166
1167     dprintf_module( stddeb, "GetProcAddress: returning %08lx\n", ret );
1168     return (FARPROC)ret;
1169 }
1170
1171
1172 /**********************************************************************
1173  *          ModuleFirst    (TOOLHELP.59)
1174  */
1175 BOOL ModuleFirst( MODULEENTRY *lpme )
1176 {
1177     lpme->wNext = hFirstModule;
1178     return ModuleNext( lpme );
1179 }
1180
1181
1182 /**********************************************************************
1183  *          ModuleNext    (TOOLHELP.60)
1184  */
1185 BOOL ModuleNext( MODULEENTRY *lpme )
1186 {
1187     NE_MODULE *pModule;
1188
1189     if (!lpme->wNext) return FALSE;
1190     if (!(pModule = (NE_MODULE *)GlobalLock( lpme->wNext ))) return FALSE;
1191     strncpy( lpme->szModule, (char *)pModule + pModule->name_table,
1192              MAX_MODULE_NAME );
1193     lpme->szModule[MAX_MODULE_NAME] = '\0';
1194     lpme->hModule = lpme->wNext;
1195     lpme->wcUsage = pModule->count;
1196     strncpy( lpme->szExePath,
1197              ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename,
1198              MAX_PATH );
1199     lpme->szExePath[MAX_PATH] = '\0';
1200     lpme->wNext = pModule->next;
1201     return TRUE;
1202 }
1203
1204
1205 /**********************************************************************
1206  *          ModuleFindName    (TOOLHELP.61)
1207  */
1208 BOOL ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1209 {
1210     lpme->wNext = GetModuleHandle( name );
1211     return ModuleNext( lpme );
1212 }
1213
1214
1215 /**********************************************************************
1216  *          ModuleFindHandle    (TOOLHELP.62)
1217  */
1218 BOOL ModuleFindHandle( MODULEENTRY *lpme, HMODULE hModule )
1219 {
1220     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1221     lpme->wNext = hModule;
1222     return ModuleNext( lpme );
1223 }