Use a memory mapping instead of file I/O to load 16-bit modules.

diff --git a/dlls/kernel/kernel16_private.h b/dlls/kernel/kernel16_private.h
index 2f4cf01..9b2ba64 100644
--- a/dlls/kernel/kernel16_private.h
+++ b/dlls/kernel/kernel16_private.h
@@ -61,11 +61,12 @@
     WORD      ne_swaparea;      /* 3c Min. swap area size */
     WORD      ne_expver;        /* 3e Expected Windows version */
     /* From here, these are extra fields not present in normal Windows */
-    HMODULE   module32;         /* 40 PE module handle for Win32 modules */
-    HMODULE16 self;             /* 44 Handle for this module */
-    WORD      self_loading_sel; /* 46 Selector used for self-loading apps. */
-    LPVOID    rsrc32_map;       /* 48 HRSRC 16->32 map (for 32-bit modules) */
-    HANDLE    fd;               /* 4c handle to the binary file */
+    HMODULE   module32;         /* PE module handle for Win32 modules */
+    HMODULE16 self;             /* Handle for this module */
+    WORD      self_loading_sel; /* Selector used for self-loading apps. */
+    LPVOID    rsrc32_map;       /* HRSRC 16->32 map (for 32-bit modules) */
+    LPCVOID   mapping;          /* mapping of the binary file */
+    SIZE_T    mapping_size;     /* size of the file mapping */
 } NE_MODULE;
 
 typedef struct
@@ -132,6 +133,14 @@
 #define NE_MODULE_NAME(pModule) \
     (((OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo))->szPathName)
 
+#define NE_GET_DATA(pModule,offset,size) \
+    ((const void *)(((offset)+(size) <= pModule->mapping_size) ? \
+                    (const char *)pModule->mapping + (offset) : NULL))
+
+#define NE_READ_DATA(pModule,buffer,offset,size) \
+    (((offset)+(size) <= pModule->mapping_size) ? \
+     (memcpy( buffer, (const char *)pModule->mapping + (offset), (size) ), TRUE) : FALSE)
+
 #define CURRENT_STACK16 ((STACK16FRAME*)MapSL((SEGPTR)NtCurrentTeb()->WOW32Reserved))
 #define CURRENT_DS      (CURRENT_STACK16->ds)
 
@@ -158,7 +167,6 @@
 extern FARPROC16 WINAPI NE_GetEntryPoint( HMODULE16 hModule, WORD ordinal );
 extern FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop );
 extern BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset );
-extern HANDLE NE_OpenFile( NE_MODULE *pModule );
 extern DWORD NE_StartTask(void);
 
 /* ne_segment.c */
diff --git a/dlls/kernel/ne_module.c b/dlls/kernel/ne_module.c
index e0f8a0c..d32d5f8 100644
--- a/dlls/kernel/ne_module.c
+++ b/dlls/kernel/ne_module.c
@@ -565,46 +565,6 @@
 
 
 /***********************************************************************
- *           NE_OpenFile
- */
-HANDLE NE_OpenFile( NE_MODULE *pModule )
-{
-    HANDLE handle;
-    char *name = NE_MODULE_NAME( pModule );
-
-    TRACE("(%p)\n", pModule );
-
-    if (pModule->fd)
-    {
-        if (!DuplicateHandle( GetCurrentProcess(), pModule->fd,
-                              GetCurrentProcess(), &handle, 0, FALSE,
-                              DUPLICATE_SAME_ACCESS )) handle = INVALID_HANDLE_VALUE;
-    }
-    else
-    {
-        handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
-                              NULL, OPEN_EXISTING, 0, 0 );
-    }
-    if (handle == INVALID_HANDLE_VALUE)
-        ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
-
-    TRACE("opened '%s' -> %p\n", name, handle);
-    return handle;
-}
-
-
-/* wrapper for SetFilePointer and ReadFile */
-static BOOL read_data( HANDLE handle, LONG offset, void *buffer, DWORD size )
-{
-    DWORD result;
-
-    if (SetFilePointer( handle, offset, NULL, SEEK_SET ) == INVALID_SET_FILE_POINTER) return FALSE;
-    if (!ReadFile( handle, buffer, size, &result, NULL )) return FALSE;
-    return (result == size);
-}
-
-
-/***********************************************************************
  *           build_bundle_data
  *
  * Build the entry table bundle data from the on-disk format. Helper for build_module.
@@ -676,24 +636,39 @@
  *
  * Build the in-memory module from the on-disk data.
  */
