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