Release 960309
[wine.git] / loader / module.c
bloba18f1da4e45fe06d095f708c43d2978d71b7b9f2
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 extern HINSTANCE PE_LoadModule( int fd, OFSTRUCT *ofs, LOADPARAMS* params );
32 static HMODULE hFirstModule = 0;
33 static HMODULE hCachedModule = 0; /* Module cached by MODULE_OpenFile */
35 #ifndef WINELIB
36 static HANDLE hInitialStack32 = 0;
37 #endif
38 /***********************************************************************
39 * MODULE_LoadBuiltin
41 * Load a built-in module. If the 'force' parameter is FALSE, we only
42 * load the module if it has not been disabled via the -dll option.
44 #ifndef WINELIB
45 static HMODULE MODULE_LoadBuiltin( LPCSTR name, BOOL force )
47 HMODULE hModule;
48 NE_MODULE *pModule;
49 SEGTABLEENTRY *pSegTable;
50 struct dll_table_s *table;
51 int i;
52 char dllname[16], *p;
54 /* Fix the name in case we have a full path and extension */
56 if ((p = strrchr( name, '\\' ))) name = p + 1;
57 strncpy( dllname, name, 15 );
58 dllname[15] = '\0';
59 if ((p = strrchr( dllname, '.' ))) *p = '\0';
61 for (i = 0, table = dll_builtin_table; i < N_BUILTINS; i++, table++)
62 if (!lstrcmpi( table->name, dllname )) break;
63 if (i >= N_BUILTINS) return 0;
64 if (!table->used && !force) return 0;
66 hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->module_start,
67 table->module_end - table->module_start,
68 0, FALSE, FALSE, FALSE, NULL );
69 if (!hModule) return 0;
70 FarSetOwner( hModule, hModule );
72 table->hModule = hModule;
74 dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
75 table->name, hModule );
77 /* Allocate the code segment */
79 pModule = (NE_MODULE *)GlobalLock( hModule );
80 pSegTable = NE_SEG_TABLE( pModule );
82 pSegTable->selector = GLOBAL_CreateBlock( GMEM_FIXED, table->code_start,
83 pSegTable->minsize, hModule,
84 TRUE, TRUE, FALSE, NULL );
85 if (!pSegTable->selector) return 0;
86 pSegTable++;
88 /* Allocate the data segment */
90 pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, pSegTable->minsize,
91 hModule, FALSE, FALSE, FALSE );
92 if (!pSegTable->selector) return 0;
93 memcpy( GlobalLock( pSegTable->selector ),
94 table->data_start, pSegTable->minsize );
96 pModule->next = hFirstModule;
97 hFirstModule = hModule;
98 return hModule;
100 #endif
102 /***********************************************************************
103 * MODULE_Init
105 * Create the built-in modules.
107 BOOL MODULE_Init(void)
109 /* For these, built-in modules are always used */
111 #ifndef WINELIB32
112 if (!MODULE_LoadBuiltin( "KERNEL", TRUE ) ||
113 !MODULE_LoadBuiltin( "GDI", TRUE ) ||
114 !MODULE_LoadBuiltin( "USER", TRUE ) ||
115 !MODULE_LoadBuiltin( "WINPROCS", TRUE )) return FALSE;
116 #endif
117 /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
119 MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
120 return TRUE;
124 /***********************************************************************
125 * MODULE_PrintModule
127 void MODULE_PrintModule( HMODULE hmodule )
129 int i, ordinal;
130 SEGTABLEENTRY *pSeg;
131 BYTE *pstr;
132 WORD *pword;
133 NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hmodule );
135 /* Dump the module info */
137 printf( "Module "NPFMT":\n", hmodule );
138 printf( "count=%d flags=%04x heap=%d stack=%d\n",
139 pModule->count, pModule->flags,
140 pModule->heap_size, pModule->stack_size );
141 printf( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
142 pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
143 pModule->seg_count, pModule->modref_count );
144 printf( "os_flags=%d swap_area=%d version=%04x\n",
145 pModule->os_flags, pModule->min_swap_area,
146 pModule->expected_version );
148 /* Dump the file info */
150 printf( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
152 /* Dump the segment table */
154 printf( "\nSegment table:\n" );
155 pSeg = NE_SEG_TABLE( pModule );
156 for (i = 0; i < pModule->seg_count; i++, pSeg++)
157 printf( "%02x: pos=%d size=%d flags=%04x minsize=%d sel="NPFMT"\n",
158 i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
159 pSeg->minsize, pSeg->selector );
161 /* Dump the resource table */
163 printf( "\nResource table:\n" );
164 if (pModule->res_table)
166 pword = (WORD *)((BYTE *)pModule + pModule->res_table);
167 printf( "Alignment: %d\n", *pword++ );
168 while (*pword)
170 struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
171 struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
172 printf( "id=%04x count=%d\n", ptr->type_id, ptr->count );
173 for (i = 0; i < ptr->count; i++, pname++)
174 printf( "offset=%d len=%d id=%04x\n",
175 pname->offset, pname->length, pname->id );
176 pword = (WORD *)pname;
179 else printf( "None\n" );
181 /* Dump the resident name table */
183 printf( "\nResident-name table:\n" );
184 pstr = (char *)pModule + pModule->name_table;
185 while (*pstr)
187 printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
188 *(WORD *)(pstr + *pstr + 1) );
189 pstr += *pstr + 1 + sizeof(WORD);
192 /* Dump the module reference table */
194 printf( "\nModule ref table:\n" );
195 if (pModule->modref_table)
197 pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
198 for (i = 0; i < pModule->modref_count; i++, pword++)
200 char *name = (char *)pModule + pModule->import_table + *pword;
201 printf( "%d: %04x -> '%*.*s'\n",
202 i, *pword, *name, *name, name + 1 );
205 else printf( "None\n" );
207 /* Dump the entry table */
209 printf( "\nEntry table:\n" );
210 pstr = (char *)pModule + pModule->entry_table;
211 ordinal = 1;
212 while (*pstr)
214 printf( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
215 if (!pstr[1])
217 ordinal += *pstr;
218 pstr += 2;
220 else if ((BYTE)pstr[1] == 0xff) /* moveable */
222 struct entry_tab_movable_s *pe = (struct entry_tab_movable_s*)(pstr+2);
223 for (i = 0; i < *pstr; i++, pe++)
224 printf( "%d: %02x:%04x (moveable)\n",
225 ordinal++, pe->seg_number, pe->offset );
226 pstr = (char *)pe;
228 else /* fixed */
230 struct entry_tab_fixed_s *pe = (struct entry_tab_fixed_s*)(pstr+2);
231 for (i = 0; i < *pstr; i++, pe++)
232 printf( "%d: %04x (fixed)\n",
233 ordinal++, pe->offset[0] + (pe->offset[1] << 8) );
234 pstr = (char *)pe;
238 /* Dump the non-resident names table */
240 printf( "\nNon-resident names table:\n" );
241 if (pModule->nrname_handle)
243 pstr = (char *)GlobalLock( pModule->nrname_handle );
244 while (*pstr)
246 printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
247 *(WORD *)(pstr + *pstr + 1) );
248 pstr += *pstr + 1 + sizeof(WORD);
251 printf( "\n" );
255 /***********************************************************************
256 * MODULE_OpenFile
258 int MODULE_OpenFile( HMODULE hModule )
260 NE_MODULE *pModule;
261 char *name;
262 const char *unixName;
264 static int cachedfd = -1;
266 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
267 dprintf_module( stddeb, "MODULE_OpenFile("NPFMT") cache: mod="NPFMT" fd=%d\n",
268 hModule, hCachedModule, cachedfd );
269 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return -1;
270 if (hCachedModule == hModule) return cachedfd;
271 close( cachedfd );
272 hCachedModule = hModule;
273 name = NE_MODULE_NAME( pModule );
274 if (!(unixName = DOSFS_GetUnixFileName( name, TRUE )) ||
275 (cachedfd = open( unixName, O_RDONLY )) == -1)
276 fprintf( stderr, "MODULE_OpenFile: can't open file '%s' for module "NPFMT"\n",
277 name, hModule );
278 dprintf_module( stddeb, "MODULE_OpenFile: opened '%s' -> %d\n",
279 name, cachedfd );
280 return cachedfd;
284 /***********************************************************************
285 * MODULE_Ne2MemFlags
287 * This function translates NE segment flags to GlobalAlloc flags
289 static WORD MODULE_Ne2MemFlags(WORD flags)
291 WORD memflags = 0;
292 #if 0
293 if (flags & NE_SEGFLAGS_DISCARDABLE)
294 memflags |= GMEM_DISCARDABLE;
295 if (flags & NE_SEGFLAGS_MOVEABLE ||
296 ( ! (flags & NE_SEGFLAGS_DATA) &&
297 ! (flags & NE_SEGFLAGS_LOADED) &&
298 ! (flags & NE_SEGFLAGS_ALLOCATED)
301 memflags |= GMEM_MOVEABLE;
302 memflags |= GMEM_ZEROINIT;
303 #else
304 memflags = GMEM_ZEROINIT | GMEM_FIXED;
305 return memflags;
306 #endif
309 /***********************************************************************
310 * MODULE_AllocateSegment (WINPROCS.26)
313 DWORD MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
315 WORD size = wSize << wElem;
316 HANDLE hMem = GlobalAlloc( MODULE_Ne2MemFlags(wFlags), size);
317 #ifdef WINELIB32
318 return (DWORD)GlobalLock(hMem);
319 #else
320 WORD selector = HIWORD(GlobalLock(hMem));
321 return MAKELONG(hMem, selector);
322 #endif
325 /***********************************************************************
326 * MODULE_CreateSegments
328 #ifndef WINELIB32
329 static BOOL MODULE_CreateSegments( HMODULE hModule )
331 SEGTABLEENTRY *pSegment;
332 NE_MODULE *pModule;
333 int i, minsize;
335 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
336 pSegment = NE_SEG_TABLE( pModule );
337 for (i = 1; i <= pModule->seg_count; i++, pSegment++)
339 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
340 if (i == pModule->ss) minsize += pModule->stack_size;
341 /* The DGROUP is allocated by MODULE_CreateInstance */
342 if (i == pModule->dgroup) continue;
343 pSegment->selector = GLOBAL_Alloc( MODULE_Ne2MemFlags(pSegment->flags),
344 minsize, hModule,
345 !(pSegment->flags & NE_SEGFLAGS_DATA),
346 FALSE,
347 FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
348 if (!pSegment->selector) return FALSE;
351 pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
352 (pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
353 return TRUE;
355 #endif
358 /***********************************************************************
359 * MODULE_GetInstance
361 #ifndef WINELIB32
362 static HINSTANCE MODULE_GetInstance( HMODULE hModule )
364 SEGTABLEENTRY *pSegment;
365 NE_MODULE *pModule;
367 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
368 if (pModule->dgroup == 0) return hModule;
370 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
372 return pSegment->selector;
374 #endif
377 /***********************************************************************
378 * MODULE_CreateInstance
380 HINSTANCE MODULE_CreateInstance( HMODULE hModule, LOADPARAMS *params )
382 SEGTABLEENTRY *pSegment;
383 NE_MODULE *pModule;
384 int minsize;
385 HINSTANCE hNewInstance, hPrevInstance;
387 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
388 if (pModule->dgroup == 0) return hModule;
390 pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
391 hPrevInstance = pSegment->selector;
393 /* if it's a library, create a new instance only the first time */
394 if (hPrevInstance)
396 if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
397 if (params == (LOADPARAMS*)-1) return hPrevInstance;
400 minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
401 if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
402 minsize += pModule->heap_size;
403 hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
404 minsize, hModule, FALSE, FALSE, FALSE );
405 if (!hNewInstance) return 0;
406 pSegment->selector = hNewInstance;
407 return hNewInstance;
411 /***********************************************************************
412 * MODULE_LoadExeHeader
414 HMODULE MODULE_LoadExeHeader( HFILE hFile, OFSTRUCT *ofs )
416 struct mz_header_s mz_header;
417 struct ne_header_s ne_header;
418 int size;
419 HMODULE hModule;
420 NE_MODULE *pModule;
421 BYTE *pData;
422 char *buffer, *fastload = NULL;
423 int fastload_offset = 0, fastload_length = 0;
425 /* Read a block from either the file or the fast-load area. */
426 #define READ(offset,size,buffer) \
427 ((fastload && ((offset) >= fastload_offset) && \
428 ((offset)+(size) <= fastload_offset+fastload_length)) ? \
429 (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
430 (_llseek( hFile, mz_header.ne_offset+(offset), SEEK_SET), \
431 FILE_Read( hFile, (buffer), (size) ) == (size)))
433 _llseek( hFile, 0, SEEK_SET );
434 if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
435 (mz_header.mz_magic != MZ_SIGNATURE)) return (HMODULE)11; /* invalid exe */
437 _llseek( hFile, mz_header.ne_offset, SEEK_SET );
438 if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
439 return (HMODULE)11; /* invalid exe */
441 if (ne_header.ne_magic == PE_SIGNATURE) return (HMODULE)21; /* win32 exe */
442 if (ne_header.ne_magic != NE_SIGNATURE) return (HMODULE)11; /* invalid exe */
444 /* We now have a valid NE header */
446 size = sizeof(NE_MODULE) +
447 /* loaded file info */
448 sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1+
449 /* segment table */
450 ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
451 /* resource table */
452 ne_header.rname_tab_offset - ne_header.resource_tab_offset +
453 /* resident names table */
454 ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
455 /* module ref table */
456 ne_header.n_mod_ref_tab * sizeof(WORD) +
457 /* imported names table */
458 ne_header.entry_tab_offset - ne_header.iname_tab_offset +
459 /* entry table length */
460 ne_header.entry_tab_length;
462 hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
463 if (!hModule) return (HMODULE)11; /* invalid exe */
464 FarSetOwner( hModule, (WORD)(DWORD)hModule );
465 pModule = (NE_MODULE *)GlobalLock( hModule );
466 memcpy( pModule, &ne_header, sizeof(NE_MODULE) );
467 pModule->count = 0;
468 pData = (BYTE *)(pModule + 1);
470 /* Read the fast-load area */
472 if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
474 fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
475 fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
476 dprintf_module( stddeb, "Using fast-load area offset=%x len=%d\n",
477 fastload_offset, fastload_length );
478 if ((fastload = (char *)malloc( fastload_length )) != NULL)
480 _llseek( hFile, mz_header.ne_offset + fastload_offset, SEEK_SET );
481 if (FILE_Read( hFile, fastload, fastload_length ) != fastload_length)
483 free( fastload );
484 fastload = NULL;
489 /* Store the filename information */
491 pModule->fileinfo = (int)pData - (int)pModule;
492 size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
493 memcpy( pData, ofs, size );
494 ((OFSTRUCT *)pData)->cBytes = size - 1;
495 pData += size;
497 /* Get the segment table */
499 pModule->seg_table = (int)pData - (int)pModule;
500 buffer = malloc( ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s) );
501 if (buffer)
503 int i;
504 struct ne_segment_table_entry_s *pSeg;
506 if (!READ( ne_header.segment_tab_offset,
507 ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
508 buffer )) return (HMODULE)11; /* invalid exe */
509 pSeg = (struct ne_segment_table_entry_s *)buffer;
510 for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
512 memcpy( pData, pSeg, sizeof(*pSeg) );
513 pData += sizeof(SEGTABLEENTRY);
515 free( buffer );
517 else return (HMODULE)11; /* invalid exe */
519 /* Get the resource table */
521 if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
523 pModule->res_table = (int)pData - (int)pModule;
524 if (!READ(ne_header.resource_tab_offset,
525 ne_header.rname_tab_offset - ne_header.resource_tab_offset,
526 pData )) return (HMODULE)11; /* invalid exe */
527 pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
529 else pModule->res_table = 0; /* No resource table */
531 /* Get the resident names table */
533 pModule->name_table = (int)pData - (int)pModule;
534 if (!READ( ne_header.rname_tab_offset,
535 ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
536 pData )) return (HMODULE)11; /* invalid exe */
537 pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
539 /* Get the module references table */
541 if (ne_header.n_mod_ref_tab > 0)
543 pModule->modref_table = (int)pData - (int)pModule;
544 if (!READ( ne_header.moduleref_tab_offset,
545 ne_header.n_mod_ref_tab * sizeof(WORD),
546 pData )) return (HMODULE)11; /* invalid exe */
547 pData += ne_header.n_mod_ref_tab * sizeof(WORD);
549 else pModule->modref_table = 0; /* No module references */
551 /* Get the imported names table */
553 pModule->import_table = (int)pData - (int)pModule;
554 if (!READ( ne_header.iname_tab_offset,
555 ne_header.entry_tab_offset - ne_header.iname_tab_offset,
556 pData )) return (HMODULE)11; /* invalid exe */
557 pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
559 /* Get the entry table */
561 pModule->entry_table = (int)pData - (int)pModule;
562 if (!READ( ne_header.entry_tab_offset,
563 ne_header.entry_tab_length,
564 pData )) return (HMODULE)11; /* invalid exe */
565 pData += ne_header.entry_tab_length;
567 /* Get the non-resident names table */
569 if (ne_header.nrname_tab_length)
571 pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
572 hModule, FALSE, FALSE, FALSE );
573 if (!pModule->nrname_handle) return (HMODULE)11; /* invalid exe */
574 buffer = GlobalLock( pModule->nrname_handle );
575 _llseek( hFile, ne_header.nrname_tab_offset, SEEK_SET );
576 if (FILE_Read( hFile, buffer, ne_header.nrname_tab_length )
577 != ne_header.nrname_tab_length) return (HMODULE)11; /* invalid exe */
579 else pModule->nrname_handle = 0;
581 /* Allocate a segment for the implicitly-loaded DLLs */
583 if (pModule->modref_count)
585 pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
586 (pModule->modref_count+1)*sizeof(HMODULE),
587 hModule, FALSE, FALSE, FALSE );
588 if (!pModule->dlls_to_init) return (HMODULE)11; /* invalid exe */
590 else pModule->dlls_to_init = 0;
592 if (debugging_module) MODULE_PrintModule( hModule );
593 pModule->next = hFirstModule;
594 hFirstModule = hModule;
595 return hModule;
599 /***********************************************************************
600 * MODULE_GetOrdinal
602 * Lookup the ordinal for a given name.
604 WORD MODULE_GetOrdinal( HMODULE hModule, char *name )
606 char buffer[256], *cpnt;
607 BYTE len;
608 NE_MODULE *pModule;
610 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
612 dprintf_module( stddeb, "MODULE_GetOrdinal("NPFMT",'%s')\n",
613 hModule, name );
615 /* First handle names of the form '#xxxx' */
617 if (name[0] == '#') return atoi( name + 1 );
619 /* Now copy and uppercase the string */
621 strcpy( buffer, name );
622 AnsiUpper( buffer );
623 len = strlen( buffer );
625 /* First search the resident names */
627 cpnt = (char *)pModule + pModule->name_table;
629 /* Skip the first entry (module name) */
630 cpnt += *cpnt + 1 + sizeof(WORD);
631 while (*cpnt)
633 dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
634 if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
636 dprintf_module( stddeb, " Found: ordinal=%d\n",
637 *(WORD *)(cpnt + *cpnt + 1) );
638 return *(WORD *)(cpnt + *cpnt + 1);
640 cpnt += *cpnt + 1 + sizeof(WORD);
643 /* Now search the non-resident names table */
645 if (!pModule->nrname_handle) return 0; /* No non-resident table */
646 cpnt = (char *)GlobalLock( pModule->nrname_handle );
648 /* Skip the first entry (module description string) */
649 cpnt += *cpnt + 1 + sizeof(WORD);
650 while (*cpnt)
652 dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
653 if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
655 dprintf_module( stddeb, " Found: ordinal=%d\n",
656 *(WORD *)(cpnt + *cpnt + 1) );
657 return *(WORD *)(cpnt + *cpnt + 1);
659 cpnt += *cpnt + 1 + sizeof(WORD);
661 return 0;
665 /***********************************************************************
666 * MODULE_GetEntryPoint
668 * Return the entry point for a given ordinal.
670 SEGPTR MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal )
672 NE_MODULE *pModule;
673 WORD curOrdinal = 1;
674 BYTE *p;
675 WORD sel, offset;
677 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
679 p = (BYTE *)pModule + pModule->entry_table;
680 while (*p && (curOrdinal + *p <= ordinal))
682 /* Skipping this bundle */
683 curOrdinal += *p;
684 switch(p[1])
686 case 0: p += 2; break; /* unused */
687 case 0xff: p += 2 + *p * 6; break; /* moveable */
688 default: p += 2 + *p * 3; break; /* fixed */
691 if (!*p) return 0;
693 switch(p[1])
695 case 0: /* unused */
696 return 0;
697 case 0xff: /* moveable */
698 p += 2 + 6 * (ordinal - curOrdinal);
699 sel = p[3];
700 offset = *(WORD *)(p + 4);
701 break;
702 default: /* fixed */
703 sel = p[1];
704 p += 2 + 3 * (ordinal - curOrdinal);
705 offset = *(WORD *)(p + 1);
706 break;
709 if (sel == 0xfe) sel = 0xffff; /* constant entry */
710 else sel = (WORD)(DWORD)NE_SEG_TABLE(pModule)[sel-1].selector;
711 return (SEGPTR)MAKELONG( offset, sel );
715 /***********************************************************************
716 * MODULE_SetEntryPoint
718 * Change the value of an entry point. Use with caution!
719 * It can only change the offset value, not the selector.
721 BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset )
723 NE_MODULE *pModule;
724 WORD curOrdinal = 1;
725 BYTE *p;
727 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
729 p = (BYTE *)pModule + pModule->entry_table;
730 while (*p && (curOrdinal + *p <= ordinal))
732 /* Skipping this bundle */
733 curOrdinal += *p;
734 switch(p[1])
736 case 0: p += 2; break; /* unused */
737 case 0xff: p += 2 + *p * 6; break; /* moveable */
738 default: p += 2 + *p * 3; break; /* fixed */
741 if (!*p) return FALSE;
743 switch(p[1])
745 case 0: /* unused */
746 return FALSE;
747 case 0xff: /* moveable */
748 p += 2 + 6 * (ordinal - curOrdinal);
749 *(WORD *)(p + 4) = offset;
750 break;
751 default: /* fixed */
752 p += 2 + 3 * (ordinal - curOrdinal);
753 *(WORD *)(p + 1) = offset;
754 break;
756 return TRUE;
760 /***********************************************************************
761 * MODULE_GetEntryPointName
763 * Return the entry point name for a given ordinal.
764 * Used only by relay debugging.
765 * Warning: returned pointer is to a Pascal-type string.
767 LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal )
769 register char *cpnt;
770 NE_MODULE *pModule;
772 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
774 /* First search the resident names */
776 cpnt = (char *)pModule + pModule->name_table;
777 while (*cpnt)
779 cpnt += *cpnt + 1 + sizeof(WORD);
780 if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
783 /* Now search the non-resident names table */
785 if (!pModule->nrname_handle) return 0; /* No non-resident table */
786 cpnt = (char *)GlobalLock( pModule->nrname_handle );
787 while (*cpnt)
789 cpnt += *cpnt + 1 + sizeof(WORD);
790 if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
792 return NULL;
796 /***********************************************************************
797 * MODULE_GetModuleName
799 LPSTR MODULE_GetModuleName( HMODULE hModule )
801 NE_MODULE *pModule;
802 BYTE *p, len;
803 static char buffer[10];
805 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return NULL;
806 p = (BYTE *)pModule + pModule->name_table;
807 len = MIN( *p, 8 );
808 memcpy( buffer, p + 1, len );
809 buffer[len] = '\0';
810 return buffer;
814 /**********************************************************************
815 * MODULE_RegisterModule
817 void MODULE_RegisterModule( HMODULE hModule )
819 NE_MODULE *pModule;
820 pModule = (NE_MODULE *)GlobalLock( hModule );
821 pModule->next = hFirstModule;
822 hFirstModule = hModule;
825 /**********************************************************************
826 * MODULE_FindModule
828 * Find a module from a path name.
830 HMODULE MODULE_FindModule( LPCSTR path )
832 HMODULE hModule = hFirstModule;
833 LPCSTR filename, dotptr, modulepath, modulename;
834 BYTE len, *name_table;
836 if (!(filename = strrchr( path, '\\' ))) filename = path;
837 else filename++;
838 if ((dotptr = strrchr( filename, '.' )) != NULL)
839 len = (BYTE)(dotptr - filename);
840 else len = strlen( filename );
842 while(hModule)
844 NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
845 if (!pModule) break;
846 modulepath = NE_MODULE_NAME(pModule);
847 if (!(modulename = strrchr( modulepath, '\\' )))
848 modulename = modulepath;
849 else modulename++;
850 if (!lstrcmpi( modulename, filename )) return hModule;
852 name_table = (BYTE *)pModule + pModule->name_table;
853 if ((*name_table == len) && !lstrncmpi(filename, name_table+1, len))
854 return hModule;
855 hModule = pModule->next;
857 return 0;
861 /**********************************************************************
862 * MODULE_FreeModule
864 * Remove a module from memory.
866 static void MODULE_FreeModule( HMODULE hModule )
868 HMODULE *hPrevModule;
869 NE_MODULE *pModule;
870 SEGTABLEENTRY *pSegment;
871 HMODULE *pModRef;
872 int i;
874 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return;
875 if (pModule->flags & NE_FFLAGS_BUILTIN)
876 return; /* Can't free built-in module */
878 /* FIXME: should call the exit code for the library here */
880 /* Remove it from the linked list */
882 hPrevModule = &hFirstModule;
883 while (*hPrevModule && (*hPrevModule != hModule))
885 hPrevModule = &((NE_MODULE *)GlobalLock( *hPrevModule ))->next;
887 if (*hPrevModule) *hPrevModule = pModule->next;
889 /* Free all the segments */
891 pSegment = NE_SEG_TABLE( pModule );
892 for (i = 1; i <= pModule->seg_count; i++, pSegment++)
894 GlobalFree( pSegment->selector );
897 /* Free the referenced modules */
899 pModRef = (HMODULE*)NE_MODULE_TABLE( pModule );
900 for (i = 0; i < pModule->modref_count; i++, pModRef++)
902 FreeModule( *pModRef );
905 /* Free the module storage */
907 if (pModule->nrname_handle) GlobalFree( pModule->nrname_handle );
908 if (pModule->dlls_to_init) GlobalFree( pModule->dlls_to_init );
909 GlobalFree( hModule );
911 /* Remove module from cache */
913 if (hCachedModule == hModule) hCachedModule = 0;
917 /**********************************************************************
918 * LoadModule (KERNEL.45)
920 HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
922 HMODULE hModule;
923 HANDLE hInstance, hPrevInstance;
924 NE_MODULE *pModule;
925 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
926 #ifndef WINELIB
927 WORD *pModRef, *pDLLs;
928 HFILE hFile;
929 int i;
931 hModule = MODULE_FindModule( name );
933 if (!hModule) /* We have to load the module */
935 OFSTRUCT ofs;
937 /* Try to load the built-in first if not disabled */
938 if ((hModule = MODULE_LoadBuiltin( name, FALSE ))) return hModule;
940 if ((hFile = OpenFile( name, &ofs, OF_READ )) == HFILE_ERROR)
942 /* Now try the built-in even if disabled */
943 if ((hModule = MODULE_LoadBuiltin( name, TRUE )))
945 fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
946 return hModule;
948 return 2; /* File not found */
951 /* Create the module structure */
953 hModule = MODULE_LoadExeHeader( hFile, &ofs );
954 if (hModule < 32)
956 /* FIXME: Hack because PE_LoadModule is recursive */
957 int fd = dup( FILE_GetUnixHandle(hFile) );
958 _lclose( hFile );
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 _lclose( hFile );
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 int fd;
1025 /* Handle self loading modules */
1026 SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
1027 SELFLOADHEADER *selfloadheader;
1028 HMODULE hselfload = GetModuleHandle("WINPROCS");
1029 WORD oldss, oldsp, saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
1030 fprintf (stderr, "Warning: %*.*s is a self-loading module\n"
1031 "Support for self-loading modules is very experimental\n",
1032 *((BYTE*)pModule + pModule->name_table),
1033 *((BYTE*)pModule + pModule->name_table),
1034 (char *)pModule + pModule->name_table + 1);
1035 NE_LoadSegment( hModule, 1 );
1036 selfloadheader = (SELFLOADHEADER *)
1037 PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
1038 selfloadheader->EntryAddrProc =
1039 MODULE_GetEntryPoint(hselfload,27);
1040 selfloadheader->MyAlloc = MODULE_GetEntryPoint(hselfload,28);
1041 selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle("KERNEL"),403);
1042 pModule->self_loading_sel = GlobalHandleToSel(
1043 GLOBAL_Alloc (GMEM_ZEROINIT,
1044 0xFF00, hModule, FALSE, FALSE, FALSE)
1046 oldss = IF1632_Saved16_ss;
1047 oldsp = IF1632_Saved16_sp;
1048 IF1632_Saved16_ss = pModule->self_loading_sel;
1049 IF1632_Saved16_sp = 0xFF00;
1050 if (!IF1632_Stack32_base) {
1051 STACK32FRAME* frame32;
1052 char *stack32Top;
1053 /* Setup an initial 32 bit stack frame */
1054 hInitialStack32 = GLOBAL_Alloc( GMEM_FIXED, 0x10000,
1055 hModule, FALSE, FALSE,
1056 FALSE );
1058 /* Create the 32-bit stack frame */
1060 *(DWORD *)GlobalLock(hInitialStack32) = 0xDEADBEEF;
1061 stack32Top = (char*)GlobalLock(hInitialStack32) +
1062 0x10000;
1063 frame32 = (STACK32FRAME *)stack32Top - 1;
1064 frame32->saved_esp = (DWORD)stack32Top;
1065 frame32->edi = 0;
1066 frame32->esi = 0;
1067 frame32->edx = 0;
1068 frame32->ecx = 0;
1069 frame32->ebx = 0;
1070 frame32->ebp = 0;
1071 frame32->retaddr = 0;
1072 frame32->codeselector = WINE_CODE_SELECTOR;
1073 /* pTask->esp = (DWORD)frame32; */
1074 IF1632_Stack32_base = WIN16_GlobalLock(hInitialStack32);
1077 /* FIXME: we probably need a DOS handle here */
1078 fd = MODULE_OpenFile( hModule );
1079 CallTo16_word_ww (selfloadheader->BootApp,
1080 pModule->self_loading_sel, hModule, fd);
1081 /* some BootApp procs overwrite the selector of dgroup */
1082 pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
1083 IF1632_Saved16_ss = oldss;
1084 IF1632_Saved16_sp = oldsp;
1085 for (i = 2; i <= pModule->seg_count; i++) NE_LoadSegment( hModule, i );
1086 if (hInitialStack32){
1087 GlobalUnlock (hInitialStack32);
1088 GlobalFree (hInitialStack32);
1089 IF1632_Stack32_base = hInitialStack32 = 0;
1092 else
1094 for (i = 1; i <= pModule->seg_count; i++)
1095 NE_LoadSegment( hModule, i );
1098 /* Fixup the functions prologs */
1100 NE_FixupPrologs( hModule );
1102 /* Make sure the usage count is 1 on the first loading of */
1103 /* the module, even if it contains circular DLL references */
1105 pModule->count = 1;
1107 /* Clear built-in flag in case it was set in the EXE file */
1109 pModule->flags &= ~NE_FFLAGS_BUILTIN;
1111 else
1113 pModule = (NE_MODULE *)GlobalLock( hModule );
1114 hPrevInstance = MODULE_GetInstance( hModule );
1115 hInstance = MODULE_CreateInstance( hModule, params );
1116 if (hInstance != hPrevInstance) /* not a library */
1117 NE_LoadSegment( hModule, pModule->dgroup );
1118 pModule->count++;
1120 #else
1121 hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(NE_MODULE) );
1122 pModule = (NE_MODULE *)GlobalLock( hModule );
1123 pModule->count = 1;
1124 pModule->magic = 0x454e;
1125 hPrevInstance = 0;
1126 hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
1127 #endif /* WINELIB */
1129 /* Create a task for this instance */
1131 if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
1133 TASK_CreateTask( hModule, hInstance, hPrevInstance,
1134 params->hEnvironment,
1135 (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
1136 *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1) );
1139 return hInstance;
1143 /**********************************************************************
1144 * FreeModule (KERNEL.46)
1146 BOOL FreeModule( HANDLE hModule )
1148 NE_MODULE *pModule;
1150 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1151 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
1153 dprintf_module( stddeb, "FreeModule: %s count %d\n",
1154 MODULE_GetModuleName(hModule), pModule->count );
1155 if (--pModule->count == 0) MODULE_FreeModule( hModule );
1156 return TRUE;
1160 /**********************************************************************
1161 * GetModuleHandle (KERNEL.47)
1163 HMODULE WIN16_GetModuleHandle( SEGPTR name )
1165 #ifdef WINELIB32
1166 if (HIWORD(name) == 0) return GetExePtr( name );
1167 #else
1168 if (HIWORD(name) == 0) return GetExePtr( LOWORD(name) );
1169 #endif
1170 return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
1173 HMODULE GetModuleHandle( LPCSTR name )
1175 return MODULE_FindModule( name );
1179 /**********************************************************************
1180 * GetModuleUsage (KERNEL.48)
1182 int GetModuleUsage( HANDLE hModule )
1184 NE_MODULE *pModule;
1186 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1187 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
1188 dprintf_module( stddeb, "GetModuleUsage("NPFMT"): returning %d\n",
1189 hModule, pModule->count );
1190 return pModule->count;
1194 /**********************************************************************
1195 * GetModuleFileName (KERNEL.49)
1197 int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
1199 NE_MODULE *pModule;
1201 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1202 if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
1203 lstrcpyn( lpFileName, NE_MODULE_NAME(pModule), nSize );
1204 dprintf_module( stddeb, "GetModuleFilename: %s\n", lpFileName );
1205 return strlen(lpFileName);
1209 /***********************************************************************
1210 * LoadLibrary (KERNEL.95)
1212 HANDLE LoadLibrary( LPCSTR libname )
1214 #ifdef WINELIB
1215 dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
1216 WINELIB_UNIMP("LoadLibrary()");
1217 return (HANDLE)0;
1218 #else
1219 HANDLE handle;
1221 dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
1223 /* This does not increment the module reference count, and will
1224 * therefore cause crashes on FreeLibrary calls.
1225 if ((handle = MODULE_FindModule( libname )) != 0) return handle;
1227 handle = LoadModule( libname, (LPVOID)-1 );
1228 if (handle == (HANDLE)2) /* file not found */
1230 char buffer[256];
1231 lstrcpyn( buffer, libname, 252 );
1232 strcat( buffer, ".dll" );
1233 handle = LoadModule( buffer, (LPVOID)-1 );
1235 if (handle >= (HANDLE)32) NE_InitializeDLLs( GetExePtr(handle) );
1236 return handle;
1237 #endif
1241 /***********************************************************************
1242 * FreeLibrary (KERNEL.96)
1244 void FreeLibrary( HANDLE handle )
1246 dprintf_module( stddeb,"FreeLibrary: "NPFMT"\n", handle );
1247 FreeModule( handle );
1251 /***********************************************************************
1252 * WinExec (KERNEL.166)
1254 HANDLE WinExec( LPSTR lpCmdLine, WORD nCmdShow )
1256 LOADPARAMS params;
1257 HLOCAL cmdShowHandle, cmdLineHandle;
1258 HANDLE handle;
1259 WORD *cmdShowPtr;
1260 char *p, *cmdline, filename[256];
1262 if (!(cmdShowHandle = GlobalAlloc( 0, 2 * sizeof(WORD) ))) return 0;
1263 if (!(cmdLineHandle = GlobalAlloc( 0, 256 ))) return 0;
1265 /* Store nCmdShow */
1267 cmdShowPtr = (WORD *)GlobalLock( cmdShowHandle );
1268 cmdShowPtr[0] = 2;
1269 cmdShowPtr[1] = nCmdShow;
1271 /* Build the filename and command-line */
1273 cmdline = (char *)GlobalLock( cmdLineHandle );
1274 strncpy( filename, lpCmdLine, 256 );
1275 filename[255] = '\0';
1276 for (p = filename; *p && (*p != ' ') && (*p != '\t'); p++);
1277 if (*p)
1279 strncpy( cmdline, p + 1, 128 );
1280 cmdline[127] = '\0';
1282 else cmdline[0] = '\0';
1283 *p = '\0';
1285 /* Now load the executable file */
1287 #ifdef WINELIB32
1288 params.hEnvironment = (HANDLE)GetDOSEnvironment();
1289 #else
1290 params.hEnvironment = (HANDLE)SELECTOROF( GetDOSEnvironment() );
1291 #endif
1292 params.cmdLine = (SEGPTR)WIN16_GlobalLock( cmdLineHandle );
1293 params.showCmd = (SEGPTR)WIN16_GlobalLock( cmdShowHandle );
1294 params.reserved = 0;
1295 handle = LoadModule( filename, &params );
1296 if (handle == (HANDLE)2) /* file not found */
1298 /* Check that the original file name did not have a suffix */
1299 p = strrchr(filename, '.');
1300 if (p && !(strchr(p, '/') || strchr(p, '\\')))
1301 return handle; /* filename already includes a suffix! */
1302 strcat( filename, ".exe" );
1303 handle = LoadModule( filename, &params );
1306 GlobalFree( cmdShowHandle );
1307 GlobalFree( cmdLineHandle );
1309 #if 0
1310 if (handle < (HANDLE)32) /* Error? */
1311 return handle;
1313 /* FIXME: Yield never returns!
1314 We may want to run more applications or start the debugger
1315 before calling Yield. If we don't Yield will be called immdiately
1316 after returning. Why is it needed for Word anyway? */
1317 Yield(); /* program is executed immediately ....needed for word */
1319 #endif
1320 return handle;
1324 /***********************************************************************
1325 * GetProcAddress (KERNEL.50)
1327 FARPROC GetProcAddress( HANDLE hModule, SEGPTR name )
1329 WORD ordinal;
1330 SEGPTR ret;
1332 if (!hModule) hModule = GetCurrentTask();
1333 hModule = GetExePtr( hModule );
1335 if (HIWORD(name) != 0)
1337 ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1338 dprintf_module( stddeb, "GetProcAddress: "NPFMT" '%s'\n",
1339 hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1341 else
1343 ordinal = LOWORD(name);
1344 dprintf_module( stddeb, "GetProcAddress: "NPFMT" %04x\n",
1345 hModule, ordinal );
1347 if (!ordinal) return (FARPROC)0;
1349 ret = MODULE_GetEntryPoint( hModule, ordinal );
1351 dprintf_module( stddeb, "GetProcAddress: returning "SPFMT"\n", ret );
1352 return (FARPROC)ret;
1356 /**********************************************************************
1357 * GetExpWinVer (KERNEL.167)
1359 WORD GetExpWinVer( HMODULE hModule )
1361 NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
1363 return pModule->expected_version;
1367 /***********************************************************************
1368 * GetWndProcEntry16 (not a Windows API function)
1370 * Return an entry point from the WINPROCS dll.
1372 #ifndef WINELIB
1373 WNDPROC GetWndProcEntry16( char *name )
1375 WORD ordinal;
1376 static HMODULE hModule = 0;
1378 if (!hModule) hModule = GetModuleHandle( "WINPROCS" );
1379 ordinal = MODULE_GetOrdinal( hModule, name );
1380 return MODULE_GetEntryPoint( hModule, ordinal );
1382 #endif
1385 /**********************************************************************
1386 * ModuleFirst (TOOLHELP.59)
1388 BOOL ModuleFirst( MODULEENTRY *lpme )
1390 lpme->wNext = hFirstModule;
1391 return ModuleNext( lpme );
1395 /**********************************************************************
1396 * ModuleNext (TOOLHELP.60)
1398 BOOL ModuleNext( MODULEENTRY *lpme )
1400 NE_MODULE *pModule;
1402 if (!lpme->wNext) return FALSE;
1403 if (!(pModule = (NE_MODULE *)GlobalLock( lpme->wNext ))) return FALSE;
1404 strncpy( lpme->szModule, (char *)pModule + pModule->name_table,
1405 MAX_MODULE_NAME );
1406 lpme->szModule[MAX_MODULE_NAME] = '\0';
1407 lpme->hModule = lpme->wNext;
1408 lpme->wcUsage = pModule->count;
1409 strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
1410 lpme->szExePath[MAX_PATH] = '\0';
1411 lpme->wNext = pModule->next;
1412 return TRUE;
1416 /**********************************************************************
1417 * ModuleFindName (TOOLHELP.61)
1419 BOOL ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
1421 lpme->wNext = GetModuleHandle( name );
1422 return ModuleNext( lpme );
1426 /**********************************************************************
1427 * ModuleFindHandle (TOOLHELP.62)
1429 BOOL ModuleFindHandle( MODULEENTRY *lpme, HMODULE hModule )
1431 hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
1432 lpme->wNext = hModule;
1433 return ModuleNext( lpme );