-static HMODULE16 build_module( const IMAGE_DOS_HEADER *mz_header, const IMAGE_OS2_HEADER *ne_header,
-                               HANDLE handle, LPCSTR path, const void *fastload,
-                               unsigned int fastload_offset, unsigned int fastload_length )
+static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR path )
 {
+    const IMAGE_DOS_HEADER *mz_header = mapping;
+    const IMAGE_OS2_HEADER *ne_header;
+    const struct ne_segment_table_entry_s *pSeg;
+    const void *ptr;
     int i;
     size_t size;
     HMODULE16 hModule;
     NE_MODULE *pModule;
-    BYTE *buffer, *pData, *ptr;
+    BYTE *buffer, *pData, *end;
     OFSTRUCT *ofs;
-    struct ne_segment_table_entry_s *pSeg;
 
-  /* 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, (const char *)fastload+(offset)-fastload_offset, (size) ), TRUE) : \
-        (handle && read_data( handle, (offset), (buffer), (size))))
+    if (mapping_size < sizeof(*mz_header)) return ERROR_BAD_FORMAT;
+    if (mz_header->e_magic != IMAGE_DOS_SIGNATURE) return ERROR_BAD_FORMAT;
+    ne_header = (const IMAGE_OS2_HEADER *)((const char *)mapping + mz_header->e_lfanew);
+    if (mz_header->e_lfanew + sizeof(*ne_header) > mapping_size) return ERROR_BAD_FORMAT;
+    if (ne_header->ne_magic == IMAGE_NT_SIGNATURE) return 21;  /* win32 exe */
+    if (ne_header->ne_magic == IMAGE_OS2_SIGNATURE_LX)
+    {
+        MESSAGE("Sorry, %s is an OS/2 linear executable (LX) file!\n", path);
+        return 12;
+    }
+    if (ne_header->ne_magic != IMAGE_OS2_SIGNATURE) return ERROR_BAD_FORMAT;
+
+    /* We now have a valid NE header */
+
+    /* check to be able to fall back to loading OS/2 programs as DOS
+     * FIXME: should this check be reversed in order to be less strict?
+     * (only fail for OS/2 ne_exetyp 0x01 here?) */
+    if ((ne_header->ne_exetyp != 0x02 /* Windows */)
+        && (ne_header->ne_exetyp != 0x04) /* Windows 386 */)
+        return ERROR_BAD_FORMAT;
 
     size = sizeof(NE_MODULE) +
              /* segment table */
@@ -724,28 +699,23 @@
     /* check programs for default minimal stack size */
     if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) && (pModule->ne_stack < 0x1400))
         pModule->ne_stack = 0x1400;
-    pModule->module32 = 0;
-    pModule->self = hModule;
-    pModule->self_loading_sel = 0;
+
+    pModule->self         = hModule;
+    pModule->mapping      = mapping;
+    pModule->mapping_size = mapping_size;
+
     pData = (BYTE *)(pModule + 1);
 
     /* Clear internal Wine flags in case they are set in the EXE file */
 
     pModule->ne_flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
 
-    /* allocate temporary buffer for segment and entry tables */
-
-    if (!(buffer = HeapAlloc( GetProcessHeap(), 0,
-                              max( ne_header->ne_cseg * sizeof(*pSeg), ne_header->ne_cbenttab ) )))
-        goto failed;
-
     /* Get the segment table */
 
     pModule->ne_segtab = pData - (BYTE *)pModule;
-    if (!READ( mz_header->e_lfanew + ne_header->ne_segtab,
-               ne_header->ne_cseg * sizeof(struct ne_segment_table_entry_s), buffer ))
+    if (!(pSeg = NE_GET_DATA( pModule, mz_header->e_lfanew + ne_header->ne_segtab,
+                              ne_header->ne_cseg * sizeof(struct ne_segment_table_entry_s) )))
         goto failed;
-    pSeg = (struct ne_segment_table_entry_s *)buffer;
     for (i = ne_header->ne_cseg; i > 0; i--, pSeg++)
     {
         memcpy( pData, pSeg, sizeof(*pSeg) );
@@ -757,8 +727,8 @@
     if (ne_header->ne_rsrctab < ne_header->ne_restab)
     {
         pModule->ne_rsrctab = pData - (BYTE *)pModule;
-        if (!READ( mz_header->e_lfanew + ne_header->ne_rsrctab,
-                   ne_header->ne_restab - ne_header->ne_rsrctab, pData )) goto failed;
+        if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_rsrctab,
+                           ne_header->ne_restab - ne_header->ne_rsrctab )) goto failed;
         pData += ne_header->ne_restab - ne_header->ne_rsrctab;
     }
     else pModule->ne_rsrctab = 0;  /* No resource table */
