Release 960516
[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 "class.h"
15 #include "dos_fs.h"
16 #include "file.h"
17 #include "global.h"
18 #include "hook.h"
19 #include "ldt.h"
20 #include "module.h"
21 #include "neexe.h"
22 #include "stackframe.h"
23 #include "task.h"
24 #include "toolhelp.h"
25 #include "stddebug.h"
26 #include "debug.h"
27
28 #include "callback.h"
29 #include "wine.h"
30
31 extern HINSTANCE PE_LoadModule( int fd, OFSTRUCT *ofs, LOADPARAMS* params );
32
33 static HMODULE hFirstModule = 0;
34 static HMODULE hCachedModule = 0;  /* Module cached by MODULE_OpenFile */
35
36 #ifndef WINELIB
37 static HANDLE hInitialStack32 = 0;
38 #endif
39
40
41 /***********************************************************************
42  *           MODULE_GetPtr
43  */
44 NE_MODULE *MODULE_GetPtr( HMODULE hModule )
45 {
46     NE_MODULE *pModule = (NE_MODULE *)GlobalLock16( hModule );
47     if (!pModule || (pModule->magic != NE_SIGNATURE) ||
48         (pModule->self != hModule)) return NULL;
49     return pModule;
50 }
51
52
53 /***********************************************************************
54  *           MODULE_DumpModule
55  */
56 void MODULE_DumpModule( HMODULE hmodule )
57 {
58     int i, ordinal;
59     SEGTABLEENTRY *pSeg;
60     BYTE *pstr;
61     WORD *pword;
62     NE_MODULE *pModule;
63
64     if (!(pModule = MODULE_GetPtr( hmodule )))
65     {
66         fprintf( stderr, "**** %04x is not a module handle\n", hmodule );
67         return;
68     }
69
70       /* Dump the module info */
71
72     printf( "Module %04x:\n", hmodule );
73     printf( "count=%d flags=%04x heap=%d stack=%d\n",
74             pModule->count, pModule->flags,
75             pModule->heap_size, pModule->stack_size );
76     printf( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
77            pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
78            pModule->seg_count, pModule->modref_count );
79     printf( "os_flags=%d swap_area=%d version=%04x\n",
80             pModule->os_flags, pModule->min_swap_area,
81             pModule->expected_version );
82     if (pModule->flags & NE_FFLAGS_WIN32)
83         printf( "PE module=%08x\n", (unsigned int)pModule->pe_module );
84
85       /* Dump the file info */
86
87     printf( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
88
89       /* Dump the segment table */
90
91     printf( "\nSegment table:\n" );
92     pSeg = NE_SEG_TABLE( pModule );
93     for (i = 0; i < pModule->seg_count; i++, pSeg++)
94         printf( "%02x: pos=%d size=%d flags=%04x minsize=%d sel=%04x\n",
95                 i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
96                 pSeg->minsize, pSeg->selector );
97
98       /* Dump the resource table */
99
100     printf( "\nResource table:\n" );
101     if (pModule->res_table)
102     {
103         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
104         printf( "Alignment: %d\n", *pword++ );
105         while (*pword)
106         {
107             struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
108             struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
109             printf( "id=%04x count=%d\n", ptr->type_id, ptr->count );
110             for (i = 0; i < ptr->count; i++, pname++)
111                 printf( "offset=%d len=%d id=%04x\n",
112                        pname->offset, pname->length, pname->id );
113             pword = (WORD *)pname;
114         }
115     }
116     else printf( "None\n" );
117
118       /* Dump the resident name table */
119
120     printf( "\nResident-name table:\n" );
121     pstr = (char *)pModule + pModule->name_table;
122     while (*pstr)
123     {
124         printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
125                 *(WORD *)(pstr + *pstr + 1) );
126         pstr += *pstr + 1 + sizeof(WORD);
127     }
128
129       /* Dump the module reference table */
130
131     printf( "\nModule ref table:\n" );
132     if (pModule->modref_table)
133     {
134         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
135         for (i = 0; i < pModule->modref_count; i++, pword++)
136         {
137             char *name = (char *)pModule + pModule->import_table + *pword;
138             printf( "%d: %04x -> '%*.*s'\n",
139                     i, *pword, *name, *name, name + 1 );
140         }
141     }
142     else printf( "None\n" );
143
144       /* Dump the entry table */
145
146     printf( "\nEntry table:\n" );
147     pstr = (char *)pModule + pModule->entry_table;
148     ordinal = 1;
149     while (*pstr)
150     {
151         printf( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
152         if (!pstr[1])
153         {
154             ordinal += *pstr;
155             pstr += 2;
156         }
157         else if ((BYTE)pstr[1] == 0xff)  /* moveable */
158         {
159             struct entry_tab_movable_s *pe = (struct entry_tab_movable_s*)(pstr+2);
160             for (i = 0; i < *pstr; i++, pe++)
161                 printf( "%d: %02x:%04x (moveable)\n",
162                         ordinal++, pe->seg_number, pe->offset );
163             pstr = (char *)pe;
164         }
165         else  /* fixed */
166         {
167             struct entry_tab_fixed_s *pe = (struct entry_tab_fixed_s*)(pstr+2);
168             for (i = 0; i < *pstr; i++, pe++)
169                 printf( "%d: %04x (fixed)\n",
170                         ordinal++, pe->offset[0] + (pe->offset[1] << 8) );
171             pstr = (char *)pe;
172         }
173     }
174
175     /* Dump the non-resident names table */
176
177     printf( "\nNon-resident names table:\n" );
178     if (pModule->nrname_handle)
179     {
180         pstr = (char *)GlobalLock16( pModule->nrname_handle );
181         while (*pstr)
182         {
183             printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
184                    *(WORD *)(pstr + *pstr + 1) );
185             pstr += *pstr + 1 + sizeof(WORD);
186         }
187     }
188     printf( "\n" );
189 }
190
191
192 /***********************************************************************
193  *           MODULE_WalkModules
194  *
195  * Walk the module list and print the modules.
196  */
197 void MODULE_WalkModules(void)
198 {
199     HMODULE hModule = hFirstModule;
200     fprintf( stderr, "Module Flags Name\n" );
201     while (hModule)
202     {
203         NE_MODULE *pModule = MODULE_GetPtr( hModule );
204         if (!pModule)
205         {
206             fprintf( stderr, "**** Bad module %04x in list\n", hModule );
207             return;
208         }
209         fprintf( stderr, " %04x  %04x  %.*s\n", hModule, pModule->flags,
210                  *((char *)pModule + pModule->name_table),
211                  (char *)pModule + pModule->name_table + 1 );
212         hModule = pModule->next;
213     }
214 }
215
216
217 /***********************************************************************
218  *           MODULE_OpenFile
219  */
220 int MODULE_OpenFile( HMODULE hModule )
221 {
222     NE_MODULE *pModule;
223     char *name;
224     const char *unixName;
225
226     static int cachedfd = -1;
227
228     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
229     dprintf_module( stddeb, "MODULE_OpenFile(%04x) cache: mod=%04x fd=%d\n",
230                     hModule, hCachedModule, cachedfd );
231     if (!(pModule = MODULE_GetPtr( hModule ))) return -1;
232     if (hCachedModule == hModule) return cachedfd;
233     close( cachedfd );
234     hCachedModule = hModule;
235     name = NE_MODULE_NAME( pModule );
236     if (!(unixName = DOSFS_GetUnixFileName( name, TRUE )) ||
237         (cachedfd = open( unixName, O_RDONLY )) == -1)
238         fprintf( stderr, "MODULE_OpenFile: can't open file '%s' for module %04x\n",
239                  name, hModule );
240     dprintf_module( stddeb, "MODULE_OpenFile: opened '%s' -> %d\n",
241                     name, cachedfd );
242     return cachedfd;
243 }
244
245
246 /***********************************************************************
247  *           MODULE_Ne2MemFlags
248  *
249  * This function translates NE segment flags to GlobalAlloc flags
250  */
251 static WORD MODULE_Ne2MemFlags(WORD flags)
252
253     WORD memflags = 0;
254 #if 0
255     if (flags & NE_SEGFLAGS_DISCARDABLE) 
256       memflags |= GMEM_DISCARDABLE;
257     if (flags & NE_SEGFLAGS_MOVEABLE || 
258         ( ! (flags & NE_SEGFLAGS_DATA) &&
259           ! (flags & NE_SEGFLAGS_LOADED) &&
260           ! (flags & NE_SEGFLAGS_ALLOCATED)
261          )
262         )
263       memflags |= GMEM_MOVEABLE;
264     memflags |= GMEM_ZEROINIT;
265 #else
266     memflags = GMEM_ZEROINIT | GMEM_FIXED;
267     return memflags;
268 #endif
269 }
270
271 /***********************************************************************
272  *           MODULE_AllocateSegment (WPROCS.26)
273  */
274
275 DWORD MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
276 {
277     WORD size = wSize << wElem;
278     HANDLE hMem = GlobalAlloc16( MODULE_Ne2MemFlags(wFlags), size);
279 #ifdef WINELIB
280     return (DWORD)GlobalLock16(hMem);
281 #else
282     WORD selector = HIWORD(WIN16_GlobalLock16(hMem));
283     return MAKELONG(hMem, selector);
284 #endif
285 }
286
287 /***********************************************************************
288  *           MODULE_CreateSegments
289  */
290 #ifndef WINELIB32
291 static BOOL MODULE_CreateSegments( HMODULE hModule )
292 {
293     SEGTABLEENTRY *pSegment;
294     NE_MODULE *pModule;
295     int i, minsize;
296
297     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
298     pSegment = NE_SEG_TABLE( pModule );
299     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
300     {
301         minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
302         if (i == pModule->ss) minsize += pModule->stack_size;
303         /* The DGROUP is allocated by MODULE_CreateInstance */
304         if (i == pModule->dgroup) continue;
305         pSegment->selector = GLOBAL_Alloc( MODULE_Ne2MemFlags(pSegment->flags),
306                                       minsize, hModule,
307                                       !(pSegment->flags & NE_SEGFLAGS_DATA),
308                                       FALSE,
309                             FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
310         if (!pSegment->selector) return FALSE;
311     }
312
313     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
314                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
315     return TRUE;
316 }
317 #endif
318
319
320 /***********************************************************************
321  *           MODULE_GetInstance
322  */
323 #ifndef WINELIB32
324 HINSTANCE MODULE_GetInstance( HMODULE hModule )
325 {
326     SEGTABLEENTRY *pSegment;
327     NE_MODULE *pModule;
328     
329     if (!(pModule = MODULE_GetPtr( 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 #endif
337
338
339 /***********************************************************************
340  *           MODULE_CreateInstance
341  */
342 HINSTANCE MODULE_CreateInstance( HMODULE hModule, LOADPARAMS *params )
343 {
344     SEGTABLEENTRY *pSegment;
345     NE_MODULE *pModule;
346     int minsize;
347     HINSTANCE hNewInstance, hPrevInstance;
348
349     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
350     if (pModule->dgroup == 0) return hModule;
351
352     pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
353     hPrevInstance = pSegment->selector;
354
355       /* if it's a library, create a new instance only the first time */
356     if (hPrevInstance)
357     {
358         if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
359         if (params == (LOADPARAMS*)-1) return hPrevInstance;
360     }
361
362     minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
363     if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
364     minsize += pModule->heap_size;
365     hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
366                                  minsize, hModule, FALSE, FALSE, FALSE );
367     if (!hNewInstance) return 0;
368     pSegment->selector = hNewInstance;
369     return hNewInstance;
370 }
371
372
373 /***********************************************************************
374  *           MODULE_LoadExeHeader
375  */
376 static HMODULE MODULE_LoadExeHeader( HFILE hFile, OFSTRUCT *ofs )
377 {
378     struct mz_header_s mz_header;
379     struct ne_header_s ne_header;
380     int size;
381     HMODULE hModule;
382     NE_MODULE *pModule;
383     BYTE *pData;
384     char *buffer, *fastload = NULL;
385     int fastload_offset = 0, fastload_length = 0;
386
387   /* Read a block from either the file or the fast-load area. */
388 #define READ(offset,size,buffer) \
389        ((fastload && ((offset) >= fastload_offset) && \
390          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
391         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
392         (_llseek( hFile, mz_header.ne_offset+(offset), SEEK_SET), \
393          FILE_Read( hFile, (buffer), (size) ) == (size)))
394
395     _llseek( hFile, 0, SEEK_SET );
396     if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
397         (mz_header.mz_magic != MZ_SIGNATURE)) return (HMODULE)11;  /* invalid exe */
398
399     _llseek( hFile, mz_header.ne_offset, SEEK_SET );
400     if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
401         return (HMODULE)11;  /* invalid exe */
402
403     if (ne_header.ne_magic == PE_SIGNATURE) return (HMODULE)21;  /* win32 exe */
404     if (ne_header.ne_magic != NE_SIGNATURE) return (HMODULE)11;  /* invalid exe */
405
406     /* We now have a valid NE header */
407
408     size = sizeof(NE_MODULE) +
409              /* loaded file info */
410            sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1+
411              /* segment table */
412            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
413              /* resource table */
414            ne_header.rname_tab_offset - ne_header.resource_tab_offset +
415              /* resident names table */
416            ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
417              /* module ref table */
418            ne_header.n_mod_ref_tab * sizeof(WORD) + 
419              /* imported names table */
420            ne_header.entry_tab_offset - ne_header.iname_tab_offset +
421              /* entry table length */
422            ne_header.entry_tab_length;
423
424     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
425     if (!hModule) return (HMODULE)11;  /* invalid exe */
426     FarSetOwner( hModule, hModule );
427     pModule = (NE_MODULE *)GlobalLock16( hModule );
428     memcpy( pModule, &ne_header, sizeof(ne_header) );
429     pModule->count = 0;
430     pModule->pe_module = NULL;
431     pModule->self = hModule;
432     pModule->self_loading_sel = 0;
433     pData = (BYTE *)(pModule + 1);
434
435     /* Clear internal Wine flags in case they are set in the EXE file */
436
437     pModule->flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
438
439     /* Read the fast-load area */
440
441     if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
442     {
443         fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
444         fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
445         dprintf_module( stddeb, "Using fast-load area offset=%x len=%d\n",
446                         fastload_offset, fastload_length );
447         if ((fastload = (char *)malloc( fastload_length )) != NULL)
448         {
449             _llseek( hFile, mz_header.ne_offset + fastload_offset, SEEK_SET );
450             if (FILE_Read( hFile, fastload, fastload_length ) != fastload_length)
451             {
452                 free( fastload );
453                 fastload = NULL;
454             }
455         }
456     }
457
458     /* Store the filename information */
459
460     pModule->fileinfo = (int)pData - (int)pModule;
461     size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
462     memcpy( pData, ofs, size );
463     ((OFSTRUCT *)pData)->cBytes = size - 1;
464     pData += size;
465
466     /* Get the segment table */
467
468     pModule->seg_table = (int)pData - (int)pModule;
469     buffer = malloc( ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s) );
470     if (buffer)
471     {
472         int i;
473         struct ne_segment_table_entry_s *pSeg;
474
475         if (!READ( ne_header.segment_tab_offset,
476              ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
477              buffer )) return (HMODULE)11;  /* invalid exe */
478         pSeg = (struct ne_segment_table_entry_s *)buffer;
479         for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
480         {
481             memcpy( pData, pSeg, sizeof(*pSeg) );
482             pData += sizeof(SEGTABLEENTRY);
483         }
484         free( buffer );
485     }
486     else
487     {
488         GlobalFree16( hModule );
489         return (HMODULE)11;  /* invalid exe */
490     }
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 (HMODULE)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 ))
510     {
511         GlobalFree16( hModule );
512         return (HMODULE)11;  /* invalid exe */
513     }
514     pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
515
516     /* Get the module references table */
517
518     if (ne_header.n_mod_ref_tab > 0)
519     {
520         pModule->modref_table = (int)pData - (int)pModule;
521         if (!READ( ne_header.moduleref_tab_offset,
522                   ne_header.n_mod_ref_tab * sizeof(WORD),
523                   pData )) return (HMODULE)11;  /* invalid exe */
524         pData += ne_header.n_mod_ref_tab * sizeof(WORD);
525     }
526     else pModule->modref_table = 0;  /* No module references */
527
528     /* Get the imported names table */
529
530     pModule->import_table = (int)pData - (int)pModule;
531     if (!READ( ne_header.iname_tab_offset, 
532                ne_header.entry_tab_offset - ne_header.iname_tab_offset,
533                pData ))
534     {
535         GlobalFree16( hModule );
536         return (HMODULE)11;  /* invalid exe */
537     }
538     pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
539
540     /* Get the entry table */
541
542     pModule->entry_table = (int)pData - (int)pModule;
543     if (!READ( ne_header.entry_tab_offset,
544                ne_header.entry_tab_length,
545                pData ))
546     {
547         GlobalFree16( hModule );
548         return (HMODULE)11;  /* invalid exe */
549     }
550     pData += ne_header.entry_tab_length;
551
552     /* Get the non-resident names table */
553
554     if (ne_header.nrname_tab_length)
555     {
556         pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
557                                                hModule, FALSE, FALSE, FALSE );
558         if (!pModule->nrname_handle)
559         {
560             GlobalFree16( hModule );
561             return (HMODULE)11;  /* invalid exe */
562         }
563         buffer = GlobalLock16( pModule->nrname_handle );
564         _llseek( hFile, ne_header.nrname_tab_offset, SEEK_SET );
565         if (FILE_Read( hFile, buffer, ne_header.nrname_tab_length )
566               != ne_header.nrname_tab_length)
567         {
568             GlobalFree16( pModule->nrname_handle );
569             GlobalFree16( hModule );
570             return (HMODULE)11;  /* invalid exe */
571         }
572     }
573     else pModule->nrname_handle = 0;
574
575     /* Allocate a segment for the implicitly-loaded DLLs */
576
577     if (pModule->modref_count)
578     {
579         pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
580                                     (pModule->modref_count+1)*sizeof(HMODULE),
581                                     hModule, FALSE, FALSE, FALSE );
582         if (!pModule->dlls_to_init)
583         {
584             if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
585             GlobalFree16( hModule );
586             return (HMODULE)11;  /* invalid exe */
587         }
588     }
589     else pModule->dlls_to_init = 0;
590
591     MODULE_RegisterModule( pModule );
592     return hModule;
593 #undef READ
594 }
595
596
597 /***********************************************************************
598  *           MODULE_GetOrdinal
599  *
600  * Lookup the ordinal for a given name.
601  */
602 WORD MODULE_GetOrdinal( HMODULE hModule, const char *name )
603 {
604     char buffer[256], *cpnt;
605     BYTE len;
606     NE_MODULE *pModule;
607
608     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
609
610     dprintf_module( stddeb, "MODULE_GetOrdinal(%04x,'%s')\n",
611                     hModule, name );
612
613       /* First handle names of the form '#xxxx' */
614
615     if (name[0] == '#') return atoi( name + 1 );
616
617       /* Now copy and uppercase the string */
618
619     strcpy( buffer, name );
620     AnsiUpper( buffer );
621     len = strlen( buffer );
622
623       /* First search the resident names */
624
625     cpnt = (char *)pModule + pModule->name_table;
626
627       /* Skip the first entry (module name) */
628     cpnt += *cpnt + 1 + sizeof(WORD);
629     while (*cpnt)
630     {
631         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
632         {
633             dprintf_module( stddeb, "  Found: ordinal=%d\n",
634                             *(WORD *)(cpnt + *cpnt + 1) );
635             return *(WORD *)(cpnt + *cpnt + 1);
636         }
637         cpnt += *cpnt + 1 + sizeof(WORD);
638     }
639
640       /* Now search the non-resident names table */
641
642     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
643     cpnt = (char *)GlobalLock16( pModule->nrname_handle );
644
645       /* Skip the first entry (module description string) */
646     cpnt += *cpnt + 1 + sizeof(WORD);
647     while (*cpnt)
648     {
649         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
650         {
651             dprintf_module( stddeb, "  Found: ordinal=%d\n",
652                             *(WORD *)(cpnt + *cpnt + 1) );
653             return *(WORD *)(cpnt + *cpnt + 1);
654         }
655         cpnt += *cpnt + 1 + sizeof(WORD);
656     }
657     return 0;
658 }
659
660
661 /***********************************************************************
662  *           MODULE_GetEntryPoint
663  *
664  * Return the entry point for a given ordinal.
665  */
666 SEGPTR MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal )
667 {
668     NE_MODULE *pModule;
669     WORD curOrdinal = 1;
670     BYTE *p;
671     WORD sel, offset;
672
673     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
674
675     p = (BYTE *)pModule + pModule->entry_table;
676     while (*p && (curOrdinal + *p <= ordinal))
677     {
678           /* Skipping this bundle */
679         curOrdinal += *p;
680         switch(p[1])
681         {
682             case 0:    p += 2; break;  /* unused */
683             case 0xff: p += 2 + *p * 6; break;  /* moveable */
684             default:   p += 2 + *p * 3; break;  /* fixed */
685         }
686     }
687     if (!*p) return 0;
688
689     switch(p[1])
690     {
691         case 0:  /* unused */
692             return 0;
693         case 0xff:  /* moveable */
694             p += 2 + 6 * (ordinal - curOrdinal);
695             sel = p[3];
696             offset = *(WORD *)(p + 4);
697             break;
698         default:  /* fixed */
699             sel = p[1];
700             p += 2 + 3 * (ordinal - curOrdinal);
701             offset = *(WORD *)(p + 1);
702             break;
703     }
704
705     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
706     else sel = (WORD)(DWORD)NE_SEG_TABLE(pModule)[sel-1].selector;
707     return PTR_SEG_OFF_TO_SEGPTR( sel, offset );
708 }
709
710
711 /***********************************************************************
712  *           MODULE_SetEntryPoint
713  *
714  * Change the value of an entry point. Use with caution!
715  * It can only change the offset value, not the selector.
716  */
717 BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset )
718 {
719     NE_MODULE *pModule;
720     WORD curOrdinal = 1;
721     BYTE *p;
722
723     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
724
725     p = (BYTE *)pModule + pModule->entry_table;
726     while (*p && (curOrdinal + *p <= ordinal))
727     {
728           /* Skipping this bundle */
729         curOrdinal += *p;
730         switch(p[1])
731         {
732             case 0:    p += 2; break;  /* unused */
733             case 0xff: p += 2 + *p * 6; break;  /* moveable */
734             default:   p += 2 + *p * 3; break;  /* fixed */
735         }
736     }
737     if (!*p) return FALSE;
738
739     switch(p[1])
740     {
741         case 0:  /* unused */
742             return FALSE;
743         case 0xff:  /* moveable */
744             p += 2 + 6 * (ordinal - curOrdinal);
745             *(WORD *)(p + 4) = offset;
746             break;
747         default:  /* fixed */
748             p += 2 + 3 * (ordinal - curOrdinal);
749             *(WORD *)(p + 1) = offset;
750             break;
751     }
752     return TRUE;
753 }
754
755
756 /***********************************************************************
757  *           MODULE_GetWndProcEntry16  (not a Windows API function)
758  *
759  * Return an entry point from the WPROCS dll.
760  */
761 #ifndef WINELIB
762 FARPROC16 MODULE_GetWndProcEntry16( const char *name )
763 {
764     WORD ordinal;
765     static HMODULE hModule = 0;
766
767     if (!hModule) hModule = GetModuleHandle( "WPROCS" );
768     ordinal = MODULE_GetOrdinal( hModule, name );
769     return MODULE_GetEntryPoint( hModule, ordinal );
770 }
771 #endif
772
773
774 /***********************************************************************
775  *           MODULE_GetWndProcEntry32  (not a Windows API function)
776  *
777  * Return an entry point from the WPROCS32 dll.
778  */
779 #ifndef WINELIB
780 FARPROC32 MODULE_GetWndProcEntry32( const char *name )
781 {
782     static HMODULE hModule = 0;
783
784     if (!hModule) hModule = GetModuleHandle( "WPROCS32" );
785     return PE_GetProcAddress( hModule, name );
786 }
787 #endif
788
789
790 /***********************************************************************
791  *           MODULE_GetModuleName
792  */
793 LPSTR MODULE_GetModuleName( HMODULE hModule )
794 {
795     NE_MODULE *pModule;
796     BYTE *p, len;
797     static char buffer[10];
798
799     if (!(pModule = MODULE_GetPtr( hModule ))) return NULL;
800     p = (BYTE *)pModule + pModule->name_table;
801     len = MIN( *p, 8 );
802     memcpy( buffer, p + 1, len );
803     buffer[len] = '\0';
804     return buffer;
805 }
806
807
808 /**********************************************************************
809  *           MODULE_RegisterModule
810  */
811 void MODULE_RegisterModule( NE_MODULE *pModule )
812 {
813     pModule->next = hFirstModule;
814     hFirstModule = pModule->self;
815 }
816
817
818 /**********************************************************************
819  *          MODULE_FindModule
820  *
821  * Find a module from a path name.
822  */
823 HMODULE MODULE_FindModule( LPCSTR path )
824 {
825     HMODULE hModule = hFirstModule;
826     LPCSTR filename, dotptr, modulepath, modulename;
827     BYTE len, *name_table;
828
829     if (!(filename = strrchr( path, '\\' ))) filename = path;
830     else filename++;
831     if ((dotptr = strrchr( filename, '.' )) != NULL)
832         len = (BYTE)(dotptr - filename);
833     else len = strlen( filename );
834
835     while(hModule)
836     {
837         NE_MODULE *pModule = MODULE_GetPtr( hModule );
838         if (!pModule) break;
839         modulepath = NE_MODULE_NAME(pModule);
840         if (!(modulename = strrchr( modulepath, '\\' )))
841             modulename = modulepath;
842         else modulename++;
843         if (!lstrcmpi( modulename, filename )) return hModule;
844
845         name_table = (BYTE *)pModule + pModule->name_table;
846         if ((*name_table == len) && !lstrncmpi(filename, name_table+1, len))
847             return hModule;
848         hModule = pModule->next;
849     }
850     return 0;
851 }
852
853
854 /**********************************************************************
855  *          MODULE_FreeModule
856  *
857  * Remove a module from memory.
858  */
859 static void MODULE_FreeModule( HMODULE hModule )
860 {
861     HMODULE *hPrevModule;
862     NE_MODULE *pModule;
863     SEGTABLEENTRY *pSegment;
864     HMODULE *pModRef;
865     int i;
866
867     if (!(pModule = MODULE_GetPtr( hModule ))) return;
868     if (pModule->flags & NE_FFLAGS_BUILTIN)
869         return;  /* Can't free built-in module */
870
871     /* FIXME: should call the exit code for the library here */
872
873     /* Free the objects owned by the module */
874
875     HOOK_FreeModuleHooks( hModule );
876     CLASS_FreeModuleClasses( hModule );
877
878     /* Clear magic number just in case */
879
880     pModule->magic = pModule->self = 0;
881
882       /* Remove it from the linked list */
883
884     hPrevModule = &hFirstModule;
885     while (*hPrevModule && (*hPrevModule != hModule))
886     {
887         hPrevModule = &(MODULE_GetPtr( *hPrevModule ))->next;
888     }
889     if (*hPrevModule) *hPrevModule = pModule->next;
890
891       /* Free all the segments */
892
893     pSegment = NE_SEG_TABLE( pModule );
894     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
895     {
896         GlobalFree16( pSegment->selector );
897     }
898
899       /* Free the referenced modules */
900
901     pModRef = (HMODULE*)NE_MODULE_TABLE( pModule );
902     for (i = 0; i < pModule->modref_count; i++, pModRef++)
903     {
904         FreeModule( *pModRef );
905     }
906
907       /* Free the module storage */
908
909     if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
910     if (pModule->dlls_to_init) GlobalFree16( pModule->dlls_to_init );
911     GlobalFree16( hModule );
912
913       /* Remove module from cache */
914
915     if (hCachedModule == hModule) hCachedModule = 0;
916 }
917
918
919 /**********************************************************************
920  *          LoadModule    (KERNEL.45)
921  */
922 HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
923 {
924     HMODULE hModule;
925     HANDLE hInstance, hPrevInstance;
926     NE_MODULE *pModule;
927     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
928 #ifndef WINELIB
929     WORD *pModRef, *pDLLs;
930     HFILE hFile;
931     int i;
932
933     hModule = MODULE_FindModule( name );
934
935     if (!hModule)  /* We have to load the module */
936     {
937         OFSTRUCT ofs;
938
939         /* Try to load the built-in first if not disabled */
940         if ((hModule = BUILTIN_LoadModule( name, FALSE ))) return hModule;
941
942         if ((hFile = OpenFile( name, &ofs, OF_READ )) == HFILE_ERROR)
943         {
944             /* Now try the built-in even if disabled */
945             if ((hModule = BUILTIN_LoadModule( name, TRUE )))
946             {
947                 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
948                 return hModule;
949             }
950             return 2;  /* File not found */
951         }
952
953           /* Create the module structure */
954
955         hModule = MODULE_LoadExeHeader( hFile, &ofs );
956         if (hModule < 32)
957         {
958             /* FIXME: Hack because PE_LoadModule is recursive */
959             int fd = dup( FILE_GetUnixHandle(hFile) );
960             _lclose( hFile );
961             if (hModule == 21) hModule = PE_LoadModule( fd, &ofs, paramBlock );
962             close( fd );
963             if (hModule < 32)
964                 fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
965                          name, hModule );
966             return hModule;
967         }
968         _lclose( hFile );
969         pModule = MODULE_GetPtr( hModule );
970
971           /* Allocate the segments for this module */
972
973         MODULE_CreateSegments( hModule );
974
975         hPrevInstance = 0;
976         hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
977
978           /* Load the referenced DLLs */
979
980         pModRef = (WORD *)((char *)pModule + pModule->modref_table);
981         pDLLs = (WORD *)GlobalLock16( pModule->dlls_to_init );
982         for (i = 0; i < pModule->modref_count; i++, pModRef++)
983         {
984             char buffer[256];
985             BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
986             memcpy( buffer, pstr + 1, *pstr );
987             strcpy( buffer + *pstr, ".dll" );
988             dprintf_module( stddeb, "Loading '%s'\n", buffer );
989             if (!(*pModRef = MODULE_FindModule( buffer )))
990             {
991                 /* If the DLL is not loaded yet, load it and store */
992                 /* its handle in the list of DLLs to initialize.   */
993                 HMODULE hDLL;
994
995                 if ((hDLL = LoadModule( buffer, (LPVOID)-1 )) == 2)  /* file not found */
996                 {
997                     char *p;
998
999                     /* Try with prepending the path of the current module */
1000                     GetModuleFileName( hModule, buffer, 256 );
1001                     if (!(p = strrchr( buffer, '\\' ))) p = buffer;
1002                     memcpy( p + 1, pstr + 1, *pstr );
1003                     strcpy( p + 1 + *pstr, ".dll" );
1004                     hDLL = LoadModule( buffer, (LPVOID)-1 );
1005                 }
1006                 if (hDLL < 32)
1007                 {
1008                     fprintf( stderr, "Could not load '%s' required by '%s', error = %d\n",
1009                              buffer, name, hDLL );
1010                     return 2;  /* file not found */
1011                 }
1012                 *pModRef = GetExePtr( hDLL );
1013                 *pDLLs++ = *pModRef;
1014             }
1015             else  /* Increment the reference count of the DLL */
1016             {
1017                 NE_MODULE *pOldDLL = MODULE_GetPtr( *pModRef );
1018                 if (pOldDLL) pOldDLL->count++;
1019             }
1020         }
1021
1022           /* Load the segments */
1023
1024         if (pModule->flags & NE_FFLAGS_SELFLOAD)
1025         {
1026                 int fd;
1027                 /* Handle self loading modules */
1028                 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
1029                 SELFLOADHEADER *selfloadheader;
1030                 HMODULE hselfload = GetModuleHandle("WPROCS");
1031                 WORD oldss, oldsp, saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
1032                 fprintf (stderr, "Warning:  %*.*s is a self-loading module\n"
1033                                 "Support for self-loading modules is very experimental\n",
1034                 *((BYTE*)pModule + pModule->name_table),
1035                 *((BYTE*)pModule + pModule->name_table),
1036                 (char *)pModule + pModule->name_table + 1);
1037                 NE_LoadSegment( hModule, 1 );
1038                 selfloadheader = (SELFLOADHEADER *)
1039                         PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
1040                 selfloadheader->EntryAddrProc = 
1041                                            MODULE_GetEntryPoint(hselfload,27);
1042                 selfloadheader->MyAlloc  = MODULE_GetEntryPoint(hselfload,28);
1043                 selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle("KERNEL"),403);
1044                 pModule->self_loading_sel = GlobalHandleToSel(
1045                                         GLOBAL_Alloc (GMEM_ZEROINIT,
1046                                         0xFF00, hModule, FALSE, FALSE, FALSE)
1047                                         );
1048                 oldss = IF1632_Saved16_ss;
1049                 oldsp = IF1632_Saved16_sp;
1050                 IF1632_Saved16_ss = pModule->self_loading_sel;
1051                 IF1632_Saved16_sp = 0xFF00;
1052                 if (!IF1632_Stack32_base) {
1053                   STACK32FRAME* frame32;
1054                   char *stack32Top;
1055                   /* Setup an initial 32 bit stack frame */
1056                   hInitialStack32 =  GLOBAL_Alloc( GMEM_FIXED, 0x10000,
1057                                                   hModule, FALSE, FALSE, 
1058                                                   FALSE );
1059
1060                   /* Create the 32-bit stack frame */
1061                   
1062                   *(DWORD *)GlobalLock16(hInitialStack32) = 0xDEADBEEF;
1063                   stack32Top = (char*)GlobalLock16(hInitialStack32) + 
1064                     0x10000;
1065                   frame32 = (STACK32FRAME *)stack32Top - 1;
1066                   frame32->saved_esp = (DWORD)stack32Top;
1067                   frame32->edi = 0;
1068                   frame32->esi = 0;
1069                   frame32->edx = 0;
1070                   frame32->ecx = 0;
1071                   frame32->ebx = 0;
1072                   frame32->ebp = 0;
1073                   frame32->retaddr = 0;
1074                   frame32->codeselector = WINE_CODE_SELECTOR;
1075                   /* pTask->esp = (DWORD)frame32; */
1076                   IF1632_Stack32_base = WIN16_GlobalLock16(hInitialStack32);
1077
1078                 }
1079                 /* FIXME: we probably need a DOS handle here */
1080                 fd = MODULE_OpenFile( hModule );
1081                 CallTo16_word_ww (selfloadheader->BootApp,
1082                         pModule->self_loading_sel, hModule, fd);
1083                 /* some BootApp procs overwrite the selector of dgroup */
1084                 pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
1085                 IF1632_Saved16_ss = oldss;
1086                 IF1632_Saved16_sp = oldsp;
1087                 for (i = 2; i <= pModule->seg_count; i++) NE_LoadSegment( hModule, i );
1088                 if (hInitialStack32){
1089                   GlobalFree16(hInitialStack32);
1090                   IF1632_Stack32_base = hInitialStack32 = 0;
1091                 }
1092         } 
1093         else
1094         {
1095             for (i = 1; i <= pModule->seg_count; i++)
1096                 NE_LoadSegment( hModule, i );
1097         }
1098
1099           /* Fixup the functions prologs */
1100
1101         NE_FixupPrologs( pModule );
1102
1103           /* Make sure the usage count is 1 on the first loading of  */
1104           /* the module, even if it contains circular DLL references */
1105
1106         pModule->count = 1;
1107     }
1108     else
1109     {
1110         pModule = MODULE_GetPtr( hModule );
1111         hPrevInstance = MODULE_GetInstance( hModule );
1112         hInstance = MODULE_CreateInstance( hModule, params );
1113         if (hInstance != hPrevInstance)  /* not a library */
1114             NE_LoadSegment( hModule, pModule->dgroup );
1115         pModule->count++;
1116     }
1117 #else
1118     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(NE_MODULE));
1119     pModule = (NE_MODULE *)GlobalLock16( hModule );
1120     pModule->count = 1;
1121     pModule->magic = NE_SIGNATURE;
1122     pModule->self = hModule;
1123     hPrevInstance = 0;
1124     hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
1125 #endif /* WINELIB */
1126
1127       /* Create a task for this instance */
1128
1129     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
1130     {
1131         TASK_CreateTask( hModule, hInstance, hPrevInstance,
1132                          params->hEnvironment,
1133                          (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
1134                          *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1) );
1135     }
1136
1137     return hInstance;
1138 }
1139
1140
1141 /**********************************************************************
1142  *          FreeModule    (KERNEL.46)
1143  */
1144 BOOL FreeModule( HANDLE hModule )
1145 {
1146     NE_MODULE *pModule;
1147
1148     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1149     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
1150
1151     dprintf_module( stddeb, "FreeModule: %s count %d\n", 
1152                     MODULE_GetModuleName(hModule), pModule->count );
1153     if (--pModule->count == 0) MODULE_FreeModule( hModule );
1154     return TRUE;
1155 }
1156
1157
1158 /**********************************************************************
1159  *          GetModuleHandle    (KERNEL.47)
1160  */
1161 HMODULE WIN16_GetModuleHandle( SEGPTR name )
1162 {
1163     if (HIWORD(name) == 0) return GetExePtr( (HANDLE)name );
1164     return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
1165 }
1166
1167 HMODULE GetModuleHandle( LPCSTR name )
1168 {
1169     return MODULE_FindModule( name );
1170 }
1171
1172
1173 /**********************************************************************
1174  *          GetModuleUsage    (KERNEL.48)
1175  */
1176 int GetModuleUsage( HANDLE hModule )
1177 {
1178     NE_MODULE *pModule;
1179
1180     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1181     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
1182     dprintf_module( stddeb, "GetModuleUsage(%04x): returning %d\n",
1183                     hModule, pModule->count );
1184     return pModule->count;
1185 }
1186
1187
1188 /**********************************************************************
1189  *          GetModuleFileName    (KERNEL.49)
1190  */
1191 int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
1192 {
1193     NE_MODULE *pModule;
1194
1195     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1196     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
1197     lstrcpyn( lpFileName, NE_MODULE_NAME(pModule), nSize );
1198     dprintf_module( stddeb, "GetModuleFilename: %s\n", lpFileName );
1199     return strlen(lpFileName);
1200 }
1201
1202
1203 /***********************************************************************
1204  *           LoadLibrary   (KERNEL.95)
1205  */
1206 HANDLE LoadLibrary( LPCSTR libname )
1207 {
1208 #ifdef WINELIB
1209     dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
1210     WINELIB_UNIMP("LoadLibrary()");
1211     return (HANDLE)0;
1212 #else
1213     HANDLE handle;
1214
1215     dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
1216
1217     /* This does not increment the module reference count, and will
1218      * therefore cause crashes on FreeLibrary calls.
1219     if ((handle = MODULE_FindModule( libname )) != 0) return handle;
1220      */
1221     handle = LoadModule( libname, (LPVOID)-1 );
1222     if (handle == (HANDLE)2)  /* file not found */
1223     {
1224         char buffer[256];
1225         lstrcpyn( buffer, libname, 252 );
1226         strcat( buffer, ".dll" );
1227         handle = LoadModule( buffer, (LPVOID)-1 );
1228     }
1229     if (handle >= (HANDLE)32) NE_InitializeDLLs( GetExePtr(handle) );
1230     return handle;
1231 #endif
1232 }
1233
1234
1235 /***********************************************************************
1236  *           FreeLibrary   (KERNEL.96)
1237  */
1238 void FreeLibrary( HANDLE handle )
1239 {
1240     dprintf_module( stddeb,"FreeLibrary: %04x\n", handle );
1241     FreeModule( handle );
1242 }
1243
1244
1245 /***********************************************************************
1246  *           WinExec   (KERNEL.166)
1247  */
1248 HANDLE WinExec( LPSTR lpCmdLine, WORD nCmdShow )
1249 {
1250     LOADPARAMS params;
1251     HGLOBAL16 cmdShowHandle, cmdLineHandle;
1252     HANDLE handle;
1253     WORD *cmdShowPtr;
1254     char *p, *cmdline, filename[256];
1255     static int use_load_module = 1;
1256
1257     if (!(cmdShowHandle = GlobalAlloc16( 0, 2 * sizeof(WORD) ))) return 0;
1258     if (!(cmdLineHandle = GlobalAlloc16( 0, 256 ))) return 0;
1259
1260       /* Store nCmdShow */
1261
1262     cmdShowPtr = (WORD *)GlobalLock16( cmdShowHandle );
1263     cmdShowPtr[0] = 2;
1264     cmdShowPtr[1] = nCmdShow;
1265
1266       /* Build the filename and command-line */
1267
1268     cmdline = (char *)GlobalLock16( cmdLineHandle );
1269     lstrcpyn( filename, lpCmdLine, sizeof(filename) - 4 /* for extension */ );
1270     for (p = filename; *p && (*p != ' ') && (*p != '\t'); p++);
1271     if (*p) lstrcpyn( cmdline, p + 1, 128 );
1272     else cmdline[0] = '\0';
1273     *p = '\0';
1274
1275       /* Now load the executable file */
1276
1277     if (use_load_module)
1278     {
1279 #ifdef WINELIB
1280         /* WINELIB: Use LoadModule() only for the program itself */
1281         use_load_module = 0;
1282         params.hEnvironment = (HANDLE)GetDOSEnvironment();
1283 #else
1284         params.hEnvironment = (HANDLE)SELECTOROF( GetDOSEnvironment() );
1285 #endif  /* WINELIB */
1286         params.cmdLine  = (SEGPTR)WIN16_GlobalLock16( cmdLineHandle );
1287         params.showCmd  = (SEGPTR)WIN16_GlobalLock16( cmdShowHandle );
1288         params.reserved = 0;
1289         handle = LoadModule( filename, &params );
1290         if (handle == 2)  /* file not found */
1291         {
1292             /* Check that the original file name did not have a suffix */
1293             p = strrchr(filename, '.');
1294             if (!p || (strchr(p, '/') && strchr(p, '\\')))
1295             {
1296                 p = filename + strlen(filename);
1297                 strcpy( p, ".exe" );
1298                 handle = LoadModule( filename, &params );
1299                 *p = '\0';  /* Remove extension */
1300             }
1301         }
1302     }
1303     else handle = 2;
1304
1305     if (handle < 32)
1306     {
1307         /* Try to start it as a unix program */
1308         if (!fork())
1309         {
1310             /* Child process */
1311             const char *unixfilename;
1312             const char *argv[256], **argptr;
1313             int iconic = (nCmdShow == SW_SHOWMINIMIZED ||
1314                           nCmdShow == SW_SHOWMINNOACTIVE);
1315
1316             /* get unixfilename */
1317             if (strchr(filename, '/') ||
1318                 strchr(filename, ':') ||
1319                 strchr(filename, '\\'))
1320                 unixfilename = DOSFS_GetUnixFileName(filename, 1);
1321             else unixfilename = filename;
1322
1323             if (unixfilename)
1324             {
1325                 /* build argv */
1326                 argptr = argv;
1327                 if (iconic) *argptr++ = "-iconic";
1328                 *argptr++ = unixfilename;
1329                 p = cmdline;
1330                 while (1)
1331                 {
1332                     while (*p && (*p == ' ' || *p == '\t')) *p++ = '\0';
1333                     if (!*p) break;
1334                     *argptr++ = p;
1335                     while (*p && *p != ' ' && *p != '\t') p++;
1336                 }
1337                 *argptr++ = 0;
1338
1339                 /* Execute */
1340                 execvp(argv[0], (char**)argv);
1341             }
1342
1343             /* Failed ! */
1344 #ifdef WINELIB
1345             /* build argv */
1346             argptr = argv;
1347             *argptr++ = "wine";
1348             if (iconic) *argptr++ = "-iconic";
1349             *argptr++ = lpCmdLine;
1350             *argptr++ = 0;
1351
1352             /* Execute */
1353             execvp(argv[0] , (char**)argv);
1354
1355             /* Failed ! */
1356             fprintf(stderr, "WinExec: can't exec 'wine %s'\n", lpCmdLine);
1357 #endif
1358             exit(1);
1359         }
1360     }
1361
1362     GlobalFree16( cmdShowHandle );
1363     GlobalFree16( cmdLineHandle );
1364
1365 #if 0
1366     if (handle < (HANDLE)32)    /* Error? */
1367         return handle;
1368     
1369 /* FIXME: Yield never returns! 
1370    We may want to run more applications or start the debugger
1371    before calling Yield. If we don't Yield will be called immdiately
1372    after returning.  Why is it needed for Word anyway? */
1373     Yield();    /* program is executed immediately ....needed for word */
1374
1375 #endif
1376     return handle;
1377 }
1378
1379
1380 /***********************************************************************
1381  *           GetProcAddress   (KERNEL.50)
1382  */
1383 FARPROC GetProcAddress( HANDLE hModule, SEGPTR name )
1384 {
1385     WORD ordinal;
1386     SEGPTR ret;
1387
1388     if (!hModule) hModule = GetCurrentTask();
1389     hModule = GetExePtr( hModule );
1390
1391     if (HIWORD(name) != 0)
1392     {
1393         ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1394         dprintf_module( stddeb, "GetProcAddress: %04x '%s'\n",
1395                         hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1396     }
1397     else
1398     {
1399         ordinal = LOWORD(name);
1400         dprintf_module( stddeb, "GetProcAddress: %04x %04x\n",
1401                         hModule, ordinal );
1402     }
1403     if (!ordinal) return (FARPROC)0;
1404
1405     ret = MODULE_GetEntryPoint( hModule, ordinal );
1406
1407     dprintf_module( stddeb, "GetProcAddress: returning %08lx\n", (DWORD)ret );
1408     return (FARPROC)ret;
1409 }
1410
1411
1412 /**********************************************************************
1413  *          GetExpWinVer    (KERNEL.167)
1414  */
1415 WORD GetExpWinVer( HMODULE hModule )
1416 {
1417     NE_MODULE *pModule = MODULE_GetPtr( hModule );
1418     return pModule ? pModule->expected_version : 0;
1419 }
1420
1421
1422 /**********************************************************************
1423  *          ModuleFirst    (TOOLHELP.59)
1424  */
1425 BOOL ModuleFirst( MODULEENTRY *lpme )
1426 {
1427     lpme->wNext = hFirstModule;
1428     return ModuleNext( lpme );
1429 }
1430
1431
1432 /**********************************************************************
1433  *          ModuleNext    (TOOLHELP.60)
1434  */
1435 BOOL ModuleNext( MODULEENTRY *lpme )
1436 {
1437     NE_MODULE *pModule;
1438
1439     if (!lpme->wNext) return FALSE;
1440     if (!(pModule = MODULE_GetPtr( lpme->wNext ))) return FALSE;
1441     strncpy( lpme->szModule, (char *)pModule + pModule->name_table,
1442              MAX_MODULE_NAME );
1443     lpme->szModule[MAX_MODULE_NAME] = '\0';
1444     lpme->hModule = lpme->wNext;
1445     lpme->wcUsage = pModule->count;
1446     strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
1447     lpme->szExePath[MAX_PATH] = '\0';
1448     lpme->wNext = pModule->next;
1449     return TRUE;
1450 }
1451
1452
1453 /**********************************************************************
1454  *          ModuleFindName    (TOOLHELP.61)
1455  */
1456 BOOL ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1457 {
1458     lpme->wNext = GetModuleHandle( name );
1459     return ModuleNext( lpme );
1460 }
1461
1462
1463 /**********************************************************************
1464  *          ModuleFindHandle    (TOOLHELP.62)
1465  */
1466 BOOL ModuleFindHandle( MODULEENTRY *lpme, HMODULE hModule )
1467 {
1468     hModule = GetExePtr( hModule );  /* In case we were passed an hInstance */
1469     lpme->wNext = hModule;
1470     return ModuleNext( lpme );
1471 }