Release 980329
[wine] / loader / module.c
1 /*
2  * Modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include "windows.h"
15 #include "class.h"
16 #include "file.h"
17 #include "global.h"
18 #include "heap.h"
19 #include "module.h"
20 #include "neexe.h"
21 #include "process.h"
22 #include "thread.h"
23 #include "resource.h"
24 #include "selectors.h"
25 #include "stackframe.h"
26 #include "task.h"
27 #include "toolhelp.h"
28 #include "debug.h"
29 #include "callback.h"
30
31 extern HINSTANCE16 PE_LoadModule( HFILE32 hf, OFSTRUCT *ofs, LOADPARAMS* params );
32
33 extern BOOL32 THREAD_InitDone;
34
35 static HMODULE16 hFirstModule = 0;
36 static HMODULE16 hCachedModule = 0;  /* Module cached by MODULE_OpenFile */
37
38 static HMODULE32 MODULE_LoadModule(LPCSTR name,BOOL32 force) { return 0; }
39 HMODULE32 (*fnBUILTIN_LoadModule)(LPCSTR name,BOOL32 force) = MODULE_LoadModule;
40
41
42 /***********************************************************************
43  *           MODULE_GetPtr
44  */
45 NE_MODULE *MODULE_GetPtr( HMODULE32 hModule )
46 {
47     HMODULE16 hnd =MODULE_HANDLEtoHMODULE16(hModule);
48
49     if (!hnd)
50         return NULL;
51     return (NE_MODULE*)GlobalLock16(hnd);
52 }
53
54 /***********************************************************************
55  *           MODULE_HANDLEtoHMODULE16
56  */
57 HMODULE16
58 MODULE_HANDLEtoHMODULE16(HANDLE32 handle) {
59     NE_MODULE   *pModule;
60
61     if (HIWORD(handle))
62     {
63         /* this is a HMODULE32 */
64
65         /* walk the list looking for the correct startaddress */
66         pModule = (NE_MODULE *)GlobalLock16( hFirstModule );
67         while (pModule)
68         {
69             if (pModule->module32 == handle) return pModule->self;
70             pModule = (NE_MODULE*)GlobalLock16(pModule->next);
71         }
72         return 0;
73     }
74     return GetExePtr(handle);
75 }
76
77 /***********************************************************************
78  *           MODULE_HANDLEtoHMODULE32
79  * return HMODULE32, if possible, HMODULE16 otherwise
80  */
81 HMODULE32
82 MODULE_HANDLEtoHMODULE32(HANDLE32 handle) {
83     NE_MODULE *pModule;
84
85     if (HIWORD(handle))
86         return (HMODULE32)handle;
87     else {
88         handle = GetExePtr(handle);
89         if (!handle)
90             return 0;
91         pModule = (NE_MODULE *)GlobalLock16( handle );
92         if (!pModule)
93             return 0;
94         
95         if (pModule->module32) return pModule->module32;
96         return handle;
97     }
98 }
99
100 /***********************************************************************
101  *           MODULE_DumpModule
102  */
103 void MODULE_DumpModule( HMODULE32 hModule )
104 {
105     int i, ordinal;
106     SEGTABLEENTRY *pSeg;
107     BYTE *pstr;
108     WORD *pword;
109     NE_MODULE *pModule;
110
111     if (!(pModule = MODULE_GetPtr( hModule )))
112     {
113         fprintf( stderr, "**** %04x is not a module handle\n", hModule );
114         return;
115     }
116
117       /* Dump the module info */
118     DUMP( "---\n" );
119     DUMP( "Module %04x:\n", hModule );
120     DUMP( "count=%d flags=%04x heap=%d stack=%d\n",
121           pModule->count, pModule->flags,
122           pModule->heap_size, pModule->stack_size );
123     DUMP( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
124           pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
125           pModule->seg_count, pModule->modref_count );
126     DUMP( "os_flags=%d swap_area=%d version=%04x\n",
127           pModule->os_flags, pModule->min_swap_area,
128           pModule->expected_version );
129     if (pModule->flags & NE_FFLAGS_WIN32)
130         DUMP( "PE module=%08x\n", pModule->module32 );
131
132       /* Dump the file info */
133     DUMP( "---\n" );
134     DUMP( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
135
136       /* Dump the segment table */
137     DUMP( "---\n" );
138     DUMP( "Segment table:\n" );
139     pSeg = NE_SEG_TABLE( pModule );
140     for (i = 0; i < pModule->seg_count; i++, pSeg++)
141         DUMP( "%02x: pos=%d size=%d flags=%04x minsize=%d sel=%04x\n",
142               i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
143               pSeg->minsize, pSeg->selector );
144
145       /* Dump the resource table */
146     DUMP( "---\n" );
147     DUMP( "Resource table:\n" );
148     if (pModule->res_table)
149     {
150         pword = (WORD *)((BYTE *)pModule + pModule->res_table);
151         DUMP( "Alignment: %d\n", *pword++ );
152         while (*pword)
153         {
154             struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
155             struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
156             DUMP( "id=%04x count=%d\n", ptr->type_id, ptr->count );
157             for (i = 0; i < ptr->count; i++, pname++)
158                 DUMP( "offset=%d len=%d id=%04x\n",
159                       pname->offset, pname->length, pname->id );
160             pword = (WORD *)pname;
161         }
162     }
163     else DUMP( "None\n" );
164
165       /* Dump the resident name table */
166     DUMP( "---\n" );
167     DUMP( "Resident-name table:\n" );
168     pstr = (char *)pModule + pModule->name_table;
169     while (*pstr)
170     {
171         DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
172               *(WORD *)(pstr + *pstr + 1) );
173         pstr += *pstr + 1 + sizeof(WORD);
174     }
175
176       /* Dump the module reference table */
177     DUMP( "---\n" );
178     DUMP( "Module ref table:\n" );
179     if (pModule->modref_table)
180     {
181         pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
182         for (i = 0; i < pModule->modref_count; i++, pword++)
183         {
184             DUMP( "%d: %04x -> '%s'\n", i, *pword,
185                     MODULE_GetModuleName(*pword));
186         }
187     }
188     else DUMP( "None\n" );
189
190       /* Dump the entry table */
191     DUMP( "---\n" );
192     DUMP( "Entry table:\n" );
193     pstr = (char *)pModule + pModule->entry_table;
194     ordinal = 1;
195     while (*pstr)
196     {
197         DUMP( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
198         if (!pstr[1])
199         {
200             ordinal += *pstr;
201             pstr += 2;
202         }
203         else if ((BYTE)pstr[1] == 0xff)  /* moveable */
204         {
205             struct entry_tab_movable_s *pe = (struct entry_tab_movable_s*)(pstr+2);
206             for (i = 0; i < *pstr; i++, pe++)
207                 DUMP( "%d: %02x:%04x (moveable)\n",
208                       ordinal++, pe->seg_number, pe->offset );
209             pstr = (char *)pe;
210         }
211         else  /* fixed */
212         {
213             struct entry_tab_fixed_s *pe = (struct entry_tab_fixed_s*)(pstr+2);
214             for (i = 0; i < *pstr; i++, pe++)
215                 DUMP( "%d: %04x (fixed)\n",
216                       ordinal++, pe->offset[0] + (pe->offset[1] << 8) );
217             pstr = (char *)pe;
218         }
219     }
220
221     /* Dump the non-resident names table */
222     DUMP( "---\n" );
223     DUMP( "Non-resident names table:\n" );
224     if (pModule->nrname_handle)
225     {
226         pstr = (char *)GlobalLock16( pModule->nrname_handle );
227         while (*pstr)
228         {
229             DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
230                    *(WORD *)(pstr + *pstr + 1) );
231             pstr += *pstr + 1 + sizeof(WORD);
232         }
233     }
234     DUMP( "\n" );
235 }
236
237
238 /***********************************************************************
239  *           MODULE_WalkModules
240  *
241  * Walk the module list and print the modules.
242  */
243 void MODULE_WalkModules(void)
244 {
245     HMODULE16 hModule = hFirstModule;
246     fprintf( stderr, "Module Flags Name\n" );
247     while (hModule)
248     {
249         NE_MODULE *pModule = MODULE_GetPtr( hModule );
250         if (!pModule)
251         {
252             fprintf( stderr, "**** Bad module %04x in list\n", hModule );
253             return;
254         }
255         fprintf( stderr, " %04x  %04x  %.*s\n", hModule, pModule->flags,
256                  *((char *)pModule + pModule->name_table),
257                  (char *)pModule + pModule->name_table + 1 );
258         hModule = pModule->next;
259     }
260 }
261
262
263 /***********************************************************************
264  *           MODULE_OpenFile
265  */
266 int MODULE_OpenFile( HMODULE32 hModule )
267 {
268     NE_MODULE *pModule;
269     DOS_FULL_NAME full_name;
270     char *name;
271
272     static int cachedfd = -1;
273
274     hModule = MODULE_HANDLEtoHMODULE16(hModule);
275     TRACE(module, "(%04x) cache: mod=%04x fd=%d\n",
276                     hModule, hCachedModule, cachedfd );
277     if (!(pModule = MODULE_GetPtr( hModule ))) return -1;
278     if (hCachedModule == hModule) return cachedfd;
279     close( cachedfd );
280     hCachedModule = hModule;
281     name = NE_MODULE_NAME( pModule );
282     if (!DOSFS_GetFullName( name, TRUE, &full_name ) ||
283         (cachedfd = open( full_name.long_name, O_RDONLY )) == -1)
284         fprintf( stderr, "MODULE_OpenFile: can't open file '%s' for module %04x\n",
285                  name, hModule );
286     TRACE(module, "opened '%s' -> %d\n",
287                     name, cachedfd );
288     return cachedfd;
289 }
290
291
292 /***********************************************************************
293  *           MODULE_Ne2MemFlags
294  *
295  * This function translates NE segment flags to GlobalAlloc flags
296  */
297 static WORD MODULE_Ne2MemFlags(WORD flags)
298
299     WORD memflags = 0;
300 #if 0
301     if (flags & NE_SEGFLAGS_DISCARDABLE) 
302       memflags |= GMEM_DISCARDABLE;
303     if (flags & NE_SEGFLAGS_MOVEABLE || 
304         ( ! (flags & NE_SEGFLAGS_DATA) &&
305           ! (flags & NE_SEGFLAGS_LOADED) &&
306           ! (flags & NE_SEGFLAGS_ALLOCATED)
307          )
308         )
309       memflags |= GMEM_MOVEABLE;
310     memflags |= GMEM_ZEROINIT;
311 #else
312     memflags = GMEM_ZEROINIT | GMEM_FIXED;
313     return memflags;
314 #endif
315 }
316
317 /***********************************************************************
318  *           MODULE_AllocateSegment (WPROCS.26)
319  */
320
321 DWORD WINAPI MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
322 {
323     WORD size = wSize << wElem;
324     HANDLE16 hMem = GlobalAlloc16( MODULE_Ne2MemFlags(wFlags), size);
325     return MAKELONG( hMem, GlobalHandleToSel(hMem) );
326 }
327
328 /***********************************************************************
329  *           MODULE_CreateSegments
330  */
331 static BOOL32 MODULE_CreateSegments( HMODULE32 hModule )
332 {
333     SEGTABLEENTRY *pSegment;
334     NE_MODULE *pModule;
335     int i, minsize;
336
337     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
338     pSegment = NE_SEG_TABLE( pModule );
339     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
340     {
341         minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
342         if (i == pModule->ss) minsize += pModule->stack_size;
343         /* The DGROUP is allocated by MODULE_CreateInstance */
344         if (i == pModule->dgroup) continue;
345         pSegment->selector = GLOBAL_Alloc( MODULE_Ne2MemFlags(pSegment->flags),
346                                       minsize, hModule,
347                                       !(pSegment->flags & NE_SEGFLAGS_DATA),
348                                       FALSE,
349                             FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
350         if (!pSegment->selector) return FALSE;
351     }
352
353     pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
354                             (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
355     return TRUE;
356 }
357
358
359 /***********************************************************************
360  *           MODULE_GetInstance
361  */
362 HINSTANCE16 MODULE_GetInstance( HMODULE32 hModule )
363 {
364     SEGTABLEENTRY *pSegment;
365     NE_MODULE *pModule;
366     
367     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
368     if (pModule->dgroup == 0) return hModule;
369
370     pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
371     
372     return pSegment->selector;
373 }
374
375
376 /***********************************************************************
377  *           MODULE_CreateInstance
378  */
379 HINSTANCE16 MODULE_CreateInstance( HMODULE16 hModule, LOADPARAMS *params )
380 {
381     SEGTABLEENTRY *pSegment;
382     NE_MODULE *pModule;
383     int minsize;
384     HINSTANCE16 hNewInstance, hPrevInstance;
385
386     if (!(pModule = MODULE_GetPtr( 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_CreateDummyModule
412  *
413  * Create a dummy NE module for Win32 or Winelib.
414  */
415 HMODULE32 MODULE_CreateDummyModule( const OFSTRUCT *ofs )
416 {
417     HMODULE32 hModule;
418     NE_MODULE *pModule;
419     SEGTABLEENTRY *pSegment;
420     char *pStr,*s;
421     int len;
422     const char* basename;
423
424     INT32 of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
425                     + strlen(ofs->szPathName) + 1;
426     INT32 size = sizeof(NE_MODULE) +
427                  /* loaded file info */
428                  of_size +
429                  /* segment table: DS,CS */
430                  2 * sizeof(SEGTABLEENTRY) +
431                  /* name table */
432                  9 +
433                  /* several empty tables */
434                  8;
435
436     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
437     if (!hModule) return (HMODULE32)11;  /* invalid exe */
438
439     FarSetOwner( hModule, hModule );
440     pModule = (NE_MODULE *)GlobalLock16( hModule );
441
442     /* Set all used entries */
443     pModule->magic            = IMAGE_OS2_SIGNATURE;
444     pModule->count            = 1;
445     pModule->next             = 0;
446     pModule->flags            = 0;
447     pModule->dgroup           = 1;
448     pModule->ss               = 1;
449     pModule->cs               = 2;
450     pModule->heap_size        = 0xe000;
451     pModule->stack_size       = 0x1000;
452     pModule->seg_count        = 2;
453     pModule->modref_count     = 0;
454     pModule->nrname_size      = 0;
455     pModule->fileinfo         = sizeof(NE_MODULE);
456     pModule->os_flags         = NE_OSFLAGS_WINDOWS;
457     pModule->expected_version = 0x030a;
458     pModule->self             = hModule;
459
460     /* Set loaded file information */
461     memcpy( pModule + 1, ofs, of_size );
462     ((OFSTRUCT *)(pModule+1))->cBytes = of_size - 1;
463
464     pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + of_size);
465     pModule->seg_table = pModule->dgroup_entry = (int)pSegment - (int)pModule;
466     /* Data segment */
467     pSegment->size    = 0;
468     pSegment->flags   = NE_SEGFLAGS_DATA;
469     pSegment->minsize = 0x1000;
470     pSegment++;
471     /* Code segment */
472     pSegment->flags   = 0;
473     pSegment++;
474
475     /* Module name */
476     pStr = (char *)pSegment;
477     pModule->name_table = (int)pStr - (int)pModule;
478     basename = strrchr(ofs->szPathName,'\\');
479     if (!basename) basename = ofs->szPathName;
480     else basename++;
481     len = strlen(basename);
482     if ((s = strchr(basename,'.'))) len = s - basename;
483     if (len > 8) len = 8;
484     *pStr = len;
485     strncpy( pStr+1, basename, len );
486     if (len < 8) pStr[len+1] = 0;
487     pStr += 9;
488
489     /* All tables zero terminated */
490     pModule->res_table = pModule->import_table = pModule->entry_table =
491                 (int)pStr - (int)pModule;
492
493     MODULE_RegisterModule( pModule );
494     return hModule;
495 }
496
497
498 /***********************************************************************
499  *           MODULE_LoadExeHeader
500  */
501 static HMODULE32 MODULE_LoadExeHeader( HFILE32 hFile, OFSTRUCT *ofs )
502 {
503     IMAGE_DOS_HEADER mz_header;
504     IMAGE_OS2_HEADER ne_header;
505     int size;
506     HMODULE32 hModule;
507     NE_MODULE *pModule;
508     BYTE *pData;
509     char *buffer, *fastload = NULL;
510     int fastload_offset = 0, fastload_length = 0;
511
512   /* Read a block from either the file or the fast-load area. */
513 #define READ(offset,size,buffer) \
514        ((fastload && ((offset) >= fastload_offset) && \
515          ((offset)+(size) <= fastload_offset+fastload_length)) ? \
516         (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
517         (_llseek32( hFile, (offset), SEEK_SET), \
518          _lread32( hFile, (buffer), (size) ) == (size)))
519
520     _llseek32( hFile, 0, SEEK_SET );
521     if ((_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
522         (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
523         return (HMODULE32)11;  /* invalid exe */
524
525     _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
526     if (_lread32( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
527         return (HMODULE32)11;  /* invalid exe */
528
529     if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE32)21;  /* win32 exe */
530     if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE32)11;  /* invalid exe */
531
532     if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
533       fprintf(stderr, "Sorry, this is an OS/2 linear executable (LX) file !\n");
534       return (HMODULE32)12;
535     }
536     /* We now have a valid NE header */
537
538     size = sizeof(NE_MODULE) +
539              /* loaded file info */
540            sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1+
541              /* segment table */
542            ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
543              /* resource table */
544            ne_header.rname_tab_offset - ne_header.resource_tab_offset +
545              /* resident names table */
546            ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
547              /* module ref table */
548            ne_header.n_mod_ref_tab * sizeof(WORD) + 
549              /* imported names table */
550            ne_header.entry_tab_offset - ne_header.iname_tab_offset +
551              /* entry table length */
552            ne_header.entry_tab_length;
553
554     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
555     if (!hModule) return (HMODULE32)11;  /* invalid exe */
556     FarSetOwner( hModule, hModule );
557     pModule = (NE_MODULE *)GlobalLock16( hModule );
558     memcpy( pModule, &ne_header, sizeof(ne_header) );
559     pModule->count = 0;
560     pModule->module32 = 0;
561     pModule->self = hModule;
562     pModule->self_loading_sel = 0;
563     pData = (BYTE *)(pModule + 1);
564
565     /* Clear internal Wine flags in case they are set in the EXE file */
566
567     pModule->flags &= ~(NE_FFLAGS_BUILTIN|NE_FFLAGS_WIN32|NE_FFLAGS_IMPLICIT);
568
569     /* Read the fast-load area */
570
571     if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
572     {
573         fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
574         fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
575         TRACE(module, "Using fast-load area offset=%x len=%d\n",
576                         fastload_offset, fastload_length );
577         if ((fastload = HeapAlloc( SystemHeap, 0, fastload_length )) != NULL)
578         {
579             _llseek32( hFile, fastload_offset, SEEK_SET);
580             if (_lread32(hFile, fastload, fastload_length) != fastload_length)
581             {
582                 HeapFree( SystemHeap, 0, fastload );
583                 fprintf(stderr, "Error reading fast-load area !\n");
584                 fastload = NULL;
585             }
586         }
587     }
588
589     /* Store the filename information */
590
591     pModule->fileinfo = (int)pData - (int)pModule;
592     size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
593     memcpy( pData, ofs, size );
594     ((OFSTRUCT *)pData)->cBytes = size - 1;
595     pData += size;
596
597     /* Get the segment table */
598
599     pModule->seg_table = (int)pData - (int)pModule;
600     buffer = HeapAlloc( SystemHeap, 0, ne_header.n_segment_tab *
601                                       sizeof(struct ne_segment_table_entry_s));
602     if (buffer)
603     {
604         int i;
605         struct ne_segment_table_entry_s *pSeg;
606
607         if (!READ( mz_header.e_lfanew + ne_header.segment_tab_offset,
608              ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
609              buffer ))
610         {
611             HeapFree( SystemHeap, 0, buffer );
612             if (fastload) HeapFree( SystemHeap, 0, fastload );
613             GlobalFree16( hModule );
614             return (HMODULE32)11;  /* invalid exe */
615         }
616         pSeg = (struct ne_segment_table_entry_s *)buffer;
617         for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
618         {
619             memcpy( pData, pSeg, sizeof(*pSeg) );
620             pData += sizeof(SEGTABLEENTRY);
621         }
622         HeapFree( SystemHeap, 0, buffer );
623     }
624     else
625     {
626         if (fastload) HeapFree( SystemHeap, 0, fastload );
627         GlobalFree16( hModule );
628         return (HMODULE32)11;  /* invalid exe */
629     }
630
631     /* Get the resource table */
632
633     if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
634     {
635         pModule->res_table = (int)pData - (int)pModule;
636         if (!READ(mz_header.e_lfanew + ne_header.resource_tab_offset,
637                   ne_header.rname_tab_offset - ne_header.resource_tab_offset,
638                   pData )) return (HMODULE32)11;  /* invalid exe */
639         pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
640         NE_InitResourceHandler( hModule );
641     }
642     else pModule->res_table = 0;  /* No resource table */
643
644     /* Get the resident names table */
645
646     pModule->name_table = (int)pData - (int)pModule;
647     if (!READ( mz_header.e_lfanew + ne_header.rname_tab_offset,
648                ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
649                pData ))
650     {
651         if (fastload) HeapFree( SystemHeap, 0, fastload );
652         GlobalFree16( hModule );
653         return (HMODULE32)11;  /* invalid exe */
654     }
655     pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
656
657     /* Get the module references table */
658
659     if (ne_header.n_mod_ref_tab > 0)
660     {
661         pModule->modref_table = (int)pData - (int)pModule;
662         if (!READ( mz_header.e_lfanew + ne_header.moduleref_tab_offset,
663                   ne_header.n_mod_ref_tab * sizeof(WORD),
664                   pData ))
665         {
666             if (fastload) HeapFree( SystemHeap, 0, fastload );
667             GlobalFree16( hModule );
668             return (HMODULE32)11;  /* invalid exe */
669         }
670         pData += ne_header.n_mod_ref_tab * sizeof(WORD);
671     }
672     else pModule->modref_table = 0;  /* No module references */
673
674     /* Get the imported names table */
675
676     pModule->import_table = (int)pData - (int)pModule;
677     if (!READ( mz_header.e_lfanew + ne_header.iname_tab_offset, 
678                ne_header.entry_tab_offset - ne_header.iname_tab_offset,
679                pData ))
680     {
681         if (fastload) HeapFree( SystemHeap, 0, fastload );
682         GlobalFree16( hModule );
683         return (HMODULE32)11;  /* invalid exe */
684     }
685     pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
686
687     /* Get the entry table */
688
689     pModule->entry_table = (int)pData - (int)pModule;
690     if (!READ( mz_header.e_lfanew + ne_header.entry_tab_offset,
691                ne_header.entry_tab_length,
692                pData ))
693     {
694         if (fastload) HeapFree( SystemHeap, 0, fastload );
695         GlobalFree16( hModule );
696         return (HMODULE32)11;  /* invalid exe */
697     }
698     pData += ne_header.entry_tab_length;
699
700     /* Free the fast-load area */
701
702 #undef READ
703     if (fastload) HeapFree( SystemHeap, 0, fastload );
704
705     /* Get the non-resident names table */
706
707     if (ne_header.nrname_tab_length)
708     {
709         pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
710                                                hModule, FALSE, FALSE, FALSE );
711         if (!pModule->nrname_handle)
712         {
713             GlobalFree16( hModule );
714             return (HMODULE32)11;  /* invalid exe */
715         }
716         buffer = GlobalLock16( pModule->nrname_handle );
717         _llseek32( hFile, ne_header.nrname_tab_offset, SEEK_SET );
718         if (_lread32( hFile, buffer, ne_header.nrname_tab_length )
719               != ne_header.nrname_tab_length)
720         {
721             GlobalFree16( pModule->nrname_handle );
722             GlobalFree16( hModule );
723             return (HMODULE32)11;  /* invalid exe */
724         }
725     }
726     else pModule->nrname_handle = 0;
727
728     /* Allocate a segment for the implicitly-loaded DLLs */
729
730     if (pModule->modref_count)
731     {
732         pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
733                                     (pModule->modref_count+1)*sizeof(HMODULE32),
734                                     hModule, FALSE, FALSE, FALSE );
735         if (!pModule->dlls_to_init)
736         {
737             if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
738             GlobalFree16( hModule );
739             return (HMODULE32)11;  /* invalid exe */
740         }
741     }
742     else pModule->dlls_to_init = 0;
743
744     MODULE_RegisterModule( pModule );
745     return hModule;
746 }
747
748
749 /***********************************************************************
750  *           MODULE_GetOrdinal
751  *
752  * Lookup the ordinal for a given name.
753  */
754 WORD MODULE_GetOrdinal( HMODULE32 hModule, const char *name )
755 {
756     unsigned char buffer[256], *cpnt;
757     BYTE len;
758     NE_MODULE *pModule;
759
760     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
761
762     TRACE(module, "(%04x,'%s')\n",
763                     hModule, name );
764
765       /* First handle names of the form '#xxxx' */
766
767     if (name[0] == '#') return atoi( name + 1 );
768
769       /* Now copy and uppercase the string */
770
771     strcpy( buffer, name );
772     CharUpper32A( buffer );
773     len = strlen( buffer );
774
775       /* First search the resident names */
776
777     cpnt = (char *)pModule + pModule->name_table;
778
779       /* Skip the first entry (module name) */
780     cpnt += *cpnt + 1 + sizeof(WORD);
781     while (*cpnt)
782     {
783         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
784         {
785             TRACE(module, "  Found: ordinal=%d\n",
786                             *(WORD *)(cpnt + *cpnt + 1) );
787             return *(WORD *)(cpnt + *cpnt + 1);
788         }
789         cpnt += *cpnt + 1 + sizeof(WORD);
790     }
791
792       /* Now search the non-resident names table */
793
794     if (!pModule->nrname_handle) return 0;  /* No non-resident table */
795     cpnt = (char *)GlobalLock16( pModule->nrname_handle );
796
797       /* Skip the first entry (module description string) */
798     cpnt += *cpnt + 1 + sizeof(WORD);
799     while (*cpnt)
800     {
801         if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
802         {
803             TRACE(module, "  Found: ordinal=%d\n",
804                             *(WORD *)(cpnt + *cpnt + 1) );
805             return *(WORD *)(cpnt + *cpnt + 1);
806         }
807         cpnt += *cpnt + 1 + sizeof(WORD);
808     }
809     return 0;
810 }
811
812
813 /***********************************************************************
814  *           MODULE_GetEntryPoint
815  *
816  * Return the entry point for a given ordinal.
817  */
818 FARPROC16 MODULE_GetEntryPoint( HMODULE32 hModule, WORD ordinal )
819 {
820     NE_MODULE *pModule;
821     WORD curOrdinal = 1;
822     BYTE *p;
823     WORD sel, offset;
824
825     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
826
827     p = (BYTE *)pModule + pModule->entry_table;
828     while (*p && (curOrdinal + *p <= ordinal))
829     {
830           /* Skipping this bundle */
831         curOrdinal += *p;
832         switch(p[1])
833         {
834             case 0:    p += 2; break;  /* unused */
835             case 0xff: p += 2 + *p * 6; break;  /* moveable */
836             default:   p += 2 + *p * 3; break;  /* fixed */
837         }
838     }
839     if (!*p) return 0;
840
841     switch(p[1])
842     {
843         case 0:  /* unused */
844             return 0;
845         case 0xff:  /* moveable */
846             p += 2 + 6 * (ordinal - curOrdinal);
847             sel = p[3];
848             offset = *(WORD *)(p + 4);
849             break;
850         default:  /* fixed */
851             sel = p[1];
852             p += 2 + 3 * (ordinal - curOrdinal);
853             offset = *(WORD *)(p + 1);
854             break;
855     }
856
857     if (sel == 0xfe) sel = 0xffff;  /* constant entry */
858     else sel = (WORD)(DWORD)NE_SEG_TABLE(pModule)[sel-1].selector;
859     return (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset );
860 }
861
862
863 /***********************************************************************
864  *           EntryAddrProc   (WPROCS.27)
865  */
866 FARPROC16 WINAPI EntryAddrProc( HMODULE16 hModule, WORD ordinal )
867 {
868     return MODULE_GetEntryPoint( hModule, ordinal );
869 }
870
871
872 /***********************************************************************
873  *           MODULE_SetEntryPoint
874  *
875  * Change the value of an entry point. Use with caution!
876  * It can only change the offset value, not the selector.
877  */
878 BOOL16 MODULE_SetEntryPoint( HMODULE32 hModule, WORD ordinal, WORD offset )
879 {
880     NE_MODULE *pModule;
881     WORD curOrdinal = 1;
882     BYTE *p;
883
884     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
885
886     p = (BYTE *)pModule + pModule->entry_table;
887     while (*p && (curOrdinal + *p <= ordinal))
888     {
889           /* Skipping this bundle */
890         curOrdinal += *p;
891         switch(p[1])
892         {
893             case 0:    p += 2; break;  /* unused */
894             case 0xff: p += 2 + *p * 6; break;  /* moveable */
895             default:   p += 2 + *p * 3; break;  /* fixed */
896         }
897     }
898     if (!*p) return FALSE;
899
900     switch(p[1])
901     {
902         case 0:  /* unused */
903             return FALSE;
904         case 0xff:  /* moveable */
905             p += 2 + 6 * (ordinal - curOrdinal);
906             *(WORD *)(p + 4) = offset;
907             break;
908         default:  /* fixed */
909             p += 2 + 3 * (ordinal - curOrdinal);
910             *(WORD *)(p + 1) = offset;
911             break;
912     }
913     return TRUE;
914 }
915
916
917 /***********************************************************************
918  *           MODULE_GetWndProcEntry16  (not a Windows API function)
919  *
920  * Return an entry point from the WPROCS dll.
921  */
922 FARPROC16 MODULE_GetWndProcEntry16( LPCSTR name )
923 {
924     FARPROC16 ret = NULL;
925
926     if (__winelib)
927     {
928         /* FIXME: hack for Winelib */
929         extern LRESULT ColorDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
930         extern LRESULT FileOpenDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
931         extern LRESULT FileSaveDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
932         extern LRESULT FindTextDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
933         extern LRESULT PrintDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
934         extern LRESULT PrintSetupDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
935         extern LRESULT ReplaceTextDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
936
937         if (!strcmp(name,"ColorDlgProc"))
938             return (FARPROC16)ColorDlgProc;
939         if (!strcmp(name,"FileOpenDlgProc"))
940             return (FARPROC16)FileOpenDlgProc;
941         if (!strcmp(name,"FileSaveDlgProc"))
942             return (FARPROC16)FileSaveDlgProc;
943         if (!strcmp(name,"FindTextDlgProc"))
944             return (FARPROC16)FindTextDlgProc;
945         if (!strcmp(name,"PrintDlgProc"))
946             return (FARPROC16)PrintDlgProc;
947         if (!strcmp(name,"PrintSetupDlgProc"))
948             return (FARPROC16)PrintSetupDlgProc;
949         if (!strcmp(name,"ReplaceTextDlgProc"))
950             return (FARPROC16)ReplaceTextDlgProc;
951         fprintf(stderr,"warning: No mapping for %s(), add one in library/miscstubs.c\n",name);
952         assert( FALSE );
953         return NULL;
954     }
955     else
956     {
957         WORD ordinal;
958         static HMODULE32 hModule = 0;
959
960         if (!hModule) hModule = GetModuleHandle16( "WPROCS" );
961         ordinal = MODULE_GetOrdinal( hModule, name );
962         if (!(ret = MODULE_GetEntryPoint( hModule, ordinal )))
963         {            
964             fprintf( stderr, "GetWndProc16: %s not found\n", name );
965             assert( FALSE );
966         }
967     }
968     return ret;
969 }
970
971
972 /***********************************************************************
973  *           MODULE_GetModuleName
974  */
975 LPSTR MODULE_GetModuleName( HMODULE32 hModule )
976 {
977     NE_MODULE *pModule;
978     BYTE *p, len;
979     static char buffer[10];
980
981     if (!(pModule = MODULE_GetPtr( hModule ))) return NULL;
982     p = (BYTE *)pModule + pModule->name_table;
983     len = MIN( *p, 8 );
984     memcpy( buffer, p + 1, len );
985     buffer[len] = '\0';
986     return buffer;
987 }
988
989
990 /**********************************************************************
991  *           MODULE_RegisterModule
992  */
993 void MODULE_RegisterModule( NE_MODULE *pModule )
994 {
995     pModule->next = hFirstModule;
996     hFirstModule = pModule->self;
997 }
998
999
1000 /**********************************************************************
1001  *          MODULE_FindModule
1002  *
1003  * Find a module from a path name.
1004  */
1005 HMODULE32 MODULE_FindModule( LPCSTR path )
1006 {
1007     HMODULE32 hModule = hFirstModule;
1008     LPCSTR filename, dotptr, modulepath, modulename;
1009     BYTE len, *name_table;
1010
1011     if (!(filename = strrchr( path, '\\' ))) filename = path;
1012     else filename++;
1013     if ((dotptr = strrchr( filename, '.' )) != NULL)
1014         len = (BYTE)(dotptr - filename);
1015     else len = strlen( filename );
1016
1017     while(hModule)
1018     {
1019         NE_MODULE *pModule = MODULE_GetPtr( hModule );
1020         if (!pModule) break;
1021         modulepath = NE_MODULE_NAME(pModule);
1022         if (!(modulename = strrchr( modulepath, '\\' )))
1023             modulename = modulepath;
1024         else modulename++;
1025         if (!lstrcmpi32A( modulename, filename )) return hModule;
1026
1027         name_table = (BYTE *)pModule + pModule->name_table;
1028         if ((*name_table == len) && !lstrncmpi32A(filename, name_table+1, len))
1029             return hModule;
1030         hModule = pModule->next;
1031     }
1032     return 0;
1033 }
1034
1035
1036 /**********************************************************************
1037  *          MODULE_CallWEP
1038  *
1039  * Call a DLL's WEP, allowing it to shut down.
1040  * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
1041  */
1042 static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
1043 {
1044     FARPROC16 WEP = (FARPROC16)0;
1045     WORD ordinal = MODULE_GetOrdinal( hModule, "WEP" );
1046
1047     if (ordinal) WEP = MODULE_GetEntryPoint( hModule, ordinal );
1048     if (!WEP)
1049     {
1050         WARN(module, "module %04x doesn't have a WEP\n", hModule );
1051         return FALSE;
1052     }
1053     return Callbacks->CallWindowsExitProc( WEP, WEP_FREE_DLL );
1054 }
1055
1056
1057 /**********************************************************************
1058  *          MODULE_FreeModule
1059  *
1060  * Remove a module from memory.
1061  */
1062 BOOL16 MODULE_FreeModule( HMODULE32 hModule, TDB* pTaskContext )
1063 {
1064     HMODULE16 *hPrevModule;
1065     NE_MODULE *pModule;
1066     SEGTABLEENTRY *pSegment;
1067     HMODULE16 *pModRef;
1068     int i;
1069
1070     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
1071     hModule = pModule->self;
1072
1073     if (((INT16)(--pModule->count)) > 0 ) return TRUE;
1074     else pModule->count = 0;
1075
1076     if (pModule->flags & NE_FFLAGS_BUILTIN)
1077         return FALSE;  /* Can't free built-in module */
1078
1079     if (pModule->flags & NE_FFLAGS_LIBMODULE) 
1080     {
1081         MODULE_CallWEP( hModule );
1082
1083         /* Free the objects owned by the DLL module */
1084
1085         if( pTaskContext && pTaskContext->userhandler )
1086         {
1087             pTaskContext->userhandler( hModule, USIG_DLL_UNLOAD, 0,
1088                                        pTaskContext->hInstance,
1089                                        pTaskContext->hQueue );
1090         }
1091     }
1092     /* Clear magic number just in case */
1093
1094     pModule->magic = pModule->self = 0;
1095
1096       /* Remove it from the linked list */
1097
1098     hPrevModule = &hFirstModule;
1099     while (*hPrevModule && (*hPrevModule != hModule))
1100     {
1101         hPrevModule = &(MODULE_GetPtr( *hPrevModule ))->next;
1102     }
1103     if (*hPrevModule) *hPrevModule = pModule->next;
1104
1105       /* Free all the segments */
1106
1107     pSegment = NE_SEG_TABLE( pModule );
1108     for (i = 1; i <= pModule->seg_count; i++, pSegment++)
1109     {
1110         GlobalFree16( pSegment->selector );
1111     }
1112
1113       /* Free the referenced modules */
1114
1115     pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
1116     for (i = 0; i < pModule->modref_count; i++, pModRef++)
1117     {
1118         FreeModule16( *pModRef );
1119     }
1120
1121       /* Free the module storage */
1122
1123     if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
1124     if (pModule->dlls_to_init) GlobalFree16( pModule->dlls_to_init );
1125     GlobalFree16( hModule );
1126
1127       /* Remove module from cache */
1128
1129     if (hCachedModule == hModule) hCachedModule = 0;
1130
1131     return TRUE;
1132 }
1133
1134
1135 /**********************************************************************
1136  *          MODULE_Load
1137  *
1138  * Implementation of LoadModule()
1139  */
1140 HINSTANCE16 MODULE_Load( LPCSTR name, LPVOID paramBlock, UINT16 uFlags)
1141 {
1142     HMODULE32 hModule;
1143     HINSTANCE16 hInstance, hPrevInstance;
1144     NE_MODULE *pModule;
1145     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
1146     OFSTRUCT ofs;
1147     HFILE32 hFile;
1148
1149     if (__winelib)
1150     {
1151         lstrcpyn32A( ofs.szPathName, name, sizeof(ofs.szPathName) );
1152         if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) return hModule;
1153         pModule = (NE_MODULE *)GlobalLock16( hModule );
1154         hPrevInstance = 0;
1155         hInstance = MODULE_CreateInstance( hModule, params );
1156     }
1157     else
1158     {
1159         hModule = MODULE_FindModule( name );
1160
1161         if (!hModule)  /* We have to load the module */
1162         {
1163             /* Try to load the built-in first if not disabled */
1164             if ((hModule = fnBUILTIN_LoadModule( name, FALSE )))
1165                 return MODULE_HANDLEtoHMODULE16( hModule );
1166             
1167             if ((hFile = OpenFile32( name, &ofs, OF_READ )) == HFILE_ERROR32)
1168             {
1169                 /* Now try the built-in even if disabled */
1170                 if ((hModule = fnBUILTIN_LoadModule( name, TRUE )))
1171                 {
1172                     fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
1173                     return MODULE_HANDLEtoHMODULE16( hModule );
1174                 }
1175                 return 2;  /* File not found */
1176             }
1177
1178             /* Create the module structure */
1179
1180             hModule = MODULE_LoadExeHeader( hFile, &ofs );
1181             if (hModule < 32)
1182             {
1183                 if (hModule == 21)
1184                     hModule = PE_LoadModule( hFile, &ofs, paramBlock );
1185                 else _lclose32( hFile );
1186
1187                 if (hModule < 32)
1188                     fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
1189                              name, hModule );
1190                 return hModule;
1191             }
1192             _lclose32( hFile );
1193             pModule = MODULE_GetPtr( hModule );
1194             pModule->flags |= uFlags; /* stamp implicitly loaded modules */
1195
1196             /* Allocate the segments for this module */
1197
1198             MODULE_CreateSegments( hModule );
1199             hPrevInstance = 0;
1200             hInstance = MODULE_CreateInstance(hModule,(LOADPARAMS*)paramBlock);
1201
1202             /* Load the referenced DLLs */
1203
1204             if (!NE_LoadDLLs( pModule )) return 2;  /* File not found */
1205
1206             /* Load the segments */
1207
1208             NE_LoadAllSegments( pModule );
1209
1210             /* Fixup the functions prologs */
1211
1212             NE_FixupPrologs( pModule );
1213
1214             /* Make sure the usage count is 1 on the first loading of  */
1215             /* the module, even if it contains circular DLL references */
1216
1217             pModule->count = 1;
1218
1219             /* Call initialization rountines for all loaded DLLs. Note that
1220              * when we load implicitly linked DLLs this will be done by InitTask().
1221              */
1222
1223             if ((pModule->flags & (NE_FFLAGS_LIBMODULE | NE_FFLAGS_IMPLICIT)) ==
1224                                        NE_FFLAGS_LIBMODULE )
1225                 NE_InitializeDLLs( hModule );
1226         }
1227         else /* module is already loaded, just create a new data segment if it's a task */
1228         {
1229             pModule = MODULE_GetPtr( hModule );
1230             hPrevInstance = MODULE_GetInstance( hModule );
1231             hInstance = MODULE_CreateInstance( hModule, params );
1232             if (hInstance != hPrevInstance)  /* not a library */
1233                 NE_LoadSegment( pModule, pModule->dgroup );
1234             pModule->count++;
1235         }
1236     } /* !winelib */
1237
1238     /* Create a task for this instance */
1239
1240     if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
1241     {
1242         HTASK16 hTask;
1243         WORD    showcmd;
1244
1245         pModule->flags |= NE_FFLAGS_GUI;
1246
1247         /* PowerPoint passes NULL as showCmd */
1248         if (params->showCmd)
1249                 showcmd = *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1);
1250         else
1251                 showcmd = 0; /* FIXME: correct */
1252
1253         hTask = TASK_CreateTask( hModule, hInstance, hPrevInstance,
1254                                  params->hEnvironment,
1255                                 (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
1256                                  showcmd );
1257
1258         if( hTask && TASK_GetNextTask(hTask)) Yield16();
1259     }
1260
1261     return hInstance;
1262 }
1263
1264
1265 /**********************************************************************
1266  *          LoadModule16    (KERNEL.45)
1267  */
1268 HINSTANCE16 LoadModule16( LPCSTR name, LPVOID paramBlock )
1269 {
1270     return MODULE_Load( name, paramBlock, 0 );
1271 }
1272
1273 /**********************************************************************
1274  *          LoadModule32    (KERNEL32.499)
1275  *
1276  * FIXME
1277  *
1278  *  This should get implemented via CreateProcess -- MODULE_Load
1279  *  is resolutely 16-bit.
1280  */
1281 DWORD LoadModule32( LPCSTR name, LPVOID paramBlock ) 
1282 {
1283 #ifdef 0
1284   LOADPARAMS32 *p = paramBlock;
1285   STARTUPINFO st;
1286   PROCESSINFORMATION pi;
1287   st.cb = sizeof(STARTUPINFO);
1288   st.wShowWindow = p->lpCmdShow[2] ; WRONG
1289
1290   BOOL32 ret = CreateProcess32A( name, p->lpCmdLine, 
1291                                  NULL, NULL, FALSE, 0, p->lpEnvAddress,
1292                                  NULL, &st, &pi);
1293   if (!ret) {
1294     /*    handle errors appropriately */
1295   }
1296   CloseHandle32(pi.hProcess);
1297   CloseHandle32(pi.hThread); 
1298
1299 #else
1300     return MODULE_Load( name, paramBlock, 0 );
1301 #endif
1302 }
1303
1304
1305 /**********************************************************************
1306  *          FreeModule16    (KERNEL.46)
1307  */
1308 BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
1309 {
1310     NE_MODULE *pModule;
1311
1312     if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
1313     TRACE(module, "%s count %d\n", 
1314                     MODULE_GetModuleName(hModule), pModule->count );
1315
1316     return MODULE_FreeModule( hModule, GlobalLock16(GetCurrentTask()) );
1317 }
1318
1319
1320 /**********************************************************************
1321  *          GetModuleHandle16    (KERNEL.47)
1322  */
1323 HMODULE16 WINAPI WIN16_GetModuleHandle( SEGPTR name )
1324 {
1325     if (HIWORD(name) == 0) return MODULE_HANDLEtoHMODULE16( (HINSTANCE16)name );
1326     return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
1327 }
1328
1329 HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
1330 {
1331     return MODULE_FindModule( name );
1332 }
1333
1334 /***********************************************************************
1335  *              GetModuleHandle         (KERNEL32.237)
1336  */
1337 HMODULE32 WINAPI GetModuleHandle32A(LPCSTR module)
1338 {
1339     HMODULE32   hModule;
1340
1341     TRACE(win32, "%s\n", module ? module : "NULL");
1342 /* Freecell uses the result of GetModuleHandleA(0) as the hInstance in
1343 all calls to e.g. CreateWindowEx. */
1344     if (module == NULL) {
1345         TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
1346         hModule = pTask->hInstance;
1347     } else
1348         hModule = MODULE_FindModule(module);
1349     return MODULE_HANDLEtoHMODULE32(hModule);
1350 }
1351
1352 HMODULE32 WINAPI GetModuleHandle32W(LPCWSTR module)
1353 {
1354     HMODULE32 hModule;
1355     LPSTR modulea = HEAP_strdupWtoA( GetProcessHeap(), 0, module );
1356     hModule = GetModuleHandle32A( modulea );
1357     HeapFree( GetProcessHeap(), 0, modulea );
1358     return hModule;
1359 }
1360
1361
1362 /**********************************************************************
1363  *          GetModuleUsage    (KERNEL.48)
1364  */
1365 INT16 WINAPI GetModuleUsage( HINSTANCE16 hModule )
1366 {
1367     NE_MODULE *pModule;
1368
1369     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
1370     TRACE(module, "(%04x): returning %d\n",
1371                     hModule, pModule->count );
1372     return pModule->count;
1373 }
1374
1375
1376 /**********************************************************************
1377  *          GetModuleFileName16    (KERNEL.49)
1378  */
1379 INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName,
1380                                   INT16 nSize )
1381 {
1382     NE_MODULE *pModule;
1383
1384     if (!hModule) hModule = GetCurrentTask();
1385     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
1386     lstrcpyn32A( lpFileName, NE_MODULE_NAME(pModule), nSize );
1387     TRACE(module, "%s\n", lpFileName );
1388     return strlen(lpFileName);
1389 }
1390
1391
1392 /***********************************************************************
1393  *              GetModuleFileName32A      (KERNEL32.235)
1394  */
1395 DWORD WINAPI GetModuleFileName32A( HMODULE32 hModule, LPSTR lpFileName,
1396                                    DWORD size )
1397 {                   
1398     NE_MODULE *pModule;
1399            
1400     if (!hModule)
1401     {
1402         TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
1403         hModule = pTask->hInstance;
1404     }
1405     if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
1406     lstrcpyn32A( lpFileName, NE_MODULE_NAME(pModule), size );
1407     TRACE(module, "%s\n", lpFileName );
1408     return strlen(lpFileName);
1409 }                   
1410  
1411
1412 /***********************************************************************
1413  *              GetModuleFileName32W      (KERNEL32.236)
1414  */
1415 DWORD WINAPI GetModuleFileName32W( HMODULE32 hModule, LPWSTR lpFileName,
1416                                    DWORD size )
1417 {
1418     LPSTR fnA = (char*)HeapAlloc( GetProcessHeap(), 0, size );
1419     DWORD res = GetModuleFileName32A( hModule, fnA, size );
1420     lstrcpynAtoW( lpFileName, fnA, size );
1421     HeapFree( GetProcessHeap(), 0, fnA );
1422     return res;
1423 }
1424
1425
1426 /**********************************************************************
1427  *          GetModuleName    (KERNEL.27)
1428  */
1429 BOOL16 WINAPI GetModuleName( HINSTANCE16 hinst, LPSTR buf, INT16 nSize )
1430 {
1431     LPSTR name = MODULE_GetModuleName(hinst);
1432
1433     if (!name) return FALSE;
1434     lstrcpyn32A( buf, name, nSize );
1435     return TRUE;
1436 }
1437
1438
1439 /***********************************************************************
1440  *           LoadLibraryEx32W   (KERNEL.513)
1441  * FIXME
1442  */
1443 HMODULE32 WINAPI LoadLibraryEx32W16( LPCSTR libname, HANDLE16 hf,
1444                                        DWORD flags )
1445 {
1446     fprintf(stderr,"LoadLibraryEx32W(%s,%d,%08lx)\n",libname,hf,flags);
1447     return LoadLibraryEx32A(libname, hf,flags);
1448 }
1449
1450 /***********************************************************************
1451  *           LoadLibraryEx32A   (KERNEL32)
1452  */
1453 HMODULE32 WINAPI LoadLibraryEx32A(LPCSTR libname,HFILE32 hfile,DWORD flags)
1454 {
1455     HMODULE32 hmod;
1456     
1457     hmod = PE_LoadLibraryEx32A(libname,PROCESS_Current(),hfile,flags);
1458     if (hmod <= 32) {
1459         char buffer[256];
1460
1461         strcpy( buffer, libname );
1462         strcat( buffer, ".dll" );
1463         hmod = PE_LoadLibraryEx32A(buffer,PROCESS_Current(),hfile,flags);
1464     }
1465     /* initialize all DLLs, which haven't been initialized yet. */
1466     PE_InitializeDLLs( PROCESS_Current(), DLL_PROCESS_ATTACH, NULL);
1467     return hmod;
1468 }
1469
1470 /***********************************************************************
1471  *           LoadLibraryA         (KERNEL32)
1472  */
1473 HMODULE32 WINAPI LoadLibrary32A(LPCSTR libname) {
1474         return LoadLibraryEx32A(libname,0,0);
1475 }
1476
1477 /***********************************************************************
1478  *           LoadLibraryW         (KERNEL32)
1479  */
1480 HMODULE32 WINAPI LoadLibrary32W(LPCWSTR libnameW)
1481 {
1482     return LoadLibraryEx32W(libnameW,0,0);
1483 }
1484
1485 /***********************************************************************
1486  *           LoadLibraryExW       (KERNEL32)
1487  */
1488 HMODULE32 WINAPI LoadLibraryEx32W(LPCWSTR libnameW,HFILE32 hfile,DWORD flags)
1489 {
1490     LPSTR libnameA = HEAP_strdupWtoA( GetProcessHeap(), 0, libnameW );
1491     HMODULE32 ret = LoadLibraryEx32A( libnameA , hfile, flags );
1492
1493     HeapFree( GetProcessHeap(), 0, libnameA );
1494     return ret;
1495 }
1496
1497 /***********************************************************************
1498  *           FreeLibrary
1499  */
1500 BOOL32 WINAPI FreeLibrary32(HINSTANCE32 hLibModule)
1501 {
1502         TRACE(module,"hLibModule=%08x\n", hLibModule);
1503         return MODULE_FreeModule(hLibModule, 
1504                                  GlobalLock16(GetCurrentTask()) );
1505 }
1506
1507
1508 /***********************************************************************
1509  *           LoadLibrary   (KERNEL.95)
1510  */
1511 HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
1512 {
1513     HINSTANCE16 handle;
1514
1515     if (__winelib)
1516     {
1517         fprintf( stderr, "LoadLibrary not supported in Winelib\n" );
1518         return 0;
1519     }
1520     TRACE(module, "(%08x) %s\n", (int)libname, libname);
1521
1522     handle = MODULE_Load( libname, (LPVOID)-1, 0 );
1523     if (handle == (HINSTANCE16)2)  /* file not found */
1524     {
1525         char buffer[256];
1526         lstrcpyn32A( buffer, libname, 252 );
1527         strcat( buffer, ".dll" );
1528         handle = MODULE_Load( buffer, (LPVOID)-1, 0 );
1529     }
1530     return handle;
1531 }
1532
1533
1534 /***********************************************************************
1535  *           PrivateLoadLibrary       (KERNEL32)
1536  *
1537  * FIXME: rough guesswork, don't know what "Private" means
1538  */
1539 HINSTANCE32 WINAPI PrivateLoadLibrary(LPCSTR libname)
1540 {
1541         return (HINSTANCE32)LoadLibrary16(libname);
1542 }
1543
1544
1545 /***********************************************************************
1546  *           FreeLibrary16   (KERNEL.96)
1547  */
1548 void WINAPI FreeLibrary16( HINSTANCE16 handle )
1549 {
1550     TRACE(module,"%04x\n", handle );
1551     FreeModule16( handle );
1552 }
1553
1554
1555 /***********************************************************************
1556  *           PrivateFreeLibrary       (KERNEL32)
1557  *
1558  * FIXME: rough guesswork, don't know what "Private" means
1559  */
1560 void WINAPI PrivateFreeLibrary(HINSTANCE32 handle)
1561 {
1562         FreeLibrary16((HINSTANCE16)handle);
1563 }
1564
1565
1566 /***********************************************************************
1567  *           WinExec16   (KERNEL.166)
1568  */
1569 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
1570 {
1571     return WinExec32( lpCmdLine, nCmdShow );
1572 }
1573
1574
1575 /***********************************************************************
1576  *           WinExec32   (KERNEL32.566)
1577  */
1578 HINSTANCE32 WINAPI WinExec32( LPCSTR lpCmdLine, UINT32 nCmdShow )
1579 {
1580     LOADPARAMS params;
1581     HGLOBAL16 cmdShowHandle, cmdLineHandle;
1582     HINSTANCE32 handle = 2;
1583     WORD *cmdShowPtr;
1584     char *p, *cmdline, filename[256];
1585     static int use_load_module = 1;
1586     int  spacelimit = 0, exhausted = 0;
1587
1588     if (!lpCmdLine)
1589         return 2;  /* File not found */
1590     if (!(cmdShowHandle = GlobalAlloc16( 0, 2 * sizeof(WORD) )))
1591         return 8;  /* Out of memory */
1592     if (!(cmdLineHandle = GlobalAlloc16( 0, 2048 )))
1593     {
1594         GlobalFree16( cmdShowHandle );
1595         return 8;  /* Out of memory */
1596     }
1597
1598     /* Keep trying to load a file by trying different filenames; e.g.,
1599        for the cmdline "abcd efg hij", try "abcd" with args "efg hij",
1600        then "abcd efg" with arg "hij", and finally "abcd efg hij" with
1601        no args */
1602
1603     while(!exhausted && handle == 2) {
1604         int spacecount = 0;
1605
1606         /* Store nCmdShow */
1607
1608         cmdShowPtr = (WORD *)GlobalLock16( cmdShowHandle );
1609         cmdShowPtr[0] = 2;
1610         cmdShowPtr[1] = nCmdShow;
1611
1612         /* Build the filename and command-line */
1613
1614         cmdline = (char *)GlobalLock16( cmdLineHandle );
1615         lstrcpyn32A(filename, lpCmdLine,
1616                     sizeof(filename) - 4 /* for extension */);
1617
1618         /* Keep grabbing characters until end-of-string, tab, or until the
1619            number of spaces is greater than the spacelimit */
1620
1621         for (p = filename; ; p++) {
1622             if(*p == ' ') {
1623                 ++spacecount;
1624                 if(spacecount > spacelimit) {
1625                     ++spacelimit;
1626                     break;
1627                 }
1628             }
1629
1630             if(*p == '\0' || *p == '\t') {
1631                 exhausted = 1;
1632                 break;
1633             }
1634         }
1635
1636         if (*p)
1637             lstrcpyn32A( cmdline + 1, p + 1, 255 );
1638         else
1639             cmdline[1] = '\0';
1640
1641         cmdline[0] = strlen( cmdline + 1 );
1642         *p = '\0';
1643         /* this is a (hopefully acceptable hack to get the whole
1644            commandline for PROCESS_Create
1645            we put it after the processed one */
1646         lstrcpyn32A(cmdline + (unsigned char)cmdline[0] +2,
1647                     lpCmdLine, 2048 - 256);
1648
1649         /* Now load the executable file */
1650
1651         if (use_load_module)
1652         {
1653             /* Winelib: Use LoadModule() only for the program itself */
1654             if (__winelib) use_load_module = 0;
1655             params.hEnvironment = (HGLOBAL16)SELECTOROF( GetDOSEnvironment() );
1656             params.cmdLine  = (SEGPTR)WIN16_GlobalLock16( cmdLineHandle );
1657             params.showCmd  = (SEGPTR)WIN16_GlobalLock16( cmdShowHandle );
1658             params.reserved = 0;
1659             handle = LoadModule32( filename, &params );
1660             if (handle == 2)  /* file not found */
1661             {
1662                 /* Check that the original file name did not have a suffix */
1663                 p = strrchr(filename, '.');
1664                 /* if there is a '.', check if either \ OR / follow */
1665                 if (!p || strchr(p, '/') || strchr(p, '\\'))
1666                 {
1667                     p = filename + strlen(filename);
1668                     strcpy( p, ".exe" );
1669                     handle = LoadModule16( filename, &params );
1670                     *p = '\0';  /* Remove extension */
1671                 }
1672             }
1673         }
1674         else
1675             handle = 2; /* file not found */
1676
1677         if (handle < 32)
1678         {
1679             /* Try to start it as a unix program */
1680             if (!fork())
1681             {
1682                 /* Child process */
1683                 DOS_FULL_NAME full_name;
1684                 const char *unixfilename = NULL;
1685                 const char *argv[256], **argptr;
1686                 int iconic = (nCmdShow == SW_SHOWMINIMIZED ||
1687                               nCmdShow == SW_SHOWMINNOACTIVE);
1688
1689                 THREAD_InitDone = FALSE; /* we didn't init this process */
1690                 /* get unixfilename */
1691                 if (strchr(filename, '/') ||
1692                     strchr(filename, ':') ||
1693                     strchr(filename, '\\'))
1694                 {
1695                     if (DOSFS_GetFullName( filename, TRUE, &full_name ))
1696                         unixfilename = full_name.long_name;
1697                 }
1698                 else unixfilename = filename;
1699
1700                 if (unixfilename)
1701                 {
1702                     /* build argv */
1703                     argptr = argv;
1704                     if (iconic) *argptr++ = "-iconic";
1705                     *argptr++ = unixfilename;
1706                     p = cmdline + 1;
1707                     while (1)
1708                     {
1709                         while (*p && (*p == ' ' || *p == '\t')) *p++ = '\0';
1710                         if (!*p) break;
1711                         *argptr++ = p;
1712                         while (*p && *p != ' ' && *p != '\t') p++;
1713                     }
1714                     *argptr++ = 0;
1715
1716                     /* Execute */
1717                     execvp(argv[0], (char**)argv);
1718                 }
1719
1720                 /* Failed ! */
1721
1722                 if (__winelib)
1723                 {
1724                     /* build argv */
1725                     argptr = argv;
1726                     *argptr++ = "wine";
1727                     if (iconic) *argptr++ = "-iconic";
1728                     *argptr++ = lpCmdLine;
1729                     *argptr++ = 0;
1730
1731                     /* Execute */
1732                     execvp(argv[0] , (char**)argv);
1733
1734                     /* Failed ! */
1735                     fprintf(stderr, "WinExec: can't exec 'wine %s'\n",
1736                             lpCmdLine);
1737                 }
1738                 exit(1);
1739             }
1740         }
1741     } /* while (!exhausted && handle < 32) */
1742
1743     GlobalFree16( cmdShowHandle );
1744     GlobalFree16( cmdLineHandle );
1745     return handle;
1746 }
1747
1748
1749 /***********************************************************************
1750  *           WIN32_GetProcAddress16   (KERNEL32.36)
1751  * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1752  */
1753 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE32 hModule, LPSTR name )
1754 {
1755     WORD        ordinal;
1756     FARPROC16   ret;
1757
1758     if (!hModule) {
1759         fprintf(stderr,"WIN32_GetProcAddress16: hModule may not be 0!\n");
1760         return (FARPROC16)0;
1761     }
1762     hModule = MODULE_HANDLEtoHMODULE16(hModule);
1763     if (HIWORD(name)) {
1764         ordinal = MODULE_GetOrdinal( hModule, name );
1765         TRACE(module, "%04x '%s'\n",
1766                         hModule, name );
1767     } else {
1768         ordinal = LOWORD(name);
1769         TRACE(module, "%04x %04x\n",
1770                         hModule, ordinal );
1771     }
1772     if (!ordinal) return (FARPROC16)0;
1773     ret = MODULE_GetEntryPoint( hModule, ordinal );
1774     TRACE(module,"returning %08x\n",(UINT32)ret);
1775     return ret;
1776 }
1777
1778 /***********************************************************************
1779  *           GetProcAddress16   (KERNEL.50)
1780  */
1781 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, SEGPTR name )
1782 {
1783     WORD ordinal;
1784     FARPROC16 ret;
1785
1786     if (!hModule) hModule = GetCurrentTask();
1787     hModule = MODULE_HANDLEtoHMODULE16( hModule );
1788
1789     if (HIWORD(name) != 0)
1790     {
1791         ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1792         TRACE(module, "%04x '%s'\n",
1793                         hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1794     }
1795     else
1796     {
1797         ordinal = LOWORD(name);
1798         TRACE(module, "%04x %04x\n",
1799                         hModule, ordinal );
1800     }
1801     if (!ordinal) return (FARPROC16)0;
1802
1803     ret = MODULE_GetEntryPoint( hModule, ordinal );
1804
1805     TRACE(module, "returning %08x\n", (UINT32)ret );
1806     return ret;
1807 }
1808
1809
1810 /***********************************************************************
1811  *           GetProcAddress32   (KERNEL32.257)
1812  */
1813 FARPROC32 WINAPI GetProcAddress32( HMODULE32 hModule, LPCSTR function )
1814 {
1815     NE_MODULE *pModule;
1816
1817     if (HIWORD(function))
1818         TRACE(win32,"(%08lx,%s)\n",(DWORD)hModule,function);
1819     else
1820         TRACE(win32,"(%08lx,%p)\n",(DWORD)hModule,function);
1821     if (!(pModule = MODULE_GetPtr( hModule )))
1822         return (FARPROC32)0;
1823     if (!pModule->module32)
1824     {
1825         fprintf(stderr,"Oops, Module 0x%08lx has got no module32?\n",
1826                 (DWORD)MODULE_HANDLEtoHMODULE32(hModule)
1827         );
1828         return (FARPROC32)0;
1829     }
1830     return PE_FindExportedFunction( PROCESS_Current(), pModule->module32,
1831                                     function );
1832 }
1833
1834 /***********************************************************************
1835  *           RtlImageNtHeaders   (NTDLL)
1836  */
1837 LPIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE32 hModule)
1838 {
1839     /* basically:
1840      * return  hModule+(((IMAGE_DOS_HEADER*)hModule)->e_lfanew); 
1841      * but we could get HMODULE16 or the like (think builtin modules)
1842      */
1843
1844     NE_MODULE *pModule;
1845
1846     if (!(pModule = MODULE_GetPtr( hModule )))
1847         return (LPIMAGE_NT_HEADERS)0;
1848     if (!(pModule->flags & NE_FFLAGS_WIN32) || !pModule->module32)
1849         return (LPIMAGE_NT_HEADERS)0;
1850     return PE_HEADER(pModule->module32);
1851 }
1852
1853
1854 /**********************************************************************
1855  *          GetExpWinVer    (KERNEL.167)
1856  */
1857 WORD WINAPI GetExpWinVer( HMODULE16 hModule )
1858 {
1859     NE_MODULE *pModule = MODULE_GetPtr( hModule );
1860     return pModule ? pModule->expected_version : 0;
1861 }
1862
1863
1864 /**********************************************************************
1865  *          IsSharedSelector    (KERNEL.345)
1866  */
1867 BOOL16 WINAPI IsSharedSelector( HANDLE16 selector )
1868 {
1869     /* Check whether the selector belongs to a DLL */
1870     NE_MODULE *pModule = MODULE_GetPtr( selector );
1871     if (!pModule) return FALSE;
1872     return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
1873 }
1874
1875
1876 /**********************************************************************
1877  *          ModuleFirst    (TOOLHELP.59)
1878  */
1879 BOOL16 WINAPI ModuleFirst( MODULEENTRY *lpme )
1880 {
1881     lpme->wNext = hFirstModule;
1882     return ModuleNext( lpme );
1883 }
1884
1885
1886 /**********************************************************************
1887  *          ModuleNext    (TOOLHELP.60)
1888  */
1889 BOOL16 WINAPI ModuleNext( MODULEENTRY *lpme )
1890 {
1891     NE_MODULE *pModule;
1892     char *name;
1893
1894     if (!lpme->wNext) return FALSE;
1895     if (!(pModule = MODULE_GetPtr( lpme->wNext ))) return FALSE;
1896     name = (char *)pModule + pModule->name_table;
1897     memcpy( lpme->szModule, name + 1, *name );
1898     lpme->szModule[(BYTE)*name] = '\0';
1899     lpme->hModule = lpme->wNext;
1900     lpme->wcUsage = pModule->count;
1901     strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
1902     lpme->szExePath[MAX_PATH] = '\0';
1903     lpme->wNext = pModule->next;
1904     return TRUE;
1905 }
1906
1907
1908 /**********************************************************************
1909  *          ModuleFindName    (TOOLHELP.61)
1910  */
1911 BOOL16 WINAPI ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1912 {
1913     lpme->wNext = GetModuleHandle16( name );
1914     return ModuleNext( lpme );
1915 }
1916
1917
1918 /**********************************************************************
1919  *          ModuleFindHandle    (TOOLHELP.62)
1920  */
1921 BOOL16 WINAPI ModuleFindHandle( MODULEENTRY *lpme, HMODULE16 hModule )
1922 {
1923     hModule = MODULE_HANDLEtoHMODULE16( hModule );
1924     lpme->wNext = hModule;
1925     return ModuleNext( lpme );
1926 }