@@ -766,8 +736,8 @@
     /* Get the resident names table */
 
     pModule->ne_restab = pData - (BYTE *)pModule;
-    if (!READ( mz_header->e_lfanew + ne_header->ne_restab,
-               ne_header->ne_modtab - ne_header->ne_restab, pData )) goto failed;
+    if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_restab,
+                       ne_header->ne_modtab - ne_header->ne_restab )) goto failed;
     pData += ne_header->ne_modtab - ne_header->ne_restab;
 
     /* Get the module references table */
@@ -775,8 +745,8 @@
     if (ne_header->ne_cmod > 0)
     {
         pModule->ne_modtab = pData - (BYTE *)pModule;
-        if (!READ( mz_header->e_lfanew + ne_header->ne_modtab,
-                   ne_header->ne_cmod * sizeof(WORD), pData )) goto failed;
+        if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_modtab,
+                           ne_header->ne_cmod * sizeof(WORD) )) goto failed;
         pData += ne_header->ne_cmod * sizeof(WORD);
     }
     else pModule->ne_modtab = 0;  /* No module references */
@@ -784,23 +754,21 @@
     /* Get the imported names table */
 
     pModule->ne_imptab = pData - (BYTE *)pModule;
-    if (!READ( mz_header->e_lfanew + ne_header->ne_imptab,
-               ne_header->ne_enttab - ne_header->ne_imptab,
-               pData )) goto failed;
+    if (!NE_READ_DATA( pModule, pData, mz_header->e_lfanew + ne_header->ne_imptab,
+                       ne_header->ne_enttab - ne_header->ne_imptab )) goto failed;
     pData += ne_header->ne_enttab - ne_header->ne_imptab;
 
     /* Load entry table, convert it to the optimized version used by Windows */
 
     pModule->ne_enttab = pData - (BYTE *)pModule;
-    if (!READ( mz_header->e_lfanew + ne_header->ne_enttab,
-               ne_header->ne_cbenttab, buffer )) goto failed;
-
-    ptr = build_bundle_data( pModule, pData, buffer );
+    if (!(ptr = NE_GET_DATA( pModule, mz_header->e_lfanew + ne_header->ne_enttab,
+                             ne_header->ne_cbenttab ))) goto failed;
+    end = build_bundle_data( pModule, pData, ptr );
 
     pData += ne_header->ne_cbenttab + sizeof(ET_BUNDLE) +
         2 * (ne_header->ne_cbenttab - ne_header->ne_cmovent*6);
 
