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/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;
+}