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