-    if (ptr > pData)
+    if (end > pData)
     {
         FIXME( "not enough space for entry table for %s\n", debugstr_a(path) );
         goto failed;
@@ -823,8 +791,8 @@
         pModule->nrname_handle = GlobalAlloc16( 0, ne_header->ne_cbnrestab );
         if (!pModule->nrname_handle) goto failed;
         FarSetOwner16( pModule->nrname_handle, hModule );
-        ptr = GlobalLock16( pModule->nrname_handle );
-        if (!read_data( handle, ne_header->ne_nrestab, ptr, ne_header->ne_cbnrestab ))
+        buffer = GlobalLock16( pModule->nrname_handle );
+        if (!NE_READ_DATA( pModule, buffer, ne_header->ne_nrestab, ne_header->ne_cbnrestab ))
         {
             GlobalFree16( pModule->nrname_handle );
             goto failed;
@@ -847,92 +815,12 @@
     }
     else pModule->dlls_to_init = 0;
 
-    HeapFree( GetProcessHeap(), 0, buffer );
     NE_RegisterModule( pModule );
-
-    if (handle)
-    {
-        UINT drive_type = GetDriveTypeA( path );
-        /* keep the file handle open if not on a removable media */
-        if (drive_type != DRIVE_REMOVABLE && drive_type != DRIVE_CDROM)
-            DuplicateHandle( GetCurrentProcess(), handle,
-                             GetCurrentProcess(), &pModule->fd, 0, FALSE,
-                             DUPLICATE_SAME_ACCESS );
-    }
-
     return hModule;
 
 failed:
-    HeapFree( GetProcessHeap(), 0, buffer );
     GlobalFree16( hModule );
     return ERROR_BAD_FORMAT;
-#undef READ
-}
-
-
-/***********************************************************************
- *           NE_LoadExeHeader
- */
-static HMODULE16 NE_LoadExeHeader( HANDLE handle, LPCSTR path )
-{
-    IMAGE_DOS_HEADER mz_header;
-    IMAGE_OS2_HEADER ne_header;
-    HMODULE16 hModule;
-    char *fastload = NULL;
-    unsigned int fastload_offset = 0, fastload_length = 0;
-
-    if (!read_data( handle, 0, &mz_header, sizeof(mz_header)) ||
-        (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
-        return ERROR_BAD_FORMAT;
-
-    if (!read_data( handle, mz_header.e_lfanew, &ne_header, sizeof(ne_header) ))
-        return ERROR_BAD_FORMAT;
-
-    if (ne_header.ne_magic == IMAGE_NT_SIGNATURE) return (HMODULE16)21;  /* win32 exe */
-    if (ne_header.ne_magic == IMAGE_OS2_SIGNATURE_LX) {
-        MESSAGE("Sorry, this is an OS/2 linear executable (LX) file!\n");
-        return (HMODULE16)12;
-    }
-    if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return ERROR_BAD_FORMAT;
-
-    /* We now have a valid NE header */
-
-    /* check to be able to fall back to loading OS/2 programs as DOS
-     * FIXME: should this check be reversed in order to be less strict?
-     * (only fail for OS/2 ne_exetyp 0x01 here?) */
-    if ((ne_header.ne_exetyp != 0x02 /* Windows */)
-        && (ne_header.ne_exetyp != 0x04) /* Windows 386 */)
-        return ERROR_BAD_FORMAT;
-
-    /* Read the fast-load area */
-
-    if (ne_header.ne_flagsothers & NE_AFLAGS_FASTLOAD)
-    {
-        fastload_offset=ne_header.ne_pretthunks << ne_header.ne_align;
-        fastload_length=ne_header.ne_psegrefbytes << ne_header.ne_align;
-        TRACE("Using fast-load area offset=%x len=%d\n",
-                        fastload_offset, fastload_length );
-        if ((fastload = HeapAlloc( GetProcessHeap(), 0, fastload_length )) != NULL)
-        {
-            if (!read_data( handle, fastload_offset, fastload, fastload_length))
-            {
-                HeapFree( GetProcessHeap(), 0, fastload );
-                WARN("Error reading fast-load area!\n");
-                fastload = NULL;
-            }
-        }
-    }
-
-    hModule = build_module( &mz_header, &ne_header, handle, path,
-                            fastload, fastload_offset, fastload_length );
-    HeapFree( GetProcessHeap(), 0, fastload );
-
-    if (hModule >= 32)
-    {
-        SNOOP16_RegisterDLL( hModule, path );
-        NE_InitResourceHandler( hModule );
-    }
-    return hModule;
 }
 
 
@@ -992,7 +880,7 @@
  *
  * Load first instance of NE module from file.
  *
- * pModule must point to a module structure prepared by NE_LoadExeHeader.
+ * pModule must point to a module structure prepared by build_module_data.
  * This routine must never be called twice on a module.
  *
  */
@@ -1042,14 +930,33 @@
     HINSTANCE16 hInstance;
     HFILE16 hFile;
     OFSTRUCT ofs;
+    HANDLE mapping;
+    void *ptr;
+    MEMORY_BASIC_INFORMATION info;
 
     /* Open file */
     if ((hFile = OpenFile16( name, &ofs, OF_READ|OF_SHARE_DENY_WRITE )) == HFILE_ERROR16)
         return ERROR_FILE_NOT_FOUND;
 
-    hModule = NE_LoadExeHeader( DosFileHandleToWin32Handle(hFile), ofs.szPathName );
+    mapping = CreateFileMappingW( DosFileHandleToWin32Handle(hFile), NULL, PAGE_WRITECOPY, 0, 0, NULL );
     _lclose16( hFile );
-    if (hModule < 32) return hModule;
+    if (!mapping) return ERROR_BAD_FORMAT;
+
+    ptr = MapViewOfFile( mapping, FILE_MAP_COPY, 0, 0, 0 );
+    CloseHandle( mapping );
+    if (!ptr) return ERROR_BAD_FORMAT;
+
+    VirtualQuery( ptr, &info, sizeof(info) );
+    hModule = build_module( ptr, info.RegionSize, ofs.szPathName );
+
+    if (hModule < 32)
+    {
+        UnmapViewOfFile( ptr );
+        return hModule;
+    }
+
+    SNOOP16_RegisterDLL( hModule, ofs.szPathName );
+    NE_InitResourceHandler( hModule );
 
     pModule = NE_GetPtr( hModule );
 
@@ -1079,14 +986,12 @@
     SEGTABLEENTRY *pSegTable;
     const IMAGE_DOS_HEADER *mz_header;
     const IMAGE_OS2_HEADER *ne_header;
-    unsigned int fastload_offset, fastload_length;
+    SIZE_T mapping_size;
 
     mz_header = descr->module;
     ne_header = (const IMAGE_OS2_HEADER *)((const BYTE *)mz_header + mz_header->e_lfanew);
-    fastload_offset = ne_header->ne_pretthunks << ne_header->ne_align;
-    fastload_length = ne_header->ne_psegrefbytes << ne_header->ne_align;
-    hModule = build_module( mz_header, ne_header, 0, descr->file_name,
-                            descr->module, fastload_offset, fastload_length );
+    mapping_size = ne_header->ne_psegrefbytes << ne_header->ne_align;
+    hModule = build_module( descr->module, mapping_size, descr->file_name );
     if (hModule < 32) return hModule;
     pModule = GlobalLock16( hModule );
     pModule->ne_flags |= NE_FFLAGS_BUILTIN;
@@ -1502,7 +1407,7 @@
     /* Clear magic number just in case */
 
     pModule->ne_magic = pModule->self = 0;
-    if (pModule->fd) CloseHandle( pModule->fd );
+    if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN)) UnmapViewOfFile( (void *)pModule->mapping );
 
       /* Remove it from the linked list */
 
