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