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