diff --git a/dlls/kernel/ne_segment.c b/dlls/kernel/ne_segment.c
index b76cf84..8756d12 100644
--- a/dlls/kernel/ne_segment.c
+++ b/dlls/kernel/ne_segment.c
@@ -116,162 +116,58 @@
 
 
 /***********************************************************************
- *           NE_LoadSegment
+ *           NE_OpenFile
  */
-BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
+static HFILE16 NE_OpenFile( NE_MODULE *pModule )
 {
-    SEGTABLEENTRY *pSegTable, *pSeg;
-    HMODULE16 *pModuleTable;
-    WORD count, i, offset, next_offset;
+    char *name = NE_MODULE_NAME( pModule );
+    HANDLE handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
+                                 NULL, OPEN_EXISTING, 0, 0 );
+
+    if (handle == INVALID_HANDLE_VALUE)
+    {
+        ERR( "Can't open file '%s' for module %04x\n", name, pModule->self );
+        return HFILE_ERROR;
+    }
+    return Win32HandleToDosFileHandle( handle );
+}
+
+
+/***********************************************************************
+ *           apply_relocations
+ *
+ * Apply relocations to a segment. Helper for NE_LoadSegment.
+ */
+static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep,
+                                      int count, int segnum )
+{
+    BYTE *func_name;
+    char buffer[256];
+    int i, ordinal;
+    WORD offset, *sp;
     HMODULE16 module;
     FARPROC16 address = 0;
-    HANDLE hf;
-    DWORD res;
-    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;
-
-    if (pSeg->flags & NE_SEGFLAGS_LOADED)
-    {
-	/* self-loader ? -> already loaded it */
-	if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
-	    return TRUE;
-
-	/* leave, except for DGROUP, as this may be the second instance */
-	if (segnum != pModule->ne_autodata)
-            return TRUE;
-    }
-
-    if (!pSeg->filepos) return TRUE;  /* No file image, just return */
-
-    pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
-
-    hf = NE_OpenFile( pModule );
-    TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
-                    segnum, pSeg->hSeg, pSeg->flags );
-    SetFilePointer( hf, pSeg->filepos << pModule->ne_align, NULL, SEEK_SET );
-    if (pSeg->size) size = pSeg->size;
-    else size = pSeg->minsize ? pSeg->minsize : 0x10000;
-    mem = GlobalLock16(pSeg->hSeg);
-    if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
-    {
- 	/* Implement self-loading segments */
- 	SELFLOADHEADER *selfloadheader;
-        void *oldstack;
-        HANDLE hFile32;
-        HFILE16 hFile16;
-        WORD args[3];
-        DWORD ret;
-
- 	selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
-        oldstack = NtCurrentTeb()->WOW32Reserved;
-        NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
-                                                           0xff00 - sizeof(STACK16FRAME));
-
-	TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%p,segnum=%d\n",
-		pModule->self,hf,segnum );
-        DuplicateHandle( GetCurrentProcess(), hf, GetCurrentProcess(), &hFile32,
-                         0, FALSE, DUPLICATE_SAME_ACCESS );
-        hFile16 = Win32HandleToDosFileHandle( hFile32 );
-        args[2] = pModule->self;
-        args[1] = hFile16;
-        args[0] = segnum;
-        WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
-        pSeg->hSeg = LOWORD(ret);
-	TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
-        _lclose16( hFile16 );
-        NtCurrentTeb()->WOW32Reserved = oldstack;
-    }
-    else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
-        ReadFile(hf, mem, size, &res, NULL);
-    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 = HeapAlloc(GetProcessHeap(), 0, size);
-      char* curr = buff;
-
-      if(buff == NULL) {
-          WARN_(dll)("Memory exhausted!\n");
-          goto fail;
-      }
-
-      ReadFile(hf, buff, size, &res, NULL);
-      while(curr < buff + size) {
-	unsigned int rept = ((short*)curr)[0];
-	unsigned int len =  ((short*)curr)[1];
-
-	curr += 2*sizeof(short);
-	for(; rept > 0; rept--) {
-	  char* bytes = curr;
-	  unsigned int byte;
-	  for(byte = 0; byte < len; byte++)
-	    *mem++ = *bytes++;
-	}
-	curr += len;
-      }
-      HeapFree(GetProcessHeap(), 0, buff);
-    }
-
-    pSeg->flags |= NE_SEGFLAGS_LOADED;
-
-    /* Perform exported function prolog fixups */
-    NE_FixupSegmentPrologs( pModule, segnum );
-
-    if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
-        goto succeed;  /* No relocation data, we are done */
-
-    ReadFile(hf, &count, sizeof(count), &res, NULL);
-    if (!count) goto succeed;
-
-    TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
-          *((BYTE *)pModule + pModule->ne_restab),
-          (char *)pModule + pModule->ne_restab + 1,
-          segnum, pSeg->hSeg );
-
-    reloc_entries = HeapAlloc(GetProcessHeap(), 0, count * sizeof(struct relocation_entry_s));
-    if(reloc_entries == NULL) {
-        WARN("Not enough memory for relocation entries!\n");
-        goto fail;
-    }
-    if (!ReadFile( hf, reloc_entries, count * sizeof(struct relocation_entry_s), &res, NULL) ||
-        (res != count * sizeof(struct relocation_entry_s)))
-    {
-        WARN("Unable to read relocation information\n" );
-        goto fail;
-    }
+    HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab);
+    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
+    SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
 
     /*
      * 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.
-	 */
+        /*
+         * 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:
+        /* If additive, there is no target chain list. Instead, add source
+           and target */
+        int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
+        switch (rep->relocation_type & 3)
+        {
+        case NE_RELTYPE_ORDINAL:
             module = pModuleTable[rep->target1-1];
-	    ordinal = rep->target2;
+            ordinal = rep->target2;
             address = NE_GetEntryPoint( module, ordinal );
             if (!address)
             {
@@ -300,9 +196,9 @@
                        ordinal, HIWORD(address), LOWORD(address),
                        NE_GetRelocAddrName( rep->address_type, additive ) );
             }
