Release 980503
Thu Apr 30 16:28:12 1998 James Juran <jrj120@psu.edu>
* [scheduler/process.c]
Implemented GetExitCodeProcess. The code is a direct translation
of GetExitCodeThread.
Mon Apr 27 22:20:25 1998 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
* [loader/pe_image.c]
Unload dummy module when PE_LoadLibraryEx32A fails with
PE_LoadImage (makes Encarta 98 installer proceed).
* [files/drive.c]
Make GetDriveType16 return DRIVE_REMOVABLE for TYPE_CDROM.
Make GetCurrentDirectory32 behave like the code does and not
like the help describes.
* [files/profile.c]
Revoke recent change in PROFILE_GetSection and try better
handling of special case.
* [include/windows.h]
Change definition of ACCEL32.
* [misc/commdlg.c]
Replace the GetXXXFilename32 macros by normal code.
Fix two reported bugs in my changes to commdlg.
* [windows/win.c]
Add a hook to catch bogus WM_SIZE messages by emitting a warning
in the appropriate case.
* [objects/bitmap.c]
Reject unreasonbable large size arguments in
CreateCompatibleBitmap32 and add an fixme for that situation.
Sun Apr 26 18:30:07 1998 Alexandre Julliard <julliard@lrc.epfl.ch>
* [include/ldt.h] [debugger/*.c] [miscemu/instr.c]
Added IS_SELECTOR_SYSTEM and IS_SELECTOR_32BIT macros.
Make instruction emulation support system selectors.
* [loader/*.c]
Started moving NE specific functions to the new loader/ne
directory.
* [memory/environ.c]
Enforce the 127 chars limit only when creating the environment of
a Win16 process.
Sun Apr 26 12:22:23 1998 Andreas Mohr <100.30936@germany.net>
* [files/file.c]
Fixed an incredible typo in CopyFile32A that made it unusable
since a rewrite in 970112 (!!).
* [files/directory.c]
Fixed GetTempPath32A/W to include trailing backslash.
* [misc/ver.c]
Make find_pe_resource "work" with corrupt files.
* [misc/wsprintf.c]
Altered WPRINTF_ParseFormatA/W to treat invalid format chars
as normal output, too.
* [msdos/dpmi.c]
Implemented "Allocate/Free real mode callback" (0x0303/0x0304).
Cross your fingers if you need to use it ;) (completely untested)
Implemented "Call real mode proc with far return" (0x0301, tested).
* [msdos/int21.c]
Fixed ioctlGenericBlkDevReq/0x60.
* [relay32/dplayx.spec] [relay32/builtin32.c] [relay32/Makefile.in]
Added built-in DPLAYX.DLL.
* [windows/win.c]
Fixed GetWindowWord()/GWW_HWNDPARENT to return the window's owner
if it has no parent (SDK).
Sat Apr 25 15:09:53 1998 M.T.Fortescue <mark@mtfhpc.demon.co.uk>
* [debugger/db_disasm.c]
Fixed disassemble bug for no-display option and 'lock',
'repne' and 'repe' prefixes.
* [debugger/registers.c]
Added textual flag description output on 'info regs'.
Sat Apr 25 14:18:26 1998 Matthew Becker <mbecker@glasscity.net>
* [*/*.c]
Added stubs and/or documentation for the following functions:
LookupPrivilegeValue, OpenService, ControlService, RegGetKeySecurity,
StartService, SetComputerName, DeleteService, CloseServiceHandle,
OpenProcessToken, OpenSCManager, DeregisterEventSource,
WaitForDebugEvent, WaitForInputIdle, RegisterEventSource,
SetDebugErrorLevel, SetConsoleCursorPosition, ChoosePixelFormat,
SetPixelFormat, GetPixelFormat, DescribePixelFormat, SwapBuffers,
PolyBezier, AbortPath, DestroyAcceleratorTable, HeapWalk,
DdeInitialize, DdeUninitialize, DdeConnectList, DdeDisconnectList,
DdeCreateStringHandle, DdePostAdvise, DdeGetData, DdeNameService,
DdeGetLastError, WNetGetDirectoryType, EnumPrinters, RegFlushKey,
RegGetKeySecurity, DllGetClassObject, DllCanUnloadNow, CreateBitmap,
CreateCompatibleBitmap, CreateBitmapIndirect, GetBitmapBits,
SetBitmapBits, LoadImage, CopyImage, LoadBitmap, DrawIcon,
CreateDiscardableBitmap, SetDIBits, GetCharABCWidths, LoadTypeLib,
SetConsoleCtrlHandler, CreateConsoleScreenBuffer, ReadConsoleInput,
GetConsoleCursorInfo, SetConsoleCursorInfo, SetConsoleWindowInfo,
SetConsoleTextAttribute, SetConsoleScreenBufferSize,
FillConsoleOutputCharacter, FillConsoleOutputAttribute,
CreateMailslot, GetMailslotInfo, GetCompressedFileSize,
GetProcessWindowStation, GetThreadDesktop, SetDebugErrorLevel,
WaitForDebugEvent, SetComputerName, CreateMDIWindow.
Thu Apr 23 23:54:04 1998 Douglas Ridgway <ridgway@winehq.com>
* [include/windows.h] [objects/enhmetafile.c] [relay32/gdi32.spec]
Implement CopyEnhMetaFile, Get/SetEnhMetaFileBits, other fixes.
* [include/windows.h] [objects/metafile.c] [relay32/gdi32.spec]
32-bit metafile fixes, implement EnumMetaFile32, GetMetaFileBitsEx.
* [objects/font.c] [graphics/x11drv/xfont.c] [graphics/x11drv/text.c]
Some rotated text support for X11R6 displays.
* [win32/newfns.c] [ole/ole2nls.c]
Moved GetNumberFormat32A.
Wed Apr 22 17:38:20 1998 David Lee Lambert <lamber45@egr.msu.edu>
* [ole/ole2nls.c] [misc/network.c]
Changed some function documentation to the new style.
* [misc/network.c] [include/windows.h] [if1632/user.spec]
[relay32/mpr.spec] [misc/mpr.c]
Added stubs for some Win32 network functions; renamed some
16-bit ones with 32-bit counterparts, as well as
WNetGetDirectoryType; moved the stubs in misc/mpr.c (three of
them!) to misc/network.c.
* [ole/compobj.c] [ole/storage.c] [ole/ole2disp.c]
[ole/ole2nls.c] [ole/folders.c] [ole/moniker.c] [ole/ole2.c]
[graphics/fontengine.c] [graphics/ddraw.c] [graphics/env.c]
[graphics/driver.c] [graphics/escape.c]
Changed fprintf's to proper debug-macros.
* [include/winnls.h]
Added some flags (for internal use).
* [ole/ole2nls.c]
Added the Unicode core function, and worked out a way to hide
the commonality of the core.
* [relay32/kernel32.spec]
Added support for GetDate/Time32A/W.
Wed Apr 22 09:16:03 1998 Gordon Chaffee <chaffee@cs.berkeley.edu>
* [win32/code_page.c]
Fixed problem with MultiByteToWideChar that was introduced in
last release. Made MultiByteToWideChar more compatible with Win32.
* [graphics/x11drv/graphics.c]
Fixed problem with drawing arcs.
Tue Apr 21 11:24:58 1998 Constantine Sapuntzakis <csapuntz@tma-1.lcs.mit.edu>
* [ole/ole2nls.c]
Move stuff from 0x409 case to Lang_En.
* [relay32/user32.spec] [windows/winpos.c]
Added stubs for GetWindowRgn32 and SetWindowRgn32. Makes Office
Paperclip happy.
Tue Apr 21 11:16:16 1998 Constantine Sapuntzakis <csapuntz@tma-1.lcs.mit.edu>
* [loader/pe_image.c]
If image is relocated, TLS addresses need to be adjusted.
* [debugger/*.c]
Generalized tests for 32-bit segments.
Tue Apr 21 02:04:59 1998 James Juran <jrj120@psu.edu>
* [misc/*.c] [miscemu/*.c] [msdos/*.c] [if1632/*.c]
[include/*.h] [loader/*.c] [memory/*.c] [multimedia/*.c]
[objects/*.c]
Almost all fprintf statements converted to appropriate
debug messages.
* [README]
Updated "GETTING MORE INFORMATION" section to include WineHQ.
* [documentation/debugger]
Fixed typo.
* [windows/defwnd.c]
Added function documentation.
Sun Apr 19 16:30:58 1998 Marcus Meissner <marcus@mud.de>
* [Make.rules.in]
Added lint target (using lclint).
* [relay32/oleaut32.spec][relay32/Makefile.in][ole/typelib.c]
[ole/ole2disp.c]
Added oleaut32 spec, added some SysString functions.
* [if1632/signal.c]
Added printing of faultaddress in Linux (using CR2 debug register).
* [configure.in]
Added <sys/types.h> for statfs checks.
* [loader/*.c][debugger/break.c][debugger/hash.c]
Started to split win32/win16 module handling, preparing support
for other binary formats (like ELF).
Sat Apr 18 10:07:41 1998 Rein Klazes <rklazes@casema.net>
* [misc/registry.c]
Fixed a bug that made RegQueryValuexxx returning
incorrect registry values.
Fri Apr 17 22:59:22 1998 Alexander V. Lukyanov <lav@long.yar.ru>
* [misc/lstr.c]
FormatMessage32*: remove linefeed when nolinefeed set;
check for target underflow.
Fri Apr 17 00:38:14 1998 Alexander V. Lukyanov <lav@long.yar.ru>
* [misc/crtdll.c]
Implement xlat_file_ptr for CRT stdin/stdout/stderr address
translation.
Wed Apr 15 20:43:56 1998 Jim Peterson <jspeter@birch.ee.vt.edu>
* [controls/menu.c]
Added 'odaction' parameter to MENU_DrawMenuItem() and redirected
WM_DRAWITEM messages to GetWindow(hwnd,GW_OWNER).
Tue Apr 14 16:17:55 1998 Berend Reitsma <berend@united-info.com>
* [graphics/metafiledrv/init.c] [graphics/painting.c]
[graphics/win16drv/init.c] [graphics/x11drv/graphics.c]
[graphics/x11drv/init.c] [include/gdi.h] [include/x11drv.h]
[relay32/gdi32.spec]
Added PolyPolyline routine.
* [windows/winproc.c]
Changed WINPROC_GetProc() to return proc instead of &(jmp proc).
diff --git a/loader/ne/Makefile.in b/loader/ne/Makefile.in
new file mode 100644
index 0000000..0acbdc1
--- /dev/null
+++ b/loader/ne/Makefile.in
@@ -0,0 +1,17 @@
+DEFS = @DLLFLAGS@ -D__WINE__
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR = @srcdir@
+VPATH = @srcdir@
+MODULE = ne
+
+C_SRCS = \
+ module.c \
+ resource.c \
+ segment.c
+
+all: $(MODULE).o
+
+@MAKE_RULES@
+
+### Dependencies:
diff --git a/loader/ne/module.c b/loader/ne/module.c
new file mode 100644
index 0000000..5cd97f8
--- /dev/null
+++ b/loader/ne/module.c
@@ -0,0 +1,736 @@
+/*
+ * NE modules
+ *
+ * Copyright 1995 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "module.h"
+#include "ldt.h"
+#include "heap.h"
+#include "global.h"
+#include "process.h"
+#include "debug.h"
+
+HMODULE16 hFirstModule = 0;
+
+/***********************************************************************
+ * NE_DumpModule
+ */
+void NE_DumpModule( HMODULE16 hModule )
+{
+ int i, ordinal;
+ SEGTABLEENTRY *pSeg;
+ BYTE *pstr;
+ WORD *pword;
+ NE_MODULE *pModule;
+
+ if (!(pModule = MODULE_GetPtr16( hModule )))
+ {
+ fprintf( stderr, "**** %04x is not a module handle\n", hModule );
+ return;
+ }
+
+ /* Dump the module info */
+ DUMP( "---\n" );
+ DUMP( "Module %04x:\n", hModule );
+ DUMP( "count=%d flags=%04x heap=%d stack=%d\n",
+ pModule->count, pModule->flags,
+ pModule->heap_size, pModule->stack_size );
+ DUMP( "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 );
+ DUMP( "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)
+ DUMP( "PE module=%08x\n", pModule->module32 );
+
+ /* Dump the file info */
+ DUMP( "---\n" );
+ DUMP( "Filename: '%s'\n", NE_MODULE_NAME(pModule) );
+
+ /* Dump the segment table */
+ DUMP( "---\n" );
+ DUMP( "Segment table:\n" );
+ pSeg = NE_SEG_TABLE( pModule );
+ for (i = 0; i < pModule->seg_count; i++, pSeg++)
+ DUMP( "%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 */
+ DUMP( "---\n" );
+ DUMP( "Resource table:\n" );
+ if (pModule->res_table)
+ {
+ pword = (WORD *)((BYTE *)pModule + pModule->res_table);
+ DUMP( "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);
+ DUMP( "id=%04x count=%d\n", ptr->type_id, ptr->count );
+ for (i = 0; i < ptr->count; i++, pname++)
+ DUMP( "offset=%d len=%d id=%04x\n",
+ pname->offset, pname->length, pname->id );
+ pword = (WORD *)pname;
+ }
+ }
+ else DUMP( "None\n" );
+
+ /* Dump the resident name table */
+ DUMP( "---\n" );
+ DUMP( "Resident-name table:\n" );
+ pstr = (char *)pModule + pModule->name_table;
+ while (*pstr)
+ {
+ DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
+ *(WORD *)(pstr + *pstr + 1) );
+ pstr += *pstr + 1 + sizeof(WORD);
+ }
+
+ /* Dump the module reference table */
+ DUMP( "---\n" );
+ DUMP( "Module ref table:\n" );
+ if (pModule->modref_table)
+ {
+ pword = (WORD *)((BYTE *)pModule + pModule->modref_table);
+ for (i = 0; i < pModule->modref_count; i++, pword++)
+ {
+ DUMP( "%d: %04x -> '%s'\n", i, *pword,
+ MODULE_GetModuleName(*pword));
+ }
+ }
+ else DUMP( "None\n" );
+
+ /* Dump the entry table */
+ DUMP( "---\n" );
+ DUMP( "Entry table:\n" );
+ pstr = (char *)pModule + pModule->entry_table;
+ ordinal = 1;
+ while (*pstr)
+ {
+ DUMP( "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 */
+ {
+ i = *pstr;
+ pstr += 2;
+ while (i--)
+ {
+ DUMP( "%d: %02x:%04x (moveable)\n",
+ ordinal++, pstr[3], *(WORD *)(pstr + 4) );
+ pstr += 6;
+ }
+ }
+ else /* fixed */
+ {
+ i = *pstr;
+ pstr += 2;
+ while (i--)
+ {
+ DUMP( "%d: %04x (fixed)\n",
+ ordinal++, *(WORD *)(pstr + 1) );
+ pstr += 3;
+ }
+ }
+ }
+
+ /* Dump the non-resident names table */
+ DUMP( "---\n" );
+ DUMP( "Non-resident names table:\n" );
+ if (pModule->nrname_handle)
+ {
+ pstr = (char *)GlobalLock16( pModule->nrname_handle );
+ while (*pstr)
+ {
+ DUMP( "%*.*s: %d\n", *pstr, *pstr, pstr + 1,
+ *(WORD *)(pstr + *pstr + 1) );
+ pstr += *pstr + 1 + sizeof(WORD);
+ }
+ }
+ DUMP( "\n" );
+}
+
+
+/***********************************************************************
+ * NE_WalkModules
+ *
+ * Walk the module list and print the modules.
+ */
+void NE_WalkModules(void)
+{
+ HMODULE16 hModule = hFirstModule;
+ fprintf( stderr, "Module Flags Name\n" );
+ while (hModule)
+ {
+ NE_MODULE *pModule = MODULE_GetPtr16( 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;
+ }
+}
+
+
+/**********************************************************************
+ * NE_RegisterModule
+ */
+void NE_RegisterModule( NE_MODULE *pModule )
+{
+ pModule->next = hFirstModule;
+ hFirstModule = pModule->self;
+}
+
+
+/***********************************************************************
+ * NE_GetOrdinal
+ *
+ * Lookup the ordinal for a given name.
+ */
+WORD NE_GetOrdinal( HMODULE16 hModule, const char *name )
+{
+ unsigned char buffer[256], *cpnt;
+ BYTE len;
+ NE_MODULE *pModule;
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return 0;
+ assert( !(pModule->flags & NE_FFLAGS_WIN32) );
+
+ 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;
+}
+
+
+/***********************************************************************
+ * NE_GetEntryPoint (WPROCS.27)
+ *
+ * Return the entry point for a given ordinal.
+ */
+FARPROC16 NE_GetEntryPoint( HMODULE16 hModule, WORD ordinal )
+{
+ NE_MODULE *pModule;
+ WORD curOrdinal = 1;
+ BYTE *p;
+ WORD sel, offset;
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return 0;
+ assert( !(pModule->flags & NE_FFLAGS_WIN32) );
+
+ 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 );
+}
+
+
+/***********************************************************************
+ * NE_SetEntryPoint
+ *
+ * Change the value of an entry point. Use with caution!
+ * It can only change the offset value, not the selector.
+ */
+BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset )
+{
+ NE_MODULE *pModule;
+ WORD curOrdinal = 1;
+ BYTE *p;
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return FALSE;
+ assert( !(pModule->flags & NE_FFLAGS_WIN32) );
+
+ 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;
+}
+
+
+/***********************************************************************
+ * NE_LoadExeHeader
+ */
+static HMODULE16 NE_LoadExeHeader( HFILE32 hFile, OFSTRUCT *ofs )
+{
+ IMAGE_DOS_HEADER mz_header;
+ IMAGE_OS2_HEADER ne_header;
+ int size;
+ HMODULE16 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 (HMODULE16)11; /* invalid exe */
+
+ _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
+ if (_lread32( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
+ return (HMODULE16)11; /* invalid exe */
+
+ if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21; /* win32 exe */
+ if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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 (HMODULE16)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(HMODULE16),
+ hModule, FALSE, FALSE, FALSE );
+ if (!pModule->dlls_to_init)
+ {
+ if (pModule->nrname_handle) GlobalFree16( pModule->nrname_handle );
+ GlobalFree16( hModule );
+ return (HMODULE16)11; /* invalid exe */
+ }
+ }
+ else pModule->dlls_to_init = 0;
+
+ NE_RegisterModule( pModule );
+ return hModule;
+}
+
+
+/***********************************************************************
+ * NE_LoadDLLs
+ *
+ * Load all DLLs implicitly linked to a module.
+ */
+static BOOL32 NE_LoadDLLs( NE_MODULE *pModule )
+{
+ int i;
+ WORD *pModRef = (WORD *)((char *)pModule + pModule->modref_table);
+ WORD *pDLLs = (WORD *)GlobalLock16( 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" );
+ TRACE(module, "Loading '%s'\n", buffer );
+ if (!(*pModRef = MODULE_FindModule16( buffer )))
+ {
+ /* If the DLL is not loaded yet, load it and store */
+ /* its handle in the list of DLLs to initialize. */
+ HMODULE16 hDLL;
+
+ if ((hDLL = MODULE_Load( buffer, NE_FFLAGS_IMPLICIT,
+ NULL, NULL, 0 )) == 2)
+ {
+ /* file not found */
+ char *p;
+
+ /* Try with prepending the path of the current module */
+ GetModuleFileName16( pModule->self, buffer, sizeof(buffer) );
+ if (!(p = strrchr( buffer, '\\' ))) p = buffer;
+ memcpy( p + 1, pstr + 1, *pstr );
+ strcpy( p + 1 + *pstr, ".dll" );
+ hDLL = MODULE_Load( buffer, NE_FFLAGS_IMPLICIT, NULL, NULL, 0);
+ }
+ if (hDLL < 32)
+ {
+ /* FIXME: cleanup what was done */
+
+ fprintf( stderr, "Could not load '%s' required by '%.*s', error = %d\n",
+ buffer, *((BYTE*)pModule + pModule->name_table),
+ (char *)pModule + pModule->name_table + 1, hDLL );
+ return FALSE;
+ }
+ *pModRef = GetExePtr( hDLL );
+ *pDLLs++ = *pModRef;
+ }
+ else /* Increment the reference count of the DLL */
+ {
+ NE_MODULE *pOldDLL = MODULE_GetPtr16( *pModRef );
+ if (pOldDLL) pOldDLL->count++;
+ }
+ }
+ return TRUE;
+}
+
+
+/**********************************************************************
+ * NE_LoadModule
+ *
+ * Implementation of LoadModule().
+ *
+ * cmd_line must contain the whole command-line, including argv[0] (and
+ * without a preceding length byte).
+ * If cmd_line is NULL, the module is loaded as a library even if it is a .exe
+ */
+HINSTANCE16 NE_LoadModule( HFILE32 hFile, OFSTRUCT *ofs, UINT16 flags,
+ LPCSTR cmd_line, LPCSTR env, UINT32 show_cmd )
+{
+ HMODULE16 hModule;
+ HINSTANCE16 hInstance;
+ NE_MODULE *pModule;
+
+ /* Create the module structure */
+
+ if ((hModule = NE_LoadExeHeader( hFile, ofs )) < 32) return hModule;
+
+ pModule = MODULE_GetPtr16( hModule );
+ pModule->flags |= flags; /* stamp implicitly loaded modules */
+
+ /* Allocate the segments for this module */
+
+ NE_CreateSegments( hModule );
+ hInstance = MODULE_CreateInstance( hModule, NULL, (cmd_line == NULL) );
+
+ /* Load the referenced DLLs */
+
+ if (!NE_LoadDLLs( pModule ))
+ return 2; /* File not found (FIXME: free everything) */
+
+ /* 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 );
+
+ /* Create a task for this instance */
+
+ if (cmd_line && !(pModule->flags & NE_FFLAGS_LIBMODULE))
+ {
+ PDB32 *pdb;
+
+ pModule->flags |= NE_FFLAGS_GUI;
+
+ pdb = PROCESS_Create( pModule, cmd_line, env, hInstance, 0, show_cmd );
+ if (pdb && (GetNumTasks() > 1)) Yield16();
+ }
+
+ return hInstance;
+}
diff --git a/loader/ne/resource.c b/loader/ne/resource.c
new file mode 100644
index 0000000..832be3b
--- /dev/null
+++ b/loader/ne/resource.c
@@ -0,0 +1,551 @@
+/*
+ * NE resource functions
+ *
+ * Copyright 1993 Robert J. Amstadt
+ * Copyright 1995 Alexandre Julliard
+ * Copyright 1997 Alex Korobka
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "windows.h"
+#include "global.h"
+#include "ldt.h"
+#include "module.h"
+#include "neexe.h"
+#include "resource.h"
+#include "debug.h"
+
+#define NEXT_TYPEINFO(pTypeInfo) ((NE_TYPEINFO *)((char*)((pTypeInfo) + 1) + \
+ (pTypeInfo)->count * sizeof(NE_NAMEINFO)))
+
+/***********************************************************************
+ * NE_FindNameTableId
+ *
+ * Find the type and resource id from their names.
+ * Return value is MAKELONG( typeId, resId ), or 0 if not found.
+ */
+static DWORD NE_FindNameTableId( NE_MODULE *pModule, SEGPTR typeId, SEGPTR resId )
+{
+ NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
+ NE_NAMEINFO *pNameInfo;
+ HGLOBAL16 handle;
+ WORD *p;
+ DWORD ret = 0;
+ int count;
+
+ for (; pTypeInfo->type_id != 0;
+ pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo+1) +
+ pTypeInfo->count * sizeof(NE_NAMEINFO)))
+ {
+ if (pTypeInfo->type_id != 0x800f) continue;
+ pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
+ for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
+ {
+ TRACE(resource, "NameTable entry: type=%04x id=%04x\n",
+ pTypeInfo->type_id, pNameInfo->id );
+ handle = LoadResource16( pModule->self,
+ (HRSRC16)((int)pNameInfo - (int)pModule) );
+ for(p = (WORD*)LockResource16(handle); p && *p; p = (WORD *)((char*)p+*p))
+ {
+ TRACE(resource," type=%04x '%s' id=%04x '%s'\n",
+ p[1], (char *)(p+3), p[2],
+ (char *)(p+3)+strlen((char *)(p+3))+1 );
+ /* Check for correct type */
+
+ if (p[1] & 0x8000)
+ {
+ if (!HIWORD(typeId)) continue;
+ if (lstrcmpi32A( (char *)PTR_SEG_TO_LIN(typeId),
+ (char *)(p + 3) )) continue;
+ }
+ else if (HIWORD(typeId) || ((typeId & ~0x8000)!= p[1]))
+ continue;
+
+ /* Now check for the id */
+
+ if (p[2] & 0x8000)
+ {
+ if (!HIWORD(resId)) continue;
+ if (lstrcmpi32A( (char *)PTR_SEG_TO_LIN(resId),
+ (char*)(p+3)+strlen((char*)(p+3))+1 )) continue;
+
+ }
+ else if (HIWORD(resId) || ((resId & ~0x8000) != p[2]))
+ continue;
+
+ /* If we get here, we've found the entry */
+
+ TRACE(resource, " Found!\n" );
+ ret = MAKELONG( p[1], p[2] );
+ break;
+ }
+ FreeResource16( handle );
+ if (ret) return ret;
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * NE_FindTypeSection
+ *
+ * Find header struct for a particular resource type.
+ */
+static NE_TYPEINFO* NE_FindTypeSection( NE_MODULE *pModule,
+ NE_TYPEINFO *pTypeInfo, SEGPTR typeId )
+{
+ /* start from pTypeInfo */
+
+ if (HIWORD(typeId) != 0) /* Named type */
+ {
+ char *str = (char *)PTR_SEG_TO_LIN( typeId );
+ BYTE len = strlen( str );
+ while (pTypeInfo->type_id)
+ {
+ if (!(pTypeInfo->type_id & 0x8000))
+ {
+ BYTE *p = (BYTE*)pModule + pModule->res_table + pTypeInfo->type_id;
+ if ((*p == len) && !lstrncmpi32A( p+1, str, len ))
+ {
+ TRACE(resource, " Found type '%s'\n", str );
+ return pTypeInfo;
+ }
+ }
+ TRACE(resource, " Skipping type %04x\n", pTypeInfo->type_id );
+ pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
+ }
+ }
+ else /* Numeric type id */
+ {
+ WORD id = LOWORD(typeId) | 0x8000;
+ while (pTypeInfo->type_id)
+ {
+ if (pTypeInfo->type_id == id)
+ {
+ TRACE(resource, " Found type %04x\n", id );
+ return pTypeInfo;
+ }
+ TRACE(resource, " Skipping type %04x\n", pTypeInfo->type_id );
+ pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
+ }
+ }
+ return NULL;
+}
+
+/***********************************************************************
+ * NE_FindResourceFromType
+ *
+ * Find a resource once the type info structure has been found.
+ */
+static HRSRC16 NE_FindResourceFromType( NE_MODULE *pModule,
+ NE_TYPEINFO *pTypeInfo, SEGPTR resId )
+{
+ BYTE *p;
+ int count;
+ NE_NAMEINFO *pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
+
+ if (HIWORD(resId) != 0) /* Named resource */
+ {
+ char *str = (char *)PTR_SEG_TO_LIN( resId );
+ BYTE len = strlen( str );
+ for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
+ {
+ if (pNameInfo->id & 0x8000) continue;
+ p = (BYTE *)pModule + pModule->res_table + pNameInfo->id;
+ if ((*p == len) && !lstrncmpi32A( p+1, str, len ))
+ return (HRSRC16)((int)pNameInfo - (int)pModule);
+ }
+ }
+ else /* Numeric resource id */
+ {
+ WORD id = LOWORD(resId) | 0x8000;
+ for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
+ if (pNameInfo->id == id)
+ return (HRSRC16)((int)pNameInfo - (int)pModule);
+ }
+ return 0;
+}
+
+
+/***********************************************************************
+ * NE_DefResourceHandler
+ *
+ * This is the default LoadProc() function.
+ */
+HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
+ HRSRC16 hRsrc )
+{
+ int fd;
+ NE_MODULE* pModule = MODULE_GetPtr16( hModule );
+ if ( pModule && (fd = MODULE_OpenFile( hModule )) >= 0)
+ {
+ HGLOBAL16 handle;
+ WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
+ NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
+
+ TRACE(resource, "loading, pos=%d, len=%d\n",
+ (int)pNameInfo->offset << sizeShift,
+ (int)pNameInfo->length << sizeShift );
+ if( hMemObj )
+ handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
+ else
+ handle = AllocResource( hModule, hRsrc, 0 );
+
+ if( handle )
+ {
+ lseek( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
+ read( fd, GlobalLock16( handle ), (int)pNameInfo->length << sizeShift );
+ }
+ return handle;
+ }
+ return (HGLOBAL16)0;
+}
+
+/***********************************************************************
+ * NE_InitResourceHandler
+ *
+ * Fill in 'resloader' fields in the resource table.
+ */
+BOOL32 NE_InitResourceHandler( HMODULE16 hModule )
+{
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
+
+ TRACE(resource,"InitResourceHandler[%04x]\n", hModule );
+
+ while(pTypeInfo->type_id)
+ {
+ pTypeInfo->resloader = (FARPROC16)&NE_DefResourceHandler;
+ pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
+ }
+ return TRUE;
+}
+
+
+/**********************************************************************
+ * SetResourceHandler (KERNEL.43)
+ */
+FARPROC16 WINAPI SetResourceHandler( HMODULE16 hModule, SEGPTR typeId,
+ FARPROC16 resourceHandler )
+{
+ FARPROC16 prevHandler = NULL;
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
+
+ if (!pModule || !pModule->res_table) return NULL;
+
+ TRACE( resource, "module=%04x type=%s\n",
+ hModule, debugres_a(PTR_SEG_TO_LIN(typeId)) );
+
+ for (;;)
+ {
+ if (!(pTypeInfo = NE_FindTypeSection( pModule, pTypeInfo, typeId )))
+ break;
+ prevHandler = pTypeInfo->resloader;
+ pTypeInfo->resloader = resourceHandler;
+ pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
+ }
+ return prevHandler;
+}
+
+
+/**********************************************************************
+ * FindResource16 (KERNEL.60)
+ */
+HRSRC16 WINAPI FindResource16( HMODULE16 hModule, SEGPTR name, SEGPTR type )
+{
+ NE_TYPEINFO *pTypeInfo;
+ HRSRC16 hRsrc;
+
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ if (!pModule || !pModule->res_table) return 0;
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ TRACE( resource, "module=%04x name=%s type=%s\n",
+ hModule, debugres_a(PTR_SEG_TO_LIN(name)),
+ debugres_a(PTR_SEG_TO_LIN(type)) );
+
+ if (HIWORD(name)) /* Check for '#xxx' name */
+ {
+ char *ptr = PTR_SEG_TO_LIN( name );
+ if (ptr[0] == '#')
+ if (!(name = (SEGPTR)atoi( ptr + 1 )))
+ {
+ WARN(resource, "Incorrect resource name: %s\n", ptr);
+ return 0;
+ }
+ }
+
+ if (HIWORD(type)) /* Check for '#xxx' type */
+ {
+ char *ptr = PTR_SEG_TO_LIN( type );
+ if (ptr[0] == '#')
+ if (!(type = (SEGPTR)atoi( ptr + 1 )))
+ {
+ WARN(resource, "Incorrect resource type: %s\n", ptr);
+ return 0;
+ }
+ }
+
+ if (HIWORD(type) || HIWORD(name))
+ {
+ DWORD id = NE_FindNameTableId( pModule, type, name );
+ if (id) /* found */
+ {
+ type = LOWORD(id);
+ name = HIWORD(id);
+ }
+ }
+
+ pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
+
+ for (;;)
+ {
+ if (!(pTypeInfo = NE_FindTypeSection( pModule, pTypeInfo, type )))
+ break;
+ if ((hRsrc = NE_FindResourceFromType(pModule, pTypeInfo, name)))
+ {
+ TRACE(resource, " Found id %08lx\n", name );
+ return hRsrc;
+ }
+ TRACE(resource, " Not found, going on\n" );
+ pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
+ }
+
+ WARN(resource, "failed!\n");
+ return 0;
+}
+
+
+/**********************************************************************
+ * AllocResource (KERNEL.66)
+ */
+HGLOBAL16 WINAPI AllocResource( HMODULE16 hModule, HRSRC16 hRsrc, DWORD size)
+{
+ NE_NAMEINFO *pNameInfo=NULL;
+ WORD sizeShift;
+
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ if (!pModule || !pModule->res_table || !hRsrc) return 0;
+
+ TRACE( resource, "module=%04x res=%04x size=%ld\n", hModule, hRsrc, size );
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
+ pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
+ if (size < (DWORD)pNameInfo->length << sizeShift)
+ size = (DWORD)pNameInfo->length << sizeShift;
+ return GLOBAL_Alloc( GMEM_FIXED, size, hModule, FALSE, FALSE, FALSE );
+}
+
+
+/**********************************************************************
+ * DirectResAlloc (KERNEL.168)
+ *
+ * Check Schulman, p. 232 for details
+ */
+HGLOBAL16 WINAPI DirectResAlloc( HINSTANCE16 hInstance, WORD wType,
+ UINT16 wSize )
+{
+ TRACE(resource,"(%04x,%04x,%04x)\n",
+ hInstance, wType, wSize );
+ if (!(hInstance = GetExePtr( hInstance ))) return 0;
+ if(wType != 0x10) /* 0x10 is the only observed value, passed from
+ CreateCursorIndirect. */
+ fprintf(stderr, "DirectResAlloc: wType = %x\n", wType);
+ return GLOBAL_Alloc(GMEM_MOVEABLE, wSize, hInstance, FALSE, FALSE, FALSE);
+}
+
+
+/**********************************************************************
+ * AccessResource16 (KERNEL.64)
+ */
+INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
+{
+ HFILE32 fd;
+
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ if (!pModule || !pModule->res_table || !hRsrc) return -1;
+
+ TRACE(resource, "module=%04x res=%04x\n", hModule, hRsrc );
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ if ((fd = _lopen32( NE_MODULE_NAME(pModule), OF_READ )) != -1)
+ {
+ WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
+ NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
+ _llseek32( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
+ }
+ return fd;
+}
+
+
+/**********************************************************************
+ * SizeofResource16 (KERNEL.65)
+ */
+DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
+{
+ NE_NAMEINFO *pNameInfo=NULL;
+ WORD sizeShift;
+
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ if (!pModule || !pModule->res_table) return 0;
+
+ TRACE(resource, "module=%04x res=%04x\n", hModule, hRsrc );
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
+ pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
+ return (DWORD)pNameInfo->length << sizeShift;
+}
+
+
+/**********************************************************************
+ * LoadResource16 (KERNEL.61)
+ */
+HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
+{
+ NE_TYPEINFO *pTypeInfo;
+ NE_NAMEINFO *pNameInfo = NULL;
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+ int d;
+
+ TRACE( resource, "module=%04x res=%04x\n", hModule, hRsrc );
+ if (!hRsrc || !pModule || !pModule->res_table) return 0;
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ /* First, verify hRsrc (just an offset from pModule to the needed pNameInfo) */
+
+ d = pModule->res_table + 2;
+ pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
+ while( hRsrc > d )
+ {
+ if (pTypeInfo->type_id == 0)
+ break; /* terminal entry */
+ d += sizeof(NE_TYPEINFO) + pTypeInfo->count * sizeof(NE_NAMEINFO);
+ if (hRsrc < d)
+ {
+ if( ((d - hRsrc)%sizeof(NE_NAMEINFO)) == 0 )
+ {
+ pNameInfo = (NE_NAMEINFO *)(((char *)pModule) + hRsrc);
+ break;
+ }
+ else
+ break; /* NE_NAMEINFO boundary mismatch */
+ }
+ pTypeInfo = (NE_TYPEINFO *)(((char *)pModule) + d);
+ }
+
+ if (pNameInfo)
+ {
+ RESOURCEHANDLER16 loader;
+ if (pNameInfo->handle
+ && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED))
+ {
+ pNameInfo->usage++;
+ TRACE(resource, " Already loaded, new count=%d\n",
+ pNameInfo->usage );
+ }
+ else
+ {
+ if (pTypeInfo->resloader)
+ loader = (RESOURCEHANDLER16)pTypeInfo->resloader;
+ else /* this is really bad */
+ {
+ fprintf( stderr, "[%04x]: Missing resource handler!!!...\n", hModule);
+ loader = NE_DefResourceHandler;
+ }
+
+ /* Finally call resource loader */
+
+ if ((pNameInfo->handle = loader(pNameInfo->handle, hModule, hRsrc)))
+ {
+ pNameInfo->usage++;
+ pNameInfo->flags |= NE_SEGFLAGS_LOADED;
+ }
+ }
+ return pNameInfo->handle;
+ }
+ return 0;
+}
+
+
+/**********************************************************************
+ * LockResource16 (KERNEL.62)
+ */
+/* 16-bit version */
+SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
+{
+ TRACE( resource, "handle=%04x\n", handle );
+ if (!handle) return (SEGPTR)0;
+
+ /* May need to reload the resource if discarded */
+
+ return (SEGPTR)WIN16_GlobalLock16( handle );
+}
+
+/* Winelib 16-bit version */
+LPVOID WINAPI LockResource16( HGLOBAL16 handle )
+{
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ return (LPVOID)PTR_SEG_TO_LIN( WIN16_LockResource16( handle ) );
+}
+
+
+/**********************************************************************
+ * FreeResource16 (KERNEL.63)
+ */
+BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
+{
+ NE_TYPEINFO *pTypeInfo;
+ NE_NAMEINFO *pNameInfo;
+ WORD count;
+ HMODULE16 hModule = GetExePtr( handle );
+ NE_MODULE *pModule = MODULE_GetPtr16( hModule );
+
+ if (!handle || !pModule || !pModule->res_table) return handle;
+
+ TRACE(resource, "handle=%04x\n", handle );
+
+ assert( !__winelib ); /* Can't use Win16 resource functions in Winelib */
+
+ pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
+ while (pTypeInfo->type_id)
+ {
+ pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
+ for (count = pTypeInfo->count; count > 0; count--)
+ {
+ if (pNameInfo->handle == handle)
+ {
+ if (pNameInfo->usage > 0) pNameInfo->usage--;
+ if (pNameInfo->usage == 0)
+ {
+ GlobalFree16( pNameInfo->handle );
+ pNameInfo->handle = 0;
+ pNameInfo->flags &= ~NE_SEGFLAGS_LOADED;
+ }
+ return 0;
+ }
+ pNameInfo++;
+ }
+ pTypeInfo = (NE_TYPEINFO *)pNameInfo;
+ }
+
+ TRACE(resource, "[%04x]: no intrinsic resource for %04x, assuming DirectResAlloc()!\n",
+ hModule, handle );
+ GlobalFree16( handle );
+ return handle;
+}
diff --git a/loader/ne/segment.c b/loader/ne/segment.c
new file mode 100644
index 0000000..99f78ce
--- /dev/null
+++ b/loader/ne/segment.c
@@ -0,0 +1,712 @@
+/*
+ * NE segment loading
+ *
+ * Copyright 1993 Robert J. Amstadt
+ * Copyright 1995 Alexandre Julliard
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include "neexe.h"
+#include "windows.h"
+#include "global.h"
+#include "task.h"
+#include "selectors.h"
+#include "callback.h"
+#include "file.h"
+#include "module.h"
+#include "stackframe.h"
+#include "debug.h"
+#include "xmalloc.h"
+
+
+/***********************************************************************
+ * NE_GetRelocAddrName
+ */
+static const char *NE_GetRelocAddrName( BYTE addr_type, int additive )
+{
+ switch(addr_type & 0x7f)
+ {
+ case NE_RADDR_LOWBYTE: return additive ? "BYTE add" : "BYTE";
+ case NE_RADDR_OFFSET16: return additive ? "OFFSET16 add" : "OFFSET16";
+ case NE_RADDR_POINTER32: return additive ? "POINTER32 add" : "POINTER32";
+ case NE_RADDR_SELECTOR: return additive ? "SELECTOR add" : "SELECTOR";
+ case NE_RADDR_POINTER48: return additive ? "POINTER48 add" : "POINTER48";
+ case NE_RADDR_OFFSET32: return additive ? "OFFSET32 add" : "OFFSET32";
+ }
+ return "???";
+}
+
+
+/***********************************************************************
+ * NE_LoadSegment
+ */
+BOOL32 NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
+{
+ SEGTABLEENTRY *pSegTable, *pSeg;
+ WORD *pModuleTable;
+ WORD count, i, offset, next_offset;
+ HMODULE16 module;
+ FARPROC16 address = 0;
+ int fd;
+ struct relocation_entry_s *rep, *reloc_entries;
+ BYTE *func_name;
+ int size;
+ char* mem;
+
+ char buffer[256];
+ int ordinal, additive;
+ unsigned short *sp;
+
+ pSegTable = NE_SEG_TABLE( pModule );
+ pSeg = pSegTable + segnum - 1;
+ pModuleTable = NE_MODULE_TABLE( pModule );
+
+ if (!pSeg->filepos) return TRUE; /* No file image, just return */
+
+ fd = MODULE_OpenFile( pModule->self );
+ TRACE(module, "Loading segment %d, selector=%04x, flags=%04x\n",
+ segnum, pSeg->selector, pSeg->flags );
+ lseek( fd, pSeg->filepos << pModule->alignment, SEEK_SET );
+ if (pSeg->size) size = pSeg->size;
+ else if (pSeg->minsize) size = pSeg->minsize;
+ else size = 0x10000;
+ mem = GlobalLock16(pSeg->selector);
+ if (pModule->flags & NE_FFLAGS_SELFLOAD && segnum > 1)
+ {
+ /* Implement self loading segments */
+ SELFLOADHEADER *selfloadheader;
+ STACK16FRAME *stack16Top;
+ DWORD oldstack;
+ WORD oldselector, newselector;
+ THDB *thdb = THREAD_Current();
+ HFILE32 hf = FILE_DupUnixHandle( fd );
+
+ selfloadheader = (SELFLOADHEADER *)
+ PTR_SEG_OFF_TO_LIN(pSegTable->selector,0);
+ oldstack = thdb->cur_stack;
+ oldselector = pSeg->selector;
+ thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
+ 0xff00 - sizeof(*stack16Top));
+ stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
+ stack16Top->frame32 = 0;
+ stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
+ stack16Top->entry_point = 0;
+ stack16Top->entry_ip = 0;
+ stack16Top->entry_cs = 0;
+ stack16Top->bp = 0;
+ stack16Top->ip = 0;
+ stack16Top->cs = 0;
+ newselector = Callbacks->CallLoadAppSegProc(selfloadheader->LoadAppSeg,
+ pModule->self, hf, segnum );
+ _lclose32( hf );
+ if (newselector != oldselector) {
+ /* Self loaders like creating their own selectors;
+ * they love asking for trouble to Wine developers
+ */
+ if (segnum == pModule->dgroup) {
+ memcpy(PTR_SEG_OFF_TO_LIN(oldselector,0),
+ PTR_SEG_OFF_TO_LIN(newselector,0),
+ pSeg->minsize ? pSeg->minsize : 0x10000);
+ FreeSelector(newselector);
+ pSeg->selector = oldselector;
+ fprintf(stderr, "A new selector was allocated for the dgroup segment\n"
+ "Old selector is %d, new one is %d", oldselector, newselector);
+ } else {
+ FreeSelector(pSeg->selector);
+ pSeg->selector = newselector;
+ }
+ }
+
+ thdb->cur_stack = oldstack;
+ }
+ else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
+ read(fd, mem, size);
+ else {
+ /*
+ The following bit of code for "iterated segments" was written without
+ any documentation on the format of these segments. It seems to work,
+ but may be missing something. If you have any doc please either send
+ it to me or fix the code yourself. gfm@werple.mira.net.au
+ */
+ char* buff = xmalloc(size);
+ char* curr = buff;
+ read(fd, buff, size);
+ while(curr < buff + size) {
+ unsigned int rept = *((short*) curr)++;
+ unsigned int len = *((short*) curr)++;
+ for(; rept > 0; rept--) {
+ char* bytes = curr;
+ unsigned int byte;
+ for(byte = 0; byte < len; byte++)
+ *mem++ = *bytes++;
+ }
+ curr += len;
+ }
+ free(buff);
+ }
+
+ pSeg->flags |= NE_SEGFLAGS_LOADED;
+ if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
+ return TRUE; /* No relocation data, we are done */
+
+ read( fd, &count, sizeof(count) );
+ if (!count) return TRUE;
+
+ TRACE(fixup, "Fixups for %.*s, segment %d, selector %04x\n",
+ *((BYTE *)pModule + pModule->name_table),
+ (char *)pModule + pModule->name_table + 1,
+ segnum, pSeg->selector );
+ TRACE(segment, "Fixups for %.*s, segment %d, selector %04x\n",
+ *((BYTE *)pModule + pModule->name_table),
+ (char *)pModule + pModule->name_table + 1,
+ segnum, pSeg->selector );
+
+ reloc_entries = (struct relocation_entry_s *)xmalloc(count * sizeof(struct relocation_entry_s));
+ if (read( fd, reloc_entries, count * sizeof(struct relocation_entry_s)) !=
+ count * sizeof(struct relocation_entry_s))
+ {
+ WARN(fixup, "Unable to read relocation information\n" );
+ return FALSE;
+ }
+
+ /*
+ * Go through the relocation table one entry at a time.
+ */
+ rep = reloc_entries;
+ for (i = 0; i < count; i++, rep++)
+ {
+ /*
+ * Get the target address corresponding to this entry.
+ */
+
+ /* If additive, there is no target chain list. Instead, add source
+ and target */
+ additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
+ rep->relocation_type &= 0x3;
+
+ switch (rep->relocation_type)
+ {
+ case NE_RELTYPE_ORDINAL:
+ module = pModuleTable[rep->target1-1];
+ ordinal = rep->target2;
+ address = NE_GetEntryPoint( module, ordinal );
+ if (!address)
+ {
+ NE_MODULE *pTarget = MODULE_GetPtr16( module );
+ if (!pTarget)
+ fprintf( stderr, "Module not found: %04x, reference %d of module %*.*s\n",
+ module, rep->target1,
+ *((BYTE *)pModule + pModule->name_table),
+ *((BYTE *)pModule + pModule->name_table),
+ (char *)pModule + pModule->name_table + 1 );
+ else
+ fprintf( stderr, "Warning: no handler for %.*s.%d, setting to 0:0\n",
+ *((BYTE *)pTarget + pTarget->name_table),
+ (char *)pTarget + pTarget->name_table + 1,
+ ordinal );
+ }
+ if (TRACE_ON(fixup))
+ {
+ NE_MODULE *pTarget = MODULE_GetPtr16( module );
+ TRACE( fixup, "%d: %.*s.%d=%04x:%04x %s\n", i + 1,
+ *((BYTE *)pTarget + pTarget->name_table),
+ (char *)pTarget + pTarget->name_table + 1,
+ ordinal, HIWORD(address), LOWORD(address),
+ NE_GetRelocAddrName( rep->address_type, additive ) );
+ }
+ break;
+
+ case NE_RELTYPE_NAME:
+ module = pModuleTable[rep->target1-1];
+ func_name = (char *)pModule + pModule->import_table + rep->target2;
+ memcpy( buffer, func_name+1, *func_name );
+ buffer[*func_name] = '\0';
+ func_name = buffer;
+ ordinal = NE_GetOrdinal( module, func_name );
+ address = NE_GetEntryPoint( module, ordinal );
+
+ if (ERR_ON(fixup) && !address)
+ {
+ NE_MODULE *pTarget = MODULE_GetPtr16( module );
+ ERR(fixup, "Warning: no handler for %.*s.%s, setting to 0:0\n",
+ *((BYTE *)pTarget + pTarget->name_table),
+ (char *)pTarget + pTarget->name_table + 1, func_name );
+ }
+ if (TRACE_ON(fixup))
+ {
+ NE_MODULE *pTarget = MODULE_GetPtr16( module );
+ TRACE( fixup, "%d: %.*s.%s=%04x:%04x %s\n", i + 1,
+ *((BYTE *)pTarget + pTarget->name_table),
+ (char *)pTarget + pTarget->name_table + 1,
+ func_name, HIWORD(address), LOWORD(address),
+ NE_GetRelocAddrName( rep->address_type, additive ) );
+ }
+ break;
+
+ case NE_RELTYPE_INTERNAL:
+ if ((rep->target1 & 0xff) == 0xff)
+ {
+ address = NE_GetEntryPoint( pModule->self, rep->target2 );
+ }
+ else
+ {
+ address = (FARPROC16)PTR_SEG_OFF_TO_SEGPTR( pSegTable[rep->target1-1].selector, rep->target2 );
+ }
+
+ TRACE( fixup,"%d: %04x:%04x %s\n",
+ i + 1, HIWORD(address), LOWORD(address),
+ NE_GetRelocAddrName( rep->address_type, additive ) );
+ break;
+
+ case NE_RELTYPE_OSFIXUP:
+ /* Relocation type 7:
+ *
+ * These appear to be used as fixups for the Windows
+ * floating point emulator. Let's just ignore them and
+ * try to use the hardware floating point. Linux should
+ * successfully emulate the coprocessor if it doesn't
+ * exist.
+ */
+ TRACE( fixup, "%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n",
+ i + 1, rep->relocation_type, rep->offset,
+ rep->target1, rep->target2,
+ NE_GetRelocAddrName( rep->address_type, additive ) );
+ continue;
+ }
+
+ offset = rep->offset;
+
+ /* Apparently, high bit of address_type is sometimes set; */
+ /* we ignore it for now */
+ if (rep->address_type > NE_RADDR_OFFSET32)
+ ERR( fixup, "WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n",
+ MODULE_GetModuleName(pModule->self), rep->address_type );
+
+ if (additive)
+ {
+ sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
+ TRACE( fixup," %04x:%04x\n", offset, *sp );
+ switch (rep->address_type & 0x7f)
+ {
+ case NE_RADDR_LOWBYTE:
+ *(BYTE *)sp += LOBYTE((int)address);
+ break;
+ case NE_RADDR_OFFSET16:
+ *sp += LOWORD(address);
+ break;
+ case NE_RADDR_POINTER32:
+ *sp += LOWORD(address);
+ *(sp+1) = HIWORD(address);
+ break;
+ case NE_RADDR_SELECTOR:
+ /* Borland creates additive records with offset zero. Strange, but OK */
+ if (*sp)
+ ERR(fixup,"Additive selector to %04x.Please report\n",*sp);
+ else
+ *sp = HIWORD(address);
+ break;
+ default:
+ goto unknown;
+ }
+ }
+ else /* non-additive fixup */
+ {
+ do
+ {
+ sp = PTR_SEG_OFF_TO_LIN( pSeg->selector, offset );
+ next_offset = *sp;
+ TRACE( fixup," %04x:%04x\n", offset, *sp );
+ switch (rep->address_type & 0x7f)
+ {
+ case NE_RADDR_LOWBYTE:
+ *(BYTE *)sp = LOBYTE((int)address);
+ break;
+ case NE_RADDR_OFFSET16:
+ *sp = LOWORD(address);
+ break;
+ case NE_RADDR_POINTER32:
+ *(FARPROC16 *)sp = address;
+ break;
+ case NE_RADDR_SELECTOR:
+ *sp = SELECTOROF(address);
+ break;
+ default:
+ goto unknown;
+ }
+ if (next_offset == offset) break; /* avoid infinite loop */
+ if (next_offset >= GlobalSize16(pSeg->selector)) break;
+ offset = next_offset;
+ } while (offset && (offset != 0xffff));
+ }
+ }
+
+ free(reloc_entries);
+ return TRUE;
+
+unknown:
+ WARN(fixup, "WARNING: %d: unknown ADDR TYPE %d, "
+ "TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
+ i + 1, rep->address_type, rep->relocation_type,
+ rep->offset, rep->target1, rep->target2);
+ free(reloc_entries);
+ return FALSE;
+}
+
+
+/***********************************************************************
+ * NE_LoadAllSegments
+ */
+BOOL32 NE_LoadAllSegments( NE_MODULE *pModule )
+{
+ int i;
+
+ if (pModule->flags & NE_FFLAGS_SELFLOAD)
+ {
+ HFILE32 hf;
+ /* Handle self loading modules */
+ SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule);
+ SELFLOADHEADER *selfloadheader;
+ STACK16FRAME *stack16Top;
+ THDB *thdb = THREAD_Current();
+ HMODULE16 hselfload = GetModuleHandle16("WPROCS");
+ DWORD oldstack;
+ WORD saved_dgroup = pSegTable[pModule->dgroup - 1].selector;
+
+ TRACE(module, "%.*s is a self-loading module!\n",
+ *((BYTE*)pModule + pModule->name_table),
+ (char *)pModule + pModule->name_table + 1);
+ if (!NE_LoadSegment( pModule, 1 )) return FALSE;
+ selfloadheader = (SELFLOADHEADER *)
+ PTR_SEG_OFF_TO_LIN(pSegTable->selector, 0);
+ selfloadheader->EntryAddrProc = NE_GetEntryPoint(hselfload,27);
+ selfloadheader->MyAlloc = NE_GetEntryPoint(hselfload,28);
+ selfloadheader->SetOwner = NE_GetEntryPoint(GetModuleHandle16("KERNEL"),403);
+ pModule->self_loading_sel = GlobalHandleToSel(GLOBAL_Alloc(GMEM_ZEROINIT, 0xFF00, pModule->self, FALSE, FALSE, FALSE));
+ oldstack = thdb->cur_stack;
+ thdb->cur_stack = PTR_SEG_OFF_TO_SEGPTR(pModule->self_loading_sel,
+ 0xff00 - sizeof(*stack16Top) );
+ stack16Top = (STACK16FRAME *)PTR_SEG_TO_LIN(thdb->cur_stack);
+ stack16Top->frame32 = 0;
+ stack16Top->ebp = 0;
+ stack16Top->ds = stack16Top->es = pModule->self_loading_sel;
+ stack16Top->entry_point = 0;
+ stack16Top->entry_ip = 0;
+ stack16Top->entry_cs = 0;
+ stack16Top->bp = 0;
+ stack16Top->ip = 0;
+ stack16Top->cs = 0;
+
+ hf = FILE_DupUnixHandle( MODULE_OpenFile( pModule->self ) );
+ Callbacks->CallBootAppProc(selfloadheader->BootApp, pModule->self, hf);
+ _lclose32(hf);
+ /* some BootApp procs overwrite the selector of dgroup */
+ pSegTable[pModule->dgroup - 1].selector = saved_dgroup;
+ thdb->cur_stack = oldstack;
+ for (i = 2; i <= pModule->seg_count; i++)
+ if (!NE_LoadSegment( pModule, i )) return FALSE;
+ }
+ else
+ {
+ for (i = 1; i <= pModule->seg_count; i++)
+ if (!NE_LoadSegment( pModule, i )) return FALSE;
+ }
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * NE_FixupPrologs
+ *
+ * Fixup the exported functions prologs.
+ */
+void NE_FixupPrologs( NE_MODULE *pModule )
+{
+ SEGTABLEENTRY *pSegTable;
+ WORD dgroup = 0;
+ WORD sel;
+ BYTE *p, *fixup_ptr, count;
+ dbg_decl_str(module, 512);
+
+ pSegTable = NE_SEG_TABLE(pModule);
+ if (pModule->flags & NE_FFLAGS_SINGLEDATA)
+ dgroup = pSegTable[pModule->dgroup-1].selector;
+
+ TRACE(module, "(%04x)\n", pModule->self );
+ p = (BYTE *)pModule + pModule->entry_table;
+ while (*p)
+ {
+ if (p[1] == 0) /* Unused entry */
+ {
+ p += 2; /* Skip it */
+ continue;
+ }
+ if (p[1] == 0xfe) /* Constant entry */
+ {
+ p += 2 + *p * 3; /* Skip it */
+ continue;
+ }
+
+ /* Now fixup the entries of this bundle */
+ count = *p;
+ sel = p[1];
+ p += 2;
+ while (count-- > 0)
+ {
+ dbg_reset_str(module);
+ dsprintf(module,"Flags: %04x, sel %02x ", *p, sel);
+ /* According to the output generated by TDUMP, the flags mean:
+ * 0x0001 function is exported
+ * 0x0002 Single data (seems to occur only in DLLs)
+ */
+ if (sel == 0xff) { /* moveable */
+ dsprintf(module, "(%02x) o %04x", p[3], *(WORD *)(p+4) );
+ fixup_ptr = (char *)GET_SEL_BASE(pSegTable[p[3]-1].selector) + *(WORD *)(p + 4);
+ } else { /* fixed */
+ dsprintf(module, "offset %04x", *(WORD *)(p+1) );
+ fixup_ptr = (char *)GET_SEL_BASE(pSegTable[sel-1].selector) +
+ *(WORD *)(p + 1);
+ }
+ TRACE(module, "%s Signature: %02x %02x %02x,ff %x\n",
+ dbg_str(module), fixup_ptr[0], fixup_ptr[1],
+ fixup_ptr[2], pModule->flags );
+ if (*p & 0x0001)
+ {
+ /* Verify the signature */
+ if (((fixup_ptr[0] == 0x1e && fixup_ptr[1] == 0x58)
+ || (fixup_ptr[0] == 0x8c && fixup_ptr[1] == 0xd8))
+ && fixup_ptr[2] == 0x90)
+ {
+ if (*p & 0x0002)
+ {
+ if (pModule->flags & NE_FFLAGS_MULTIPLEDATA)
+ {
+ /* can this happen? */
+ fprintf( stderr, "FixupPrologs got confused\n" );
+ }
+ else if (pModule->flags & NE_FFLAGS_SINGLEDATA)
+ {
+ *fixup_ptr = 0xb8; /* MOV AX, */
+ *(WORD *)(fixup_ptr+1) = dgroup;
+ }
+ }
+ else
+ {
+ if (pModule->flags & NE_FFLAGS_MULTIPLEDATA) {
+ fixup_ptr[0] = 0x90; /* non-library: NOPs */
+ fixup_ptr[1] = 0x90;
+ fixup_ptr[2] = 0x90;
+ }
+ }
+ } else {
+ WARN(fixup, "Unknown signature\n" );
+ }
+ }
+ else
+ TRACE(module,"\n");
+ p += (sel == 0xff) ? 6 : 3;
+ }
+ }
+}
+
+
+/***********************************************************************
+ * NE_InitDLL
+ *
+ * Call the DLL initialization code
+ */
+static BOOL32 NE_InitDLL( TDB* pTask, HMODULE16 hModule )
+{
+ NE_MODULE *pModule;
+ SEGTABLEENTRY *pSegTable;
+ CONTEXT context;
+
+ /* Registers at initialization must be:
+ * cx heap size
+ * di library instance
+ * ds data segment if any
+ * es:si command line (always 0)
+ */
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return FALSE;
+ pSegTable = NE_SEG_TABLE( pModule );
+
+ if (!(pModule->flags & NE_FFLAGS_LIBMODULE) ||
+ (pModule->flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/
+
+ /* Call USER signal handler. This is necessary to install a
+ * proper loader for HICON and HCURSOR resources that this DLL
+ * may contain. InitApp() does this for task modules. */
+
+ if (pTask && pTask->userhandler)
+ {
+ pTask->userhandler( hModule, USIG_DLL_LOAD, 0, pTask->hInstance,
+ pTask->hQueue );
+ }
+
+ if (!pModule->cs) return TRUE; /* no initialization code */
+
+ memset( &context, 0, sizeof(context) );
+
+ if (!(pModule->flags & NE_FFLAGS_SINGLEDATA))
+ {
+ if (pModule->flags & NE_FFLAGS_MULTIPLEDATA || pModule->dgroup)
+ {
+ /* Not SINGLEDATA */
+ fprintf(stderr, "Library is not marked SINGLEDATA\n");
+ exit(1);
+ }
+ else /* DATA NONE DLL */
+ {
+ DS_reg(&context) = 0;
+ ECX_reg(&context) = 0;
+ }
+ }
+ else /* DATA SINGLE DLL */
+ {
+ if (pModule->dgroup) {
+ DS_reg(&context) = pSegTable[pModule->dgroup-1].selector;
+ ECX_reg(&context) = pModule->heap_size;
+ }
+ else /* hmm, DLL has no dgroup,
+ but why has it NE_FFLAGS_SINGLEDATA set ?
+ Buggy DLL compiler ? */
+ {
+ DS_reg(&context) = 0;
+ ECX_reg(&context) = 0;
+ }
+ }
+
+ CS_reg(&context) = pSegTable[pModule->cs-1].selector;
+ EIP_reg(&context) = pModule->ip;
+ EBP_reg(&context) = OFFSETOF(THREAD_Current()->cur_stack)
+ + (WORD)&((STACK16FRAME*)0)->bp;
+ EDI_reg(&context) = DS_reg(&context) ? DS_reg(&context) : hModule;
+
+
+ pModule->cs = 0; /* Don't initialize it twice */
+ TRACE(dll, "Calling LibMain, cs:ip=%04lx:%04x ds=%04lx di=%04x cx=%04x\n",
+ CS_reg(&context), IP_reg(&context), DS_reg(&context),
+ DI_reg(&context), CX_reg(&context) );
+ Callbacks->CallRegisterShortProc( &context, 0 );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * NE_InitializeDLLs
+ *
+ * Recursively initialize all DLLs (according to the order in which
+ * they where loaded).
+ */
+void NE_InitializeDLLs( HMODULE16 hModule )
+{
+ TDB* pTask = (TDB*)GlobalLock16(GetCurrentTask());
+ NE_MODULE *pModule;
+ HMODULE16 *pDLL;
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return;
+ if (pModule->flags & NE_FFLAGS_WIN32) return;
+
+ if (pModule->dlls_to_init)
+ {
+ HGLOBAL16 to_init = pModule->dlls_to_init;
+ pModule->dlls_to_init = 0;
+ for (pDLL = (HMODULE16 *)GlobalLock16( to_init ); *pDLL; pDLL++)
+ {
+ NE_InitializeDLLs( *pDLL );
+ }
+ GlobalFree16( to_init );
+ }
+ NE_InitDLL( pTask, hModule );
+}
+
+
+/***********************************************************************
+ * PatchCodeHandle
+ *
+ * Needed for self-loading modules.
+ */
+
+/* It does nothing */
+void WINAPI PatchCodeHandle(HANDLE16 hSel)
+{
+ fprintf(stderr,"PatchCodeHandle(%04x),stub!\n",hSel);
+}
+
+
+/***********************************************************************
+ * NE_Ne2MemFlags
+ *
+ * This function translates NE segment flags to GlobalAlloc flags
+ */
+static WORD NE_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
+}
+
+/***********************************************************************
+ * NE_AllocateSegment (WPROCS.26)
+ */
+DWORD WINAPI NE_AllocateSegment( WORD wFlags, WORD wSize, WORD wElem )
+{
+ WORD size = wSize << wElem;
+ HANDLE16 hMem = GlobalAlloc16( NE_Ne2MemFlags(wFlags), size);
+ return MAKELONG( hMem, GlobalHandleToSel(hMem) );
+}
+
+
+/***********************************************************************
+ * NE_CreateSegments
+ */
+BOOL32 NE_CreateSegments( HMODULE16 hModule )
+{
+ SEGTABLEENTRY *pSegment;
+ NE_MODULE *pModule;
+ int i, minsize;
+
+ if (!(pModule = MODULE_GetPtr16( hModule ))) return FALSE;
+ assert( !(pModule->flags & NE_FFLAGS_WIN32) );
+
+ 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( NE_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;
+}