Sun Mar 15 03:46:50 1998 Dimitrie O. Paun <dimi@mail.cs.toronto.edu> * [*/*] Fixed some dprintf_ such that there is one and only one new line for each dprintf and that new line occurs at the end. Transformed some fprintfs into proper debug statements. Removed much redundancy from most of the debug statements. The redundancy appeared because now the component and function name is output automatically. Most debug statements also used to output the name of the function. All these changes prepared the source to switch completely to the new debugging interface. For more info, refer to ./documentation/debug-msg Sat Mar 14 19:45:23 1997 Andreas Mohr <100.30936@germany.net> * [misc/shell.c] [if1632/kernel.spec] Changed parameters of FUNC004() to fix a crash. Not sure if this fix is correct (doc wanted). * [windows/user.c] [if1632/user.spec] [include/user.h] Implemented UserSeeUserDo. * [msdos/int21.c] [include/msdos.h] Added "GET LIST OF LISTS" (INT 21/52h). Sat Mar 14 15:48:02 1998 Douglas Ridgway <ridgway@gmcl.com> * [include/windows.h] [relay32/gdi32.spec] [objects/enhmetafile.c] Beginnings of enhanced metafile support. Fri Mar 13 20:53:09 1998 John Richardson <jrichard@zko.dec.com> * [win32/console.c] Restart interrupted console writes. Fri Mar 13 18:59:24 1998 Matthew Becker <mbecker@glasscity.net> * [*/*.c] Updated documentation for API manpages. * [windows/dce.c] ReleaseDC16: Fixed cast. * [include/windows.h] [memory/virtual.c] VirtualQuery{Ex} should return DWORD instead of BOOL32. Fri Mar 13 13:03:06 1998 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de> * [README][documentation/status/] README updated, added lzexpand,version and multimedia status notes to new documentation/status directory. * [ole/*.c][if1632/typelib.spec] Added typelib stubs, several small additions and fixes. * [loader/pe_image.c] Fixed a small bug (fixup_imports got passed the wrong hModule in a remapcase). * [loader/signal.c][if1632/signal.c][misc/winsock_dns.c] [loader/module.c] Fixed some recursive debugger crashes (caused by invalid FS). * [misc/registry.c] Two bugs fixed. Fri Mar 13 04:55:01 1998 David Lee Lambert <lamber45@egr.msu.edu> * [include/winnt.h] [include/winnls.h] Moved LANG_xxx flags to winnls.h * [include/winnls.h] Added flags for GetDateFormat(); fixed validity of LOCALE_SYSTEM_DEFAULT. * [include/windows.h] Added GetTimeFormat() prototypes. * [ole/ole2nls.c] Implemented ASCII date- and time-functions, using an optimized common core; added stubs for Unicode versions; started work on a Unicode core. * [AUTHORS] Added my name. Mon Mar 9 20:10:15 1998 Eric Kohl <ekohl@abo.rhein-zeitung.de> * [relay32/comctl32.spec] [include/imagelist.h] [include/commctrl.h] [misc/imagelist.c] [misc/Makefile.in] First attempt at implementing ImageLists. Sun Mar 8 20:19:49 1998 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> * [files/dos_fs.c] [configure.in] Try to get FileTimeToLocalFileTime,FileTimeToSystemTime and SystemTimeToFileTime right. Use timegm() where available. * [misc/lstr.c] Fix an off by one error in FormatMessage and handle the case when args = NULL (used by programs to get the length of the string). * [win32/console.c] Actual display a per-process Title string, better working attempt for WriteConsole32W and ReadConsole32W. Fri Mar 6 20:33:45 1998 Slaven Rezic <eserte@cs.tu-berlin.de> * [include/config.h.in][configure.in][multimedia/audio.c] [multimedia/dsound.c] Added check for FreeBSD sound system. Sun Mar 1 17:40:10 1998 Jason Schonberg <schon@mti.sgi.com> * [controls/edit.c] [include/ole.h] [include/shlobj.h] Removed final commas in enum types. Mon Feb 23 07:52:18 1998 Luiz Otavio L. Zorzella <zorzella@nr.conexware.com> * [multimedia/time.c] Workaround to avoid infinite recursion inside timeGetTime. * [multimedia/audio.c] WODM_GETNUMDEVS and WIDM_GETNUMDEVS only return 1 now if the SOUND_DEV can be opened, or if it's busy.
1926 lines
57 KiB
C
1926 lines
57 KiB
C
/*
|
|
* Modules
|
|
*
|
|
* Copyright 1995 Alexandre Julliard
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include "windows.h"
|
|
#include "class.h"
|
|
#include "file.h"
|
|
#include "global.h"
|
|
#include "heap.h"
|
|
#include "module.h"
|
|
#include "neexe.h"
|
|
#include "process.h"
|
|
#include "thread.h"
|
|
#include "resource.h"
|
|
#include "selectors.h"
|
|
#include "stackframe.h"
|
|
#include "task.h"
|
|
#include "toolhelp.h"
|
|
#include "debug.h"
|
|
#include "callback.h"
|
|
|
|
extern HINSTANCE16 PE_LoadModule( HFILE32 hf, OFSTRUCT *ofs, LOADPARAMS* params );
|
|
|
|
extern BOOL32 THREAD_InitDone;
|
|
|
|
static HMODULE16 hFirstModule = 0;
|
|
static HMODULE16 hCachedModule = 0; /* Module cached by MODULE_OpenFile */
|
|
|
|
static HMODULE32 MODULE_LoadModule(LPCSTR name,BOOL32 force) { return 0; }
|
|
HMODULE32 (*fnBUILTIN_LoadModule)(LPCSTR name,BOOL32 force) = MODULE_LoadModule;
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetPtr
|
|
*/
|
|
NE_MODULE *MODULE_GetPtr( HMODULE32 hModule )
|
|
{
|
|
HMODULE16 hnd =MODULE_HANDLEtoHMODULE16(hModule);
|
|
|
|
if (!hnd)
|
|
return NULL;
|
|
return (NE_MODULE*)GlobalLock16(hnd);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_HANDLEtoHMODULE16
|
|
*/
|
|
HMODULE16
|
|
MODULE_HANDLEtoHMODULE16(HANDLE32 handle) {
|
|
NE_MODULE *pModule;
|
|
|
|
if (HIWORD(handle))
|
|
{
|
|
/* this is a HMODULE32 */
|
|
|
|
/* walk the list looking for the correct startaddress */
|
|
pModule = (NE_MODULE *)GlobalLock16( hFirstModule );
|
|
while (pModule)
|
|
{
|
|
if (pModule->module32 == handle) return pModule->self;
|
|
pModule = (NE_MODULE*)GlobalLock16(pModule->next);
|
|
}
|
|
return 0;
|
|
}
|
|
return GetExePtr(handle);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_HANDLEtoHMODULE32
|
|
* return HMODULE32, if possible, HMODULE16 otherwise
|
|
*/
|
|
HMODULE32
|
|
MODULE_HANDLEtoHMODULE32(HANDLE32 handle) {
|
|
NE_MODULE *pModule;
|
|
|
|
if (HIWORD(handle))
|
|
return (HMODULE32)handle;
|
|
else {
|
|
handle = GetExePtr(handle);
|
|
if (!handle)
|
|
return 0;
|
|
pModule = (NE_MODULE *)GlobalLock16( handle );
|
|
if (!pModule)
|
|
return 0;
|
|
|
|
if (pModule->module32) return pModule->module32;
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_DumpModule
|
|
*/
|
|
void MODULE_DumpModule( HMODULE32 hModule )
|
|
{
|
|
int i, ordinal;
|
|
SEGTABLEENTRY *pSeg;
|
|
BYTE *pstr;
|
|
WORD *pword;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule )))
|
|
{
|
|
fprintf( stderr, "**** %04x is not a module handle\n", hModule );
|
|
return;
|
|
}
|
|
|
|
/* Dump the module info */
|
|
|
|
printf( "Module %04x:\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 );
|
|
if (pModule->flags & NE_FFLAGS_WIN32)
|
|
printf( "PE module=%08x\n", pModule->module32 );
|
|
|
|
/* Dump the file info */
|
|
|
|
printf( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
|
|
|
|
/* 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=%04x\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++)
|
|
{
|
|
printf( "%d: %04x -> '%s'\n", i, *pword,
|
|
MODULE_GetModuleName(*pword));
|
|
}
|
|
}
|
|
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 *)GlobalLock16( 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_WalkModules
|
|
*
|
|
* Walk the module list and print the modules.
|
|
*/
|
|
void MODULE_WalkModules(void)
|
|
{
|
|
HMODULE16 hModule = hFirstModule;
|
|
fprintf( stderr, "Module Flags Name\n" );
|
|
while (hModule)
|
|
{
|
|
NE_MODULE *pModule = MODULE_GetPtr( hModule );
|
|
if (!pModule)
|
|
{
|
|
fprintf( stderr, "**** Bad module %04x in list\n", hModule );
|
|
return;
|
|
}
|
|
fprintf( stderr, " %04x %04x %.*s\n", hModule, pModule->flags,
|
|
*((char *)pModule + pModule->name_table),
|
|
(char *)pModule + pModule->name_table + 1 );
|
|
hModule = pModule->next;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_OpenFile
|
|
*/
|
|
int MODULE_OpenFile( HMODULE32 hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
DOS_FULL_NAME full_name;
|
|
char *name;
|
|
|
|
static int cachedfd = -1;
|
|
|
|
hModule = MODULE_HANDLEtoHMODULE16(hModule);
|
|
TRACE(module, "(%04x) cache: mod=%04x fd=%d\n",
|
|
hModule, hCachedModule, cachedfd );
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return -1;
|
|
if (hCachedModule == hModule) return cachedfd;
|
|
close( cachedfd );
|
|
hCachedModule = hModule;
|
|
name = NE_MODULE_NAME( pModule );
|
|
if (!DOSFS_GetFullName( name, TRUE, &full_name ) ||
|
|
(cachedfd = open( full_name.long_name, O_RDONLY )) == -1)
|
|
fprintf( stderr, "MODULE_OpenFile: can't open file '%s' for module %04x\n",
|
|
name, hModule );
|
|
TRACE(module, "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 (WPROCS.26)
|
|
*/
|
|
|
|
DWORD WINAPI MODULE_AllocateSegment(WORD wFlags, WORD wSize, WORD wElem)
|
|
{
|
|
WORD size = wSize << wElem;
|
|
HANDLE16 hMem = GlobalAlloc16( MODULE_Ne2MemFlags(wFlags), size);
|
|
return MAKELONG( hMem, GlobalHandleToSel(hMem) );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MODULE_CreateSegments
|
|
*/
|
|
static BOOL32 MODULE_CreateSegments( HMODULE32 hModule )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
int i, minsize;
|
|
|
|
if (!(pModule = MODULE_GetPtr( 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
|
|
*/
|
|
HINSTANCE16 MODULE_GetInstance( HMODULE32 hModule )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
|
|
if (pModule->dgroup == 0) return hModule;
|
|
|
|
pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
|
|
|
|
return pSegment->selector;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_CreateInstance
|
|
*/
|
|
HINSTANCE16 MODULE_CreateInstance( HMODULE16 hModule, LOADPARAMS *params )
|
|
{
|
|
SEGTABLEENTRY *pSegment;
|
|
NE_MODULE *pModule;
|
|
int minsize;
|
|
HINSTANCE16 hNewInstance, hPrevInstance;
|
|
|
|
if (!(pModule = MODULE_GetPtr( 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_CreateDummyModule
|
|
*
|
|
* Create a dummy NE module for Win32 or Winelib.
|
|
*/
|
|
HMODULE32 MODULE_CreateDummyModule( const OFSTRUCT *ofs )
|
|
{
|
|
HMODULE32 hModule;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegment;
|
|
char *pStr,*s;
|
|
int len;
|
|
const char* basename;
|
|
|
|
INT32 of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
|
|
+ strlen(ofs->szPathName) + 1;
|
|
INT32 size = sizeof(NE_MODULE) +
|
|
/* loaded file info */
|
|
of_size +
|
|
/* segment table: DS,CS */
|
|
2 * sizeof(SEGTABLEENTRY) +
|
|
/* name table */
|
|
9 +
|
|
/* several empty tables */
|
|
8;
|
|
|
|
hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
|
|
if (!hModule) return (HMODULE32)11; /* invalid exe */
|
|
|
|
FarSetOwner( hModule, hModule );
|
|
pModule = (NE_MODULE *)GlobalLock16( hModule );
|
|
|
|
/* Set all used entries */
|
|
pModule->magic = IMAGE_OS2_SIGNATURE;
|
|
pModule->count = 1;
|
|
pModule->next = 0;
|
|
pModule->flags = 0;
|
|
pModule->dgroup = 1;
|
|
pModule->ss = 1;
|
|
pModule->cs = 2;
|
|
pModule->heap_size = 0xe000;
|
|
pModule->stack_size = 0x1000;
|
|
pModule->seg_count = 2;
|
|
pModule->modref_count = 0;
|
|
pModule->nrname_size = 0;
|
|
pModule->fileinfo = sizeof(NE_MODULE);
|
|
pModule->os_flags = NE_OSFLAGS_WINDOWS;
|
|
pModule->expected_version = 0x030a;
|
|
pModule->self = hModule;
|
|
|
|
/* Set loaded file information */
|
|
memcpy( pModule + 1, ofs, of_size );
|
|
((OFSTRUCT *)(pModule+1))->cBytes = of_size - 1;
|
|
|
|
pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + of_size);
|
|
pModule->seg_table = pModule->dgroup_entry = (int)pSegment - (int)pModule;
|
|
/* Data segment */
|
|
pSegment->size = 0;
|
|
pSegment->flags = NE_SEGFLAGS_DATA;
|
|
pSegment->minsize = 0x1000;
|
|
pSegment++;
|
|
/* Code segment */
|
|
pSegment->flags = 0;
|
|
pSegment++;
|
|
|
|
/* Module name */
|
|
pStr = (char *)pSegment;
|
|
pModule->name_table = (int)pStr - (int)pModule;
|
|
basename = strrchr(ofs->szPathName,'\\');
|
|
if (!basename) basename = ofs->szPathName;
|
|
else basename++;
|
|
len = strlen(basename);
|
|
if ((s = strchr(basename,'.'))) len = s - basename;
|
|
if (len > 8) len = 8;
|
|
*pStr = len;
|
|
strncpy( pStr+1, basename, len );
|
|
if (len < 8) pStr[len+1] = 0;
|
|
pStr += 9;
|
|
|
|
/* All tables zero terminated */
|
|
pModule->res_table = pModule->import_table = pModule->entry_table =
|
|
(int)pStr - (int)pModule;
|
|
|
|
MODULE_RegisterModule( pModule );
|
|
return hModule;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_LoadExeHeader
|
|
*/
|
|
static HMODULE32 MODULE_LoadExeHeader( HFILE32 hFile, OFSTRUCT *ofs )
|
|
{
|
|
IMAGE_DOS_HEADER mz_header;
|
|
IMAGE_OS2_HEADER ne_header;
|
|
int size;
|
|
HMODULE32 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) : \
|
|
(_llseek32( hFile, (offset), SEEK_SET), \
|
|
_lread32( hFile, (buffer), (size) ) == (size)))
|
|
|
|
_llseek32( hFile, 0, SEEK_SET );
|
|
if ((_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
|
|
(mz_header.e_magic != IMAGE_DOS_SIGNATURE))
|
|
return (HMODULE32)11; /* invalid exe */
|
|
|
|
_llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
|
|
if (_lread32( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
|
|
return (HMODULE32)11; /* invalid exe */
|
|
|
|
if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE32)21; /* win32 exe */
|
|
if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE32)11; /* invalid exe */
|
|
|
|
if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
|
|
fprintf(stderr, "Sorry, this is an OS/2 linear executable (LX) file !\n");
|
|
return (HMODULE32)12;
|
|
}
|
|
/* We now have a valid NE header */
|
|
|
|
size = sizeof(NE_MODULE) +
|
|
/* loaded file info */
|
|
sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1+
|
|
/* 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 = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
|
|
if (!hModule) return (HMODULE32)11; /* invalid exe */
|
|
FarSetOwner( hModule, hModule );
|
|
pModule = (NE_MODULE *)GlobalLock16( hModule );
|
|
memcpy( pModule, &ne_header, sizeof(ne_header) );
|
|
pModule->count = 0;
|
|
pModule->module32 = 0;
|
|
pModule->self = hModule;
|
|
pModule->self_loading_sel = 0;
|
|
pData = (BYTE *)(pModule + 1);
|
|
|
|
/* Clear internal Wine flags in case they are set in the EXE file */
|
|
|
|
pModule->flags &= ~(NE_FFLAGS_BUILTIN|NE_FFLAGS_WIN32|NE_FFLAGS_IMPLICIT);
|
|
|
|
/* 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;
|
|
TRACE(module, "Using fast-load area offset=%x len=%d\n",
|
|
fastload_offset, fastload_length );
|
|
if ((fastload = HeapAlloc( SystemHeap, 0, fastload_length )) != NULL)
|
|
{
|
|
_llseek32( hFile, fastload_offset, SEEK_SET);
|
|
if (_lread32(hFile, fastload, fastload_length) != fastload_length)
|
|
{
|
|
HeapFree( SystemHeap, 0, fastload );
|
|
fprintf(stderr, "Error reading fast-load area !\n");
|
|
fastload = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Store the filename information */
|
|
|
|
pModule->fileinfo = (int)pData - (int)pModule;
|
|
size = sizeof(OFSTRUCT)-sizeof(ofs->szPathName)+strlen(ofs->szPathName)+1;
|
|
memcpy( pData, ofs, size );
|
|
((OFSTRUCT *)pData)->cBytes = size - 1;
|
|
pData += size;
|
|
|
|
/* Get the segment table */
|
|
|
|
pModule->seg_table = (int)pData - (int)pModule;
|
|
buffer = HeapAlloc( SystemHeap, 0, 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( mz_header.e_lfanew + ne_header.segment_tab_offset,
|
|
ne_header.n_segment_tab * sizeof(struct ne_segment_table_entry_s),
|
|
buffer ))
|
|
{
|
|
HeapFree( SystemHeap, 0, buffer );
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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);
|
|
}
|
|
HeapFree( SystemHeap, 0, buffer );
|
|
}
|
|
else
|
|
{
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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(mz_header.e_lfanew + ne_header.resource_tab_offset,
|
|
ne_header.rname_tab_offset - ne_header.resource_tab_offset,
|
|
pData )) return (HMODULE32)11; /* invalid exe */
|
|
pData += ne_header.rname_tab_offset - ne_header.resource_tab_offset;
|
|
NE_InitResourceHandler( hModule );
|
|
}
|
|
else pModule->res_table = 0; /* No resource table */
|
|
|
|
/* Get the resident names table */
|
|
|
|
pModule->name_table = (int)pData - (int)pModule;
|
|
if (!READ( mz_header.e_lfanew + ne_header.rname_tab_offset,
|
|
ne_header.moduleref_tab_offset - ne_header.rname_tab_offset,
|
|
pData ))
|
|
{
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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( mz_header.e_lfanew + ne_header.moduleref_tab_offset,
|
|
ne_header.n_mod_ref_tab * sizeof(WORD),
|
|
pData ))
|
|
{
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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( mz_header.e_lfanew + ne_header.iname_tab_offset,
|
|
ne_header.entry_tab_offset - ne_header.iname_tab_offset,
|
|
pData ))
|
|
{
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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( mz_header.e_lfanew + ne_header.entry_tab_offset,
|
|
ne_header.entry_tab_length,
|
|
pData ))
|
|
{
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)11; /* invalid exe */
|
|
}
|
|
pData += ne_header.entry_tab_length;
|
|
|
|
/* Free the fast-load area */
|
|
|
|
#undef READ
|
|
if (fastload) HeapFree( SystemHeap, 0, fastload );
|
|
|
|
/* 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)
|
|
{
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)11; /* invalid exe */
|
|
}
|
|
buffer = GlobalLock16( pModule->nrname_handle );
|
|
_llseek32( hFile, ne_header.nrname_tab_offset, SEEK_SET );
|
|
if (_lread32( hFile, buffer, ne_header.nrname_tab_length )
|
|
!= ne_header.nrname_tab_length)
|
|
{
|
|
GlobalFree16( pModule->nrname_handle );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)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(HMODULE32),
|
|
hModule, FALSE, FALSE, FALSE );
|
|
if (!pModule->dlls_to_init)
|
|
{
|
|
if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
|
|
GlobalFree16( hModule );
|
|
return (HMODULE32)11; /* invalid exe */
|
|
}
|
|
}
|
|
else pModule->dlls_to_init = 0;
|
|
|
|
MODULE_RegisterModule( pModule );
|
|
return hModule;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetOrdinal
|
|
*
|
|
* Lookup the ordinal for a given name.
|
|
*/
|
|
WORD MODULE_GetOrdinal( HMODULE32 hModule, const char *name )
|
|
{
|
|
unsigned char buffer[256], *cpnt;
|
|
BYTE len;
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
|
|
|
|
TRACE(module, "(%04x,'%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 );
|
|
CharUpper32A( 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)
|
|
{
|
|
if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
|
|
{
|
|
TRACE(module, " 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 *)GlobalLock16( pModule->nrname_handle );
|
|
|
|
/* Skip the first entry (module description string) */
|
|
cpnt += *cpnt + 1 + sizeof(WORD);
|
|
while (*cpnt)
|
|
{
|
|
if (((BYTE)*cpnt == len) && !memcmp( cpnt+1, buffer, len ))
|
|
{
|
|
TRACE(module, " 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.
|
|
*/
|
|
FARPROC16 MODULE_GetEntryPoint( HMODULE32 hModule, WORD ordinal )
|
|
{
|
|
NE_MODULE *pModule;
|
|
WORD curOrdinal = 1;
|
|
BYTE *p;
|
|
WORD sel, offset;
|
|
|
|
if (!(pModule = MODULE_GetPtr( 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 = (WORD)(DWORD)NE_SEG_TABLE(pModule)[sel-1].selector;
|
|
return (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( sel, offset );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* EntryAddrProc (WPROCS.27)
|
|
*/
|
|
FARPROC16 WINAPI EntryAddrProc( HMODULE16 hModule, WORD ordinal )
|
|
{
|
|
return MODULE_GetEntryPoint( hModule, ordinal );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_SetEntryPoint
|
|
*
|
|
* Change the value of an entry point. Use with caution!
|
|
* It can only change the offset value, not the selector.
|
|
*/
|
|
BOOL16 MODULE_SetEntryPoint( HMODULE32 hModule, WORD ordinal, WORD offset )
|
|
{
|
|
NE_MODULE *pModule;
|
|
WORD curOrdinal = 1;
|
|
BYTE *p;
|
|
|
|
if (!(pModule = MODULE_GetPtr( 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_GetWndProcEntry16 (not a Windows API function)
|
|
*
|
|
* Return an entry point from the WPROCS dll.
|
|
*/
|
|
FARPROC16 MODULE_GetWndProcEntry16( LPCSTR name )
|
|
{
|
|
FARPROC16 ret = NULL;
|
|
|
|
if (__winelib)
|
|
{
|
|
/* FIXME: hack for Winelib */
|
|
extern LRESULT ColorDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT FileOpenDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT FileSaveDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT FindTextDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT PrintDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT PrintSetupDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
extern LRESULT ReplaceTextDlgProc(HWND16,UINT16,WPARAM16,LPARAM);
|
|
|
|
if (!strcmp(name,"ColorDlgProc"))
|
|
return (FARPROC16)ColorDlgProc;
|
|
if (!strcmp(name,"FileOpenDlgProc"))
|
|
return (FARPROC16)FileOpenDlgProc;
|
|
if (!strcmp(name,"FileSaveDlgProc"))
|
|
return (FARPROC16)FileSaveDlgProc;
|
|
if (!strcmp(name,"FindTextDlgProc"))
|
|
return (FARPROC16)FindTextDlgProc;
|
|
if (!strcmp(name,"PrintDlgProc"))
|
|
return (FARPROC16)PrintDlgProc;
|
|
if (!strcmp(name,"PrintSetupDlgProc"))
|
|
return (FARPROC16)PrintSetupDlgProc;
|
|
if (!strcmp(name,"ReplaceTextDlgProc"))
|
|
return (FARPROC16)ReplaceTextDlgProc;
|
|
fprintf(stderr,"warning: No mapping for %s(), add one in library/miscstubs.c\n",name);
|
|
assert( FALSE );
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
WORD ordinal;
|
|
static HMODULE32 hModule = 0;
|
|
|
|
if (!hModule) hModule = GetModuleHandle16( "WPROCS" );
|
|
ordinal = MODULE_GetOrdinal( hModule, name );
|
|
if (!(ret = MODULE_GetEntryPoint( hModule, ordinal )))
|
|
{
|
|
fprintf( stderr, "GetWndProc16: %s not found\n", name );
|
|
assert( FALSE );
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MODULE_GetModuleName
|
|
*/
|
|
LPSTR MODULE_GetModuleName( HMODULE32 hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
BYTE *p, len;
|
|
static char buffer[10];
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return NULL;
|
|
p = (BYTE *)pModule + pModule->name_table;
|
|
len = MIN( *p, 8 );
|
|
memcpy( buffer, p + 1, len );
|
|
buffer[len] = '\0';
|
|
return buffer;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_RegisterModule
|
|
*/
|
|
void MODULE_RegisterModule( NE_MODULE *pModule )
|
|
{
|
|
pModule->next = hFirstModule;
|
|
hFirstModule = pModule->self;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_FindModule
|
|
*
|
|
* Find a module from a path name.
|
|
*/
|
|
HMODULE32 MODULE_FindModule( LPCSTR path )
|
|
{
|
|
HMODULE32 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 = MODULE_GetPtr( hModule );
|
|
if (!pModule) break;
|
|
modulepath = NE_MODULE_NAME(pModule);
|
|
if (!(modulename = strrchr( modulepath, '\\' )))
|
|
modulename = modulepath;
|
|
else modulename++;
|
|
if (!lstrcmpi32A( modulename, filename )) return hModule;
|
|
|
|
name_table = (BYTE *)pModule + pModule->name_table;
|
|
if ((*name_table == len) && !lstrncmpi32A(filename, name_table+1, len))
|
|
return hModule;
|
|
hModule = pModule->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_CallWEP
|
|
*
|
|
* Call a DLL's WEP, allowing it to shut down.
|
|
* FIXME: we always pass the WEP WEP_FREE_DLL, never WEP_SYSTEM_EXIT
|
|
*/
|
|
static BOOL16 MODULE_CallWEP( HMODULE16 hModule )
|
|
{
|
|
FARPROC16 WEP = (FARPROC16)0;
|
|
WORD ordinal = MODULE_GetOrdinal( hModule, "WEP" );
|
|
|
|
if (ordinal) WEP = MODULE_GetEntryPoint( hModule, ordinal );
|
|
if (!WEP)
|
|
{
|
|
WARN(module, "module %04x doesn't have a WEP\n", hModule );
|
|
return FALSE;
|
|
}
|
|
return Callbacks->CallWindowsExitProc( WEP, WEP_FREE_DLL );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_FreeModule
|
|
*
|
|
* Remove a module from memory.
|
|
*/
|
|
BOOL16 MODULE_FreeModule( HMODULE32 hModule, TDB* pTaskContext )
|
|
{
|
|
HMODULE16 *hPrevModule;
|
|
NE_MODULE *pModule;
|
|
SEGTABLEENTRY *pSegment;
|
|
HMODULE16 *pModRef;
|
|
int i;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
|
|
hModule = pModule->self;
|
|
|
|
if (((INT16)(--pModule->count)) > 0 ) return TRUE;
|
|
else pModule->count = 0;
|
|
|
|
if (pModule->flags & NE_FFLAGS_BUILTIN)
|
|
return FALSE; /* Can't free built-in module */
|
|
|
|
if (pModule->flags & NE_FFLAGS_LIBMODULE)
|
|
{
|
|
MODULE_CallWEP( hModule );
|
|
|
|
/* Free the objects owned by the DLL module */
|
|
|
|
if( pTaskContext && pTaskContext->userhandler )
|
|
{
|
|
pTaskContext->userhandler( hModule, USIG_DLL_UNLOAD, 0,
|
|
pTaskContext->hInstance,
|
|
pTaskContext->hQueue );
|
|
}
|
|
}
|
|
/* Clear magic number just in case */
|
|
|
|
pModule->magic = pModule->self = 0;
|
|
|
|
/* Remove it from the linked list */
|
|
|
|
hPrevModule = &hFirstModule;
|
|
while (*hPrevModule && (*hPrevModule != hModule))
|
|
{
|
|
hPrevModule = &(MODULE_GetPtr( *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++)
|
|
{
|
|
GlobalFree16( pSegment->selector );
|
|
}
|
|
|
|
/* Free the referenced modules */
|
|
|
|
pModRef = (HMODULE16*)NE_MODULE_TABLE( pModule );
|
|
for (i = 0; i < pModule->modref_count; i++, pModRef++)
|
|
{
|
|
FreeModule16( *pModRef );
|
|
}
|
|
|
|
/* Free the module storage */
|
|
|
|
if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
|
|
if (pModule->dlls_to_init) GlobalFree16( pModule->dlls_to_init );
|
|
GlobalFree16( hModule );
|
|
|
|
/* Remove module from cache */
|
|
|
|
if (hCachedModule == hModule) hCachedModule = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* MODULE_Load
|
|
*
|
|
* Implementation of LoadModule()
|
|
*/
|
|
HINSTANCE16 MODULE_Load( LPCSTR name, LPVOID paramBlock, UINT16 uFlags)
|
|
{
|
|
HMODULE32 hModule;
|
|
HINSTANCE16 hInstance, hPrevInstance;
|
|
NE_MODULE *pModule;
|
|
LOADPARAMS *params = (LOADPARAMS *)paramBlock;
|
|
OFSTRUCT ofs;
|
|
HFILE32 hFile;
|
|
|
|
if (__winelib)
|
|
{
|
|
lstrcpyn32A( ofs.szPathName, name, sizeof(ofs.szPathName) );
|
|
if ((hModule = MODULE_CreateDummyModule( &ofs )) < 32) return hModule;
|
|
pModule = (NE_MODULE *)GlobalLock16( hModule );
|
|
hPrevInstance = 0;
|
|
hInstance = MODULE_CreateInstance( hModule, params );
|
|
}
|
|
else
|
|
{
|
|
hModule = MODULE_FindModule( name );
|
|
|
|
if (!hModule) /* We have to load the module */
|
|
{
|
|
/* Try to load the built-in first if not disabled */
|
|
if ((hModule = fnBUILTIN_LoadModule( name, FALSE )))
|
|
return MODULE_HANDLEtoHMODULE16( hModule );
|
|
|
|
if ((hFile = OpenFile32( name, &ofs, OF_READ )) == HFILE_ERROR32)
|
|
{
|
|
/* Now try the built-in even if disabled */
|
|
if ((hModule = fnBUILTIN_LoadModule( name, TRUE )))
|
|
{
|
|
fprintf( stderr, "Warning: could not load Windows DLL '%s', using built-in module.\n", name );
|
|
return MODULE_HANDLEtoHMODULE16( hModule );
|
|
}
|
|
return 2; /* File not found */
|
|
}
|
|
|
|
/* Create the module structure */
|
|
|
|
hModule = MODULE_LoadExeHeader( hFile, &ofs );
|
|
if (hModule < 32)
|
|
{
|
|
if (hModule == 21)
|
|
hModule = PE_LoadModule( hFile, &ofs, paramBlock );
|
|
else _lclose32( hFile );
|
|
|
|
if (hModule < 32)
|
|
fprintf( stderr, "LoadModule: can't load '%s', error=%d\n",
|
|
name, hModule );
|
|
return hModule;
|
|
}
|
|
_lclose32( hFile );
|
|
pModule = MODULE_GetPtr( hModule );
|
|
pModule->flags |= uFlags; /* stamp implicitly loaded modules */
|
|
|
|
/* Allocate the segments for this module */
|
|
|
|
MODULE_CreateSegments( hModule );
|
|
hPrevInstance = 0;
|
|
hInstance = MODULE_CreateInstance(hModule,(LOADPARAMS*)paramBlock);
|
|
|
|
/* Load the referenced DLLs */
|
|
|
|
if (!NE_LoadDLLs( pModule )) return 2; /* File not found */
|
|
|
|
/* Load the segments */
|
|
|
|
NE_LoadAllSegments( pModule );
|
|
|
|
/* Fixup the functions prologs */
|
|
|
|
NE_FixupPrologs( pModule );
|
|
|
|
/* Make sure the usage count is 1 on the first loading of */
|
|
/* the module, even if it contains circular DLL references */
|
|
|
|
pModule->count = 1;
|
|
|
|
/* Call initialization rountines for all loaded DLLs. Note that
|
|
* when we load implicitly linked DLLs this will be done by InitTask().
|
|
*/
|
|
|
|
if ((pModule->flags & (NE_FFLAGS_LIBMODULE | NE_FFLAGS_IMPLICIT)) ==
|
|
NE_FFLAGS_LIBMODULE )
|
|
NE_InitializeDLLs( hModule );
|
|
}
|
|
else /* module is already loaded, just create a new data segment if it's a task */
|
|
{
|
|
pModule = MODULE_GetPtr( hModule );
|
|
hPrevInstance = MODULE_GetInstance( hModule );
|
|
hInstance = MODULE_CreateInstance( hModule, params );
|
|
if (hInstance != hPrevInstance) /* not a library */
|
|
NE_LoadSegment( pModule, pModule->dgroup );
|
|
pModule->count++;
|
|
}
|
|
} /* !winelib */
|
|
|
|
/* Create a task for this instance */
|
|
|
|
if (!(pModule->flags & NE_FFLAGS_LIBMODULE) && (paramBlock != (LPVOID)-1))
|
|
{
|
|
HTASK16 hTask;
|
|
WORD showcmd;
|
|
|
|
pModule->flags |= NE_FFLAGS_GUI;
|
|
|
|
/* PowerPoint passes NULL as showCmd */
|
|
if (params->showCmd)
|
|
showcmd = *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1);
|
|
else
|
|
showcmd = 0; /* FIXME: correct */
|
|
|
|
hTask = TASK_CreateTask( hModule, hInstance, hPrevInstance,
|
|
params->hEnvironment,
|
|
(LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
|
|
showcmd );
|
|
|
|
if( hTask && TASK_GetNextTask(hTask)) Yield16();
|
|
}
|
|
|
|
return hInstance;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* LoadModule16 (KERNEL.45)
|
|
*/
|
|
HINSTANCE16 LoadModule16( LPCSTR name, LPVOID paramBlock )
|
|
{
|
|
return MODULE_Load( name, paramBlock, 0 );
|
|
}
|
|
|
|
/**********************************************************************
|
|
* LoadModule32 (KERNEL32.499)
|
|
*
|
|
* FIXME
|
|
*
|
|
* This should get implemented via CreateProcess -- MODULE_Load
|
|
* is resolutely 16-bit.
|
|
*/
|
|
DWORD LoadModule32( LPCSTR name, LPVOID paramBlock )
|
|
{
|
|
#ifdef 0
|
|
LOADPARAMS32 *p = paramBlock;
|
|
STARTUPINFO st;
|
|
PROCESSINFORMATION pi;
|
|
st.cb = sizeof(STARTUPINFO);
|
|
st.wShowWindow = p->lpCmdShow[2] ; WRONG
|
|
|
|
BOOL32 ret = CreateProcess32A( name, p->lpCmdLine,
|
|
NULL, NULL, FALSE, 0, p->lpEnvAddress,
|
|
NULL, &st, &pi);
|
|
if (!ret) {
|
|
/* handle errors appropriately */
|
|
}
|
|
CloseHandle32(pi.hProcess);
|
|
CloseHandle32(pi.hThread);
|
|
|
|
#else
|
|
return MODULE_Load( name, paramBlock, 0 );
|
|
#endif
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* FreeModule16 (KERNEL.46)
|
|
*/
|
|
BOOL16 WINAPI FreeModule16( HMODULE16 hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return FALSE;
|
|
TRACE(module, "%s count %d\n",
|
|
MODULE_GetModuleName(hModule), pModule->count );
|
|
|
|
return MODULE_FreeModule( hModule, GlobalLock16(GetCurrentTask()) );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleHandle16 (KERNEL.47)
|
|
*/
|
|
HMODULE16 WINAPI WIN16_GetModuleHandle( SEGPTR name )
|
|
{
|
|
if (HIWORD(name) == 0) return MODULE_HANDLEtoHMODULE16( (HINSTANCE16)name );
|
|
return MODULE_FindModule( PTR_SEG_TO_LIN(name) );
|
|
}
|
|
|
|
HMODULE16 WINAPI GetModuleHandle16( LPCSTR name )
|
|
{
|
|
return MODULE_FindModule( name );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetModuleHandle (KERNEL32.237)
|
|
*/
|
|
HMODULE32 WINAPI GetModuleHandle32A(LPCSTR module)
|
|
{
|
|
HMODULE32 hModule;
|
|
|
|
TRACE(win32, "%s\n", module ? module : "NULL");
|
|
/* Freecell uses the result of GetModuleHandleA(0) as the hInstance in
|
|
all calls to e.g. CreateWindowEx. */
|
|
if (module == NULL) {
|
|
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
|
|
hModule = pTask->hInstance;
|
|
} else
|
|
hModule = MODULE_FindModule(module);
|
|
return MODULE_HANDLEtoHMODULE32(hModule);
|
|
}
|
|
|
|
HMODULE32 WINAPI GetModuleHandle32W(LPCWSTR module)
|
|
{
|
|
HMODULE32 hModule;
|
|
LPSTR modulea = HEAP_strdupWtoA( GetProcessHeap(), 0, module );
|
|
hModule = GetModuleHandle32A( modulea );
|
|
HeapFree( GetProcessHeap(), 0, modulea );
|
|
return hModule;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleUsage (KERNEL.48)
|
|
*/
|
|
INT16 WINAPI GetModuleUsage( HINSTANCE16 hModule )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
|
|
TRACE(module, "(%04x): returning %d\n",
|
|
hModule, pModule->count );
|
|
return pModule->count;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleFileName16 (KERNEL.49)
|
|
*/
|
|
INT16 WINAPI GetModuleFileName16( HINSTANCE16 hModule, LPSTR lpFileName,
|
|
INT16 nSize )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (!hModule) hModule = GetCurrentTask();
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
|
|
lstrcpyn32A( lpFileName, NE_MODULE_NAME(pModule), nSize );
|
|
TRACE(module, "%s\n", lpFileName );
|
|
return strlen(lpFileName);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetModuleFileName32A (KERNEL32.235)
|
|
*/
|
|
DWORD WINAPI GetModuleFileName32A( HMODULE32 hModule, LPSTR lpFileName,
|
|
DWORD size )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (!hModule)
|
|
{
|
|
TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
|
|
hModule = pTask->hInstance;
|
|
}
|
|
if (!(pModule = MODULE_GetPtr( hModule ))) return 0;
|
|
lstrcpyn32A( lpFileName, NE_MODULE_NAME(pModule), size );
|
|
TRACE(module, "%s\n", lpFileName );
|
|
return strlen(lpFileName);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetModuleFileName32W (KERNEL32.236)
|
|
*/
|
|
DWORD WINAPI GetModuleFileName32W( HMODULE32 hModule, LPWSTR lpFileName,
|
|
DWORD size )
|
|
{
|
|
LPSTR fnA = (char*)HeapAlloc( GetProcessHeap(), 0, size );
|
|
DWORD res = GetModuleFileName32A( hModule, fnA, size );
|
|
lstrcpynAtoW( lpFileName, fnA, size );
|
|
HeapFree( GetProcessHeap(), 0, fnA );
|
|
return res;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetModuleName (KERNEL.27)
|
|
*/
|
|
BOOL16 WINAPI GetModuleName( HINSTANCE16 hinst, LPSTR buf, INT16 nSize )
|
|
{
|
|
LPSTR name = MODULE_GetModuleName(hinst);
|
|
|
|
if (!name) return FALSE;
|
|
lstrcpyn32A( buf, name, nSize );
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LoadLibraryEx32W (KERNEL.513)
|
|
* FIXME
|
|
*/
|
|
HMODULE32 WINAPI LoadLibraryEx32W16( LPCSTR libname, HANDLE16 hf,
|
|
DWORD flags )
|
|
{
|
|
fprintf(stderr,"LoadLibraryEx32W(%s,%d,%08lx)\n",libname,hf,flags);
|
|
return LoadLibraryEx32A(libname, hf,flags);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* LoadLibraryEx32A (KERNEL32)
|
|
*/
|
|
HMODULE32 WINAPI LoadLibraryEx32A(LPCSTR libname,HFILE32 hfile,DWORD flags)
|
|
{
|
|
HMODULE32 hmod;
|
|
|
|
hmod = PE_LoadLibraryEx32A(libname,PROCESS_Current(),hfile,flags);
|
|
if (hmod <= 32) {
|
|
char buffer[256];
|
|
|
|
strcpy( buffer, libname );
|
|
strcat( buffer, ".dll" );
|
|
hmod = PE_LoadLibraryEx32A(buffer,PROCESS_Current(),hfile,flags);
|
|
}
|
|
/* initialize all DLLs, which haven't been initialized yet. */
|
|
PE_InitializeDLLs( PROCESS_Current(), DLL_PROCESS_ATTACH, NULL);
|
|
return hmod;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* LoadLibraryA (KERNEL32)
|
|
*/
|
|
HMODULE32 WINAPI LoadLibrary32A(LPCSTR libname) {
|
|
return LoadLibraryEx32A(libname,0,0);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* LoadLibraryW (KERNEL32)
|
|
*/
|
|
HMODULE32 WINAPI LoadLibrary32W(LPCWSTR libnameW)
|
|
{
|
|
return LoadLibraryEx32W(libnameW,0,0);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* LoadLibraryExW (KERNEL32)
|
|
*/
|
|
HMODULE32 WINAPI LoadLibraryEx32W(LPCWSTR libnameW,HFILE32 hfile,DWORD flags)
|
|
{
|
|
LPSTR libnameA = HEAP_strdupWtoA( GetProcessHeap(), 0, libnameW );
|
|
HMODULE32 ret = LoadLibraryEx32A( libnameA , hfile, flags );
|
|
|
|
HeapFree( GetProcessHeap(), 0, libnameA );
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* FreeLibrary
|
|
*/
|
|
BOOL32 WINAPI FreeLibrary32(HINSTANCE32 hLibModule)
|
|
{
|
|
TRACE(module,"hLibModule=%08x\n", hLibModule);
|
|
return MODULE_FreeModule(hLibModule,
|
|
GlobalLock16(GetCurrentTask()) );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LoadLibrary (KERNEL.95)
|
|
*/
|
|
HINSTANCE16 WINAPI LoadLibrary16( LPCSTR libname )
|
|
{
|
|
HINSTANCE16 handle;
|
|
|
|
if (__winelib)
|
|
{
|
|
fprintf( stderr, "LoadLibrary not supported in Winelib\n" );
|
|
return 0;
|
|
}
|
|
TRACE(module, "(%08x) %s\n", (int)libname, libname);
|
|
|
|
handle = MODULE_Load( libname, (LPVOID)-1, 0 );
|
|
if (handle == (HINSTANCE16)2) /* file not found */
|
|
{
|
|
char buffer[256];
|
|
lstrcpyn32A( buffer, libname, 252 );
|
|
strcat( buffer, ".dll" );
|
|
handle = MODULE_Load( buffer, (LPVOID)-1, 0 );
|
|
}
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PrivateLoadLibrary (KERNEL32)
|
|
*
|
|
* FIXME: rough guesswork, don't know what "Private" means
|
|
*/
|
|
HINSTANCE32 WINAPI PrivateLoadLibrary(LPCSTR libname)
|
|
{
|
|
return (HINSTANCE32)LoadLibrary16(libname);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* FreeLibrary16 (KERNEL.96)
|
|
*/
|
|
void WINAPI FreeLibrary16( HINSTANCE16 handle )
|
|
{
|
|
TRACE(module,"%04x\n", handle );
|
|
FreeModule16( handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PrivateFreeLibrary (KERNEL32)
|
|
*
|
|
* FIXME: rough guesswork, don't know what "Private" means
|
|
*/
|
|
void WINAPI PrivateFreeLibrary(HINSTANCE32 handle)
|
|
{
|
|
FreeLibrary16((HINSTANCE16)handle);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* WinExec16 (KERNEL.166)
|
|
*/
|
|
HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
|
|
{
|
|
return WinExec32( lpCmdLine, nCmdShow );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* WinExec32 (KERNEL32.566)
|
|
*/
|
|
HINSTANCE32 WINAPI WinExec32( LPCSTR lpCmdLine, UINT32 nCmdShow )
|
|
{
|
|
LOADPARAMS params;
|
|
HGLOBAL16 cmdShowHandle, cmdLineHandle;
|
|
HINSTANCE32 handle = 2;
|
|
WORD *cmdShowPtr;
|
|
char *p, *cmdline, filename[256];
|
|
static int use_load_module = 1;
|
|
int spacelimit = 0, exhausted = 0;
|
|
|
|
if (!lpCmdLine)
|
|
return 2; /* File not found */
|
|
if (!(cmdShowHandle = GlobalAlloc16( 0, 2 * sizeof(WORD) )))
|
|
return 8; /* Out of memory */
|
|
if (!(cmdLineHandle = GlobalAlloc16( 0, 2048 )))
|
|
{
|
|
GlobalFree16( cmdShowHandle );
|
|
return 8; /* Out of memory */
|
|
}
|
|
|
|
/* Keep trying to load a file by trying different filenames; e.g.,
|
|
for the cmdline "abcd efg hij", try "abcd" with args "efg hij",
|
|
then "abcd efg" with arg "hij", and finally "abcd efg hij" with
|
|
no args */
|
|
|
|
while(!exhausted && handle == 2) {
|
|
int spacecount = 0;
|
|
|
|
/* Store nCmdShow */
|
|
|
|
cmdShowPtr = (WORD *)GlobalLock16( cmdShowHandle );
|
|
cmdShowPtr[0] = 2;
|
|
cmdShowPtr[1] = nCmdShow;
|
|
|
|
/* Build the filename and command-line */
|
|
|
|
cmdline = (char *)GlobalLock16( cmdLineHandle );
|
|
lstrcpyn32A(filename, lpCmdLine,
|
|
sizeof(filename) - 4 /* for extension */);
|
|
|
|
/* Keep grabbing characters until end-of-string, tab, or until the
|
|
number of spaces is greater than the spacelimit */
|
|
|
|
for (p = filename; ; p++) {
|
|
if(*p == ' ') {
|
|
++spacecount;
|
|
if(spacecount > spacelimit) {
|
|
++spacelimit;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(*p == '\0' || *p == '\t') {
|
|
exhausted = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*p)
|
|
lstrcpyn32A( cmdline + 1, p + 1, 255 );
|
|
else
|
|
cmdline[1] = '\0';
|
|
|
|
cmdline[0] = strlen( cmdline + 1 );
|
|
*p = '\0';
|
|
/* this is a (hopefully acceptable hack to get the whole
|
|
commandline for PROCESS_Create
|
|
we put it after the processed one */
|
|
lstrcpyn32A(cmdline + (unsigned char)cmdline[0] +2,
|
|
lpCmdLine, 2048 - 256);
|
|
|
|
/* Now load the executable file */
|
|
|
|
if (use_load_module)
|
|
{
|
|
/* Winelib: Use LoadModule() only for the program itself */
|
|
if (__winelib) use_load_module = 0;
|
|
params.hEnvironment = (HGLOBAL16)SELECTOROF( GetDOSEnvironment() );
|
|
params.cmdLine = (SEGPTR)WIN16_GlobalLock16( cmdLineHandle );
|
|
params.showCmd = (SEGPTR)WIN16_GlobalLock16( cmdShowHandle );
|
|
params.reserved = 0;
|
|
handle = LoadModule32( filename, ¶ms );
|
|
if (handle == 2) /* file not found */
|
|
{
|
|
/* Check that the original file name did not have a suffix */
|
|
p = strrchr(filename, '.');
|
|
/* if there is a '.', check if either \ OR / follow */
|
|
if (!p || strchr(p, '/') || strchr(p, '\\'))
|
|
{
|
|
p = filename + strlen(filename);
|
|
strcpy( p, ".exe" );
|
|
handle = LoadModule16( filename, ¶ms );
|
|
*p = '\0'; /* Remove extension */
|
|
}
|
|
}
|
|
}
|
|
else
|
|
handle = 2; /* file not found */
|
|
|
|
if (handle < 32)
|
|
{
|
|
/* Try to start it as a unix program */
|
|
if (!fork())
|
|
{
|
|
/* Child process */
|
|
DOS_FULL_NAME full_name;
|
|
const char *unixfilename = NULL;
|
|
const char *argv[256], **argptr;
|
|
int iconic = (nCmdShow == SW_SHOWMINIMIZED ||
|
|
nCmdShow == SW_SHOWMINNOACTIVE);
|
|
|
|
THREAD_InitDone = FALSE; /* we didn't init this process */
|
|
/* get unixfilename */
|
|
if (strchr(filename, '/') ||
|
|
strchr(filename, ':') ||
|
|
strchr(filename, '\\'))
|
|
{
|
|
if (DOSFS_GetFullName( filename, TRUE, &full_name ))
|
|
unixfilename = full_name.long_name;
|
|
}
|
|
else unixfilename = filename;
|
|
|
|
if (unixfilename)
|
|
{
|
|
/* build argv */
|
|
argptr = argv;
|
|
if (iconic) *argptr++ = "-iconic";
|
|
*argptr++ = unixfilename;
|
|
p = cmdline + 1;
|
|
while (1)
|
|
{
|
|
while (*p && (*p == ' ' || *p == '\t')) *p++ = '\0';
|
|
if (!*p) break;
|
|
*argptr++ = p;
|
|
while (*p && *p != ' ' && *p != '\t') p++;
|
|
}
|
|
*argptr++ = 0;
|
|
|
|
/* Execute */
|
|
execvp(argv[0], (char**)argv);
|
|
}
|
|
|
|
/* Failed ! */
|
|
|
|
if (__winelib)
|
|
{
|
|
/* build argv */
|
|
argptr = argv;
|
|
*argptr++ = "wine";
|
|
if (iconic) *argptr++ = "-iconic";
|
|
*argptr++ = lpCmdLine;
|
|
*argptr++ = 0;
|
|
|
|
/* Execute */
|
|
execvp(argv[0] , (char**)argv);
|
|
|
|
/* Failed ! */
|
|
fprintf(stderr, "WinExec: can't exec 'wine %s'\n",
|
|
lpCmdLine);
|
|
}
|
|
exit(1);
|
|
}
|
|
}
|
|
} /* while (!exhausted && handle < 32) */
|
|
|
|
GlobalFree16( cmdShowHandle );
|
|
GlobalFree16( cmdLineHandle );
|
|
return handle;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* WIN32_GetProcAddress16 (KERNEL32.36)
|
|
* Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
|
|
*/
|
|
FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE32 hModule, LPSTR name )
|
|
{
|
|
WORD ordinal;
|
|
FARPROC16 ret;
|
|
|
|
if (!hModule) {
|
|
fprintf(stderr,"WIN32_GetProcAddress16: hModule may not be 0!\n");
|
|
return (FARPROC16)0;
|
|
}
|
|
hModule = MODULE_HANDLEtoHMODULE16(hModule);
|
|
if (HIWORD(name)) {
|
|
ordinal = MODULE_GetOrdinal( hModule, name );
|
|
TRACE(module, "%04x '%s'\n",
|
|
hModule, name );
|
|
} else {
|
|
ordinal = LOWORD(name);
|
|
TRACE(module, "%04x %04x\n",
|
|
hModule, ordinal );
|
|
}
|
|
if (!ordinal) return (FARPROC16)0;
|
|
ret = MODULE_GetEntryPoint( hModule, ordinal );
|
|
TRACE(module,"returning %08x\n",(UINT32)ret);
|
|
return ret;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* GetProcAddress16 (KERNEL.50)
|
|
*/
|
|
FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, SEGPTR name )
|
|
{
|
|
WORD ordinal;
|
|
FARPROC16 ret;
|
|
|
|
if (!hModule) hModule = GetCurrentTask();
|
|
hModule = MODULE_HANDLEtoHMODULE16( hModule );
|
|
|
|
if (HIWORD(name) != 0)
|
|
{
|
|
ordinal = MODULE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
|
|
TRACE(module, "%04x '%s'\n",
|
|
hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
|
|
}
|
|
else
|
|
{
|
|
ordinal = LOWORD(name);
|
|
TRACE(module, "%04x %04x\n",
|
|
hModule, ordinal );
|
|
}
|
|
if (!ordinal) return (FARPROC16)0;
|
|
|
|
ret = MODULE_GetEntryPoint( hModule, ordinal );
|
|
|
|
TRACE(module, "returning %08x\n", (UINT32)ret );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* GetProcAddress32 (KERNEL32.257)
|
|
*/
|
|
FARPROC32 WINAPI GetProcAddress32( HMODULE32 hModule, LPCSTR function )
|
|
{
|
|
NE_MODULE *pModule;
|
|
|
|
if (HIWORD(function))
|
|
TRACE(win32,"(%08lx,%s)\n",(DWORD)hModule,function);
|
|
else
|
|
TRACE(win32,"(%08lx,%p)\n",(DWORD)hModule,function);
|
|
if (!(pModule = MODULE_GetPtr( hModule )))
|
|
return (FARPROC32)0;
|
|
if (!pModule->module32)
|
|
{
|
|
fprintf(stderr,"Oops, Module 0x%08lx has got no module32?\n",
|
|
(DWORD)MODULE_HANDLEtoHMODULE32(hModule)
|
|
);
|
|
return (FARPROC32)0;
|
|
}
|
|
return PE_FindExportedFunction( PROCESS_Current(), pModule->module32,
|
|
function );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RtlImageNtHeaders (NTDLL)
|
|
*/
|
|
LPIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE32 hModule)
|
|
{
|
|
/* basically:
|
|
* return hModule+(((IMAGE_DOS_HEADER*)hModule)->e_lfanew);
|
|
* but we could get HMODULE16 or the like (think builtin modules)
|
|
*/
|
|
|
|
NE_MODULE *pModule;
|
|
|
|
if (!(pModule = MODULE_GetPtr( hModule )))
|
|
return (LPIMAGE_NT_HEADERS)0;
|
|
if (!(pModule->flags & NE_FFLAGS_WIN32) || !pModule->module32)
|
|
return (LPIMAGE_NT_HEADERS)0;
|
|
return PE_HEADER(pModule->module32);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* GetExpWinVer (KERNEL.167)
|
|
*/
|
|
WORD WINAPI GetExpWinVer( HMODULE16 hModule )
|
|
{
|
|
NE_MODULE *pModule = MODULE_GetPtr( hModule );
|
|
return pModule ? pModule->expected_version : 0;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* IsSharedSelector (KERNEL.345)
|
|
*/
|
|
BOOL16 WINAPI IsSharedSelector( HANDLE16 selector )
|
|
{
|
|
/* Check whether the selector belongs to a DLL */
|
|
NE_MODULE *pModule = MODULE_GetPtr( selector );
|
|
if (!pModule) return FALSE;
|
|
return (pModule->flags & NE_FFLAGS_LIBMODULE) != 0;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFirst (TOOLHELP.59)
|
|
*/
|
|
BOOL16 WINAPI ModuleFirst( MODULEENTRY *lpme )
|
|
{
|
|
lpme->wNext = hFirstModule;
|
|
return ModuleNext( lpme );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleNext (TOOLHELP.60)
|
|
*/
|
|
BOOL16 WINAPI ModuleNext( MODULEENTRY *lpme )
|
|
{
|
|
NE_MODULE *pModule;
|
|
char *name;
|
|
|
|
if (!lpme->wNext) return FALSE;
|
|
if (!(pModule = MODULE_GetPtr( lpme->wNext ))) return FALSE;
|
|
name = (char *)pModule + pModule->name_table;
|
|
memcpy( lpme->szModule, name + 1, *name );
|
|
lpme->szModule[(BYTE)*name] = '\0';
|
|
lpme->hModule = lpme->wNext;
|
|
lpme->wcUsage = pModule->count;
|
|
strncpy( lpme->szExePath, NE_MODULE_NAME(pModule), MAX_PATH );
|
|
lpme->szExePath[MAX_PATH] = '\0';
|
|
lpme->wNext = pModule->next;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFindName (TOOLHELP.61)
|
|
*/
|
|
BOOL16 WINAPI ModuleFindName( MODULEENTRY *lpme, LPCSTR name )
|
|
{
|
|
lpme->wNext = GetModuleHandle16( name );
|
|
return ModuleNext( lpme );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* ModuleFindHandle (TOOLHELP.62)
|
|
*/
|
|
BOOL16 WINAPI ModuleFindHandle( MODULEENTRY *lpme, HMODULE16 hModule )
|
|
{
|
|
hModule = MODULE_HANDLEtoHMODULE16( hModule );
|
|
lpme->wNext = hModule;
|
|
return ModuleNext( lpme );
|
|
}
|