-	    break;
+            break;
 
-	  case NE_RELTYPE_NAME:
+        case NE_RELTYPE_NAME:
             module = pModuleTable[rep->target1-1];
             func_name = (char *)pModule + pModule->ne_imptab + rep->target2;
             memcpy( buffer, func_name+1, *func_name );
@@ -321,51 +217,51 @@
             if (!address) address = (FARPROC16) 0xdeadbeef;
             if (TRACE_ON(fixup))
             {
-	        NE_MODULE *pTarget = NE_GetPtr( module );
+                NE_MODULE *pTarget = NE_GetPtr( module );
                 TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1,
                        *((BYTE *)pTarget + pTarget->ne_restab),
                        (char *)pTarget + pTarget->ne_restab + 1,
                        func_name, HIWORD(address), LOWORD(address),
                        NE_GetRelocAddrName( rep->address_type, additive ) );
             }
-	    break;
+            break;
 
-	  case NE_RELTYPE_INTERNAL:
-	    if ((rep->target1 & 0xff) == 0xff)
-	    {
-		address  = NE_GetEntryPoint( pModule->self, rep->target2 );
-	    }
-	    else
-	    {
+        case NE_RELTYPE_INTERNAL:
+            if ((rep->target1 & 0xff) == 0xff)
+            {
+                address  = NE_GetEntryPoint( pModule->self, rep->target2 );
+            }
+            else
+            {
                 address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 );
-	    }
+            }
 
