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