Release 950522
Sun May 21 12:30:30 1995 Alexandre Julliard (julliard@sunsite.unc.edu)
* [debugger/hash.c] [debugger/info.c]
Added support for symbolic segmented addresses. Add symbols for all
built-in API entry points.
* [if1632/relay.c] [include/dlls.h]
Removed dll_table structure, as we now use the built-in module
structures.
* [if1632/relay.c] [loader/main.c]
Removed winestat option, as it was no longer very meaningful.
* [include/stackframe.h]
New macro MAKE_SEGPTR that creates a segmented pointer to a local
variable on the 32-bit stack.
* [loader/module.c]
Added support for multiple instances of an application.
Implemented LoadModule() and FreeModule().
* [loader/ne_image.c] [loader/task.c]
Moved initialisation of built-in DLLs to InitTask().
* [memory/global.c]
Implemented discardable blocks.
* [misc/file.c]
Search path of current executable in OpenFile().
Fixed bug with searching in Windows path.
* [misc/lstr.c]
Hard-coded translation tables for Ansi<->Oem.
* [misc/user.c]
Moved some global initializations to InitApp(), because they need
a task context to be performed.
* [objects/dc.c]
Handle R2_BLACK and R2_WHITE specially so that they work correctly
with palette displays.
* [tools/build.c]
Suppressed generation of the C file for DLL specs, because it's no
longer needed. Output all the assembly code directly to stdout.
Some changes to integrate Win32 support from Martin von Loewis.
* [windows/msgbox.c]
Moved message box code from misc/ to windows/.
Mon May 15 23:40:04 1995 Martin Ayotte (wine@trgcorp.mksinfo.qc.ca)
* [misc/audio.c] [misc/mcicda.c] [misc/mcianim.c] [misc/midi.c]
[misc/mmaux.c] [misc/mmsystem.c]
Modify code & use pointers conversion macros.
Make cdaudio & wave devices work again (only using some applets).
* [misc/profile.c]
Change getc() to fgetc() where needed.
Mon May 15 22:10:56 1995 Martin von Loewis <loewis@informatik.hu-berlin.de>
* [if1632/Imakefile]
added entries for the new files gdi32.spec, kernel32.spec,
user32.spec, shell32.spec and winprocs32.spec.
* [if1632/commdlg.spec][if1632/kernel.spec][if1632/shell.spec]
[if1632/storage.spec][if1632/system.spec][if1632/user.spec]
ChooseFont, RESERVED5, InternalExtractIcon: Marked as stubs
ExtractAssociatedIcon, DoEnvironmentSubst, DumpIcon:
stub implementations provided
marked storage.dll,storege.sys functions as stubs
* [include/pe_image.h]
Added structures WIN32_builtin and WIN32_function
* [include/peexe.h]
PE_Import_Directory: renamed reserved fields to
TimeDate, Forwarder, Thunk_List
* [include/winerror.h]
New file.
* [loader/main.c]
called RELAY32_Init
* [loader/pe_image.c]
xmmap: map BSS anonymous
dump_imports: renamed to fixup_imports, do the fixup of imported
symbols
PE_LoadImage: pass raw data size to xmmap
* [loader/resource.c]
DumpIcon: new function
* [misc/kernel32.c]
New file.
* [misc/main.c]
make stdout and stderr unbuffered
* [misc/shell.c]
DoEnvironmentSubst: new function
* [objects/font.c]
FONT_MatchFont: try oblique if there is no italic
* [rc/Imakefile][rc/parser.l]
yywrap: new function
Don't link with libfl.a on Linux
* [tools/build.c]
Added keywords stdcall, subsystem, base
GenerateForWin32: new function
BuildSpecFiles: call GenerateForWin32 if subsystem is win32
Mon May 15 10:38:14 1995 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* [controls/listbox.c] [controls/combo.c] [windows/defwnd.c]
Minor fixes.
* [misc/message.c] [misc/main.c] [rc/sysres*.rc] [include/texts.h]
Rewrote message box handling.
* [windows/dialog.c]
Dialogs should be invisible until after WM_INITDIALOG is seent.
Don't switch to invisible dialog items on a TAB keypress.
* [windows/mdi.c]
Send WM_NCPAINT message in MDIRestoreChild().
* [windows/painting.c]
Fixed typo (&& -> &).
* [windows/message.c] [if1632/user.spec]
Implemented PostAppMessage().
* [windows/event.c]
SetCapture(0) should act like ReleaseCapture().
Tue May 9 11:55:52 1995 Eddie C. Dost (ecd@dressler.de)
* [Imakefile]
Changed CDEBUGFLAGS for systems running __ELF__ (temporarily)
Added ASFLAGS to exported variables.
* [debugger/readline/Imakefile]
Moved defines for libreadline from DEFINES to EXTRA_DEFINES
* [memory/local.c] [miscemu/int21.c]
Added some more debugging outputs.
Mon May 8 00:55:27 MET DST 1995 Dag Asheim (dash@ifi.uio.no)
* [misc/message.c]
Fixed a "FIXME" concerning norwegian translation.
Sun May 7 23:25:23 1995 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* [*/*]
Removed warnings in a couple of files and deleted some obsolete code.
* [controls/listbox.c]
Cleanup, speed improvements & lots of bug fixes.
* [controls/combo.c]
Mostly rewritten. This is still very buggy, but not quite as bad as
before.
* [include/commdlg.h] [misc/commdlg.c]
Removed the need for sysres.dll. Small bug fixes.
* [objects/oembitmap.c] [include/bitmaps/<many>] [include/windows.h]
[loader/library.c] [loader/main.c] [rc/sysres*.rc]
Removed sysres.dll and replaced the remaining bitmaps/icons with
XPM equivalents.
* [misc/message.c] [windows/nonclient.c] [misc/main.c]
[if1632/winprocs.spec]
"About Wine..." now brings up a standard ShellAbout() window with
the Wine icon and the list of contributors.
* [misc/shell.c]
Fixed ShellAbout()/AboutDialogProc() to show the right icon.
* [windows/event.c]
Small hack for non-alphanumeric keys: Dont't send the ascii value in
the WM_KEYDOWN message, but some unused code instead. Should be done
properly by sending different codes for each key. The edit control
used to get a VK_DELETE message each time the user typed '.'.
* [windows/class.c]
Removed a check for CS_GLOBALCLASS in CLASS_FindClassByName().
This used to be no problem, but breaks Resource Workshop in 950403.
* [objects/dib.c]
New diagnostic for a bug I've been encountering. If it shows up,
please report it.
Sun May 7 23:11:18 EDT 1995 William Magro (wmagro@tc.cornell.edu)
* [objects/color.c]
Handle situation when 'dc' exists, but palette mapping
does not. (Fixes kidpix2 demo.)
Sun May 7 03:32:00 1995 Charles M. Hannum (mycroft@mit.edu)
* [loader/ldt.c]
LDT_Print: Only show the number of entries that the kernel
returned. Make this work for NetBSD.
Fri May 5 02:53:26 1995 Charles M. Hannum (mycroft@mit.edu)
* [debugger/dbg.y] [include/wine.h] [loader/signal.c]
Modify cs and ds selector values for NetBSD-current.
* [debugger/debug.l]
$sp, $esp: Use RN_ESP_AT_SIGNAL rather than RN_ESP.
* [debugger/regpos.h]
Modify sigcontext format for NetBSD-current.
SC_ESP: Use RN_ESP_AT_SIGNAL rather than RN_ESP.
* [include/ldt.h]
SELECTOR_TO_ENTRY: Explicitly clear the top half of the selector
value, since only 16 bits of it may have been saved.
* [misc/winsocket.c]
Set structure packing with `#pragma pack' to accomodate
other/older compilers.
Tue May 2 18:15:01 1995 Paal Beyer (beyer@idt.unit.no)
* [misc/commdlg.c]
Fixed path-names so when changing directory the listboxes
changes too.
* [debugger/dbg.y debugger/debug.l wine.ini]
Added SymbolTableFile to wine.ini so symbols can be read
without standing in the directory containing wine.sym.
Added the possibility to specify full name of wine.sym from
the debugger prompt.
diff --git a/loader/module.c b/loader/module.c
index 7ea2944..c4af5bf 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -12,20 +12,19 @@
#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"
/* #define DEBUG_MODULE */
#include "debug.h"
-extern BYTE KERNEL_Module_Start[], KERNEL_Module_End[];
-
-extern struct dll_name_table_entry_s dll_builtin_table[];
-
static HMODULE hFirstModule = 0;
@@ -36,18 +35,20 @@
*/
BOOL MODULE_Init(void)
{
+ extern void load_entrypoints( HMODULE );
+
HMODULE hModule;
NE_MODULE *pModule;
SEGTABLEENTRY *pSegTable;
struct dll_table_s *table;
+ char *dosmem;
int i;
/* Create the built-in modules */
- for (i = 0; i < N_BUILTINS; i++)
+ for (i = 0, table = dll_builtin_table; i < N_BUILTINS; i++, table++)
{
- if (!dll_builtin_table[i].dll_is_used) continue;
- table = dll_builtin_table[i].table;
+ if (!table->used) continue;
hModule = GLOBAL_CreateBlock( GMEM_MOVEABLE, table->module_start,
table->module_end - table->module_start,
@@ -58,7 +59,7 @@
table->hModule = hModule;
dprintf_module( stddeb, "Built-in %s: hmodule=%04x\n",
- dll_builtin_table[i].dll_name, hModule );
+ table->name, hModule );
/* Allocate the code segment */
@@ -81,7 +82,51 @@
pModule->next = hFirstModule;
hFirstModule = hModule;
+ load_entrypoints( hModule );
}
+
+ /* Initialize some KERNEL exported values */
+
+ if (!(hModule = GetModuleHandle( "KERNEL" ))) return TRUE;
+
+ /* KERNEL.178: __WINFLAGS */
+ MODULE_SetEntryPoint( hModule, 178, GetWinFlags() );
+
+ /* Allocate 7 64k segments for 0000, A000, B000, C000, D000, E000, F000. */
+
+ dosmem = malloc( 0x70000 );
+
+ MODULE_SetEntryPoint( hModule, 183, /* KERNEL.183: __0000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 193, /* KERNEL.193: __0040H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x400,
+ 0x100, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 174, /* KERNEL.174: __A000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x10000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 181, /* KERNEL.181: __B000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x20000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 182, /* KERNEL.182: __B800H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x28000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 195, /* KERNEL.195: __C000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x30000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 179, /* KERNEL.179: __D000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x40000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 190, /* KERNEL.190: __E000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x50000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 173, /* KERNEL.173: __ROMBIOS */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+ MODULE_SetEntryPoint( hModule, 194, /* KERNEL.194: __F000H */
+ GLOBAL_CreateBlock( GMEM_FIXED, dosmem + 0x60000,
+ 0x10000, hModule, FALSE, FALSE, FALSE ) );
+
return TRUE;
}
@@ -237,7 +282,7 @@
close( cachedfd );
hCachedModule = hModule;
name = ((LOADEDFILEINFO*)((char*)pModule + pModule->fileinfo))->filename;
- cachedfd = open( name /* DOS_GetUnixFileName( name ) */, O_RDONLY );
+ cachedfd = open( DOS_GetUnixFileName( name ), O_RDONLY );
dprintf_module( stddeb, "MODULE_OpenFile: opened '%s' -> %d\n",
name, cachedfd );
return cachedfd;
@@ -263,7 +308,9 @@
{
/* FIXME: this is needed because heap growing is not implemented */
pModule->heap_size = 0x10000 - minsize;
+ /* For tasks, the DGROUP is allocated by MODULE_MakeNewInstance */
minsize = 0x10000;
+ if (!(pModule->flags & NE_FFLAGS_LIBMODULE)) continue;
}
pSegment->selector = GLOBAL_Alloc( GMEM_ZEROINIT | GMEM_FIXED,
minsize, hModule,
@@ -282,7 +329,7 @@
/***********************************************************************
* MODULE_LoadExeHeader
*/
-HMODULE MODULE_LoadExeHeader( int fd, char *filename )
+HMODULE MODULE_LoadExeHeader( int fd, OFSTRUCT *ofs )
{
struct mz_header_s mz_header;
struct ne_header_s ne_header;
@@ -316,7 +363,7 @@
size = sizeof(NE_MODULE) +
/* loaded file info */
- sizeof(LOADEDFILEINFO) + strlen(filename) +
+ sizeof(LOADEDFILEINFO) + strlen(ofs->szPathName) +
/* segment table */
ne_header.n_segment_tab * sizeof(SEGTABLEENTRY) +
/* resource table */
@@ -335,6 +382,7 @@
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 */
@@ -359,12 +407,12 @@
/* Store the filename information */
pModule->fileinfo = (int)pData - (int)pModule;
- ((LOADEDFILEINFO*)pData)->length = sizeof(LOADEDFILEINFO)+strlen(filename);
+ ((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, filename );
+ strcpy( ((LOADEDFILEINFO*)pData)->filename, ofs->szPathName );
pData += ((LOADEDFILEINFO*)pData)->length--;
/* Get the segment table */
@@ -451,6 +499,17 @@
}
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 11; /* invalid exe */
+ }
+ else pModule->dlls_to_init = 0;
+
if (debugging_module) MODULE_PrintModule( hModule );
pModule->next = hFirstModule;
hFirstModule = hModule;
@@ -459,6 +518,62 @@
/***********************************************************************
+ * MODULE_MakeNewInstance
+ *
+ * Create a new instance of the specified module.
+ */
+HINSTANCE MODULE_MakeNewInstance( HMODULE hModule, LOADPARAMS *params )
+{
+ NE_MODULE *pModule;
+ SEGTABLEENTRY *pSegment;
+ HINSTANCE hNewInstance, hPrevInstance;
+ int minsize;
+
+ if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
+ if (!pModule->dgroup) return hModule; /* No DGROUP -> return the module */
+
+ pSegment = NE_SEG_TABLE( pModule ) + pModule->dgroup - 1;
+ hPrevInstance = pSegment->selector;
+
+ /* Don't create a new instance if it's a library */
+
+ if (pModule->flags & NE_FFLAGS_LIBMODULE) return hPrevInstance;
+ if (params == (LOADPARAMS*)-1) return hPrevInstance;
+
+ /* Allocate the new data segment */
+
+ 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;
+ NE_LoadSegment( hModule, pModule->dgroup );
+
+ /* Create a new task for this instance */
+ if (!TASK_CreateTask( hModule, hNewInstance, hPrevInstance,
+ params->hEnvironment,
+ (LPSTR)PTR_SEG_TO_LIN( params->cmdLine ),
+ *((WORD *)PTR_SEG_TO_LIN(params->showCmd)+1) ))
+ {
+ GlobalFree( hNewInstance );
+ return 0;
+ }
+
+ /* Initialize the local heap */
+
+ if (pModule->heap_size)
+ {
+ WORD heapstart = pSegment->minsize;
+ if (pModule->ss == pModule->dgroup) heapstart += pModule->stack_size;
+ LocalInit( hNewInstance, heapstart, heapstart + pModule->heap_size );
+ }
+ return hNewInstance;
+}
+
+
+/***********************************************************************
* MODULE_GetOrdinal
*
* Lookup the ordinal for a given name.
@@ -538,8 +653,6 @@
if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return 0;
- dprintf_module( stddeb, "MODULE_GetEntryPoint(%04x,%d)\n",
- hModule, ordinal );
p = (BYTE *)pModule + pModule->entry_table;
while (*p && (curOrdinal + *p <= ordinal))
{
@@ -552,16 +665,11 @@
default: p += 2 + *p * 3; break; /* fixed */
}
}
- if (!*p)
- {
- dprintf_module( stddeb, " Not found (last=%d)\n", curOrdinal-1 );
- return 0;
- }
+ if (!*p) return 0;
switch(p[1])
{
case 0: /* unused */
- dprintf_module( stddeb, " Found, but entry is unused\n" );
return 0;
case 0xff: /* moveable */
p += 2 + 6 * (ordinal - curOrdinal);
@@ -575,8 +683,6 @@
break;
}
- dprintf_module( stddeb, " Found, logical addr = %04x:%04x\n",
- sel, offset );
if (sel == 0xfe) sel = 0xffff; /* constant entry */
else sel = NE_SEG_TABLE(pModule)[sel-1].selector;
return MAKELONG( offset, sel );
@@ -584,6 +690,87 @@
/***********************************************************************
+ * 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 )
@@ -602,10 +789,208 @@
/**********************************************************************
+ * 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;
+ 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;
+ 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;
+ WORD *pModRef;
+ int i;
+
+ if (!(pModule = (NE_MODULE *)GlobalLock( hModule ))) return;
+
+ /* 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 );
+}
+
+
+/**********************************************************************
* LoadModule (KERNEL.45)
*/
-HINSTANCE MODULE_LoadModule( LPCSTR name, LPVOID paramBlock )
+HINSTANCE LoadModule( LPCSTR name, LPVOID paramBlock )
{
+ HMODULE hModule;
+ HANDLE hInstance;
+ NE_MODULE *pModule;
+ WORD *pModRef, *pDLLs;
+ int i, fd;
+
+ hModule = MODULE_FindModule( name );
+ if (!hModule) /* We have to load the module */
+ {
+ OFSTRUCT ofs;
+ if (strchr( name, '/' )) name = DOS_GetDosFileName( name );
+ if ((fd = OpenFile( name, &ofs, OF_READ )) == -1)
+ return 2; /* File not found */
+
+ /* Create the module structure */
+
+ if ((hModule = MODULE_LoadExeHeader( fd, &ofs )) < 32)
+ {
+ 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 );
+
+ /* 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 (except the DGROUP) */
+
+ for (i = 1; i <= pModule->seg_count; i++)
+ if (i != pModule->dgroup) NE_LoadSegment( hModule, i );
+
+ /* Create an instance for this module */
+
+ hInstance = MODULE_MakeNewInstance( hModule, (LOADPARAMS*)paramBlock );
+
+ /* 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;
+ }
+ else
+ {
+ pModule = (NE_MODULE *)GlobalLock( hModule );
+ hInstance = MODULE_MakeNewInstance( hModule, (LOADPARAMS*)paramBlock );
+ pModule->count++;
+ }
+
+ 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;
+
+ if (--pModule->count == 0) MODULE_FreeModule( hModule );
+ return TRUE;
}
@@ -614,21 +999,15 @@
*/
HMODULE GetModuleHandle( LPCSTR name )
{
- char buffer[16];
- BYTE len;
- HMODULE hModule;
+ BYTE len = strlen(name);
+ HMODULE hModule = hFirstModule;
- strncpy( buffer, name, 15 );
- buffer[15] = '\0';
- len = strlen(buffer);
- AnsiUpper( buffer );
-
- hModule = hFirstModule;
while( hModule )
{
NE_MODULE *pModule = (NE_MODULE *)GlobalLock( hModule );
char *pname = (char *)pModule + pModule->name_table;
- if (((BYTE)*pname == len) && !memcmp( pname+1, buffer, len )) break;
+ if (((BYTE)*pname == len) && !strncasecmp( pname+1, name, len ))
+ break;
hModule = pModule->next;
}
dprintf_module( stddeb, "GetModuleHandle('%s'): returning %04x\n",
@@ -669,6 +1048,122 @@
}
+/***********************************************************************
+ * LoadLibrary (KERNEL.95)
+ */
+HANDLE LoadLibrary( LPCSTR libname )
+{
+ HANDLE handle;
+
+ dprintf_module( stddeb, "LoadLibrary: (%08x) %s\n", (int)libname, libname);
+ handle = LoadModule( libname, (LPVOID)-1 );
+ if (handle == 2) /* file not found */
+ {
+ char buffer[256];
+ strcpy( buffer, libname );
+ strcat( buffer, ".dll" );
+ handle = LoadModule( buffer, (LPVOID)-1 );
+ }
+ if (handle >= 32) NE_InitializeDLLs( handle );
+ return handle;
+}
+
+
+/***********************************************************************
+ * FreeLibrary (KERNEL.96)
+ */
+void FreeLibrary( HANDLE handle )
+{
+ dprintf_module( stddeb,"FreeLibrary: %04x\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 = SELECTOROF( GetDOSEnvironment() );
+ params.cmdLine = WIN16_GlobalLock( cmdLineHandle );
+ params.showCmd = WIN16_GlobalLock( cmdShowHandle );
+ params.reserved = 0;
+ handle = LoadModule( filename, ¶ms );
+ if (handle == 2) /* file not found */
+ {
+ strcat( filename, ".exe" );
+ handle = LoadModule( filename, ¶ms );
+ }
+
+ GlobalFree( cmdShowHandle );
+ GlobalFree( cmdLineHandle );
+ 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: %04x '%s'\n",
+ hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
+ }
+ else
+ {
+ ordinal = LOWORD(name);
+ dprintf_module( stddeb, "GetProcAddress: %04x %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;
+}
+
+
/**********************************************************************
* ModuleFirst (TOOLHELP.59)
*/