Sun Oct 1 15:48:34 1995 Alexandre Julliard <julliard@sunsite.unc> * [controls/menu.c] Fixed GetMenuString() for non-string items. * [debugger/*.c] First attempt to check validity of pointers before memory accesses. For now only segmented pointers are checked. * [debugger/dbg.y] [memory/ldt.c] Added possibility to dump only one segment with 'info segment'. * [include/bitmaps/ocr_*] Added all OEM cursors as XPM bitmaps. * [include/cursoricon.h] [objects/cursoricon.c] Rewrote all cursor and icon management to use the same memory layout as Windows, and to factor common code between icons and cursors. Implemented icon directory lookup to find the best matching icon (i.e. the color one). Implemented CopyCursor() and DumpIcon(). * [loader/module.c] For disabled built-in modules, we now try to load the Windows DLL first, and if this fails we fall back to using the built-in module anyway. * [memory/global.c] Fixed GlobalHandle() to return the correct selector in the high word even if we are passed a handle in the first place. * [miscemu/instr.c] Take into account the size of the operand and of the stack segment when incrementing the stack pointer. Avoid referencing FS_reg and GS_reg on *BSD. * [objects/dib.c] All DIB functions now accept a BITMAPCOREHEADER format bitmap. Monochrome DIBs are created as monochrome bitmap iff they are black and white. * [objects/oembitmap.c] Added support for OEM cursors, changed OBM_LoadIcon to use the new icon memory layout. * [rc/sysres_Fr.rc] Added French [Fr] language support. * [win32/environment.c] Fixed GetCommandLineA() to use current PDB. * [windows/event.c] [windows/winpos.c] Simulate a mouse motion event upon SetWindowPos() to force the cursor to be set correctly. Sat Sep 30 17:49:32 Cameron Heide (heide@ee.ualberta.ca) * [win32/*] New Win32 kernel functions: GetACP, GetCPInfo, GetEnvironmentVariableA, GetFileType, GetLastError, GetOEMCP, GetStartupInfoA, GetTimeZoneInformation, SetEnvironmentVariable, SetFilePointer, SetLastError, VirtualAlloc, VirtualFree, WriteFile. Completed implementations of GetCommandLineA. * [include/kernel32.h] New file. * [loader/main.c] Call initialization function for Win32 data (doesn't currently do anything). * [misc/main.c] Implemented GetEnvironmentVariableA, SetEnvironmentVariableA. Sat Sep 30 00:26:56 1995 Niels de Carpentier <niels@cindy.et.tudelft.nl> * [windows/winpos.c][miscemu/emulate.c][loader/module.c] [misc/commdlg.c] Misc. bug fixes Fri Sep 29 16:16:13 1995 Jim Peterson <jspeter@birch.ee.vt.edu> * [*/*] For Winelib, explicit casts have been placed where warnings were usually generated. printf formats which give the format for printing a handle as "%04x" or something similar have been changed to use the NPFMT macro defined in include/wintypes.h. Some times, explicit casts were also necessary. Parameter, field, and variable declarations have been made more exact, such as converting 'WORD wParam' to 'WPARAM wParam' or 'WORD hFont' to 'HFONT hFont'. Any call of the form GetWindowWord(hwnd,GWW_HINSTANCE) has been replaced with a call to WIN_GetWindowInstance(hwnd). * [controls/combo.c] Added WINELIB32 support in CLBoxGetCombo(). * [include/dialog.h] Commented out the '#ifndef WINELIB' around the '#pragma pack(1)'. winelib needs the packing as well (e.g. when accessing resources like sysres_DIALOG_SHELL_ABOUT_MSGBOX). * [include/windows.h] Got rid of the F[a-k] macros, which were cluttering up the global namespace. * [include/windows.h] [windows/defwnd.c] Added Win32 messages WM_CTLCOLOR*. * [include/wintypes.h] Put in preprocessor '#define WINELIB32' if appropriate and changed the types of some typedefs (WPARAM, HANDLE) based on this. * [loader/module.c] [toolkit/miscstubs.c] Added #ifdef'd portion in LoadModule to handle loading a WINElib module (already loaded, just init values). '#ifdef'ed out the definition for GetWndProcEntry16 and added a new version to toolkit/miscstubs.c. * [misc/shell.c] Adjusted the lengths of AppName and AppMisc from 512,512 to 128,906. Same amount of total storage, but much more reasonable. Also, changed calls to strcpy() in ShellAbout() to calls to strncpy() instead. This was a difficult bug to track down, but the AppMisc field was being initialized with the contributers text, which was much larger than 512 characters. * [toolkit/atom.c] New file for atom-handling functions. Copied from memory/atom.c and then heavily modified. Right now, it's just a linked list of atoms. Consider it as a hash table with just one entry. It's easily changed later. * [toolkit/heap.c] Commented out the heap functions with a "#ifdef WINELIB16" and put in a Win32 version (which is basically a modified copy). * [toolkit/sup.c] [toolkit/miscstubs.c] Moved the stuff I put in toolkit/sup.c into toolkit/miscstubs.c and added quite a few more stubs. * [toolkit/winmain.c] Rearranged startup code in _WinMain. I think this will work. * [toolkit/Makefile.in] Added targets for 'hello' and 'hello2' in case anyone cares to try out the sample programs. Wed Sep 27 23:13:43 1995 Anand Kumria <akumria@ozemail.com.au> * [miscemu/int2f.c] [miscemu/vxd.c] [if1632/winprocs.spec] First attempt at support for some VxDs. Comm, Shell and Pagefile. Tue Sep 26 21:34:45 1995 Hans de Graaff <graaff@twi72.twi.tudelft.nl> * [misc/dos_fs.c] DOS_SimplifyPath: Also remove "/./" from path. (Happens when starting applications like 'wine ./excel.exe') Sat Sep 23 23:32:40 1995 Morten Welinder <terra@diku.dk> * [configure.in] Avoid relative path for wine.ini. * [rc/sysres_Da.rc] Support for Danish [Da] language. * [misc/main.c] [miscemu/cpu.c] Return the processor we're running on correctly. * [miscemu/int2f.c] Minor stuff in int 0x2f, function 0x16. Sat Sep 23 1995 17:58:04 Marcus Meissner <msmeissn@faui01.informatik.uni-erlangen.de> * [misc/shell.c] [misc/main.c] Implement saving and loading of the registry database (needed for OLE). Very experimental. Fixed ShellExecute(). * [miscemu/int21.c] EEXIST is not a critical error condition for mkdir(). Fri Sep 22 01:33:34 1995 Alex Korobka <alex@phm6.pharm.sunysb.edu> * [include/shell.h] [misc/shell.c] Implemented 4 drag/drop functions with documented functionality. * [multimedia/time.c] "Fixed" MMSysTimeCallback kludge so Excel5 loads up without crashing. * [*/*] Added new files, more message definitions, structures, debug info, etc. Rewrote message logging functions to produce output similar to WinSight. Check out -debugmsg +message option. * [misc/file.c] Fixed GetDriveType return value. * [windows/message.c] Hooks are invoked in normal order. * [miscemu/*] Added some functions and interrupts. * [misc/shell.c] Implemented Drag... functions. Thu Sep 21 23:50:12 1995 Jukka Iivonen <iivonen@cc.helsinki.fi> * [rc/sysres_Fi.rc] [rc/sysres.rc] First attempt at Finnish [Fi] language support.
1344 lines
42 KiB
C
1344 lines
42 KiB
C
/*
|
|
* Modules
|
|
*
|
|
* Copyright 1995 Alexandre Julliard
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include "windows.h"
|
|
#include "dlls.h"
|
|
#include "dos_fs.h"
|
|
#include "global.h"
|
|
#include "ldt.h"
|
|
#include "module.h"
|
|
#include "neexe.h"
|
|
#include "stackframe.h"
|
|
#include "task.h"
|
|
#include "toolhelp.h"
|
|
#include "stddebug.h"
|
|
#include "debug.h"
|
|
|
|
#include "callback.h"
|
|
|
|
static HMODULE hFirstModule = 0;
|
|
static HMODULE hCachedModule = 0; /* Module cached by MODULE_OpenFile */
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_LoadBuiltin
|
|
*
|
|
* Load a built-in module. If the 'force' parameter is FALSE, we only
|
|
* load the module if it has not been disabled via the -dll option.
|
|
*/
|
|
static HMODULE MODULE_LoadBuiltin( LPCSTR name, BOOL force )
|
|
{
|
|
#ifndef WINELIB /* JBP: Not really allowed in libwine.a (FIXME:?) */
|
|
HMODULE hModule;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegTable;
|
|
struct dll_table_s *table;
|
|
int i;
|
|
char dllname[16], *p;
|
|
|
|
/* Fix the name in case we have a full path and extension */
|
|
|
|
if ((p = strrchr( name, '\\' ))) name = p + 1;
|
|
strncpy( dllname, name, 15 );
|
|
dllname[15] = '\0';
|
|
if ((p = strrchr( dllname, '.' ))) *p = '\0';
|
|
|
|
for (i = 0, table = dll_builtin_table; i < N_BUILTINS; i++, table++)
|
|
if (!strcasecmp( table->name, dllname )) break;
|
|
if (i >= N_BUILTINS) return 0;
|
|
if (!table->used && !force) return 0;
|
|
|
|
hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->module_start,
|
|
table->module_end - table->module_start,
|
|
0, FALSE, FALSE, FALSE, NULL );
|
|
if (!hModule) return 0;
|
|
FarSetOwner( hModule, hModule );
|
|
|
|
table->hModule = hModule;
|
|
|
|
dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
|
|
table->name, hModule );
|
|
|
|
/* Allocate the code segment */
|
|
|
|
pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
pSegTable = NE_SEG_TABLE( pModule );
|
|
|
|
pSegTable->selector = GLOBAL_CreateBlock( GMEM_FIXED, table->code_start,
|
|
pSegTable->minsize, hModule,
|
|
TRUE, TRUE, FALSE, NULL );
|
|
if (!pSegTable->selector) return 0;
|
|
pSegTable++;
|
|
|
|
/* Allocate the data segment */
|
|
|
|
pSegTable->selector = GLOBAL_Alloc( GMEM_FIXED, pSegTable->minsize,
|
|
hModule, FALSE, FALSE, FALSE );
|
|
if (!pSegTable->selector) return 0;
|
|
memcpy( GlobalLock( pSegTable->selector ),
|
|
table->data_start, pSegTable->minsize );
|
|
|
|
pModule->next = hFirstModule;
|
|
hFirstModule = hModule;
|
|
return hModule;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_Init
|
|
*
|
|
* Create the built-in modules.
|
|
*/
|
|
BOOL MODULE_Init(void)
|
|
{
|
|
/* For these, built-in modules are always used */
|
|
|
|
if (!MODULE_LoadBuiltin( "KERNEL", TRUE ) ||
|
|
!MODULE_LoadBuiltin( "GDI", TRUE ) ||
|
|
!MODULE_LoadBuiltin( "USER", TRUE ) ||
|
|
!MODULE_LoadBuiltin( "WINPROCS", TRUE )) return FALSE;
|
|
|
|
#else
|
|
fprintf(stderr, "JBP: MODULE_Init() ignored.\n");
|
|
#endif
|
|
/* Initialize KERNEL.178 (__WINFLAGS) with the correct flags value */
|
|
|
|
MODULE_SetEntryPoint( GetModuleHandle( "KERNEL" ), 178, GetWinFlags() );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_PrintModule
|
|
*/
|
|
void MODULE_PrintModule( HMODULE hmodule )
|
|
{
|
|
int i, ordinal;
|
|
SEGTABLEENTRY *pSeg;
|
|
BYTE *pstr;
|
|
WORD *pword;
|
|
NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hmodule );
|
|
|
|
/* Dump the module info */
|
|
|
|
printf( "Module "NPFMT":\n", hmodule );
|
|
printf( "count=%d flags=%04x heap=%d stack=%d\n",
|
|
pModule->count, pModule->flags,
|
|
pModule->heap_size, pModule->stack_size );
|
|
printf( "cs:ip=%04x:%04x ss:sp=%04x:%04x ds=%04x nb seg=%d modrefs=%d\n",
|
|
pModule->cs, pModule->ip, pModule->ss, pModule->sp, pModule->dgroup,
|
|
pModule->seg_count, pModule->modref_count );
|
|
printf( "os_flags=%d swap_area=%d version=%04x\n",
|
|
pModule->os_flags, pModule->min_swap_area,
|
|
pModule->expected_version );
|
|
|
|
/* Dump the file info */
|
|
|
|
printf( "Filename: '%s'\n",
|
|
((LOADEDFILEINFO *)((BYTE *)pModule + pModule->fileinfo))->filename );
|
|
|
|
/* Dump the segment table */
|
|
|
|
printf( "\nSegment table:\n" );
|
|
pSeg = NE_SEG_TABLE( pModule );
|
|
for (i = 0; i < pModule->seg_count; i++, pSeg++)
|
|
printf( "%02x: pos=%d size=%d flags=%04x minsize=%d sel="NPFMT"\n",
|
|
i + 1, pSeg->filepos, pSeg->size, pSeg->flags,
|
|
pSeg->minsize, pSeg->selector );
|
|
|
|
/* Dump the resource table */
|
|
|
|
printf( "\nResource table:\n" );
|
|
if (pModule->res_table)
|
|
{
|
|
pword = (WORD *)((BYTE *)pModule + pModule->res_table);
|
|
printf( "Alignment: %d\n", *pword++ );
|
|
while (*pword)
|
|
{
|
|
struct resource_typeinfo_s *ptr = (struct resource_typeinfo_s *)pword;
|
|
struct resource_nameinfo_s *pname = (struct resource_nameinfo_s *)(ptr + 1);
|
|
printf( "id=%04x count=%d\n", ptr->type_id, ptr->count );
|
|
for (i = 0; i < ptr->count; i++, pname++)
|
|
printf( "offset=%d len=%d id=%04x\n",
|
|
pname->offset, pname->length, pname->id );
|
|
pword = (WORD *)pname;
|
|
}
|
|
}
|
|
else printf( "None\n" );
|
|
|
|
/* Dump the resident name table */
|
|
|
|
printf( "\nResident-name table:\n" );
|
|
pstr = (char *)pModule + pModule->name_table;
|
|
while (*pstr)
|
|
{
|
|
printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
|
|
*(WORD *)(pstr + *pstr + 1) );
|
|
pstr += *pstr + 1 + sizeof(WORD);
|
|
}
|
|
|
|
/* Dump the module reference table */
|
|
|
|
printf( "\nModule ref table:\n" );
|
|
if (pModule->modref_table)
|
|
{
|
|
pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
|
|
for (i = 0; i < pModule->modref_count; i++, pword++)
|
|
{
|
|
char *name = (char *)pModule + pModule->import_table + *pword;
|
|
printf( "%d: %04x -> '%*.*s'\n",
|
|
i, *pword, *name, *name, name + 1 );
|
|
}
|
|
}
|
|
else printf( "None\n" );
|
|
|
|
/* Dump the entry table */
|
|
|
|
printf( "\nEntry table:\n" );
|
|
pstr = (char *)pModule + pModule->entry_table;
|
|
ordinal = 1;
|
|
while (*pstr)
|
|
{
|
|
printf( "Bundle %d-%d: %02x\n", ordinal, ordinal + *pstr - 1, pstr[1]);
|
|
if (!pstr[1])
|
|
{
|
|
ordinal += *pstr;
|
|
pstr += 2;
|
|
}
|
|
else if ((BYTE)pstr[1] == 0xff) /* moveable */
|
|
{
|
|
struct entry_tab_movable_s *pe = (struct entry_tab_movable_s*)(pstr+2);
|
|
for (i = 0; i < *pstr; i++, pe++)
|
|
printf( "%d: %02x:%04x (moveable)\n",
|
|
ordinal++, pe->seg_number, pe->offset );
|
|
pstr = (char *)pe;
|
|
}
|
|
else /* fixed */
|
|
{
|
|
struct entry_tab_fixed_s *pe = (struct entry_tab_fixed_s*)(pstr+2);
|
|
for (i = 0; i < *pstr; i++, pe++)
|
|
printf( "%d: %04x (fixed)\n",
|
|
ordinal++, pe->offset[0] + (pe->offset[1] << 8) );
|
|
pstr = (char *)pe;
|
|
}
|
|
}
|
|
|
|
/* Dump the non-resident names table */
|
|
|
|
printf( "\nNon-resident names table:\n" );
|
|
if (pModule->nrname_handle)
|
|
{
|
|
pstr = (char *)GlobalLock( pModule->nrname_handle );
|
|
while (*pstr)
|
|
{
|
|
printf( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
|
|
*(WORD *)(pstr + *pstr + 1) );
|
|
pstr += *pstr + 1 + sizeof(WORD);
|
|
}
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_OpenFile
|
|
*/
|
|
int MODULE_OpenFile( HMODULE hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
char *name;
|
|
|
|
static int cachedfd = -1;
|
|
|
|
hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
|
|
dprintf_module( stddeb, "MODULE_OpenFile("NPFMT") cache: mod="NPFMT" fd=%d\n",
|
|
hModule, hCachedModule, cachedfd );
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return -1;
|
|
if (hCachedModule == hModule) return cachedfd;
|
|
close( cachedfd );
|
|
hCachedModule = hModule;
|
|
name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
|
|
cachedfd = open( DOS_GetUnixFileName( name ), O_RDONLY );
|
|
dprintf_module( stddeb, "MODULE_OpenFile: opened '%s' -> %d\n",
|
|
name, cachedfd );
|
|
return cachedfd;
|
|
}
|
|
/***********************************************************************
|
|
* MODULE_Ne2MemFlags
|
|
*/
|
|
|
|
/* This function translates NE segment flags to GlobalAlloc flags */
|
|
|
|
static WORD MODULE_Ne2MemFlags(WORD flags)
|
|
{
|
|
WORD memflags = 0;
|
|
#if 0
|
|
if (flags & NE_SEGFLAGS_DISCARDABLE)
|
|
memflags |= GMEM_DISCARDABLE;
|
|
if (flags & NE_SEGFLAGS_MOVEABLE ||
|
|
( ! (flags & NE_SEGFLAGS_DATA) &&
|
|
! (flags & NE_SEGFLAGS_LOADED) &&
|
|
! (flags & NE_SEGFLAGS_ALLOCATED)
|
|
)
|
|
)
|
|
memflags |= GMEM_MOVEABLE;
|
|
memflags |= GMEM_ZEROINIT;
|
|
#else
|
|
memflags = GMEM_ZEROINIT | GMEM_FIXED;
|
|
return memflags;
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_AllocateSegment (WINPROCS.26)
|
|
*/
|
|
|
|
DWORD MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
|
|
{
|
|
WORD size = wSize << wElem;
|
|
HANDLE hMem = GlobalAlloc( MODULE_Ne2MemFlags(wFlags), size);
|
|
#ifdef WINELIB32
|
|
return (DWORD)GlobalLock(hMem);
|
|
#else
|
|
WORD selector = HIWORD(GlobalLock(hMem));
|
|
return MAKELONG(hMem, selector);
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_CreateSegments
|
|
*/
|
|
static BOOL MODULE_CreateSegments( HMODULE hModule )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
int i, minsize;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
|
|
pSegment = NE_SEG_TABLE( pModule );
|
|
for (i = 1; i <= pModule->seg_count; i++, pSegment++)
|
|
{
|
|
minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
|
|
if (i == pModule->ss) minsize += pModule->stack_size;
|
|
/* The DGROUP is allocated by MODULE_CreateInstance */
|
|
if (i == pModule->dgroup) continue;
|
|
pSegment->selector = GLOBAL_Alloc( MODULE_Ne2MemFlags(pSegment->flags),
|
|
minsize, hModule,
|
|
!(pSegment->flags & NE_SEGFLAGS_DATA),
|
|
FALSE,
|
|
FALSE /*pSegment->flags & NE_SEGFLAGS_READONLY*/ );
|
|
if (!pSegment->selector) return FALSE;
|
|
}
|
|
|
|
pModule->dgroup_entry = pModule->dgroup ? pModule->seg_table +
|
|
(pModule->dgroup - 1) * sizeof(SEGTABLEENTRY) : 0;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetInstance
|
|
*/
|
|
static HINSTANCE MODULE_GetInstance( HMODULE hModule )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
if (pModule->dgroup == 0) return hModule;
|
|
|
|
pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
|
|
|
|
return pSegment->selector;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_CreateInstance
|
|
*/
|
|
HINSTANCE MODULE_CreateInstance( HMODULE hModule, LOADPARAMS *params )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
int minsize;
|
|
HINSTANCE hNewInstance, hPrevInstance;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
if (pModule->dgroup == 0) return hModule;
|
|
|
|
pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
|
|
hPrevInstance = pSegment->selector;
|
|
|
|
/* if it's a library, create a new instance only the first time */
|
|
if (hPrevInstance)
|
|
{
|
|
if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
|
|
if (params == (LOADPARAMS*)-1) return hPrevInstance;
|
|
}
|
|
|
|
minsize = pSegment->minsize ? pSegment->minsize : 0x10000;
|
|
if (pModule->ss == pModule->dgroup) minsize += pModule->stack_size;
|
|
minsize += pModule->heap_size;
|
|
hNewInstance = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
|
|
minsize, hModule, FALSE, FALSE, FALSE );
|
|
if (!hNewInstance) return 0;
|
|
pSegment->selector = hNewInstance;
|
|
return hNewInstance;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_LoadExeHeader
|
|
*/
|
|
HMODULE MODULE_LoadExeHeader( int fd, OFSTRUCT *ofs )
|
|
{
|
|
struct mz_header_s mz_header;
|
|
struct ne_header_s ne_header;
|
|
int size;
|
|
HMODULE hModule;
|
|
NE_MODULE *pModule;
|
|
BYTE *pData;
|
|
char *buffer, *fastload = NULL;
|
|
int fastload_offset = 0, fastload_length = 0;
|
|
|
|
/* Read a block from either the file or the fast-load area. */
|
|
#define READ(offset,size,buffer) \
|
|
((fastload && ((offset) >= fastload_offset) && \
|
|
((offset)+(size) <= fastload_offset+fastload_length)) ? \
|
|
(memcpy( buffer, fastload+(offset)-fastload_offset, (size) ), TRUE) : \
|
|
(lseek( fd, mz_header.ne_offset+(offset), SEEK_SET), \
|
|
read( fd, (buffer), (size) ) == (size)))
|
|
|
|
lseek( fd, 0, SEEK_SET );
|
|
if ((read( fd, &mz_header, sizeof(mz_header) ) != sizeof(mz_header)) ||
|
|
(mz_header.mz_magic != MZ_SIGNATURE)) return (HMODULE)11; /* invalid exe */
|
|
|
|
lseek( fd, mz_header.ne_offset, SEEK_SET );
|
|
if (read( fd, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
|
|
return (HMODULE)11; /* invalid exe */
|
|
|
|
if (ne_header.ne_magic == PE_SIGNATURE) return (HMODULE)21; /* win32 exe */
|
|
if (ne_header.ne_magic != NE_SIGNATURE) return (HMODULE)11; /* invalid exe */
|
|
|
|
/* We now have a valid NE header */
|
|
|
|
size = sizeof(NE_MODULE) +
|
|
/* loaded file info */
|
|
sizeof(LOADEDFILEINFO) + strlen(ofs->szPathName) +
|
|
/* segment table */
|
|
ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
|
|
/* resource table */
|
|
ne_header.rname_tab_offset - ne_header.resource_tab_offset +
|
|
/* resident names table */
|
|
ne_header.moduleref_tab_offset - ne_header.rname_tab_offset +
|
|
/* module ref table */
|
|
ne_header.n_mod_ref_tab * sizeof(WORD) +
|
|
/* imported names table */
|
|
ne_header.entry_tab_offset - ne_header.iname_tab_offset +
|
|
/* entry table length */
|
|
ne_header.entry_tab_length;
|
|
|
|
hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
|
|
if (!hModule) return (HMODULE)11; /* invalid exe */
|
|
FarSetOwner( hModule, hModule );
|
|
pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
memcpy( pModule, &ne_header, sizeof(NE_MODULE) );
|
|
pModule->count = 0;
|
|
pData = (BYTE *)(pModule + 1);
|
|
|
|
/* Read the fast-load area */
|
|
|
|
if (ne_header.additional_flags & NE_AFLAGS_FASTLOAD)
|
|
{
|
|
fastload_offset=ne_header.fastload_offset<<ne_header.align_shift_count;
|
|
fastload_length=ne_header.fastload_length<<ne_header.align_shift_count;
|
|
dprintf_module( stddeb, "Using fast-load area offset=%x len=%d\n",
|
|
fastload_offset, fastload_length );
|
|
if ((fastload = (char *)malloc( fastload_length )) != NULL)
|
|
{
|
|
lseek( fd, mz_header.ne_offset + fastload_offset, SEEK_SET );
|
|
if (read( fd, fastload, fastload_length ) != fastload_length)
|
|
{
|
|
free( fastload );
|
|
fastload = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Store the filename information */
|
|
|
|
pModule->fileinfo = (int)pData - (int)pModule;
|
|
((LOADEDFILEINFO*)pData)->length = sizeof(LOADEDFILEINFO)+strlen(ofs->szPathName);
|
|
((LOADEDFILEINFO*)pData)->fixed_media = TRUE;
|
|
((LOADEDFILEINFO*)pData)->error = 0;
|
|
((LOADEDFILEINFO*)pData)->date = 0;
|
|
((LOADEDFILEINFO*)pData)->time = 0;
|
|
strcpy( ((LOADEDFILEINFO*)pData)->filename, ofs->szPathName );
|
|
pData += ((LOADEDFILEINFO*)pData)->length--;
|
|
|
|
/* Get the segment table */
|
|
|
|
pModule->seg_table = (int)pData - (int)pModule;
|
|
buffer = malloc( ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s) );
|
|
if (buffer)
|
|
{
|
|
int i;
|
|
struct ne_segment_table_entry_s *pSeg;
|
|
|
|
if (!READ( ne_header.segment_tab_offset,
|
|
ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
|
|
buffer )) return (HMODULE)11; /* invalid exe */
|
|
pSeg = (struct ne_segment_table_entry_s *)buffer;
|
|
for (i = ne_header.n_segment_tab; i > 0; i--, pSeg++)
|
|
{
|
|
memcpy( pData, pSeg, sizeof(*pSeg) );
|
|
pData += sizeof(SEGTABLEENTRY);
|
|
}
|
|
free( buffer );
|
|
}
|
|
else return (HMODULE)11; /* invalid exe */
|
|
|
|
/* Get the resource table */
|
|
|
|
if (ne_header.resource_tab_offset < ne_header.rname_tab_offset)
|
|
{
|
|
pModule->res_table = (int)pData - (int)pModule;
|
|
if (!READ(ne_header.resource_tab_offset,
|
|
ne_header.rname_tab_offset - ne_header.resource_tab_offset,
|
|
pData )) return (HMODULE)11; /* invalid exe */
|
|
pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
|
|
}
|
|
else pModule->res_table = 0; /* No resource table */
|
|
|
|
/* Get the resident names table */
|
|
|
|
pModule->name_table = (int)pData - (int)pModule;
|
|
if (!READ( ne_header.rname_tab_offset,
|
|
ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
|
|
pData )) return (HMODULE)11; /* invalid exe */
|
|
pData += ne_header.moduleref_tab_offset - ne_header.rname_tab_offset;
|
|
|
|
/* Get the module references table */
|
|
|
|
if (ne_header.n_mod_ref_tab > 0)
|
|
{
|
|
pModule->modref_table = (int)pData - (int)pModule;
|
|
if (!READ( ne_header.moduleref_tab_offset,
|
|
ne_header.n_mod_ref_tab * sizeof(WORD),
|
|
pData )) return (HMODULE)11; /* invalid exe */
|
|
pData += ne_header.n_mod_ref_tab * sizeof(WORD);
|
|
}
|
|
else pModule->modref_table = 0; /* No module references */
|
|
|
|
/* Get the imported names table */
|
|
|
|
pModule->import_table = (int)pData - (int)pModule;
|
|
if (!READ( ne_header.iname_tab_offset,
|
|
ne_header.entry_tab_offset - ne_header.iname_tab_offset,
|
|
pData )) return (HMODULE)11; /* invalid exe */
|
|
pData += ne_header.entry_tab_offset - ne_header.iname_tab_offset;
|
|
|
|
/* Get the entry table */
|
|
|
|
pModule->entry_table = (int)pData - (int)pModule;
|
|
if (!READ( ne_header.entry_tab_offset,
|
|
ne_header.entry_tab_length,
|
|
pData )) return (HMODULE)11; /* invalid exe */
|
|
pData += ne_header.entry_tab_length;
|
|
|
|
/* Get the non-resident names table */
|
|
|
|
if (ne_header.nrname_tab_length)
|
|
{
|
|
pModule->nrname_handle = GLOBAL_Alloc( 0, ne_header.nrname_tab_length,
|
|
hModule, FALSE, FALSE, FALSE );
|
|
if (!pModule->nrname_handle) return (HMODULE)11; /* invalid exe */
|
|
buffer = GlobalLock( pModule->nrname_handle );
|
|
lseek( fd, ne_header.nrname_tab_offset, SEEK_SET );
|
|
if (read( fd, buffer, ne_header.nrname_tab_length )
|
|
!= ne_header.nrname_tab_length) return (HMODULE)11; /* invalid exe */
|
|
}
|
|
else pModule->nrname_handle = 0;
|
|
|
|
/* Allocate a segment for the implicitly-loaded DLLs */
|
|
|
|
if (pModule->modref_count)
|
|
{
|
|
pModule->dlls_to_init = GLOBAL_Alloc(GMEM_ZEROINIT,
|
|
(pModule->modref_count+1)*sizeof(HMODULE),
|
|
hModule, FALSE, FALSE, FALSE );
|
|
if (!pModule->dlls_to_init) return (HMODULE)11; /* invalid exe */
|
|
}
|
|
else pModule->dlls_to_init = 0;
|
|
|
|
if (debugging_module) MODULE_PrintModule( hModule );
|
|
pModule->next = hFirstModule;
|
|
hFirstModule = hModule;
|
|
return hModule;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetOrdinal
|
|
*
|
|
* Lookup the ordinal for a given name.
|
|
*/
|
|
WORD MODULE_GetOrdinal( HMODULE hModule, char *name )
|
|
{
|
|
char buffer[256], *cpnt;
|
|
BYTE len;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
|
|
dprintf_module( stddeb, "MODULE_GetOrdinal("NPFMT",'%s')\n",
|
|
hModule, name );
|
|
|
|
/* First handle names of the form '#xxxx' */
|
|
|
|
if (name[0] == '#') return atoi( name + 1 );
|
|
|
|
/* Now copy and uppercase the string */
|
|
|
|
strcpy( buffer, name );
|
|
AnsiUpper( buffer );
|
|
len = strlen( buffer );
|
|
|
|
/* First search the resident names */
|
|
|
|
cpnt = (char *)pModule + pModule->name_table;
|
|
|
|
/* Skip the first entry (module name) */
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
while (*cpnt)
|
|
{
|
|
dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
|
|
if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
|
|
{
|
|
dprintf_module( stddeb, " Found: ordinal=%d\n",
|
|
*(WORD *)(cpnt + *cpnt + 1) );
|
|
return *(WORD *)(cpnt + *cpnt + 1);
|
|
}
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
}
|
|
|
|
/* Now search the non-resident names table */
|
|
|
|
if (!pModule->nrname_handle) return 0; /* No non-resident table */
|
|
cpnt = (char *)GlobalLock( pModule->nrname_handle );
|
|
|
|
/* Skip the first entry (module description string) */
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
while (*cpnt)
|
|
{
|
|
dprintf_module( stddeb, " Checking '%*.*s'\n", *cpnt, *cpnt, cpnt+1 );
|
|
if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
|
|
{
|
|
dprintf_module( stddeb, " Found: ordinal=%d\n",
|
|
*(WORD *)(cpnt + *cpnt + 1) );
|
|
return *(WORD *)(cpnt + *cpnt + 1);
|
|
}
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetEntryPoint
|
|
*
|
|
* Return the entry point for a given ordinal.
|
|
*/
|
|
DWORD MODULE_GetEntryPoint( HMODULE hModule, WORD ordinal )
|
|
{
|
|
NE_MODULE *pModule;
|
|
WORD curOrdinal = 1;
|
|
BYTE *p;
|
|
WORD sel, offset;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
|
|
p = (BYTE *)pModule + pModule->entry_table;
|
|
while (*p && (curOrdinal + *p <= ordinal))
|
|
{
|
|
/* Skipping this bundle */
|
|
curOrdinal += *p;
|
|
switch(p[1])
|
|
{
|
|
case 0: p += 2; break; /* unused */
|
|
case 0xff: p += 2 + *p * 6; break; /* moveable */
|
|
default: p += 2 + *p * 3; break; /* fixed */
|
|
}
|
|
}
|
|
if (!*p) return 0;
|
|
|
|
switch(p[1])
|
|
{
|
|
case 0: /* unused */
|
|
return 0;
|
|
case 0xff: /* moveable */
|
|
p += 2 + 6 * (ordinal - curOrdinal);
|
|
sel = p[3];
|
|
offset = *(WORD *)(p + 4);
|
|
break;
|
|
default: /* fixed */
|
|
sel = p[1];
|
|
p += 2 + 3 * (ordinal - curOrdinal);
|
|
offset = *(WORD *)(p + 1);
|
|
break;
|
|
}
|
|
|
|
if (sel == 0xfe) sel = 0xffff; /* constant entry */
|
|
else sel = NE_SEG_TABLE(pModule)[sel-1].selector;
|
|
return MAKELONG( offset, sel );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_SetEntryPoint
|
|
*
|
|
* Change the value of an entry point. Use with caution!
|
|
* It can only change the offset value, not the selector.
|
|
*/
|
|
BOOL MODULE_SetEntryPoint( HMODULE hModule, WORD ordinal, WORD offset )
|
|
{
|
|
NE_MODULE *pModule;
|
|
WORD curOrdinal = 1;
|
|
BYTE *p;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
|
|
|
|
p = (BYTE *)pModule + pModule->entry_table;
|
|
while (*p && (curOrdinal + *p <= ordinal))
|
|
{
|
|
/* Skipping this bundle */
|
|
curOrdinal += *p;
|
|
switch(p[1])
|
|
{
|
|
case 0: p += 2; break; /* unused */
|
|
case 0xff: p += 2 + *p * 6; break; /* moveable */
|
|
default: p += 2 + *p * 3; break; /* fixed */
|
|
}
|
|
}
|
|
if (!*p) return FALSE;
|
|
|
|
switch(p[1])
|
|
{
|
|
case 0: /* unused */
|
|
return FALSE;
|
|
case 0xff: /* moveable */
|
|
p += 2 + 6 * (ordinal - curOrdinal);
|
|
*(WORD *)(p + 4) = offset;
|
|
break;
|
|
default: /* fixed */
|
|
p += 2 + 3 * (ordinal - curOrdinal);
|
|
*(WORD *)(p + 1) = offset;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetEntryPointName
|
|
*
|
|
* Return the entry point name for a given ordinal.
|
|
* Used only by relay debugging.
|
|
* Warning: returned pointer is to a Pascal-type string.
|
|
*/
|
|
LPSTR MODULE_GetEntryPointName( HMODULE hModule, WORD ordinal )
|
|
{
|
|
register char *cpnt;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
|
|
/* First search the resident names */
|
|
|
|
cpnt = (char *)pModule + pModule->name_table;
|
|
while (*cpnt)
|
|
{
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
|
|
}
|
|
|
|
/* Now search the non-resident names table */
|
|
|
|
if (!pModule->nrname_handle) return 0; /* No non-resident table */
|
|
cpnt = (char *)GlobalLock( pModule->nrname_handle );
|
|
while (*cpnt)
|
|
{
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
if (*(WORD *)(cpnt + *cpnt + 1) == ordinal) return cpnt;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetModuleName
|
|
*/
|
|
LPSTR MODULE_GetModuleName( HMODULE hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
BYTE *p, len;
|
|
static char buffer[10];
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return NULL;
|
|
p = (BYTE *)pModule + pModule->name_table;
|
|
len = min( *p, 8 );
|
|
memcpy( buffer, p + 1, len );
|
|
buffer[len] = '\0';
|
|
return buffer;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_FindModule
|
|
*
|
|
* Find a module from a path name.
|
|
*/
|
|
HMODULE MODULE_FindModule( LPCSTR path )
|
|
{
|
|
HMODULE hModule = hFirstModule;
|
|
LPCSTR filename, dotptr, modulepath, modulename;
|
|
BYTE len, *name_table;
|
|
|
|
if (!(filename = strrchr( path, '\\' ))) filename = path;
|
|
else filename++;
|
|
if ((dotptr = strrchr( filename, '.' )) != NULL)
|
|
len = (BYTE)(dotptr - filename);
|
|
else len = strlen( filename );
|
|
|
|
while(hModule)
|
|
{
|
|
NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
if (!pModule) break;
|
|
modulepath = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
|
|
if (!(modulename = strrchr( modulepath, '\\' )))
|
|
modulename = modulepath;
|
|
else modulename++;
|
|
if (!strcasecmp( modulename, filename )) return hModule;
|
|
|
|
name_table = (BYTE *)pModule + pModule->name_table;
|
|
if ((*name_table == len) && !strncasecmp(filename, name_table+1, len))
|
|
return hModule;
|
|
hModule = pModule->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_FreeModule
|
|
*
|
|
* Remove a module from memory.
|
|
*/
|
|
static void MODULE_FreeModule( HMODULE hModule )
|
|
{
|
|
HMODULE *hPrevModule;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegment;
|
|
HMODULE *pModRef;
|
|
int i;
|
|
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return;
|
|
if (pModule->flags & NE_FFLAGS_BUILTIN)
|
|
return; /* Can't free built-in module */
|
|
|
|
/* FIXME: should call the exit code for the library here */
|
|
|
|
/* Remove it from the linked list */
|
|
|
|
hPrevModule = &hFirstModule;
|
|
while (*hPrevModule && (*hPrevModule != hModule))
|
|
{
|
|
hPrevModule = &((NE_MODULE *)GlobalLock( *hPrevModule ))->next;
|
|
}
|
|
if (*hPrevModule) *hPrevModule = pModule->next;
|
|
|
|
/* Free all the segments */
|
|
|
|
pSegment = NE_SEG_TABLE( pModule );
|
|
for (i = 1; i <= pModule->seg_count; i++, pSegment++)
|
|
{
|
|
GlobalFree( pSegment->selector );
|
|
}
|
|
|
|
/* Free the referenced modules */
|
|
|
|
pModRef = NE_MODULE_TABLE( pModule );
|
|
for (i = 0; i < pModule->modref_count; i++, pModRef++)
|
|
{
|
|
FreeModule( *pModRef );
|
|
}
|
|
|
|
/* Free the module storage */
|
|
|
|
if (pModule->nrname_handle) GlobalFree( pModule->nrname_handle );
|
|
if (pModule->dlls_to_init) GlobalFree( pModule->dlls_to_init );
|
|
GlobalFree( hModule );
|
|
|
|
/* Remove module from cache */
|
|
|
|
if (hCachedModule == hModule) hCachedModule = 0;
|
|
}
|
|
|
|
|
|
HINSTANCE PE_LoadModule(int fd, OFSTRUCT *ofs, LOADPARAMS* params);
|
|
|
|
/**********************************************************************
|
|
* LoadModule (KERNEL.45)
|
|
*/
|
|
HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
|
|
{
|
|
HMODULE hModule;
|
|
HANDLE hInstance, hPrevInstance;
|
|
NE_MODULE *pModule;
|
|
LOADPARAMS *params = (LOADPARAMS *)paramBlock;
|
|
#ifndef WINELIB /* JBP: Disabled for now in winelib.a */
|
|
WORD *pModRef, *pDLLs;
|
|
int i, fd;
|
|
|
|
hModule = MODULE_FindModule( name );
|
|
|
|
if (!hModule) /* We have to load the module */
|
|
{
|
|
OFSTRUCT ofs;
|
|
|
|
/* Try to load the built-in first if not disabled */
|
|
if ((hModule = MODULE_LoadBuiltin( name, FALSE ))) return hModule;
|
|
|
|
if (strchr( name, '/' )) name = DOS_GetDosFileName( name );
|
|
if ((fd = OpenFile( name, &ofs, OF_READ )) == -1)
|
|
{
|
|
/* Now try the built-in even if disabled */
|
|
if ((hModule = MODULE_LoadBuiltin( name, TRUE )))
|
|
{
|
|
fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
|
|
return hModule;
|
|
}
|
|
return 2; /* File not found */
|
|
}
|
|
|
|
/* Create the module structure */
|
|
|
|
if ((hModule = MODULE_LoadExeHeader( fd, &ofs )) < 32)
|
|
{
|
|
if(hModule == 21)
|
|
return PE_LoadModule(fd,&ofs,paramBlock);
|
|
close( fd );
|
|
fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
|
|
name, hModule );
|
|
return hModule;
|
|
}
|
|
pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
|
|
/* Allocate the segments for this module */
|
|
|
|
MODULE_CreateSegments( hModule );
|
|
|
|
hPrevInstance = 0;
|
|
hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
|
|
|
|
/* Load the referenced DLLs */
|
|
|
|
pModRef = (WORD *)((char *)pModule + pModule->modref_table);
|
|
pDLLs = (WORD *)GlobalLock( pModule->dlls_to_init );
|
|
for (i = 0; i < pModule->modref_count; i++, pModRef++)
|
|
{
|
|
char buffer[256];
|
|
BYTE *pstr = (BYTE *)pModule + pModule->import_table + *pModRef;
|
|
memcpy( buffer, pstr + 1, *pstr );
|
|
strcpy( buffer + *pstr, ".dll" );
|
|
dprintf_module( stddeb, "Loading '%s'\n", buffer );
|
|
if (!(*pModRef = MODULE_FindModule( buffer )))
|
|
{
|
|
/* If the DLL is not loaded yet, load it and store */
|
|
/* its handle in the list of DLLs to initialize. */
|
|
HMODULE hDLL;
|
|
|
|
if ((hDLL = LoadModule( buffer, (LPVOID)-1 )) == 2) /* file not found */
|
|
{
|
|
char *p;
|
|
|
|
/* Try with prepending the path of the current module */
|
|
GetModuleFileName( hModule, buffer, 256 );
|
|
if (!(p = strrchr( buffer, '\\' ))) p = buffer;
|
|
memcpy( p + 1, pstr + 1, *pstr );
|
|
strcpy( p + 1 + *pstr, ".dll" );
|
|
hDLL = LoadModule( buffer, (LPVOID)-1 );
|
|
}
|
|
if (hDLL < 32)
|
|
{
|
|
fprintf( stderr, "Could not load '%s' required by '%s', error = %d\n",
|
|
buffer, name, hDLL );
|
|
return 2; /* file not found */
|
|
}
|
|
*pModRef = GetExePtr( hDLL );
|
|
*pDLLs++ = *pModRef;
|
|
}
|
|
else /* Increment the reference count of the DLL */
|
|
{
|
|
NE_MODULE *pOldDLL = (NE_MODULE *)GlobalLock( *pModRef );
|
|
if (pOldDLL) pOldDLL->count++;
|
|
}
|
|
}
|
|
|
|
/* Load the segments */
|
|
|
|
if (pModule->flags & NE_FFLAGS_SELFLOAD)
|
|
{
|
|
/* Handle self loading modules */
|
|
SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
|
|
SELFLOADHEADER *selfloadheader;
|
|
HMODULE hselfload = GetModuleHandle("WINPROCS");
|
|
WORD oldss, oldsp, saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
|
|
fprintf (stderr, "Warning: %*.*s is a self-loading module\n"
|
|
"Support for self-loading modules is very experimental\n",
|
|
*((BYTE*)pModule + pModule->name_table),
|
|
*((BYTE*)pModule + pModule->name_table),
|
|
(char *)pModule + pModule->name_table + 1);
|
|
NE_LoadSegment( hModule, 1 );
|
|
selfloadheader = (SELFLOADHEADER *)
|
|
PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
|
|
selfloadheader->EntryAddrProc =
|
|
MODULE_GetEntryPoint(hselfload,27);
|
|
selfloadheader->MyAlloc = MODULE_GetEntryPoint(hselfload,28);
|
|
selfloadheader->SetOwner = MODULE_GetEntryPoint(GetModuleHandle("KERNEL"),403);
|
|
pModule->self_loading_sel = GlobalHandleToSel(
|
|
GLOBAL_Alloc (GMEM_ZEROINIT,
|
|
0xFF00, hModule, FALSE, FALSE, FALSE)
|
|
);
|
|
oldss = IF1632_Saved16_ss;
|
|
oldsp = IF1632_Saved16_sp;
|
|
IF1632_Saved16_ss = pModule->self_loading_sel;
|
|
IF1632_Saved16_sp = 0xFF00;
|
|
CallTo16_word_ww (selfloadheader->BootApp,
|
|
pModule->self_loading_sel, hModule, fd);
|
|
/* some BootApp procs overwrite the selector of dgroup */
|
|
pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
|
|
IF1632_Saved16_ss = oldss;
|
|
IF1632_Saved16_sp = oldsp;
|
|
for (i = 2; i <= pModule->seg_count; i++) NE_LoadSegment( hModule, i );
|
|
}
|
|
else
|
|
{
|
|
for (i = 1; i <= pModule->seg_count; i++)
|
|
NE_LoadSegment( hModule, i );
|
|
}
|
|
|
|
/* Fixup the functions prologs */
|
|
|
|
NE_FixupPrologs( hModule );
|
|
|
|
/* Make sure the usage count is 1 on the first loading of */
|
|
/* the module, even if it contains circular DLL references */
|
|
|
|
pModule->count = 1;
|
|
|
|
/* Clear built-in flag in case it was set in the EXE file */
|
|
|
|
pModule->flags &= ~NE_FFLAGS_BUILTIN;
|
|
}
|
|
else
|
|
{
|
|
pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
hPrevInstance = MODULE_GetInstance( hModule );
|
|
hInstance = MODULE_CreateInstance( hModule, params );
|
|
if (hInstance != hPrevInstance) /* not a library */
|
|
NE_LoadSegment( hModule, pModule->dgroup );
|
|
pModule->count++;
|
|
}
|
|
#else
|
|
hModule = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(NE_MODULE) );
|
|
pModule = (NE_MODULE *)GlobalLock( hModule );
|
|
pModule->count = 1;
|
|
pModule->magic = 0x454e;
|
|
hPrevInstance = 0;
|
|
hInstance = MODULE_CreateInstance( hModule, (LOADPARAMS*)paramBlock );
|
|
#endif /* WINELIB */
|
|
|
|
/* Create a task for this instance */
|
|
|
|
if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
|
|
{
|
|
TASK_CreateTask( hModule, hInstance, hPrevInstance,
|
|
params->hEnvironment,
|
|
(LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
|
|
*((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1) );
|
|
}
|
|
|
|
return hInstance;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* FreeModule (KERNEL.46)
|
|
*/
|
|
BOOL FreeModule( HANDLE hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return FALSE;
|
|
|
|
dprintf_module( stddeb, "FreeModule: %s count %d\n",
|
|
MODULE_GetModuleName(hModule), pModule->count );
|
|
if (--pModule->count == 0) MODULE_FreeModule( hModule );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleHandle (KERNEL.47)
|
|
*/
|
|
HMODULE WIN16_GetModuleHandle( SEGPTR name )
|
|
{
|
|
#ifdef WINELIB32
|
|
if (HIWORD(name) == 0) return GetExePtr( name );
|
|
#else
|
|
if (HIWORD(name) == 0) return GetExePtr( LOWORD(name) );
|
|
#endif
|
|
return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
|
|
}
|
|
|
|
HMODULE GetModuleHandle( LPCSTR name )
|
|
{
|
|
return MODULE_FindModule( name );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleUsage (KERNEL.48)
|
|
*/
|
|
int GetModuleUsage( HANDLE hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
dprintf_module( stddeb, "GetModuleUsage("NPFMT"): returning %d\n",
|
|
hModule, pModule->count );
|
|
return pModule->count;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleFileName (KERNEL.49)
|
|
*/
|
|
int GetModuleFileName( HANDLE hModule, LPSTR lpFileName, short nSize )
|
|
{
|
|
NE_MODULE *pModule;
|
|
char *name;
|
|
|
|
hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
|
|
name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
|
|
strncpy( lpFileName, name, nSize );
|
|
lpFileName[nSize-1] = '\0';
|
|
dprintf_module( stddeb, "GetModuleFilename: %s\n", lpFileName );
|
|
return strlen(lpFileName);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LoadLibrary (KERNEL.95)
|
|
*/
|
|
HANDLE LoadLibrary( LPCSTR libname )
|
|
{
|
|
HANDLE handle;
|
|
|
|
dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
|
|
/* This does not increment the module reference count, and will
|
|
* therefore cause crashes on FreeLibrary calls.
|
|
if ((handle = MODULE_FindModule( libname )) != 0) return handle;
|
|
*/
|
|
handle = LoadModule( libname, (LPVOID)-1 );
|
|
if (handle == (HANDLE)2) /* file not found */
|
|
{
|
|
char buffer[256];
|
|
strcpy( buffer, libname );
|
|
strcat( buffer, ".dll" );
|
|
handle = LoadModule( buffer, (LPVOID)-1 );
|
|
}
|
|
if (handle >= (HANDLE)32) NE_InitializeDLLs( GetExePtr(handle) );
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FreeLibrary (KERNEL.96)
|
|
*/
|
|
void FreeLibrary( HANDLE handle )
|
|
{
|
|
dprintf_module( stddeb,"FreeLibrary: "NPFMT"\n", handle );
|
|
FreeModule( handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* WinExec (KERNEL.166)
|
|
*/
|
|
HANDLE WinExec( LPSTR lpCmdLine, WORD nCmdShow )
|
|
{
|
|
LOADPARAMS params;
|
|
HLOCAL cmdShowHandle, cmdLineHandle;
|
|
HANDLE handle;
|
|
WORD *cmdShowPtr;
|
|
char *p, *cmdline, filename[256];
|
|
|
|
if (!(cmdShowHandle = GlobalAlloc( 0, 2 * sizeof(WORD) ))) return 0;
|
|
if (!(cmdLineHandle = GlobalAlloc( 0, 256 ))) return 0;
|
|
|
|
/* Store nCmdShow */
|
|
|
|
cmdShowPtr = (WORD *)GlobalLock( cmdShowHandle );
|
|
cmdShowPtr[0] = 2;
|
|
cmdShowPtr[1] = nCmdShow;
|
|
|
|
/* Build the filename and command-line */
|
|
|
|
cmdline = (char *)GlobalLock( cmdLineHandle );
|
|
strncpy( filename, lpCmdLine, 256 );
|
|
filename[255] = '\0';
|
|
for (p = filename; *p && (*p != ' ') && (*p != '\t'); p++);
|
|
if (*p)
|
|
{
|
|
strncpy( cmdline, p + 1, 128 );
|
|
cmdline[127] = '\0';
|
|
}
|
|
else cmdline[0] = '\0';
|
|
*p = '\0';
|
|
|
|
/* Now load the executable file */
|
|
|
|
params.hEnvironment = (HANDLE)SELECTOROF( GetDOSEnvironment() );
|
|
params.cmdLine = (SEGPTR)WIN16_GlobalLock( cmdLineHandle );
|
|
params.showCmd = (SEGPTR)WIN16_GlobalLock( cmdShowHandle );
|
|
params.reserved = 0;
|
|
handle = LoadModule( filename, ¶ms );
|
|
if (handle == (HANDLE)2) /* file not found */
|
|
{
|
|
strcat( filename, ".exe" );
|
|
handle = LoadModule( filename, ¶ms );
|
|
}
|
|
|
|
GlobalFree( cmdShowHandle );
|
|
GlobalFree( cmdLineHandle );
|
|
Yield(); /* program is executed immediatly ....needed for word */
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetProcAddress (KERNEL.50)
|
|
*/
|
|
FARPROC GetProcAddress( HANDLE hModule, SEGPTR name )
|
|
{
|
|
WORD ordinal;
|
|
SEGPTR ret;
|
|
|
|
if (!hModule) hModule = GetCurrentTask();
|
|
hModule = GetExePtr( hModule );
|
|
|
|
if (HIWORD(name) != 0)
|
|
{
|
|
ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
|
|
dprintf_module( stddeb, "GetProcAddress: "NPFMT" '%s'\n",
|
|
hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
|
|
}
|
|
else
|
|
{
|
|
ordinal = LOWORD(name);
|
|
dprintf_module( stddeb, "GetProcAddress: "NPFMT" %04x\n",
|
|
hModule, ordinal );
|
|
}
|
|
if (!ordinal) return (FARPROC)0;
|
|
|
|
ret = MODULE_GetEntryPoint( hModule, ordinal );
|
|
|
|
dprintf_module( stddeb, "GetProcAddress: returning %08lx\n", ret );
|
|
return (FARPROC)ret;
|
|
}
|
|
|
|
|
|
#ifndef WINELIB
|
|
/***********************************************************************
|
|
* GetWndProcEntry16 (not a Windows API function)
|
|
*
|
|
* Return an entry point from the WINPROCS dll.
|
|
*/
|
|
WNDPROC GetWndProcEntry16( char *name )
|
|
{
|
|
WORD ordinal;
|
|
static HMODULE hModule = 0;
|
|
|
|
if (!hModule) hModule = GetModuleHandle( "WINPROCS" );
|
|
ordinal = MODULE_GetOrdinal( hModule, name );
|
|
return MODULE_GetEntryPoint( hModule, ordinal );
|
|
}
|
|
#endif
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFirst (TOOLHELP.59)
|
|
*/
|
|
BOOL ModuleFirst( MODULEENTRY *lpme )
|
|
{
|
|
lpme->wNext = hFirstModule;
|
|
return ModuleNext( lpme );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleNext (TOOLHELP.60)
|
|
*/
|
|
BOOL ModuleNext( MODULEENTRY *lpme )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (!lpme->wNext) return FALSE;
|
|
if (!(pModule = (NE_MODULE *)GlobalLock( lpme->wNext ))) return FALSE;
|
|
strncpy( lpme->szModule, (char *)pModule + pModule->name_table,
|
|
MAX_MODULE_NAME );
|
|
lpme->szModule[MAX_MODULE_NAME] = '\0';
|
|
lpme->hModule = lpme->wNext;
|
|
lpme->wcUsage = pModule->count;
|
|
strncpy( lpme->szExePath,
|
|
((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename,
|
|
MAX_PATH );
|
|
lpme->szExePath[MAX_PATH] = '\0';
|
|
lpme->wNext = pModule->next;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFindName (TOOLHELP.61)
|
|
*/
|
|
BOOL ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
|
|
{
|
|
lpme->wNext = GetModuleHandle( name );
|
|
return ModuleNext( lpme );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFindHandle (TOOLHELP.62)
|
|
*/
|
|
BOOL ModuleFindHandle( MODULEENTRY *lpme, HMODULE hModule )
|
|
{
|
|
hModule = GetExePtr( hModule ); /* In case we were passed an hInstance */
|
|
lpme->wNext = hModule;
|
|
return ModuleNext( lpme );
|
|
}
|