Release 960225
[wine.git] / loader / module.c
blobe97c806e504a3b558c6530b8d4ebaf39ddece040
1 /*
2 * Modules
4 * Copyright 1995 Alexandre Julliard
5 */
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"
27 #include "callback.h"
28 #include "wine.h"
30 static HMODULE hFirstModule = 0;
31 static HMODULE hCachedModule = 0; /* Module cached by MODULE_OpenFile */
33 #ifndef WINELIB
34 static HANDLE hInitialStack32 = 0;
35 #endif
36 /***********************************************************************
37 * MODULE_LoadBuiltin
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.
42 #ifndef WINELIB
43 static HMODULE MODULE_LoadBuiltin( LPCSTR name, BOOL force )
45 HMODULE hModule;
46 NE_MODULE *pModule;
47 SEGTABLEENTRY *pSegTable;
48 struct dll_table_s *table;
49 int i;
50 char dllname[16], *p;
52 /* Fix the name in case we have a full path and extension */
54 if ((p = strrchr( name, '\\' ))) name = p + 1;
55 strncpy( dllname, name, 15 );
56 dllname[15] = '\0';
57 if ((p = strrchr( dllname, '.' ))) *p = '\0';
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;
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 );
70 table->hModule = hModule;
72 dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
73 table->name, hModule );
75 /* Allocate the code segment */
77 pModule = (NE_MODULE *)GlobalLock( hModule );
78 pSegTable = NE_SEG_TABLE( pModule );
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++;
86 /* Allocate the data segment */
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 );
94 pModule->next = hFirstModule;
95 hFirstModule = hModule;
96 return hModule;
98 #endif
100 /***********************************************************************
101 * MODULE_Init
103 * Create the built-in modules.
105 BOOL MODULE_Init(void)
107 /* For these, built-in modules are always used */
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 */
117 MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
118 return TRUE;
122 /***********************************************************************
123 * MODULE_PrintModule
125 void MODULE_PrintModule( HMODULE hmodule )
127 int i, ordinal;
128 SEGTABLEENTRY *pSeg;
129 BYTE *pstr;
130 WORD *pword;
131 NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hmodule );
133 /* Dump the module info */
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 );
146 /* Dump the file info */
148 printf( "Filename: '%s'\n",
149 ((LOADEDFILEINFO *)((BYTE *)pModule + pModule->fileinfo))->filename );
151 /* Dump the segment table */
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 );
160 /* Dump the resource table */
162 printf( "\nResource table:\n" );
163 if (pModule->res_table)
165 pword = (WORD *)((BYTE *)pModule + pModule->res_table);
166 printf( "Alignment: %d\n", *pword++ );
167 while (*pword)
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;
178 else printf( "None\n" );
180 /* Dump the resident name table */
182 printf( "\nResident-name table:\n" );
183 pstr = (char *)pModule + pModule->name_table;
184 while (*pstr)
186 printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
187 *(WORD *)(pstr + *pstr + 1) );
188 pstr += *pstr + 1 + sizeof(WORD);
191 /* Dump the module reference table */
193 printf( "\nModule ref table:\n" );
194 if (pModule->modref_table)
196 pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
197 for (i = 0; i < pModule->modref_count; i++, pword++)
199 char *name = (char *)pModule + pModule->import_table + *pword;
200 printf( "%d: %04x -> '%*.*s'\n",
201 i, *pword, *name, *name, name + 1 );
204 else printf( "None\n" );
206 /* Dump the entry table */
208 printf( "\nEntry table:\n" );
209 pstr = (char *)pModule + pModule->entry_table;
210 ordinal = 1;
211 while (*pstr)
213 printf( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
214 if (!pstr[1])
216 ordinal += *pstr;
217 pstr += 2;
219 else if ((BYTE)pstr[1] == 0xff) /* moveable */
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;
227 else /* fixed */
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;
237 /* Dump the non-resident names table */
239 printf( "\nNon-resident names table:\n" );
240 if (pModule->nrname_handle)
242 pstr = (char *)GlobalLock( pModule->nrname_handle );
243 while (*pstr)
245 printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
246 *(WORD *)(pstr + *pstr + 1) );
247 pstr += *pstr + 1 + sizeof(WORD);
250 printf( "\n" );
254 /***********************************************************************
255 * MODULE_OpenFile
257 int MODULE_OpenFile( HMODULE hModule )
259 NE_MODULE *pModule;
260 char *name;
261 const char *unixName;
263 static int cachedfd = -1;
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;
283 /***********************************************************************
284 * MODULE_Ne2MemFlags
286 * This function translates NE segment flags to GlobalAlloc flags
288 static WORD MODULE_Ne2MemFlags(WORD flags)
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)
300 memflags |= GMEM_MOVEABLE;
301 memflags |= GMEM_ZEROINIT;
302 #else
303 memflags = GMEM_ZEROINIT | GMEM_FIXED;
304 return memflags;
305 #endif
308 /***********************************************************************
309 * MODULE_AllocateSegment (WINPROCS.26)
312 DWORD MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
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
324 /***********************************************************************
325 * MODULE_CreateSegments
327 #ifndef WINELIB32
328 static BOOL MODULE_CreateSegments( HMODULE hModule )
330 SEGTABLEENTRY *pSegment;
331 NE_MODULE *pModule;
332 int i, minsize;
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++)
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;
350 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
351 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
352 return TRUE;
354 #endif
357 /***********************************************************************
358 * MODULE_GetInstance
360 #ifndef WINELIB32
361 static HINSTANCE MODULE_GetInstance( HMODULE hModule )
363 SEGTABLEENTRY *pSegment;
364 NE_MODULE *pModule;
366 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
367 if (pModule->dgroup == 0) return hModule;
369 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
371 return pSegment->selector;
373 #endif
376 /***********************************************************************
377 * MODULE_CreateInstance
379 HINSTANCE MODULE_CreateInstance( HMODULE hModule, LOADPARAMS *params )
381 SEGTABLEENTRY *pSegment;
382 NE_MODULE *pModule;
383 int minsize;
384 HINSTANCE hNewInstance, hPrevInstance;
386 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
387 if (pModule->dgroup == 0) return hModule;
389 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
390 hPrevInstance = pSegment->selector;
392 /* if it's a library, create a new instance only the first time */
393 if (hPrevInstance)
395 if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
396 if (params == (LOADPARAMS*)-1) return hPrevInstance;
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;
410 /***********************************************************************
411 * MODULE_LoadExeHeader
413 HMODULE MODULE_LoadExeHeader( int fd, OFSTRUCT *ofs )
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;
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)))
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 */
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 */
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 */
443 /* We now have a valid NE header */
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;
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);
469 /* Read the fast-load area */
471 if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
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)
479 lseek( fd, mz_header.ne_offset + fastload_offset, SEEK_SET );
480 if (read( fd, fastload, fastload_length ) != fastload_length)
482 free( fastload );
483 fastload = NULL;
488 /* Store the filename information */
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--;
499 /* Get the segment table */
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)
505 int i;
506 struct ne_segment_table_entry_s *pSeg;
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++)
514 memcpy( pData, pSeg, sizeof(*pSeg) );
515 pData += sizeof(SEGTABLEENTRY);
517 free( buffer );
519 else return (HMODULE)11; /* invalid exe */
521 /* Get the resource table */
523 if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
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;
531 else pModule->res_table = 0; /* No resource table */
533 /* Get the resident names table */
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;
541 /* Get the module references table */
543 if (ne_header.n_mod_ref_tab > 0)
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);
551 else pModule->modref_table = 0; /* No module references */
553 /* Get the imported names table */
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;
561 /* Get the entry table */
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;
569 /* Get the non-resident names table */
571 if (ne_header.nrname_tab_length)
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 */
581 else pModule->nrname_handle = 0;
583 /* Allocate a segment for the implicitly-loaded DLLs */
585 if (pModule->modref_count)
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 */
592 else pModule->dlls_to_init = 0;
594 if (debugging_module) MODULE_PrintModule( hModule );
595 pModule->next = hFirstModule;
596 hFirstModule = hModule;
597 return hModule;
601 /***********************************************************************
602 * MODULE_GetOrdinal
604 * Lookup the ordinal for a given name.
606 WORD MODULE_GetOrdinal( HMODULE hModule, char *name )
608 char buffer[256], *cpnt;
609 BYTE len;
610 NE_MODULE *pModule;
612 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
614 dprintf_module( stddeb, "MODULE_GetOrdinal("NPFMT",'%s')\n",
615 hModule, name );
617 /* First handle names of the form '#xxxx' */
619 if (name[0] == '#') return atoi( name + 1 );
621 /* Now copy and uppercase the string */
623 strcpy( buffer, name );
624 AnsiUpper( buffer );
625 len = strlen( buffer );
627 /* First search the resident names */
629 cpnt = (char *)pModule + pModule->name_table;
631 /* Skip the first entry (module name) */
632 cpnt += *cpnt + 1 + sizeof(WORD);
633 while (*cpnt)
635 dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
636 if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
638 dprintf_module( stddeb, " Found: ordinal=%d\n",
639 *(WORD *)(cpnt + *cpnt + 1) );
640 return *(WORD *)(cpnt + *cpnt + 1);
642 cpnt += *cpnt + 1 + sizeof(WORD);
645 /* Now search the non-resident names table */
647 if (!pModule->nrname_handle) return 0; /* No non-resident table */
648 cpnt = (char *)GlobalLock( pModule->nrname_handle );
650 /* Skip the first entry (module description string) */
651 cpnt += *cpnt + 1 + sizeof(WORD);
652 while (*cpnt)
654 dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
655 if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
657 dprintf_module( stddeb, " Found: ordinal=%d\n",
658 *(WORD *)(cpnt + *cpnt + 1) );
659 return *(WORD *)(cpnt + *cpnt + 1);
661 cpnt += *cpnt + 1 + sizeof(WORD);
663 return 0;
667 /***********************************************************************
668 * MODULE_GetEntryPoint
670 * Return the entry point for a given ordinal.
672 SEGPTR MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal )
674 NE_MODULE *pModule;
675 WORD curOrdinal = 1;
676 BYTE *p;
677 WORD sel, offset;
679 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
681 p = (BYTE *)pModule + pModule->entry_table;
682 while (*p && (curOrdinal + *p <= ordinal))
684 /* Skipping this bundle */
685 curOrdinal += *p;
686 switch(p[1])
688 case 0: p += 2; break; /* unused */
689 case 0xff: p += 2 + *p * 6; break; /* moveable */
690 default: p += 2 + *p * 3; break; /* fixed */
693 if (!*p) return 0;
695 switch(p[1])
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;
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 );
717 /***********************************************************************
718 * MODULE_SetEntryPoint
720 * Change the value of an entry point. Use with caution!
721 * It can only change the offset value, not the selector.
723 BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset )
725 NE_MODULE *pModule;
726 WORD curOrdinal = 1;
727 BYTE *p;
729 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
731 p = (BYTE *)pModule + pModule->entry_table;
732 while (*p && (curOrdinal + *p <= ordinal))
734 /* Skipping this bundle */
735 curOrdinal += *p;
736 switch(p[1])
738 case 0: p += 2; break; /* unused */
739 case 0xff: p += 2 + *p * 6; break; /* moveable */
740 default: p += 2 + *p * 3; break; /* fixed */
743 if (!*p) return FALSE;
745 switch(p[1])
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;
758 return TRUE;
762 /***********************************************************************
763 * MODULE_GetEntryPointName
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.
769 LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal )
771 register char *cpnt;
772 NE_MODULE *pModule;
774 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
776 /* First search the resident names */
778 cpnt = (char *)pModule + pModule->name_table;
779 while (*cpnt)
781 cpnt += *cpnt + 1 + sizeof(WORD);
782 if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
785 /* Now search the non-resident names table */
787 if (!pModule->nrname_handle) return 0; /* No non-resident table */
788 cpnt = (char *)GlobalLock( pModule->nrname_handle );
789 while (*cpnt)
791 cpnt += *cpnt + 1 + sizeof(WORD);
792 if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
794 return NULL;
798 /***********************************************************************
799 * MODULE_GetModuleName
801 LPSTR MODULE_GetModuleName( HMODULE hModule )
803 NE_MODULE *pModule;
804 BYTE *p, len;
805 static char buffer[10];
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;
816 /**********************************************************************
817 * MODULE_RegisterModule
819 void MODULE_RegisterModule( HMODULE hModule )
821 NE_MODULE *pModule;
822 pModule = (NE_MODULE *)GlobalLock( hModule );
823 pModule->next = hFirstModule;
824 hFirstModule = hModule;
827 /**********************************************************************
828 * MODULE_FindModule
830 * Find a module from a path name.
832 HMODULE MODULE_FindModule( LPCSTR path )
834 HMODULE hModule = hFirstModule;
835 LPCSTR filename, dotptr, modulepath, modulename;
836 BYTE len, *name_table;
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 );
844 while(hModule)
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;
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;
859 return 0;
863 /**********************************************************************
864 * MODULE_FreeModule
866 * Remove a module from memory.
868 static void MODULE_FreeModule( HMODULE hModule )
870 HMODULE *hPrevModule;
871 NE_MODULE *pModule;
872 SEGTABLEENTRY *pSegment;
873 HMODULE *pModRef;
874 int i;
876 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return;
877 if (pModule->flags & NE_FFLAGS_BUILTIN)
878 return; /* Can't free built-in module */
880 /* FIXME: should call the exit code for the library here */
882 /* Remove it from the linked list */
884 hPrevModule = &hFirstModule;
885 while (*hPrevModule && (*hPrevModule != hModule))
887 hPrevModule = &((NE_MODULE *)GlobalLock( *hPrevModule ))->next;
889 if (*hPrevModule) *hPrevModule = pModule->next;
891 /* Free all the segments */
893 pSegment = NE_SEG_TABLE( pModule );
894 for (i = 1; i <= pModule->seg_count; i++, pSegment++)
896 GlobalFree( pSegment->selector );
899 /* Free the referenced modules */
901 pModRef = (HMODULE*)NE_MODULE_TABLE( pModule );
902 for (i = 0; i < pModule->modref_count; i++, pModRef++)
904 FreeModule( *pModRef );
907 /* Free the module storage */
909 if (pModule->nrname_handle) GlobalFree( pModule->nrname_handle );
910 if (pModule->dlls_to_init) GlobalFree( pModule->dlls_to_init );
911 GlobalFree( hModule );
913 /* Remove module from cache */
915 if (hCachedModule == hModule) hCachedModule = 0;
919 HINSTANCE PE_LoadModule(int fd, OFSTRUCT *ofs, LOADPARAMS* params);
921 /**********************************************************************
922 * LoadModule (KERNEL.45)
924 HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
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;
934 hModule = MODULE_FindModule( name );
936 if (!hModule) /* We have to load the module */
938 OFSTRUCT ofs;
940 /* Try to load the built-in first if not disabled */
941 if ((hModule = MODULE_LoadBuiltin( name, FALSE ))) return hModule;
943 if ((fd = FILE_OpenFile( name, &ofs, OF_READ )) == -1)
945 /* Now try the built-in even if disabled */
946 if ((hModule = MODULE_LoadBuiltin( name, TRUE )))
948 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
949 return hModule;
951 return 2; /* File not found */
954 /* Create the module structure */
956 hModule = MODULE_LoadExeHeader( fd, &ofs );
957 if (hModule < 32)
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;
966 close( fd );
967 pModule = (NE_MODULE *)GlobalLock( hModule );
969 /* Allocate the segments for this module */
971 MODULE_CreateSegments( hModule );
973 hPrevInstance = 0;
974 hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
976 /* Load the referenced DLLs */
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++)
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 )))
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;
993 if ((hDLL = LoadModule( buffer, (LPVOID)-1 )) == 2) /* file not found */
995 char *p;
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 );
1004 if (hDLL < 32)
1006 fprintf( stderr, "Could not load '%s' required by '%s', error = %d\n",
1007 buffer, name, hDLL );
1008 return 2; /* file not found */
1010 *pModRef = GetExePtr( hDLL );
1011 *pDLLs++ = *pModRef;
1013 else /* Increment the reference count of the DLL */
1015 NE_MODULE *pOldDLL = (NE_MODULE *)GlobalLock( *pModRef );
1016 if (pOldDLL) pOldDLL->count++;
1020 /* Load the segments */
1022 if (pModule->flags & NE_FFLAGS_SELFLOAD)
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)
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 );
1057 /* Create the 32-bit stack frame */
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);
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;
1089 else
1091 for (i = 1; i <= pModule->seg_count; i++)
1092 NE_LoadSegment( hModule, i );
1095 /* Fixup the functions prologs */
1097 NE_FixupPrologs( hModule );
1099 /* Make sure the usage count is 1 on the first loading of */
1100 /* the module, even if it contains circular DLL references */
1102 pModule->count = 1;
1104 /* Clear built-in flag in case it was set in the EXE file */
1106 pModule->flags &= ~NE_FFLAGS_BUILTIN;
1108 else
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++;
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 */
1126 /* Create a task for this instance */
1128 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
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) );
1136 return hInstance;
1140 /**********************************************************************
1141 * FreeModule (KERNEL.46)
1143 BOOL FreeModule( HANDLE hModule )
1145 NE_MODULE *pModule;
1147 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1148 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
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;
1157 /**********************************************************************
1158 * GetModuleHandle (KERNEL.47)
1160 HMODULE WIN16_GetModuleHandle( SEGPTR name )
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) );
1170 HMODULE GetModuleHandle( LPCSTR name )
1172 return MODULE_FindModule( name );
1176 /**********************************************************************
1177 * GetModuleUsage (KERNEL.48)
1179 int GetModuleUsage( HANDLE hModule )
1181 NE_MODULE *pModule;
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;
1191 /**********************************************************************
1192 * GetModuleFileName (KERNEL.49)
1194 int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
1196 NE_MODULE *pModule;
1197 char *name;
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);
1208 /***********************************************************************
1209 * LoadLibrary (KERNEL.95)
1211 HANDLE LoadLibrary( LPCSTR libname )
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;
1220 dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
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;
1226 handle = LoadModule( libname, (LPVOID)-1 );
1227 if (handle == (HANDLE)2) /* file not found */
1229 char buffer[256];
1230 lstrcpyn( buffer, libname, 252 );
1231 strcat( buffer, ".dll" );
1232 handle = LoadModule( buffer, (LPVOID)-1 );
1234 if (handle >= (HANDLE)32) NE_InitializeDLLs( GetExePtr(handle) );
1235 return handle;
1236 #endif
1240 /***********************************************************************
1241 * FreeLibrary (KERNEL.96)
1243 void FreeLibrary( HANDLE handle )
1245 dprintf_module( stddeb,"FreeLibrary: "NPFMT"\n", handle );
1246 FreeModule( handle );
1250 /***********************************************************************
1251 * WinExec (KERNEL.166)
1253 HANDLE WinExec( LPSTR lpCmdLine, WORD nCmdShow )
1255 LOADPARAMS params;
1256 HLOCAL cmdShowHandle, cmdLineHandle;
1257 HANDLE handle;
1258 WORD *cmdShowPtr;
1259 char *p, *cmdline, filename[256];
1261 if (!(cmdShowHandle = GlobalAlloc( 0, 2 * sizeof(WORD) ))) return 0;
1262 if (!(cmdLineHandle = GlobalAlloc( 0, 256 ))) return 0;
1264 /* Store nCmdShow */
1266 cmdShowPtr = (WORD *)GlobalLock( cmdShowHandle );
1267 cmdShowPtr[0] = 2;
1268 cmdShowPtr[1] = nCmdShow;
1270 /* Build the filename and command-line */
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)
1278 strncpy( cmdline, p + 1, 128 );
1279 cmdline[127] = '\0';
1281 else cmdline[0] = '\0';
1282 *p = '\0';
1284 /* Now load the executable file */
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 */
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 );
1305 GlobalFree( cmdShowHandle );
1306 GlobalFree( cmdLineHandle );
1308 #if 0
1309 if (handle < (HANDLE)32) /* Error? */
1310 return handle;
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 */
1318 #endif
1319 return handle;
1323 /***********************************************************************
1324 * GetProcAddress (KERNEL.50)
1326 FARPROC GetProcAddress( HANDLE hModule, SEGPTR name )
1328 WORD ordinal;
1329 SEGPTR ret;
1331 if (!hModule) hModule = GetCurrentTask();
1332 hModule = GetExePtr( hModule );
1334 if (HIWORD(name) != 0)
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) );
1340 else
1342 ordinal = LOWORD(name);
1343 dprintf_module( stddeb, "GetProcAddress: "NPFMT" %04x\n",
1344 hModule, ordinal );
1346 if (!ordinal) return (FARPROC)0;
1348 ret = MODULE_GetEntryPoint( hModule, ordinal );
1350 dprintf_module( stddeb, "GetProcAddress: returning "SPFMT"\n", ret );
1351 return (FARPROC)ret;
1355 /**********************************************************************
1356 * GetExpWinVer (KERNEL.167)
1358 WORD GetExpWinVer( HMODULE hModule )
1360 NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
1362 return pModule->expected_version;
1366 /***********************************************************************
1367 * GetWndProcEntry16 (not a Windows API function)
1369 * Return an entry point from the WINPROCS dll.
1371 #ifndef WINELIB
1372 WNDPROC GetWndProcEntry16( char *name )
1374 WORD ordinal;
1375 static HMODULE hModule = 0;
1377 if (!hModule) hModule = GetModuleHandle( "WINPROCS" );
1378 ordinal = MODULE_GetOrdinal( hModule, name );
1379 return MODULE_GetEntryPoint( hModule, ordinal );
1381 #endif
1384 /**********************************************************************
1385 * ModuleFirst (TOOLHELP.59)
1387 BOOL ModuleFirst( MODULEENTRY *lpme )
1389 lpme->wNext = hFirstModule;
1390 return ModuleNext( lpme );
1394 /**********************************************************************
1395 * ModuleNext (TOOLHELP.60)
1397 BOOL ModuleNext( MODULEENTRY *lpme )
1399 NE_MODULE *pModule;
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;
1417 /**********************************************************************
1418 * ModuleFindName (TOOLHELP.61)
1420 BOOL ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1422 lpme->wNext = GetModuleHandle( name );
1423 return ModuleNext( lpme );
1427 /**********************************************************************
1428 * ModuleFindHandle (TOOLHELP.62)
1430 BOOL ModuleFindHandle( MODULEENTRY *lpme, HMODULE hModule )
1432 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1433 lpme->wNext = hModule;
1434 return ModuleNext( lpme );