-	    TRACE("%d: %04x:%04x %s\n",
-                   i + 1, HIWORD(address), LOWORD(address),
-                   NE_GetRelocAddrName( rep->address_type, additive ) );
-	    break;
+            TRACE("%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("%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;
-	}
+        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("%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;
+        offset  = rep->offset;
 
         /* Apparently, high bit of address_type is sometimes set; */
         /* we ignore it for now */
-	if (rep->address_type > NE_RADDR_OFFSET32)
+        if (rep->address_type > NE_RADDR_OFFSET32)
         {
             char module[10];
             GetModuleName16( pModule->self, module, sizeof(module) );
@@ -383,17 +279,17 @@
                 *(BYTE *)sp += LOBYTE((int)address);
                 break;
             case NE_RADDR_OFFSET16:
-		*sp += LOWORD(address);
+                *sp += LOWORD(address);
                 break;
             case NE_RADDR_POINTER32:
-		*sp += LOWORD(address);
-		*(sp+1) = HIWORD(address);
+                *sp += LOWORD(address);
+                *(sp+1) = HIWORD(address);
                 break;
             case NE_RADDR_SELECTOR:
-		/* Borland creates additive records with offset zero. Strange, but OK */
+                /* Borland creates additive records with offset zero. Strange, but OK */
                 if (*sp)
                     ERR("Additive selector to %04x.Please report\n",*sp);
-		else
+                else
                     *sp = HIWORD(address);
                 break;
             default:
@@ -404,6 +300,8 @@
         {
             do
             {
+                WORD next_offset;
+
                 sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) );
                 next_offset = *sp;
                 TRACE("    %04x:%04x\n", offset, *sp );
@@ -430,11 +328,6 @@
             } while (offset != 0xffff);
         }
     }
-
-    HeapFree(GetProcessHeap(), 0, reloc_entries);
-
-succeed:
-    CloseHandle(hf);
     return TRUE;
 
 unknown:
@@ -442,15 +335,126 @@
          "TYPE %d,  OFFSET %04x,  TARGET %04x %04x\n",
          i + 1, rep->address_type, rep->relocation_type,
          rep->offset, rep->target1, rep->target2);
-    HeapFree(GetProcessHeap(), 0, reloc_entries);
-
-fail:
-    CloseHandle(hf);
     return FALSE;
 }
 
 
 /***********************************************************************
+ *           NE_LoadSegment
+ */
+BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum )
+{
+    WORD count;
+    DWORD pos;
+    const struct relocation_entry_s *rep;
+    int size;
+    SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule );
+    SEGTABLEENTRY *pSeg = pSegTable + segnum - 1;
+
+    if (pSeg->flags & NE_SEGFLAGS_LOADED)
+    {
+	/* self-loader ? -> already loaded it */
+	if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
+	    return TRUE;
+
+	/* leave, except for DGROUP, as this may be the second instance */
+	if (segnum != pModule->ne_autodata)
+            return TRUE;
+    }
+
+    if (!pSeg->filepos) return TRUE;  /* No file image, just return */
+
+    TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n",
+                    segnum, pSeg->hSeg, pSeg->flags );
+    pos = pSeg->filepos << pModule->ne_align;
+    if (pSeg->size) size = pSeg->size;
+    else size = pSeg->minsize ? pSeg->minsize : 0x10000;
+
+    if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1)
+    {
+ 	/* Implement self-loading segments */
+ 	SELFLOADHEADER *selfloadheader;
+        void *oldstack;
+        HFILE16 hFile16;
+        WORD args[3];
+        DWORD ret;
+
+ 	selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) );
+        oldstack = NtCurrentTeb()->WOW32Reserved;
+        NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
+                                                           0xff00 - sizeof(STACK16FRAME));
+
+        hFile16 = NE_OpenFile( pModule );
+        TRACE_(dll)("CallLoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d\n",
+                    pModule->self,hFile16,segnum );
+        args[2] = pModule->self;
+        args[1] = hFile16;
+        args[0] = segnum;
+        WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret );
+        pSeg->hSeg = LOWORD(ret);
+	TRACE_(dll)("Ret CallLoadAppSegProc: hSeg = 0x%04x\n", pSeg->hSeg);
+        _lclose16( hFile16 );
+        NtCurrentTeb()->WOW32Reserved = oldstack;
+    }
+    else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED))
+    {
+        void *mem = GlobalLock16(pSeg->hSeg);
+        if (!NE_READ_DATA( pModule, mem, pos, size ))
+            return FALSE;
+        pos += 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.
+        */
+        const char *buff = NE_GET_DATA( pModule, pos, size );
+        const char* curr = buff;
+        char *mem = GlobalLock16(pSeg->hSeg);
+
+        pos += size;
+        if (buff == NULL) return FALSE;
+
+        while(curr < buff + size) {
+            unsigned int rept = ((short*)curr)[0];
+            unsigned int len =  ((short*)curr)[1];
+
+            curr += 2*sizeof(short);
+            while (rept--)
+            {
+                memcpy( mem, curr, len );
+                mem += len;
+            }
+            curr += len;
+        }
+    }
+
+    pSeg->flags |= NE_SEGFLAGS_LOADED;
+
+    /* Perform exported function prolog fixups */
+    NE_FixupSegmentPrologs( pModule, segnum );
+
+    if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA))
+        return TRUE;  /* No relocation data, we are done */
+
+    if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE;
+    pos += sizeof(count);
+
+    TRACE("Fixups for %.*s, segment %d, hSeg %04x\n",
+          *((BYTE *)pModule + pModule->ne_restab),
+          (char *)pModule + pModule->ne_restab + 1,
+          segnum, pSeg->hSeg );
+
+    if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) )))
+        return FALSE;
+
+    return apply_relocations( pModule, rep, count, segnum );
+}
+
+
+/***********************************************************************
  *           NE_LoadAllSegments
  */
 BOOL NE_LoadAllSegments( NE_MODULE *pModule )
