4 * Copyright 1995 Alexandre Julliard
12 #include "wine/winbase16.h"
27 #include "stackframe.h"
31 FARPROC16 (*fnSNOOP16_GetProcAddress16
)(HMODULE16
,DWORD
,FARPROC16
) = NULL
;
32 void (*fnSNOOP16_RegisterDLL
)(NE_MODULE
*,LPCSTR
) = NULL
;
34 #define hFirstModule (pThhook->hExeHead)
36 static NE_MODULE
*pCachedModule
= 0; /* Module cached by NE_OpenFile */
37 static HMODULE16
GetModuleFromPath(LPCSTR name
);
39 static HMODULE16
NE_LoadBuiltin(LPCSTR name
,BOOL force
) { return 0; }
40 HMODULE16 (*fnBUILTIN_LoadModule
)(LPCSTR name
,BOOL force
) = NE_LoadBuiltin
;
43 /***********************************************************************
46 NE_MODULE
*NE_GetPtr( HMODULE16 hModule
)
48 return (NE_MODULE
*)GlobalLock16( GetExePtr(hModule
) );
52 /***********************************************************************
55 void NE_DumpModule( HMODULE16 hModule
)
63 if (!(pModule
= NE_GetPtr( hModule
)))
65 MSG( "**** %04x is not a module handle\n", hModule
);
69 /* Dump the module info */
71 DUMP( "Module %04x:\n", hModule
);
72 DUMP( "count=%d flags=%04x heap=%d stack=%d\n",
73 pModule
->count
, pModule
->flags
,
74 pModule
->heap_size
, pModule
->stack_size
);
75 DUMP( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
76 pModule
->cs
, pModule
->ip
, pModule
->ss
, pModule
->sp
, pModule
->dgroup
,
77 pModule
->seg_count
, pModule
->modref_count
);
78 DUMP( "os_flags=%d swap_area=%d version=%04x\n",
79 pModule
->os_flags
, pModule
->min_swap_area
,
80 pModule
->expected_version
);
81 if (pModule
->flags
& NE_FFLAGS_WIN32
)
82 DUMP( "PE module=%08x\n", pModule
->module32
);
84 /* Dump the file info */
86 DUMP( "Filename: '%s'\n", NE_MODULE_NAME(pModule
) );
88 /* Dump the segment table */
90 DUMP( "Segment table:\n" );
91 pSeg
= NE_SEG_TABLE( pModule
);
92 for (i
= 0; i
< pModule
->seg_count
; i
++, pSeg
++)
93 DUMP( "%02x: pos=%d size=%d flags=%04x minsize=%d hSeg=%04x\n",
94 i
+ 1, pSeg
->filepos
, pSeg
->size
, pSeg
->flags
,
95 pSeg
->minsize
, pSeg
->hSeg
);
97 /* Dump the resource table */
99 DUMP( "Resource table:\n" );
100 if (pModule
->res_table
)
102 pword
= (WORD
*)((BYTE
*)pModule
+ pModule
->res_table
);
103 DUMP( "Alignment: %d\n", *pword
++ );
106 struct resource_typeinfo_s
*ptr
= (struct resource_typeinfo_s
*)pword
;
107 struct resource_nameinfo_s
*pname
= (struct resource_nameinfo_s
*)(ptr
+ 1);
108 DUMP( "id=%04x count=%d\n", ptr
->type_id
, ptr
->count
);
109 for (i
= 0; i
< ptr
->count
; i
++, pname
++)
110 DUMP( "offset=%d len=%d id=%04x\n",
111 pname
->offset
, pname
->length
, pname
->id
);
112 pword
= (WORD
*)pname
;
115 else DUMP( "None\n" );
117 /* Dump the resident name table */
119 DUMP( "Resident-name table:\n" );
120 pstr
= (char *)pModule
+ pModule
->name_table
;
123 DUMP( "%*.*s: %d\n", *pstr
, *pstr
, pstr
+ 1,
124 *(WORD
*)(pstr
+ *pstr
+ 1) );
125 pstr
+= *pstr
+ 1 + sizeof(WORD
);
128 /* Dump the module reference table */
130 DUMP( "Module ref table:\n" );
131 if (pModule
->modref_table
)
133 pword
= (WORD
*)((BYTE
*)pModule
+ pModule
->modref_table
);
134 for (i
= 0; i
< pModule
->modref_count
; i
++, pword
++)
137 GetModuleName16( *pword
, name
, sizeof(name
) );
138 DUMP( "%d: %04x -> '%s'\n", i
, *pword
, name
);
141 else DUMP( "None\n" );
143 /* Dump the entry table */
145 DUMP( "Entry table:\n" );
146 pstr
= (char *)pModule
+ pModule
->entry_table
;
150 DUMP( "Bundle %d-%d: %02x\n", ordinal
, ordinal
+ *pstr
- 1, pstr
[1]);
156 else if ((BYTE
)pstr
[1] == 0xff) /* moveable */
162 DUMP( "%d: %02x:%04x (moveable)\n",
163 ordinal
++, pstr
[3], *(WORD
*)(pstr
+ 4) );
173 DUMP( "%d: %04x (fixed)\n",
174 ordinal
++, *(WORD
*)(pstr
+ 1) );
180 /* Dump the non-resident names table */
182 DUMP( "Non-resident names table:\n" );
183 if (pModule
->nrname_handle
)
185 pstr
= (char *)GlobalLock16( pModule
->nrname_handle
);
188 DUMP( "%*.*s: %d\n", *pstr
, *pstr
, pstr
+ 1,
189 *(WORD
*)(pstr
+ *pstr
+ 1) );
190 pstr
+= *pstr
+ 1 + sizeof(WORD
);
197 /***********************************************************************
200 * Walk the module list and print the modules.
202 void NE_WalkModules(void)
204 HMODULE16 hModule
= hFirstModule
;
205 MSG( "Module Flags Name\n" );
208 NE_MODULE
*pModule
= NE_GetPtr( hModule
);
211 MSG( "Bad module %04x in list\n", hModule
);
214 MSG( " %04x %04x %.*s\n", hModule
, pModule
->flags
,
215 *((char *)pModule
+ pModule
->name_table
),
216 (char *)pModule
+ pModule
->name_table
+ 1 );
217 hModule
= pModule
->next
;
222 /**********************************************************************
225 void NE_RegisterModule( NE_MODULE
*pModule
)
227 pModule
->next
= hFirstModule
;
228 hFirstModule
= pModule
->self
;
232 /***********************************************************************
235 * Lookup the ordinal for a given name.
237 WORD
NE_GetOrdinal( HMODULE16 hModule
, const char *name
)
239 unsigned char buffer
[256], *cpnt
;
243 if (!(pModule
= NE_GetPtr( hModule
))) return 0;
244 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
246 TRACE( module
, "(%04x,'%s')\n", hModule
, name
);
248 /* First handle names of the form '#xxxx' */
250 if (name
[0] == '#') return atoi( name
+ 1 );
252 /* Now copy and uppercase the string */
254 strcpy( buffer
, name
);
255 CharUpperA( buffer
);
256 len
= strlen( buffer
);
258 /* First search the resident names */
260 cpnt
= (char *)pModule
+ pModule
->name_table
;
262 /* Skip the first entry (module name) */
263 cpnt
+= *cpnt
+ 1 + sizeof(WORD
);
266 if (((BYTE
)*cpnt
== len
) && !memcmp( cpnt
+1, buffer
, len
))
268 TRACE(module
, " Found: ordinal=%d\n",
269 *(WORD
*)(cpnt
+ *cpnt
+ 1) );
270 return *(WORD
*)(cpnt
+ *cpnt
+ 1);
272 cpnt
+= *cpnt
+ 1 + sizeof(WORD
);
275 /* Now search the non-resident names table */
277 if (!pModule
->nrname_handle
) return 0; /* No non-resident table */
278 cpnt
= (char *)GlobalLock16( pModule
->nrname_handle
);
280 /* Skip the first entry (module description string) */
281 cpnt
+= *cpnt
+ 1 + sizeof(WORD
);
284 if (((BYTE
)*cpnt
== len
) && !memcmp( cpnt
+1, buffer
, len
))
286 TRACE(module
, " Found: ordinal=%d\n",
287 *(WORD
*)(cpnt
+ *cpnt
+ 1) );
288 return *(WORD
*)(cpnt
+ *cpnt
+ 1);
290 cpnt
+= *cpnt
+ 1 + sizeof(WORD
);
296 /***********************************************************************
297 * NE_GetEntryPoint (WPROCS.27)
299 * Return the entry point for a given ordinal.
301 FARPROC16
NE_GetEntryPoint( HMODULE16 hModule
, WORD ordinal
)
303 return NE_GetEntryPointEx( hModule
, ordinal
, TRUE
);
305 FARPROC16
NE_GetEntryPointEx( HMODULE16 hModule
, WORD ordinal
, BOOL16 snoop
)
312 if (!(pModule
= NE_GetPtr( hModule
))) return 0;
313 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
315 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
316 while (*p
&& (curOrdinal
+ *p
<= ordinal
))
318 /* Skipping this bundle */
322 case 0: p
+= 2; break; /* unused */
323 case 0xff: p
+= 2 + *p
* 6; break; /* moveable */
324 default: p
+= 2 + *p
* 3; break; /* fixed */
333 case 0xff: /* moveable */
334 p
+= 2 + 6 * (ordinal
- curOrdinal
);
336 offset
= *(WORD
*)(p
+ 4);
340 p
+= 2 + 3 * (ordinal
- curOrdinal
);
341 offset
= *(WORD
*)(p
+ 1);
345 if (sel
== 0xfe) sel
= 0xffff; /* constant entry */
346 else sel
= GlobalHandleToSel16(NE_SEG_TABLE(pModule
)[sel
-1].hSeg
);
348 return (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( sel
, offset
);
349 if (!snoop
|| !fnSNOOP16_GetProcAddress16
)
350 return (FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( sel
, offset
);
352 return (FARPROC16
)fnSNOOP16_GetProcAddress16(hModule
,ordinal
,(FARPROC16
)PTR_SEG_OFF_TO_SEGPTR( sel
, offset
));
356 /***********************************************************************
359 * Change the value of an entry point. Use with caution!
360 * It can only change the offset value, not the selector.
362 BOOL16
NE_SetEntryPoint( HMODULE16 hModule
, WORD ordinal
, WORD offset
)
368 if (!(pModule
= NE_GetPtr( hModule
))) return FALSE
;
369 assert( !(pModule
->flags
& NE_FFLAGS_WIN32
) );
371 p
= (BYTE
*)pModule
+ pModule
->entry_table
;
372 while (*p
&& (curOrdinal
+ *p
<= ordinal
))
374 /* Skipping this bundle */
378 case 0: p
+= 2; break; /* unused */
379 case 0xff: p
+= 2 + *p
* 6; break; /* moveable */
380 default: p
+= 2 + *p
* 3; break; /* fixed */
383 if (!*p
) return FALSE
;
389 case 0xff: /* moveable */
390 p
+= 2 + 6 * (ordinal
- curOrdinal
);
391 *(WORD
*)(p
+ 4) = offset
;
394 p
+= 2 + 3 * (ordinal
- curOrdinal
);
395 *(WORD
*)(p
+ 1) = offset
;
402 /***********************************************************************
405 HANDLE
NE_OpenFile( NE_MODULE
*pModule
)
409 static HANDLE cachedfd
= -1;
411 TRACE( module
, "(%p) cache: mod=%p fd=%d\n",
412 pModule
, pCachedModule
, cachedfd
);
413 if (pCachedModule
== pModule
) return cachedfd
;
414 CloseHandle( cachedfd
);
415 pCachedModule
= pModule
;
416 name
= NE_MODULE_NAME( pModule
);
417 if ((cachedfd
= CreateFileA( name
, GENERIC_READ
, FILE_SHARE_READ
,
418 NULL
, OPEN_EXISTING
, 0, -1 )) == -1)
419 MSG( "Can't open file '%s' for module %04x\n", name
, pModule
->self
);
421 /* FIXME: should not be necessary */
422 cachedfd
= ConvertToGlobalHandle(cachedfd
);
423 TRACE(module
, "opened '%s' -> %d\n",
429 /***********************************************************************
432 static HMODULE16
NE_LoadExeHeader( HFILE16 hFile
, OFSTRUCT
*ofs
)
434 IMAGE_DOS_HEADER mz_header
;
435 IMAGE_OS2_HEADER ne_header
;
440 char *buffer
, *fastload
= NULL
;
441 int fastload_offset
= 0, fastload_length
= 0;
443 /* Read a block from either the file or the fast-load area. */
444 #define READ(offset,size,buffer) \
445 ((fastload && ((offset) >= fastload_offset) && \
446 ((offset)+(size) <= fastload_offset+fastload_length)) ? \
447 (memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
448 (_llseek16( hFile, (offset), SEEK_SET), \
449 _hread16( hFile, (buffer), (size) ) == (size)))
451 _llseek16( hFile
, 0, SEEK_SET
);
452 if ((_hread16(hFile
,&mz_header
,sizeof(mz_header
)) != sizeof(mz_header
)) ||
453 (mz_header
.e_magic
!= IMAGE_DOS_SIGNATURE
))
454 return (HMODULE16
)11; /* invalid exe */
456 _llseek16( hFile
, mz_header
.e_lfanew
, SEEK_SET
);
457 if (_hread16( hFile
, &ne_header
, sizeof(ne_header
) ) != sizeof(ne_header
))
458 return (HMODULE16
)11; /* invalid exe */
460 if (ne_header
.ne_magic
== IMAGE_NT_SIGNATURE
) return (HMODULE16
)21; /* win32 exe */
461 if (ne_header
.ne_magic
!= IMAGE_OS2_SIGNATURE
) return (HMODULE16
)11; /* invalid exe */
463 if (ne_header
.ne_magic
== IMAGE_OS2_SIGNATURE_LX
) {
464 MSG("Sorry, this is an OS/2 linear executable (LX) file !\n");
465 return (HMODULE16
)12;
468 /* We now have a valid NE header */
470 size
= sizeof(NE_MODULE
) +
472 ne_header
.n_segment_tab
* sizeof(SEGTABLEENTRY
) +
474 ne_header
.rname_tab_offset
- ne_header
.resource_tab_offset
+
475 /* resident names table */
476 ne_header
.moduleref_tab_offset
- ne_header
.rname_tab_offset
+
477 /* module ref table */
478 ne_header
.n_mod_ref_tab
* sizeof(WORD
) +
479 /* imported names table */
480 ne_header
.entry_tab_offset
- ne_header
.iname_tab_offset
+
481 /* entry table length */
482 ne_header
.entry_tab_length
+
483 /* loaded file info */
484 sizeof(OFSTRUCT
)-sizeof(ofs
->szPathName
)+strlen(ofs
->szPathName
)+1;
486 hModule
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, size
);
487 if (!hModule
) return (HMODULE16
)11; /* invalid exe */
488 FarSetOwner16( hModule
, hModule
);
489 pModule
= (NE_MODULE
*)GlobalLock16( hModule
);
490 memcpy( pModule
, &ne_header
, sizeof(ne_header
) );
492 /* check *programs* for default minimal stack size */
493 if ( (!(pModule
->flags
& NE_FFLAGS_LIBMODULE
))
494 && (pModule
->stack_size
< 0x1400) )
495 pModule
->stack_size
= 0x1400;
496 pModule
->module32
= 0;
497 pModule
->self
= hModule
;
498 pModule
->self_loading_sel
= 0;
499 pData
= (BYTE
*)(pModule
+ 1);
501 /* Clear internal Wine flags in case they are set in the EXE file */
503 pModule
->flags
&= ~(NE_FFLAGS_BUILTIN
| NE_FFLAGS_WIN32
);
505 /* Read the fast-load area */
507 if (ne_header
.additional_flags
& NE_AFLAGS_FASTLOAD
)
509 fastload_offset
=ne_header
.fastload_offset
<<ne_header
.align_shift_count
;
510 fastload_length
=ne_header
.fastload_length
<<ne_header
.align_shift_count
;
511 TRACE(module
, "Using fast-load area offset=%x len=%d\n",
512 fastload_offset
, fastload_length
);
513 if ((fastload
= HeapAlloc( SystemHeap
, 0, fastload_length
)) != NULL
)
515 _llseek16( hFile
, fastload_offset
, SEEK_SET
);
516 if (_hread16(hFile
, fastload
, fastload_length
) != fastload_length
)
518 HeapFree( SystemHeap
, 0, fastload
);
519 WARN( module
, "Error reading fast-load area!\n");
525 /* Get the segment table */
527 pModule
->seg_table
= (int)pData
- (int)pModule
;
528 buffer
= HeapAlloc( SystemHeap
, 0, ne_header
.n_segment_tab
*
529 sizeof(struct ne_segment_table_entry_s
));
533 struct ne_segment_table_entry_s
*pSeg
;
535 if (!READ( mz_header
.e_lfanew
+ ne_header
.segment_tab_offset
,
536 ne_header
.n_segment_tab
* sizeof(struct ne_segment_table_entry_s
),
539 HeapFree( SystemHeap
, 0, buffer
);
540 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
541 GlobalFree16( hModule
);
542 return (HMODULE16
)11; /* invalid exe */
544 pSeg
= (struct ne_segment_table_entry_s
*)buffer
;
545 for (i
= ne_header
.n_segment_tab
; i
> 0; i
--, pSeg
++)
547 memcpy( pData
, pSeg
, sizeof(*pSeg
) );
548 pData
+= sizeof(SEGTABLEENTRY
);
550 HeapFree( SystemHeap
, 0, buffer
);
554 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
555 GlobalFree16( hModule
);
556 return (HMODULE16
)11; /* invalid exe */
559 /* Get the resource table */
561 if (ne_header
.resource_tab_offset
< ne_header
.rname_tab_offset
)
563 pModule
->res_table
= (int)pData
- (int)pModule
;
564 if (!READ(mz_header
.e_lfanew
+ ne_header
.resource_tab_offset
,
565 ne_header
.rname_tab_offset
- ne_header
.resource_tab_offset
,
566 pData
)) return (HMODULE16
)11; /* invalid exe */
567 pData
+= ne_header
.rname_tab_offset
- ne_header
.resource_tab_offset
;
568 NE_InitResourceHandler( hModule
);
570 else pModule
->res_table
= 0; /* No resource table */
572 /* Get the resident names table */
574 pModule
->name_table
= (int)pData
- (int)pModule
;
575 if (!READ( mz_header
.e_lfanew
+ ne_header
.rname_tab_offset
,
576 ne_header
.moduleref_tab_offset
- ne_header
.rname_tab_offset
,
579 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
580 GlobalFree16( hModule
);
581 return (HMODULE16
)11; /* invalid exe */
583 pData
+= ne_header
.moduleref_tab_offset
- ne_header
.rname_tab_offset
;
585 /* Get the module references table */
587 if (ne_header
.n_mod_ref_tab
> 0)
589 pModule
->modref_table
= (int)pData
- (int)pModule
;
590 if (!READ( mz_header
.e_lfanew
+ ne_header
.moduleref_tab_offset
,
591 ne_header
.n_mod_ref_tab
* sizeof(WORD
),
594 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
595 GlobalFree16( hModule
);
596 return (HMODULE16
)11; /* invalid exe */
598 pData
+= ne_header
.n_mod_ref_tab
* sizeof(WORD
);
600 else pModule
->modref_table
= 0; /* No module references */
602 /* Get the imported names table */
604 pModule
->import_table
= (int)pData
- (int)pModule
;
605 if (!READ( mz_header
.e_lfanew
+ ne_header
.iname_tab_offset
,
606 ne_header
.entry_tab_offset
- ne_header
.iname_tab_offset
,
609 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
610 GlobalFree16( hModule
);
611 return (HMODULE16
)11; /* invalid exe */
613 pData
+= ne_header
.entry_tab_offset
- ne_header
.iname_tab_offset
;
615 /* Get the entry table */
617 pModule
->entry_table
= (int)pData
- (int)pModule
;
618 if (!READ( mz_header
.e_lfanew
+ ne_header
.entry_tab_offset
,
619 ne_header
.entry_tab_length
,
622 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
623 GlobalFree16( hModule
);
624 return (HMODULE16
)11; /* invalid exe */
626 pData
+= ne_header
.entry_tab_length
;
628 /* Store the filename information */
630 pModule
->fileinfo
= (int)pData
- (int)pModule
;
631 size
= sizeof(OFSTRUCT
)-sizeof(ofs
->szPathName
)+strlen(ofs
->szPathName
)+1;
632 memcpy( pData
, ofs
, size
);
633 ((OFSTRUCT
*)pData
)->cBytes
= size
- 1;
636 /* Free the fast-load area */
639 if (fastload
) HeapFree( SystemHeap
, 0, fastload
);
641 /* Get the non-resident names table */
643 if (ne_header
.nrname_tab_length
)
645 pModule
->nrname_handle
= GLOBAL_Alloc( 0, ne_header
.nrname_tab_length
,
646 hModule
, FALSE
, FALSE
, FALSE
);
647 if (!pModule
->nrname_handle
)
649 GlobalFree16( hModule
);
650 return (HMODULE16
)11; /* invalid exe */
652 buffer
= GlobalLock16( pModule
->nrname_handle
);
653 _llseek16( hFile
, ne_header
.nrname_tab_offset
, SEEK_SET
);
654 if (_hread16( hFile
, buffer
, ne_header
.nrname_tab_length
)
655 != ne_header
.nrname_tab_length
)
657 GlobalFree16( pModule
->nrname_handle
);
658 GlobalFree16( hModule
);
659 return (HMODULE16
)11; /* invalid exe */
662 else pModule
->nrname_handle
= 0;
664 /* Allocate a segment for the implicitly-loaded DLLs */
666 if (pModule
->modref_count
)
668 pModule
->dlls_to_init
= GLOBAL_Alloc(GMEM_ZEROINIT
,
669 (pModule
->modref_count
+1)*sizeof(HMODULE16
),
670 hModule
, FALSE
, FALSE
, FALSE
);
671 if (!pModule
->dlls_to_init
)
673 if (pModule
->nrname_handle
) GlobalFree16( pModule
->nrname_handle
);
674 GlobalFree16( hModule
);
675 return (HMODULE16
)11; /* invalid exe */
678 else pModule
->dlls_to_init
= 0;
680 NE_RegisterModule( pModule
);
681 if (fnSNOOP16_RegisterDLL
)
682 fnSNOOP16_RegisterDLL(pModule
,ofs
->szPathName
);
687 /***********************************************************************
690 * Load all DLLs implicitly linked to a module.
692 static BOOL
NE_LoadDLLs( NE_MODULE
*pModule
)
695 WORD
*pModRef
= (WORD
*)((char *)pModule
+ pModule
->modref_table
);
696 WORD
*pDLLs
= (WORD
*)GlobalLock16( pModule
->dlls_to_init
);
698 for (i
= 0; i
< pModule
->modref_count
; i
++, pModRef
++)
701 BYTE
*pstr
= (BYTE
*)pModule
+ pModule
->import_table
+ *pModRef
;
702 memcpy( buffer
, pstr
+ 1, *pstr
);
703 *(buffer
+ *pstr
) = 0; /* terminate it */
704 if (!strchr(buffer
,'.')) /* only append .dll if no extension yet.
705 handles a request for krnl386.exe*/
706 strcpy( buffer
+ *pstr
, ".dll" );
707 TRACE(module
, "Loading '%s'\n", buffer
);
708 if (!(*pModRef
= GetModuleHandle16( buffer
)))
710 /* If the DLL is not loaded yet, load it and store */
711 /* its handle in the list of DLLs to initialize. */
714 if ((hDLL
= NE_LoadModule( buffer
, TRUE
)) == 2)
719 /* Try with prepending the path of the current module */
720 GetModuleFileName16( pModule
->self
, buffer
, sizeof(buffer
) );
721 if (!(p
= strrchr( buffer
, '\\' ))) p
= buffer
;
722 memcpy( p
+ 1, pstr
+ 1, *pstr
);
723 strcpy( p
+ 1 + *pstr
, ".dll" );
724 hDLL
= NE_LoadModule( buffer
, TRUE
);
728 /* FIXME: cleanup what was done */
730 MSG( "Could not load '%s' required by '%.*s', error=%d\n",
731 buffer
, *((BYTE
*)pModule
+ pModule
->name_table
),
732 (char *)pModule
+ pModule
->name_table
+ 1, hDLL
);
735 *pModRef
= GetExePtr( hDLL
);
738 else /* Increment the reference count of the DLL */
740 NE_MODULE
*pOldDLL
= NE_GetPtr( *pModRef
);
741 if (pOldDLL
) pOldDLL
->count
++;
748 /**********************************************************************
751 * Load first instance of NE module from file.
752 * (Note: caller is responsible for ensuring the module isn't
755 static HINSTANCE16
NE_LoadFileModule( HFILE16 hFile
, OFSTRUCT
*ofs
,
758 HINSTANCE16 hInstance
;
762 /* Create the module structure */
764 hModule
= NE_LoadExeHeader( hFile
, ofs
);
765 if (hModule
< 32) return hModule
;
766 pModule
= NE_GetPtr( hModule
);
768 /* Allocate the segments for this module */
770 if (!NE_CreateSegments( pModule
) ||
771 !(hInstance
= NE_CreateInstance( pModule
, NULL
, FALSE
)))
773 GlobalFreeAll16( hModule
);
774 return 8; /* Insufficient memory */
777 /* Load the referenced DLLs */
779 if (!NE_LoadDLLs( pModule
))
780 return 2; /* File not found (FIXME: free everything) */
782 /* Load the segments */
784 NE_LoadAllSegments( pModule
);
786 /* Fixup the functions prologs */
788 NE_FixupPrologs( pModule
);
790 /* Make sure the usage count is 1 on the first loading of */
791 /* the module, even if it contains circular DLL references */
795 /* Call initialization rountines for all loaded DLLs. Note that
796 * when we load implicitly linked DLLs this will be done by InitTask().
799 if (!implicit
&& (pModule
->flags
& NE_FFLAGS_LIBMODULE
))
800 NE_InitializeDLLs( hModule
);
805 /**********************************************************************
808 * Load first instance of NE module, deciding whether to use
809 * built-in module or load module from file.
810 * (Note: caller is responsible for ensuring the module isn't
813 HINSTANCE16
NE_LoadModule( LPCSTR name
, BOOL implicit
)
815 HINSTANCE16 hInstance
;
820 /* Try to load the built-in first if not disabled */
822 if ((hModule
= fnBUILTIN_LoadModule( name
, FALSE
))) return hModule
;
824 if ((hFile
= OpenFile16( name
, &ofs
, OF_READ
)) == HFILE_ERROR16
)
826 /* Now try the built-in even if disabled */
827 if ((hModule
= fnBUILTIN_LoadModule( name
, TRUE
)))
829 MSG( "Could not load Windows DLL '%s', using built-in module.\n",
833 return 2; /* File not found */
836 hInstance
= NE_LoadFileModule( hFile
, &ofs
, implicit
);
842 /**********************************************************************
843 * LoadModule16 (KERNEL.45)
845 HINSTANCE16 WINAPI
LoadModule16( LPCSTR name
, LPVOID paramBlock
)
847 BOOL lib_only
= !paramBlock
|| (paramBlock
== (LPVOID
)-1);
848 LOADPARAMS16
*params
;
849 LPSTR cmd_line
, new_cmd_line
;
851 STARTUPINFOA startup
;
852 PROCESS_INFORMATION info
;
853 HINSTANCE16 hInstance
, hPrevInstance
= 0;
860 if ( (hModule
= GetModuleFromPath(name
) ) != 0 )
862 /* Special case: second instance of an already loaded NE module */
864 if ( !( pModule
= NE_GetPtr( hModule
) ) ) return (HINSTANCE16
)11;
865 if ( pModule
->module32
) return (HINSTANCE16
)21;
867 hInstance
= NE_CreateInstance( pModule
, &hPrevInstance
, lib_only
);
868 if ( hInstance
!= hPrevInstance
) /* not a library */
869 NE_LoadSegment( pModule
, pModule
->dgroup
);
875 /* Main case: load first instance of NE module */
877 if ( (hInstance
= NE_LoadModule( name
, FALSE
)) < 32 );
880 if ( !(pModule
= NE_GetPtr( hInstance
)) )
881 return (HINSTANCE16
)11;
884 /* If library module, we're finished */
886 if ( ( pModule
->flags
& NE_FFLAGS_LIBMODULE
) || lib_only
)
889 /* Create a task for this instance */
891 pModule
->flags
|= NE_FFLAGS_GUI
; /* FIXME: is this necessary? */
893 params
= (LOADPARAMS16
*)paramBlock
;
894 cmd_line
= (LPSTR
)PTR_SEG_TO_LIN( params
->cmdLine
);
895 if (!cmd_line
) cmd_line
= "";
896 else if (*cmd_line
) cmd_line
++; /* skip the length byte */
898 if (!(new_cmd_line
= HeapAlloc( GetProcessHeap(), 0,
899 strlen(cmd_line
)+strlen(name
)+2 )))
901 strcpy( new_cmd_line
, name
);
902 strcat( new_cmd_line
, " " );
903 strcat( new_cmd_line
, cmd_line
);
905 if (params
->hEnvironment
) env
= GlobalLock16( params
->hEnvironment
);
907 memset( &info
, '\0', sizeof(info
) );
908 memset( &startup
, '\0', sizeof(startup
) );
909 startup
.cb
= sizeof(startup
);
912 startup
.dwFlags
= STARTF_USESHOWWINDOW
;
913 startup
.wShowWindow
= ((UINT16
*)PTR_SEG_TO_LIN(params
->showCmd
))[1];
916 pdb
= PROCESS_Create( pModule
, new_cmd_line
, env
,
917 hInstance
, hPrevInstance
, TRUE
, &startup
, &info
);
919 CloseHandle( info
.hThread
);
920 CloseHandle( info
.hProcess
);
922 if (params
->hEnvironment
) GlobalUnlock16( params
->hEnvironment
);
923 HeapFree( GetProcessHeap(), 0, new_cmd_line
);
927 if (pdb
) TASK_StartTask( pdb
->task
);
932 /**********************************************************************
935 BOOL
NE_CreateProcess( HFILE hFile
, OFSTRUCT
*ofs
, LPCSTR cmd_line
,
936 LPCSTR env
, BOOL inherit
, LPSTARTUPINFOA startup
,
937 LPPROCESS_INFORMATION info
)
939 HINSTANCE16 hInstance
, hPrevInstance
= 0;
944 /* Special case: second instance of an already loaded NE module */
946 if ( ( hModule
= GetModuleFromPath( ofs
->szPathName
) ) != 0 )
948 if ( !( pModule
= NE_GetPtr( hModule
) )
949 || ( pModule
->flags
& NE_FFLAGS_LIBMODULE
)
950 || pModule
->module32
)
952 SetLastError( ERROR_BAD_FORMAT
);
956 hInstance
= NE_CreateInstance( pModule
, &hPrevInstance
, FALSE
);
957 if ( hInstance
!= hPrevInstance
) /* not a library */
958 NE_LoadSegment( pModule
, pModule
->dgroup
);
963 /* Main case: load first instance of NE module */
966 /* If we didn't get a file handle, return */
968 if ( hFile
== HFILE_ERROR
)
971 /* Allocate temporary HFILE16 for NE_LoadFileModule */
973 if (!DuplicateHandle( GetCurrentProcess(), hFile
,
974 GetCurrentProcess(), &hFile
,
975 0, FALSE
, DUPLICATE_SAME_ACCESS
))
977 SetLastError( ERROR_INVALID_HANDLE
);
980 hFile16
= FILE_AllocDosHandle( hFile
);
984 hInstance
= NE_LoadFileModule( hFile16
, ofs
, TRUE
);
985 _lclose16( hFile16
);
987 if ( hInstance
< 32 )
989 SetLastError( hInstance
);
993 if ( !( pModule
= NE_GetPtr( hInstance
) )
994 || ( pModule
->flags
& NE_FFLAGS_LIBMODULE
) )
997 SetLastError( ERROR_BAD_FORMAT
);
1002 /* Create a task for this instance */
1004 pModule
->flags
|= NE_FFLAGS_GUI
; /* FIXME: is this necessary? */
1006 if ( !PROCESS_Create( pModule
, cmd_line
, env
,
1007 hInstance
, hPrevInstance
, inherit
, startup
, info
) )
1013 /***********************************************************************
1014 * LoadLibrary16 (KERNEL.95)
1016 HINSTANCE16 WINAPI
LoadLibrary16( LPCSTR libname
)
1018 char dllname
[256], *p
;
1020 TRACE( module
, "(%08x) %s\n", (int)libname
, libname
);
1022 /* Append .DLL to name if no extension present */
1024 strcpy( dllname
, libname
);
1025 if (!(p
= strrchr( dllname
, '.')) || strchr( p
, '/' ) || strchr( p
, '\\'))
1026 strcat( dllname
, ".DLL" );
1028 /* Load library module */
1030 return LoadModule16( dllname
, (LPVOID
)-1 );
1034 /**********************************************************************
1037 * Call a DLL's WEP, allowing it to shut down.
1038 * FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
1040 static BOOL16
MODULE_CallWEP( HMODULE16 hModule
)
1042 FARPROC16 WEP
= (FARPROC16
)0;
1043 WORD ordinal
= NE_GetOrdinal( hModule
, "WEP" );
1045 if (ordinal
) WEP
= NE_GetEntryPoint( hModule
, ordinal
);
1048 WARN(module
, "module %04x doesn't have a WEP\n", hModule
);
1051 return Callbacks
->CallWindowsExitProc( WEP
, WEP_FREE_DLL
);
1055 /**********************************************************************
1058 * Implementation of FreeModule16().
1060 static BOOL16
NE_FreeModule( HMODULE16 hModule
, BOOL call_wep
)
1062 HMODULE16
*hPrevModule
;
1067 if (!(pModule
= NE_GetPtr( hModule
))) return FALSE
;
1068 hModule
= pModule
->self
;
1070 TRACE( module
, "%04x count %d\n", hModule
, pModule
->count
);
1072 if (((INT16
)(--pModule
->count
)) > 0 ) return TRUE
;
1073 else pModule
->count
= 0;
1075 if (pModule
->flags
& NE_FFLAGS_BUILTIN
)
1076 return FALSE
; /* Can't free built-in module */
1080 if (pModule
->flags
& NE_FFLAGS_LIBMODULE
)
1082 TDB
*pTask
= (TDB
*)GlobalLock16( GetCurrentTask() );
1083 MODULE_CallWEP( hModule
);
1085 /* Free the objects owned by the DLL module */
1087 if (pTask
&& pTask
->userhandler
)
1088 pTask
->userhandler( hModule
, USIG_DLL_UNLOAD
, 0,
1089 pTask
->hInstance
, pTask
->hQueue
);
1092 call_wep
= FALSE
; /* We are freeing a task -> no more WEPs */
1096 /* Clear magic number just in case */
1098 pModule
->magic
= pModule
->self
= 0;
1100 /* Remove it from the linked list */
1102 hPrevModule
= &hFirstModule
;
1103 while (*hPrevModule
&& (*hPrevModule
!= hModule
))
1105 hPrevModule
= &(NE_GetPtr( *hPrevModule
))->next
;
1107 if (*hPrevModule
) *hPrevModule
= pModule
->next
;
1109 /* Free the referenced modules */
1111 pModRef
= (HMODULE16
*)NE_MODULE_TABLE( pModule
);
1112 for (i
= 0; i
< pModule
->modref_count
; i
++, pModRef
++)
1114 NE_FreeModule( *pModRef
, call_wep
);
1117 /* Free the module storage */
1119 GlobalFreeAll16( hModule
);
1121 /* Remove module from cache */
1123 if (pCachedModule
== pModule
) pCachedModule
= NULL
;
1128 /**********************************************************************
1129 * FreeModule16 (KERNEL.46)
1131 BOOL16 WINAPI
FreeModule16( HMODULE16 hModule
)
1133 return NE_FreeModule( hModule
, TRUE
);
1137 /***********************************************************************
1138 * FreeLibrary16 (KERNEL.96)
1140 void WINAPI
FreeLibrary16( HINSTANCE16 handle
)
1142 TRACE(module
,"%04x\n", handle
);
1143 FreeModule16( handle
);
1147 /**********************************************************************
1148 * GetModuleName (KERNEL.27)
1150 BOOL16 WINAPI
GetModuleName16( HINSTANCE16 hinst
, LPSTR buf
, INT16 count
)
1155 if (!(pModule
= NE_GetPtr( hinst
))) return FALSE
;
1156 p
= (BYTE
*)pModule
+ pModule
->name_table
;
1157 if (count
> *p
) count
= *p
+ 1;
1160 memcpy( buf
, p
+ 1, count
- 1 );
1161 buf
[count
-1] = '\0';
1167 /**********************************************************************
1168 * GetModuleUsage (KERNEL.48)
1170 INT16 WINAPI
GetModuleUsage16( HINSTANCE16 hModule
)
1172 NE_MODULE
*pModule
= NE_GetPtr( hModule
);
1173 return pModule
? pModule
->count
: 0;
1177 /**********************************************************************
1178 * GetExpWinVer (KERNEL.167)
1180 WORD WINAPI
GetExpWinVer16( HMODULE16 hModule
)
1182 NE_MODULE
*pModule
= NE_GetPtr( hModule
);
1183 return pModule
? pModule
->expected_version
: 0;
1187 /**********************************************************************
1188 * GetModuleFileName16 (KERNEL.49)
1190 INT16 WINAPI
GetModuleFileName16( HINSTANCE16 hModule
, LPSTR lpFileName
,
1195 if (!hModule
) hModule
= GetCurrentTask();
1196 if (!(pModule
= NE_GetPtr( hModule
))) return 0;
1197 lstrcpynA( lpFileName
, NE_MODULE_NAME(pModule
), nSize
);
1198 TRACE(module
, "%s\n", lpFileName
);
1199 return strlen(lpFileName
);
1203 /**********************************************************************
1204 * GetModuleHandle16 (KERNEL.47)
1206 * Find a module from a module name.
1210 * the win16 module handle if found
1212 * HIWORD (undocumented, see "Undocumented Windows", chapter 5):
1213 * Always hFirstModule
1215 DWORD WINAPI
WIN16_GetModuleHandle( SEGPTR name
)
1217 if (HIWORD(name
) == 0)
1218 return MAKELONG(GetExePtr( (HINSTANCE16
)name
), hFirstModule
);
1219 return MAKELONG(GetModuleHandle16( PTR_SEG_TO_LIN(name
)), hFirstModule
);
1222 HMODULE16 WINAPI
GetModuleHandle16( LPCSTR name
)
1224 HMODULE16 hModule
= hFirstModule
;
1225 LPCSTR filename
, dotptr
;
1226 BYTE len
, *name_table
;
1228 if (!(filename
= strrchr( name
, '\\' )))
1232 FIXME(module
,"illegal usage of GetModuleHandle16\n");
1235 if ((dotptr
= strrchr( filename
, '.' )) != NULL
)
1236 len
= (BYTE
)(dotptr
- filename
);
1237 else len
= strlen( filename
);
1241 NE_MODULE
*pModule
= NE_GetPtr( hModule
);
1242 if (!pModule
) break;
1245 modulepath = NE_MODULE_NAME(pModule);
1246 TRACE(module,"name %s modulepath %s\n",name,modulepath);
1247 if (!(modulename = strrchr( modulepath, '\\' )))
1248 modulename = modulepath;
1250 if (!lstrcmpiA( modulename, filename )) return hModule;
1253 name_table
= (BYTE
*)pModule
+ pModule
->name_table
;
1254 if ((*name_table
== len
) && !lstrncmpiA(filename
, name_table
+1, len
))
1256 hModule
= pModule
->next
;
1262 /**********************************************************************
1263 * ModuleFirst (TOOLHELP.59)
1265 BOOL16 WINAPI
ModuleFirst16( MODULEENTRY
*lpme
)
1267 lpme
->wNext
= hFirstModule
;
1268 return ModuleNext16( lpme
);
1272 /**********************************************************************
1273 * ModuleNext (TOOLHELP.60)
1275 BOOL16 WINAPI
ModuleNext16( MODULEENTRY
*lpme
)
1280 if (!lpme
->wNext
) return FALSE
;
1281 if (!(pModule
= NE_GetPtr( lpme
->wNext
))) return FALSE
;
1282 name
= (char *)pModule
+ pModule
->name_table
;
1283 memcpy( lpme
->szModule
, name
+ 1, min(*name
, MAX_MODULE_NAME
) );
1284 lpme
->szModule
[min(*name
, MAX_MODULE_NAME
)] = '\0';
1285 lpme
->hModule
= lpme
->wNext
;
1286 lpme
->wcUsage
= pModule
->count
;
1287 lstrcpynA( lpme
->szExePath
, NE_MODULE_NAME(pModule
), sizeof(lpme
->szExePath
) );
1288 lpme
->wNext
= pModule
->next
;
1293 /**********************************************************************
1294 * ModuleFindName (TOOLHELP.61)
1296 BOOL16 WINAPI
ModuleFindName16( MODULEENTRY
*lpme
, LPCSTR name
)
1298 lpme
->wNext
= GetModuleHandle16( name
);
1299 return ModuleNext16( lpme
);
1303 /**********************************************************************
1304 * ModuleFindHandle (TOOLHELP.62)
1306 BOOL16 WINAPI
ModuleFindHandle16( MODULEENTRY
*lpme
, HMODULE16 hModule
)
1308 hModule
= GetExePtr( hModule
);
1309 lpme
->wNext
= hModule
;
1310 return ModuleNext16( lpme
);
1312 /**********************************************************************
1314 * try to find a ne-module with the same path as a given name
1316 static HMODULE16
GetModuleFromPath(LPCSTR name
)
1318 MODULEENTRY lookforit
;
1320 DOS_FULL_NAME nametoload
, nametocompare
;
1325 if (!DOSFS_GetFullName(name
,TRUE
,&nametoload
))
1326 /* we don't have a full qualified path */
1327 return GetModuleHandle16( name
);
1328 lookforit
.dwSize
=sizeof(MODULEENTRY
);
1329 for (ModuleFirst16(&lookforit
);
1330 ModuleNext16(&lookforit
);)
1332 pModule
= NE_GetPtr( lookforit
.hModule
);
1335 modulepath
= NE_MODULE_NAME(pModule
);
1338 /* Only comparing the Unix path will give valid results*/
1339 if (DOSFS_GetFullName(modulepath
,TRUE
,&nametocompare
))
1340 if (!strcmp(nametoload
.long_name
,nametocompare
.long_name
))
1341 return lookforit
.hModule
;
1348 /***************************************************************************
1349 * MapHModuleLS (KERNEL32.520)
1351 HMODULE16 WINAPI
MapHModuleLS(HMODULE hmod
) {
1355 return ((TDB
*)GlobalLock16(GetCurrentTask()))->hInstance
;
1357 return hmod
; /* we already have a 16 bit module handle */
1358 pModule
= (NE_MODULE
*)GlobalLock16(hFirstModule
);
1360 if (pModule
->module32
== hmod
)
1361 return pModule
->self
;
1362 pModule
= (NE_MODULE
*)GlobalLock16(pModule
->next
);
1367 /***************************************************************************
1368 * MapHModuleSL (KERNEL32.521)
1370 HMODULE WINAPI
MapHModuleSL(HMODULE16 hmod
) {
1374 TDB
*pTask
= (TDB
*)GlobalLock16(GetCurrentTask());
1376 hmod
= pTask
->hModule
;
1378 pModule
= (NE_MODULE
*)GlobalLock16(hmod
);
1379 if ( (pModule
->magic
!=IMAGE_OS2_SIGNATURE
) ||
1380 !(pModule
->flags
& NE_FFLAGS_WIN32
)
1383 return pModule
->module32
;
1386 /***************************************************************************
1387 * MapHInstLS (KERNEL32.516)
1389 REGS_ENTRYPOINT(MapHInstLS
) {
1390 EAX_reg(context
) = MapHModuleLS(EAX_reg(context
));
1393 /***************************************************************************
1394 * MapHInstSL (KERNEL32.518)
1396 REGS_ENTRYPOINT(MapHInstSL
) {
1397 EAX_reg(context
) = MapHModuleSL(EAX_reg(context
));
1400 /***************************************************************************
1401 * MapHInstLS_PN (KERNEL32.517)
1403 REGS_ENTRYPOINT(MapHInstLS_PN
) {
1404 if (EAX_reg(context
))
1405 EAX_reg(context
) = MapHModuleLS(EAX_reg(context
));
1408 /***************************************************************************
1409 * MapHInstSL_PN (KERNEL32.519)
1411 REGS_ENTRYPOINT(MapHInstSL_PN
) {
1412 if (EAX_reg(context
))
1413 EAX_reg(context
) = MapHModuleSL(EAX_reg(context
));
1416 /***************************************************************************
1417 * WIN16_MapHInstLS (KERNEL.472)
1419 VOID WINAPI
WIN16_MapHInstLS( CONTEXT
*context
) {
1420 EAX_reg(context
) = MapHModuleLS(EAX_reg(context
));
1423 /***************************************************************************
1424 * WIN16_MapHInstSL (KERNEL.473)
1426 VOID WINAPI
WIN16_MapHInstSL( CONTEXT
*context
) {
1427 EAX_reg(context
) = MapHModuleSL(EAX_reg(context
));