4 * Copyright 1995 Alexandre Julliard
11 #include <sys/types.h>
21 #include "stackframe.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 */
36 static HANDLE hInitialStack32
= 0;
38 /***********************************************************************
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.
45 static HMODULE
MODULE_LoadBuiltin( LPCSTR name
, BOOL force
)
49 SEGTABLEENTRY
*pSegTable
;
50 struct dll_table_s
*table
;
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 );
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;
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
;
102 /***********************************************************************
105 * Create the built-in modules.
107 BOOL
MODULE_Init(void)
109 /* For these, built-in modules are always used */
112 if (!MODULE_LoadBuiltin( "KERNEL", TRUE
) ||
113 !MODULE_LoadBuiltin( "GDI", TRUE
) ||
114 !MODULE_LoadBuiltin( "USER", TRUE
) ||
115 !MODULE_LoadBuiltin( "WINPROCS", TRUE
)) return FALSE
;
117 /* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
119 MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
124 /***********************************************************************
127 void MODULE_PrintModule( HMODULE hmodule
)
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
++ );
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
;
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
;
214 printf( "Bundle %d-%d: %02x\n", ordinal
, ordinal
+ *pstr
- 1, pstr
[1]);
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
);
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) );
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
);
246 printf( "%*.*s: %d\n", *pstr
, *pstr
, pstr
+ 1,
247 *(WORD
*)(pstr
+ *pstr
+ 1) );
248 pstr
+= *pstr
+ 1 + sizeof(WORD
);
255 /***********************************************************************
258 int MODULE_OpenFile( HMODULE hModule
)
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
;
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",
278 dprintf_module( stddeb
, "MODULE_OpenFile: opened '%s' -> %d\n",
284 /***********************************************************************
287 * This function translates NE segment flags to GlobalAlloc flags
289 static WORD
MODULE_Ne2MemFlags(WORD flags
)
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
;
304 memflags
= GMEM_ZEROINIT
| GMEM_FIXED
;
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
);
318 return (DWORD
)GlobalLock(hMem
);
320 WORD selector
= HIWORD(GlobalLock(hMem
));
321 return MAKELONG(hMem
, selector
);
325 /***********************************************************************
326 * MODULE_CreateSegments
329 static BOOL
MODULE_CreateSegments( HMODULE hModule
)
331 SEGTABLEENTRY
*pSegment
;
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
),
345 !(pSegment
->flags
& NE_SEGFLAGS_DATA
),
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;
358 /***********************************************************************
362 static HINSTANCE
MODULE_GetInstance( HMODULE hModule
)
364 SEGTABLEENTRY
*pSegment
;
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
;
377 /***********************************************************************
378 * MODULE_CreateInstance
380 HINSTANCE
MODULE_CreateInstance( HMODULE hModule
, LOADPARAMS
*params
)
382 SEGTABLEENTRY
*pSegment
;
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 */
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
;
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
;
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+
450 ne_header
.n_segment_tab
* sizeof(SEGTABLEENTRY
) +
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
) );
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
)
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;
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
) );
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
);
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
;
599 /***********************************************************************
602 * Lookup the ordinal for a given name.
604 WORD
MODULE_GetOrdinal( HMODULE hModule
, char *name
)
606 char buffer
[256], *cpnt
;
610 if (!(pModule
= (NE_MODULE
*)GlobalLock( hModule
))) return 0;
612 dprintf_module( stddeb
, "MODULE_GetOrdinal("NPFMT
",'%s')\n",
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
);
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
);
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
);
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
);
665 /***********************************************************************
666 * MODULE_GetEntryPoint
668 * Return the entry point for a given ordinal.
670 SEGPTR
MODULE_GetEntryPoint( HMODULE hModule
, WORD ordinal
)
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 */
686 case 0: p
+= 2; break; /* unused */
687 case 0xff: p
+= 2 + *p
* 6; break; /* moveable */
688 default: p
+= 2 + *p
* 3; break; /* fixed */
697 case 0xff: /* moveable */
698 p
+= 2 + 6 * (ordinal
- curOrdinal
);
700 offset
= *(WORD
*)(p
+ 4);
704 p
+= 2 + 3 * (ordinal
- curOrdinal
);
705 offset
= *(WORD
*)(p
+ 1);
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
)
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 */
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
;
747 case 0xff: /* moveable */
748 p
+= 2 + 6 * (ordinal
- curOrdinal
);
749 *(WORD
*)(p
+ 4) = offset
;
752 p
+= 2 + 3 * (ordinal
- curOrdinal
);
753 *(WORD
*)(p
+ 1) = offset
;
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
)
772 if (!(pModule
= (NE_MODULE
*)GlobalLock( hModule
))) return 0;
774 /* First search the resident names */
776 cpnt
= (char *)pModule
+ pModule
->name_table
;
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
);
789 cpnt
+= *cpnt
+ 1 + sizeof(WORD
);
790 if (*(WORD
*)(cpnt
+ *cpnt
+ 1) == ordinal
) return cpnt
;
796 /***********************************************************************
797 * MODULE_GetModuleName
799 LPSTR
MODULE_GetModuleName( HMODULE hModule
)
803 static char buffer
[10];
805 if (!(pModule
= (NE_MODULE
*)GlobalLock( hModule
))) return NULL
;
806 p
= (BYTE
*)pModule
+ pModule
->name_table
;
808 memcpy( buffer
, p
+ 1, len
);
814 /**********************************************************************
815 * MODULE_RegisterModule
817 void MODULE_RegisterModule( HMODULE hModule
)
820 pModule
= (NE_MODULE
*)GlobalLock( hModule
);
821 pModule
->next
= hFirstModule
;
822 hFirstModule
= hModule
;
825 /**********************************************************************
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
;
838 if ((dotptr
= strrchr( filename
, '.' )) != NULL
)
839 len
= (BYTE
)(dotptr
- filename
);
840 else len
= strlen( filename
);
844 NE_MODULE
*pModule
= (NE_MODULE
*)GlobalLock( hModule
);
846 modulepath
= NE_MODULE_NAME(pModule
);
847 if (!(modulename
= strrchr( modulepath
, '\\' )))
848 modulename
= modulepath
;
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
))
855 hModule
= pModule
->next
;
861 /**********************************************************************
864 * Remove a module from memory.
866 static void MODULE_FreeModule( HMODULE hModule
)
868 HMODULE
*hPrevModule
;
870 SEGTABLEENTRY
*pSegment
;
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
)
923 HANDLE hInstance
, hPrevInstance
;
925 LOADPARAMS
*params
= (LOADPARAMS
*)paramBlock
;
927 WORD
*pModRef
, *pDLLs
;
931 hModule
= MODULE_FindModule( name
);
933 if (!hModule
) /* We have to load the module */
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
);
948 return 2; /* File not found */
951 /* Create the module structure */
953 hModule
= MODULE_LoadExeHeader( hFile
, &ofs
);
956 /* FIXME: Hack because PE_LoadModule is recursive */
957 int fd
= dup( FILE_GetUnixHandle(hFile
) );
959 if (hModule
== 21) hModule
= PE_LoadModule( fd
, &ofs
, paramBlock
);
962 fprintf( stderr
, "LoadModule: can't load '%s', error=%d\n",
967 pModule
= (NE_MODULE
*)GlobalLock( hModule
);
969 /* Allocate the segments for this module */
971 MODULE_CreateSegments( hModule
);
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
++)
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. */
993 if ((hDLL
= LoadModule( buffer
, (LPVOID
)-1 )) == 2) /* file not found */
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 );
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
)
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
;
1053 /* Setup an initial 32 bit stack frame */
1054 hInitialStack32
= GLOBAL_Alloc( GMEM_FIXED
, 0x10000,
1055 hModule
, FALSE
, FALSE
,
1058 /* Create the 32-bit stack frame */
1060 *(DWORD
*)GlobalLock(hInitialStack32
) = 0xDEADBEEF;
1061 stack32Top
= (char*)GlobalLock(hInitialStack32
) +
1063 frame32
= (STACK32FRAME
*)stack32Top
- 1;
1064 frame32
->saved_esp
= (DWORD
)stack32Top
;
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;
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 */
1107 /* Clear built-in flag in case it was set in the EXE file */
1109 pModule
->flags
&= ~NE_FFLAGS_BUILTIN
;
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
);
1121 hModule
= GlobalAlloc( GMEM_MOVEABLE
| GMEM_ZEROINIT
, sizeof(NE_MODULE
) );
1122 pModule
= (NE_MODULE
*)GlobalLock( hModule
);
1124 pModule
->magic
= 0x454e;
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) );
1143 /**********************************************************************
1144 * FreeModule (KERNEL.46)
1146 BOOL
FreeModule( HANDLE hModule
)
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
);
1160 /**********************************************************************
1161 * GetModuleHandle (KERNEL.47)
1163 HMODULE
WIN16_GetModuleHandle( SEGPTR name
)
1166 if (HIWORD(name
) == 0) return GetExePtr( name
);
1168 if (HIWORD(name
) == 0) return GetExePtr( LOWORD(name
) );
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
)
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
)
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
)
1215 dprintf_module( stddeb
, "LoadLibrary: (%08x) %s\n", (int)libname
, libname
);
1216 WINELIB_UNIMP("LoadLibrary()");
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 */
1231 lstrcpyn( buffer
, libname
, 252 );
1232 strcat( buffer
, ".dll" );
1233 handle
= LoadModule( buffer
, (LPVOID
)-1 );
1235 if (handle
>= (HANDLE
)32) NE_InitializeDLLs( GetExePtr(handle
) );
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
)
1257 HLOCAL cmdShowHandle
, cmdLineHandle
;
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
);
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
++);
1279 strncpy( cmdline
, p
+ 1, 128 );
1280 cmdline
[127] = '\0';
1282 else cmdline
[0] = '\0';
1285 /* Now load the executable file */
1288 params
.hEnvironment
= (HANDLE
)GetDOSEnvironment();
1290 params
.hEnvironment
= (HANDLE
)SELECTOROF( GetDOSEnvironment() );
1292 params
.cmdLine
= (SEGPTR
)WIN16_GlobalLock( cmdLineHandle
);
1293 params
.showCmd
= (SEGPTR
)WIN16_GlobalLock( cmdShowHandle
);
1294 params
.reserved
= 0;
1295 handle
= LoadModule( filename
, ¶ms
);
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
, ¶ms
);
1306 GlobalFree( cmdShowHandle
);
1307 GlobalFree( cmdLineHandle
);
1310 if (handle
< (HANDLE
)32) /* Error? */
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 */
1324 /***********************************************************************
1325 * GetProcAddress (KERNEL.50)
1327 FARPROC
GetProcAddress( HANDLE hModule
, SEGPTR name
)
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
) );
1343 ordinal
= LOWORD(name
);
1344 dprintf_module( stddeb
, "GetProcAddress: "NPFMT
" %04x\n",
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.
1373 WNDPROC
GetWndProcEntry16( char *name
)
1376 static HMODULE hModule
= 0;
1378 if (!hModule
) hModule
= GetModuleHandle( "WINPROCS" );
1379 ordinal
= MODULE_GetOrdinal( hModule
, name
);
1380 return MODULE_GetEntryPoint( hModule
, ordinal
);
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
)
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
,
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
;
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
);