@@ -460,7 +464,6 @@
 
     if (pModule->ne_flags & NE_FFLAGS_SELFLOAD)
     {
-        HANDLE hf;
         HFILE16 hFile16;
         HGLOBAL16 sel;
         /* Handle self-loading modules */
@@ -484,8 +487,7 @@
         NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR(pModule->self_loading_sel,
                                                            0xff00 - sizeof(STACK16FRAME) );
 
-        hf = NE_OpenFile(pModule);
-        hFile16 = Win32HandleToDosFileHandle( hf );
+        hFile16 = NE_OpenFile(pModule);
         TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n",
               pModule->self,hFile16);
         args[1] = pModule->self;
diff --git a/dlls/kernel/resource16.c b/dlls/kernel/resource16.c
index 1bf17d1..2ca2b7c 100644
--- a/dlls/kernel/resource16.c
+++ b/dlls/kernel/resource16.c
@@ -330,53 +330,42 @@
 HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
                                         HRSRC16 hRsrc )
 {
-    HANDLE fd;
+    HGLOBAL16 handle;
+    WORD sizeShift;
+    NE_NAMEINFO* pNameInfo;
     NE_MODULE* pModule = NE_GetPtr( hModule );
-    if (pModule && (pModule->ne_flags & NE_FFLAGS_BUILTIN))
+
+    if (!pModule) return 0;
+
+    sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
+    pNameInfo = (NE_NAMEINFO *)((char *)pModule + hRsrc);
+
+    if ( hMemObj )
+        handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
+    else
+        handle = AllocResource16( hModule, hRsrc, 0 );
+
+    if (handle)
     {
-        HGLOBAL16 handle;
-        WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
-        NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
-
-        if ( hMemObj )
-            handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
-        else
-            handle = AllocResource16( hModule, hRsrc, 0 );
-
-        if ( handle )
+        if (pModule->ne_flags & NE_FFLAGS_BUILTIN)
         {
             /* NOTE: hRsrcMap points to start of built-in resource data */
             memcpy( GlobalLock16( handle ),
                     (char *)pModule->rsrc32_map + (pNameInfo->offset << sizeShift),
                     pNameInfo->length << sizeShift );
         }
-        return handle;
-    }
-    if (pModule && (fd = NE_OpenFile( pModule )) != INVALID_HANDLE_VALUE)
-    {
-        HGLOBAL16 handle;
-        WORD sizeShift = *(WORD *)((char *)pModule + pModule->ne_rsrctab);
-        NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
-
-        TRACE("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 = AllocResource16( hModule, hRsrc, 0 );
-
-        if( handle )
         {
-            DWORD res;
-            SetFilePointer( fd, (int)pNameInfo->offset << sizeShift, NULL, SEEK_SET );
-            ReadFile( fd, GlobalLock16( handle ), (int)pNameInfo->length << sizeShift,
-                      &res, NULL );
+            if (!NE_READ_DATA( pModule, GlobalLock16( handle ),
+                               (int)pNameInfo->offset << sizeShift,
+                               (int)pNameInfo->length << sizeShift ))
+            {
+                GlobalFree16( handle );
+                handle = 0;
+            }
         }
-        CloseHandle(fd);
-        return handle;
     }
-    return (HGLOBAL16)0;
+    return handle;
 }