First version of DLL preloader.
[wincetools.git] / loader / ntdll_loader.c
index c15a5d5..3acf297 100644 (file)
-/* From wine1.2-1.1.42/dlls/ntdll/loader.c  */
-
-/*
- * Loader functions
- *
- * Copyright 1995, 2003 Alexandre Julliard
- * Copyright 2002 Dmitry Timoshkov for CodeWeavers
- * Copyright 2010 g10 Code GmbH
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-
-
-#include <assert.h>
-
-#include "himemce.h"
-
-PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)
-{
-    IMAGE_NT_HEADERS *ret;
-    IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
-
-    ret = NULL;
-    if (dos->e_magic == IMAGE_DOS_SIGNATURE)
-    {
-        ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
-        if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
-    }
-    return ret;
-}
-
-\f
-/* internal representation of 32bit modules. per process. */
-typedef struct _wine_modref
-{
-    LDR_MODULE            ldr;
-    int                   nDeps;
-    struct _wine_modref **deps;
-} WINE_MODREF;
-
-#define MAX_MODREFS 4
-WINE_MODREF *modrefs[MAX_MODREFS];
-int nr_modrefs;
-
-
-static WINE_MODREF *current_modref;
-
-
-/* convert from straight ASCII to Unicode without depending on the current codepage */
-static void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )
-{
-  while (len--) *dst++ = (unsigned char)*src++;
-}
-
-
-/***********************************************************************
- *           RtlImageDirectoryEntryToData   (NTDLL.@)
- */
-PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
-{
-  const IMAGE_NT_HEADERS *nt;
-  DWORD addr;
-
-  if ((ULONG_PTR)module & 1)  /* mapped as data file */
-    {
-      module = (HMODULE)((ULONG_PTR)module & ~1);
-      image = FALSE;
-    }
-  if (!(nt = MyRtlImageNtHeader( module ))) return NULL;
-  if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
-    {
-      const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
-
-      if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
-      if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
-      *size = nt64->OptionalHeader.DataDirectory[dir].Size;
-      if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
-    }
-  else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
-    {
-      const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
-
-      if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
-      if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
-      *size = nt32->OptionalHeader.DataDirectory[dir].Size;
-      if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
-    }
-  else return NULL;
-
-#if 0
-  /* not mapped as image, need to find the section containing the virtual address */
-  return RtlImageRvaToVa( nt, module, addr, NULL );
-#else
-  return NULL;
-#endif
-}
-
-
-/* convert PE image VirtualAddress to Real Address */
-static void *get_rva( HMODULE module, DWORD va )
-{
-  return (void *)((char *)module + va);
-}
-
-
-#define allocate_stub(x,y) (0xdeadbeef)
-
-/*************************************************************************
- *              import_dll
- *
- * Import the dll specified by the given import descriptor.
- * The loader_section must be locked while calling this function.
- */
-static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )
-{
-  NTSTATUS status = STATUS_SUCCESS;
-  //  WINE_MODREF *wmImp;
-  HMODULE imp_mod;
-  //  const IMAGE_EXPORT_DIRECTORY *exports;
-  //  DWORD exp_size;
-  const IMAGE_THUNK_DATA *import_list;
-  IMAGE_THUNK_DATA *thunk_list;
-  WCHAR buffer[32];
-  const char *name = get_rva( module, descr->Name );
-  DWORD len = strlen(name);
-#if 0
-  PVOID protect_base;
-  SIZE_T protect_size = 0;
-  DWORD protect_old;
-#endif
-
-  thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
-  if (descr->OriginalFirstThunk)
-    import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
-  else
-    import_list = thunk_list;
-
-  while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */
-
-  if (len * sizeof(WCHAR) < sizeof(buffer))
-    {
-      ascii_to_unicode( buffer, name, len );
-      buffer[len] = 0;
-      //      status = load_dll( load_path, buffer, 0, &wmImp );
-      imp_mod = LoadLibrary (buffer);
-      if (imp_mod == INVALID_HANDLE_VALUE)
-       status = GetLastError ();
-    }
-  else  /* need to allocate a larger buffer */
-    {
-      WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );
-      if (!ptr) return NULL;
-      ascii_to_unicode( ptr, name, len );
-      ptr[len] = 0;
-      // status = load_dll( load_path, ptr, 0, &wmImp );
-      imp_mod = LoadLibrary (ptr);
-      if (imp_mod == INVALID_HANDLE_VALUE)
-       status = GetLastError ();
-      free (ptr);
-    }
-  if (status)
-    {
-      if (status == STATUS_DLL_NOT_FOUND)
-       TRACE("Library %s (which is needed by %s) not found\n",
-           name, current_modref->ldr.FullDllName);
-      else
-       TRACE("Loading library %s (which is needed by %s) failed (error %x).\n",
-           name, current_modref->ldr.FullDllName, status);
-      return NULL;
-    }
-
-#if 0
-  /* unprotect the import address table since it can be located in
-   * readonly section */
-  while (import_list[protect_size].u1.Ordinal) protect_size++;
-  protect_base = thunk_list;
-  protect_size *= sizeof(*thunk_list);
-  NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
-                         &protect_size, PAGE_WRITECOPY, &protect_old );
-#endif
-
-#if 0
-  imp_mod = wmImp->ldr.BaseAddress;
-  exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
-
-  if (!exports)
-    {
-      /* set all imported function to deadbeef */
-      while (import_list->u1.Ordinal)
-        {
-         if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
-            {
-             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
-             WARN("No implementation for %s.%d", name, ordinal );
-             thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
-            }
-         else
-            {
-             IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
-             WARN("No implementation for %s.%s", name, pe_name->Name );
-             thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
-            }
-         WARN(" imported from %s, allocating stub %p\n",
-              current_modref->ldr.FullDllName,
-              (void *)thunk_list->u1.Function );
-         import_list++;
-         thunk_list++;
-        }
-      goto done;
-    }
-#endif
-
-  while (import_list->u1.Ordinal)
-    {
-      if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
-        {
-         int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
-
-         //      thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
-         //                                                                ordinal - exports->Base, load_path );
-         thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));
-         if (!thunk_list->u1.Function)
-            {
-             thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );
-             TRACE("No implementation for %s.%d imported from %s, setting to %p\n",
-                   name, ordinal, current_modref->ldr.FullDllName,
-                   (void *)thunk_list->u1.Function );
-            }
-         TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
-        }
-      else  /* import by name */
-        {
-         IMAGE_IMPORT_BY_NAME *pe_name;
-         pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
-         //      thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
-         //                                                              (const char*)pe_name->Name,
-         //                                                              pe_name->Hint, load_path );
-         thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, (const char*)pe_name->Name);
-         if (!thunk_list->u1.Function)
-            {
-             thunk_list->u1.Function = (PDWORD) allocate_stub( name, (const char*)pe_name->Name );
-             TRACE("No implementation for %s.%s imported from %s, setting to %p\n",
-                   name, pe_name->Name, current_modref->ldr.FullDllName,
-                   (void *)thunk_list->u1.Function );
-            }
-         TRACE("--- %s %s.%d = %p\n",
-               pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
-        }
-      import_list++;
-      thunk_list++;
-    }
-  // done:
-#if 0
-  /* restore old protection of the import address table */
-  NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );
-  return wmImp;
-#endif
-  return (void*)1;
-}
-
-
-
-/****************************************************************
- *       fixup_imports
- *
- * Fixup all imports of a given module.
- * The loader_section must be locked while calling this function.
- */
-static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
-{
-  int i, nb_imports;
-  const IMAGE_IMPORT_DESCRIPTOR *imports;
-  WINE_MODREF *prev;
-  DWORD size;
-  NTSTATUS status;
-  //  ULONG_PTR cookie;
-
-  if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */
-  wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
-  
-  if (!(imports = MyRtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
-                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
-    return STATUS_SUCCESS;
-  
-  nb_imports = 0;
-  while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
-  
-  if (!nb_imports) return STATUS_SUCCESS;  /* no imports */
-  
-#if 0
-  if (!create_module_activation_context( &wm->ldr ))
-    RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
-#endif
-  
-#if 0
-  /* Allocate module dependency list */
-  wm->nDeps = nb_imports;
-  wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );
-#endif
-
-  /* load the imported modules. They are automatically
-   * added to the modref list of the process.
-   */
-  prev = current_modref;
-  current_modref = wm;
-  status = STATUS_SUCCESS;
-  for (i = 0; i < nb_imports; i++)
-    {
-      //      if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))
-      if (! import_dll( wm->ldr.BaseAddress, &imports[i], load_path ))
-       status = STATUS_DLL_NOT_FOUND;
-    }
-  current_modref = prev;
-  //  if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
-  return status;
-}
-
-
-static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
-{
-       return FALSE;
-}
-
-
-/*************************************************************************
- *              get_modref
- *
- * Looks for the referenced HMODULE in the current process
- * The loader_section must be locked while calling this function.
- */
-static WINE_MODREF *get_modref( HMODULE hmod )
-{
-  int i;
-  for (i = 0; i < nr_modrefs; i++)
-    if (modrefs[i]->ldr.BaseAddress == hmod)
-      return modrefs[i];
-  return NULL;
-}
-
-
-
-static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )
-{
-    WINE_MODREF *wm;
-    const WCHAR *p;
-    const IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader(hModule);
-#if 0
-    PLIST_ENTRY entry, mark;
-#endif
-
-    if (!(wm = malloc (sizeof(*wm)))) return NULL;
-
-    wm->nDeps    = 0;
-    wm->deps     = NULL;
-
-    wm->ldr.BaseAddress   = hModule;
-    wm->ldr.EntryPoint    = NULL;
-    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;
-    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;
-    wm->ldr.LoadCount     = 1;
-    wm->ldr.TlsIndex      = -1;
-    wm->ldr.SectionHandle = NULL;
-    wm->ldr.CheckSum      = 0;
-    wm->ldr.TimeDateStamp = 0;
-    wm->ldr.ActivationContext = 0;
-
-    wcscpy (wm->ldr.FullDllName, filename);
-    if ((p = wcsrchr( wm->ldr.FullDllName, L'\\' ))) p++;
-    else p = wm->ldr.FullDllName;
-    wcscpy (wm->ldr.BaseDllName, p );
-
-    if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))
-    {
-        wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
-        if (nt->OptionalHeader.AddressOfEntryPoint)
-            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
-    }
-
-#if 0
-    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
-                   &wm->ldr.InLoadOrderModuleList);
-
-    /* insert module in MemoryList, sorted in increasing base addresses */
-    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
-    for (entry = mark->Flink; entry != mark; entry = entry->Flink)
-    {
-        if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
-            break;
-    }
-    entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
-    wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
-    wm->ldr.InMemoryOrderModuleList.Flink = entry;
-    entry->Blink = &wm->ldr.InMemoryOrderModuleList;
-
-    /* wait until init is called for inserting into this list */
-    wm->ldr.InInitializationOrderModuleList.Flink = NULL;
-    wm->ldr.InInitializationOrderModuleList.Blink = NULL;
-#endif
-
-    modrefs[nr_modrefs++] = wm;
-
-    return wm;
-}
-
-
-static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
-                                 DWORD flags, WINE_MODREF** pwm )
-{
-  void *module;
-  HANDLE mapping;
-  LARGE_INTEGER size;
-  SIZE_T len = 0;
-  WINE_MODREF *wm;
-  NTSTATUS status;
-
-  TRACE("Trying native dll %S\n", name);
-  
-  size.QuadPart = 0;
-  status = MyNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
-                             NULL, &size, PAGE_READONLY, SEC_IMAGE, file );
-  if (status != STATUS_SUCCESS) return status;
-  
-  module = NULL;
-  status = MyNtMapViewOfSection( mapping, NtCurrentProcess(),
-                                &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
-  CloseHandle( mapping );
-  if (status < 0) return status;
-  
-  /* create the MODREF */
-  
-  if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;
-  
-  /* fixup imports */
-  
-  if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
-    {
-#if 1
-      return (STATUS_NOT_IMPLEMENTED);
-#else
-      if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)
-        {
-#if 0
-         /* the module has only be inserted in the load & memory order lists */
-         RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
-         RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
-         
-         /* FIXME: there are several more dangling references
-          * left. Including dlls loaded by this dll before the
-          * failed one. Unrolling is rather difficult with the
-          * current structure and we can leave them lying
-          * around with no problems, so we don't care.
-          * As these might reference our wm, we don't free it.
-          */
-#endif
-         return status;
-        }
-#endif
-    }
-  
-  TRACE( "Loaded %S at %p: native\n", wm->ldr.FullDllName, module );
-  
-  wm->ldr.LoadCount = 1;
-  *pwm = wm;
-  return STATUS_SUCCESS;
-}
-
-
-static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,
-                               WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )
-{
-  HMODULE hnd = GetModuleHandle (NULL);
-  int len;
-  
-  assert (handle);
-  assert (*size = MAX_PATH);
-  
-  if (libname[0] == L'/' || libname[0] == L'\\')
-    {
-      wcscpy (filename, libname);
-    }
-  else
-    {
-      len = GetModuleFileName (hnd, filename, MAX_PATH);
-      filename[len++] = L'\\';
-      wcscpy (&filename[len], libname);
-    }
-  TRACE( "opening %S\n", filename);
-  
-  if (handle)
-    {
-      *handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL,
-                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
-      TRACE ("find_dll_file: 0x%p (0x%x)\n", *handle, GetFileSize (*handle, NULL));
-    }
-  return STATUS_SUCCESS;
-}
-
-
-static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )
-{
-    WCHAR filename[MAX_PATH];
-    ULONG size;
-    HANDLE handle = 0;
-    NTSTATUS nts;
-
-    TRACE( "looking for %S in %S\n", libname, load_path ? load_path : L"default path" );
-
-    *pwm = NULL;
-    size = MAX_PATH;
-    find_dll_file( load_path, libname, filename, &size, pwm, &handle );
-    
-    if (!handle)
-      nts = STATUS_DLL_NOT_FOUND;
-    else
-      nts = load_native_dll( load_path, filename, handle, flags, pwm );
-    
-    if (nts == STATUS_SUCCESS)
-      {
-        /* Initialize DLL just loaded */
-        TRACE("Loaded module %S at %p\n", filename, (*pwm)->ldr.BaseAddress);
-        if (handle)
-         CloseHandle( handle );
-        return nts;
-      }
-    
-    TRACE("Failed to load module %S; status=%x\n", libname, nts);
-    if (handle)
-      CloseHandle( handle );
-    return nts;
-}
-
-
-NTSTATUS MyLdrLoadDll(LPCWSTR path_name, DWORD flags,
-                     LPCWSTR libname, HMODULE* hModule)
-{
-  WINE_MODREF *wm;
-  NTSTATUS nts;
-
-  /* Support for dll path removed.  */
-  nts = load_dll( path_name, libname, flags, &wm );
-
-  /* For now.  */
-  assert (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS);
-#if 0
-  if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
-    {
-      nts = process_attach( wm, NULL );
-      if (nts != STATUS_SUCCESS)
-        {
-         LdrUnloadDll(wm->ldr.BaseAddress);
-         wm = NULL;
-        }
-    }
-#endif
-  *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
-
-  return nts;
-}
-
-
-
-/***********************************************************************
- *           LdrProcessRelocationBlock  (NTDLL.@)
- *
- * Apply relocations to a given page of a mapped PE image.
- */
-IMAGE_BASE_RELOCATION * MyLdrProcessRelocationBlock( void *page, UINT count,
-                                                    USHORT *relocs, INT_PTR delta )
-{
-  while (count--)
-    {
-      USHORT offset = *relocs & 0xfff;
-      int type = *relocs >> 12;
-      switch(type)
-        {
-        case IMAGE_REL_BASED_ABSOLUTE:
-         break;
-#if 1
-        case IMAGE_REL_BASED_HIGH:
-         *(short *)((char *)page + offset) += HIWORD(delta);
-         break;
-        case IMAGE_REL_BASED_LOW:
-         *(short *)((char *)page + offset) += LOWORD(delta);
-         break;
-        case IMAGE_REL_BASED_HIGHLOW:
-         *(int *)((char *)page + offset) += delta;
-         break;
-#else
-        case IMAGE_REL_BASED_DIR64:
-         *(INT_PTR *)((char *)page + offset) += delta;
-         break;
-#endif
-        default:
-         TRACE("Unknown/unsupported fixup type %x.\n", type);
-         return NULL;
-        }
-      relocs++;
-    }
-  return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */
-}
-
-
-void MyLdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
-                          ULONG_PTR unknown3, ULONG_PTR unknown4 )
-{
-  static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};
-  NTSTATUS status;
-  WINE_MODREF *wm;
-  LPCWSTR load_path = NULL;
-  PEB *peb = current_peb();
-  IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader( peb->ImageBaseAddress );
-  void (*_kernel_start) (void *ptr) = kernel_start;
-
-#if 0
-  if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */
-#endif
-
-  /* allocate the modref for the main exe (if not already done) */
-  wm = get_modref( peb->ImageBaseAddress );
-  assert( wm );
-  if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)
-    {
-      TRACE("%S is a dll, not an executable\n", wm->ldr.FullDllName );
-      exit(1);
-    }
-
-  //  peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;
-  //  version_init( wm->ldr.FullDllName );
-
-  //  LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,
-  //                                REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );
-
-  /* the main exe needs to be the first in the load order list */
-  //  RemoveEntryList( &wm->ldr.InLoadOrderModuleList );
-  //  InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );
-
-  //  if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;
-  //  if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;
-
-  //  actctx_init();
-  //  load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;
-  if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;
-  //  if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;
-  //  if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;
-  //  heap_set_debug_flags( GetProcessHeap() );
-
-#if 0
-  /* FIXME: This may be interesting at some point.  */
-  status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );
-  if (status != STATUS_SUCCESS) goto error;
-#endif
-
-  //  virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );
-  //  virtual_clear_thread_stack();
-  //  wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
-  // stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );
-  _kernel_start (peb);
-
- error:
-  TRACE( "Main exe initialization for %S failed, status %x\n",
-        wm->ldr.FullDllName, status);
-        //      peb->ProcessParameters->ImagePathName, status );
-  //  NtTerminateProcess( GetCurrentProcess(), status );
-  exit (1);
-}
+/* From wine1.2-1.1.42/dlls/ntdll/loader.c  */\r
+\r
+/*\r
+ * Loader functions\r
+ *\r
+ * Copyright 1995, 2003 Alexandre Julliard\r
+ * Copyright 2002 Dmitry Timoshkov for CodeWeavers\r
+ * Copyright 2010 g10 Code GmbH\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or (at your option) any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
+ */\r
+\r
+\r
+\r
+#include <assert.h>\r
+\r
+#include "wine.h"\r
+\r
+PIMAGE_NT_HEADERS MyRtlImageNtHeader(HMODULE hModule)\r
+{\r
+    IMAGE_NT_HEADERS *ret;\r
+    IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;\r
+\r
+    ret = NULL;\r
+    if (dos->e_magic == IMAGE_DOS_SIGNATURE)\r
+    {\r
+        ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);\r
+        if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;\r
+    }\r
+    return ret;\r
+}\r
+\r
+\f\r
+/* internal representation of 32bit modules. per process. */\r
+typedef struct _wine_modref\r
+{\r
+    LDR_MODULE            ldr;\r
+    int                   nDeps;\r
+    struct _wine_modref **deps;\r
+} WINE_MODREF;\r
+\r
+/* FIXME: cmp with himemce-map.h */\r
+#define MAX_MODREFS 64\r
+WINE_MODREF *modrefs[MAX_MODREFS];\r
+int nr_modrefs;\r
+\r
+\r
+static WINE_MODREF *current_modref;\r
+\r
+\r
+/* convert from straight ASCII to Unicode without depending on the current codepage */\r
+static void ascii_to_unicode( WCHAR *dst, const char *src, size_t len )\r
+{\r
+  while (len--) *dst++ = (unsigned char)*src++;\r
+}\r
+\r
+\r
+/***********************************************************************\r
+ *           RtlImageDirectoryEntryToData   (NTDLL.@)\r
+ */\r
+PVOID MyRtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )\r
+{\r
+  const IMAGE_NT_HEADERS *nt;\r
+  DWORD addr;\r
+\r
+  if ((ULONG_PTR)module & 1)  /* mapped as data file */\r
+    {\r
+      module = (HMODULE)((ULONG_PTR)module & ~1);\r
+      image = FALSE;\r
+    }\r
+  if (!(nt = MyRtlImageNtHeader( module ))) return NULL;\r
+  if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)\r
+    {\r
+      const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;\r
+\r
+      if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;\r
+      if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;\r
+      *size = nt64->OptionalHeader.DataDirectory[dir].Size;\r
+      if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;\r
+    }\r
+  else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)\r
+    {\r
+      const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;\r
+\r
+      if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;\r
+      if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;\r
+      *size = nt32->OptionalHeader.DataDirectory[dir].Size;\r
+      if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;\r
+    }\r
+  else return NULL;\r
+\r
+#if 0\r
+  /* not mapped as image, need to find the section containing the virtual address */\r
+  return RtlImageRvaToVa( nt, module, addr, NULL );\r
+#else\r
+  return NULL;\r
+#endif\r
+}\r
+\r
+\r
+/* convert PE image VirtualAddress to Real Address */\r
+static void *get_rva( HMODULE module, DWORD va )\r
+{\r
+  return (void *)((char *)module + va);\r
+}\r
+\r
+\r
+#define allocate_stub(x,y) (0xdeadbeef)\r
+\r
+/*************************************************************************\r
+ *              import_dll\r
+ *\r
+ * Import the dll specified by the given import descriptor.\r
+ * The loader_section must be locked while calling this function.\r
+ */\r
+static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path )\r
+{\r
+  NTSTATUS status = STATUS_SUCCESS;\r
+  //  WINE_MODREF *wmImp;\r
+  HMODULE imp_mod;\r
+  //  const IMAGE_EXPORT_DIRECTORY *exports;\r
+  //  DWORD exp_size;\r
+  const IMAGE_THUNK_DATA *import_list;\r
+  IMAGE_THUNK_DATA *thunk_list;\r
+  WCHAR buffer[32];\r
+  const char *name = get_rva( module, descr->Name );\r
+  DWORD len = strlen(name);\r
+#if 0\r
+  PVOID protect_base;\r
+  SIZE_T protect_size = 0;\r
+  DWORD protect_old;\r
+#endif\r
+\r
+  thunk_list = get_rva( module, (DWORD)descr->FirstThunk );\r
+  if (descr->OriginalFirstThunk)\r
+    import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );\r
+  else\r
+    import_list = thunk_list;\r
+\r
+  while (len && name[len-1] == ' ') len--;  /* remove trailing spaces */\r
+\r
+  if (len * sizeof(WCHAR) < sizeof(buffer))\r
+    {\r
+      ascii_to_unicode( buffer, name, len );\r
+      buffer[len] = 0;\r
+      //      status = load_dll( load_path, buffer, 0, &wmImp );\r
+      imp_mod = LoadLibrary (buffer);\r
+      if (imp_mod == INVALID_HANDLE_VALUE)\r
+       status = GetLastError ();\r
+    }\r
+  else  /* need to allocate a larger buffer */\r
+    {\r
+      WCHAR *ptr = malloc ((len + 1) * sizeof(WCHAR) );\r
+      if (!ptr) return NULL;\r
+      ascii_to_unicode( ptr, name, len );\r
+      ptr[len] = 0;\r
+      // status = load_dll( load_path, ptr, 0, &wmImp );\r
+      imp_mod = LoadLibrary (ptr);\r
+      if (imp_mod == INVALID_HANDLE_VALUE)\r
+       status = GetLastError ();\r
+      free (ptr);\r
+    }\r
+  if (status)\r
+    {\r
+      if (status == STATUS_DLL_NOT_FOUND)\r
+       TRACE("Library %s (which is needed by %s) not found\n",\r
+           name, current_modref->ldr.FullDllName);\r
+      else\r
+       TRACE("Loading library %s (which is needed by %s) failed (error %x).\n",\r
+           name, current_modref->ldr.FullDllName, status);\r
+      return NULL;\r
+    }\r
+\r
+#if 0\r
+  /* unprotect the import address table since it can be located in\r
+   * readonly section */\r
+  while (import_list[protect_size].u1.Ordinal) protect_size++;\r
+  protect_base = thunk_list;\r
+  protect_size *= sizeof(*thunk_list);\r
+  NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,\r
+                         &protect_size, PAGE_WRITECOPY, &protect_old );\r
+#endif\r
+\r
+#if 0\r
+  imp_mod = wmImp->ldr.BaseAddress;\r
+  exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );\r
+\r
+  if (!exports)\r
+    {\r
+      /* set all imported function to deadbeef */\r
+      while (import_list->u1.Ordinal)\r
+        {\r
+         if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
+            {\r
+             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
+             WARN("No implementation for %s.%d", name, ordinal );\r
+             thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );\r
+            }\r
+         else\r
+            {\r
+             IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
+             WARN("No implementation for %s.%s", name, pe_name->Name );\r
+             thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );\r
+            }\r
+         WARN(" imported from %s, allocating stub %p\n",\r
+              current_modref->ldr.FullDllName,\r
+              (void *)thunk_list->u1.Function );\r
+         import_list++;\r
+         thunk_list++;\r
+        }\r
+      goto done;\r
+    }\r
+#endif\r
+\r
+  while (import_list->u1.Ordinal)\r
+    {\r
+      if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))\r
+        {\r
+         int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);\r
+\r
+         //      thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,\r
+         //                                                                ordinal - exports->Base, load_path );\r
+         thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddress (imp_mod, (void *) (ordinal & 0xffff));\r
+         if (!thunk_list->u1.Function)\r
+            {\r
+             thunk_list->u1.Function = (PDWORD) allocate_stub( name, IntToPtr(ordinal) );\r
+             TRACE("No implementation for %s.%d imported from %s, setting to %p\n",\r
+                   name, ordinal, current_modref->ldr.FullDllName,\r
+                   (void *)thunk_list->u1.Function );\r
+            }\r
+         TRACE("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );\r
+        }\r
+      else  /* import by name */\r
+        {\r
+         IMAGE_IMPORT_BY_NAME *pe_name;\r
+         pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );\r
+         //      thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,\r
+         //                                                              (const char*)pe_name->Name,\r
+         //                                                              pe_name->Hint, load_path );\r
+         thunk_list->u1.Function = (PDWORD)(ULONG_PTR)GetProcAddressA (imp_mod, (const char*)pe_name->Name);\r
+         if (!thunk_list->u1.Function)\r
+            {\r
+             thunk_list->u1.Function = (PDWORD) allocate_stub( name, (const char*)pe_name->Name );\r
+             TRACE("No implementation for %s.%s imported from %s, setting to %p\n",\r
+                   name, pe_name->Name, current_modref->ldr.FullDllName,\r
+                   (void *)thunk_list->u1.Function );\r
+            }\r
+         TRACE("--- %s %s.%d = %p\n",\r
+               pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);\r
+        }\r
+      import_list++;\r
+      thunk_list++;\r
+    }\r
+  // done:\r
+#if 0\r
+  /* restore old protection of the import address table */\r
+  NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, NULL );\r
+  return wmImp;\r
+#endif\r
+  return (void*)1;\r
+}\r
+\r
+\r
+\r
+/****************************************************************\r
+ *       fixup_imports\r
+ *\r
+ * Fixup all imports of a given module.\r
+ * The loader_section must be locked while calling this function.\r
+ */\r
+static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )\r
+{\r
+  int i, nb_imports;\r
+  const IMAGE_IMPORT_DESCRIPTOR *imports;\r
+  WINE_MODREF *prev;\r
+  DWORD size;\r
+  NTSTATUS status;\r
+  //  ULONG_PTR cookie;\r
+\r
+  if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS;  /* already done */\r
+  wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;\r
+  \r
+  if (!(imports = MyRtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,\r
+                                                 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))\r
+    return STATUS_SUCCESS;\r
+  \r
+  nb_imports = 0;\r
+  while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;\r
+  \r
+  if (!nb_imports) return STATUS_SUCCESS;  /* no imports */\r
+  \r
+#if 0\r
+  if (!create_module_activation_context( &wm->ldr ))\r
+    RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );\r
+#endif\r
+  \r
+#if 0\r
+  /* Allocate module dependency list */\r
+  wm->nDeps = nb_imports;\r
+  wm->deps  = RtlAllocateHeap( GetProcessHeap(), 0, nb_imports*sizeof(WINE_MODREF *) );\r
+#endif\r
+\r
+  /* load the imported modules. They are automatically\r
+   * added to the modref list of the process.\r
+   */\r
+  prev = current_modref;\r
+  current_modref = wm;\r
+  status = STATUS_SUCCESS;\r
+  for (i = 0; i < nb_imports; i++)\r
+    {\r
+      //      if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i], load_path )))\r
+      if (! import_dll( wm->ldr.BaseAddress, &imports[i], load_path ))\r
+       status = STATUS_DLL_NOT_FOUND;\r
+    }\r
+  current_modref = prev;\r
+  //  if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );\r
+  return status;\r
+}\r
+\r
+\r
+static BOOL is_dll_native_subsystem( HMODULE module, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )\r
+{\r
+       return FALSE;\r
+}\r
+\r
+\r
+/*************************************************************************\r
+ *              get_modref\r
+ *\r
+ * Looks for the referenced HMODULE in the current process\r
+ * The loader_section must be locked while calling this function.\r
+ */\r
+static WINE_MODREF *get_modref( HMODULE hmod )\r
+{\r
+  int i;\r
+  for (i = 0; i < nr_modrefs; i++)\r
+    if (modrefs[i]->ldr.BaseAddress == hmod)\r
+      return modrefs[i];\r
+  return NULL;\r
+}\r
+\r
+\r
+\r
+static WINE_MODREF *alloc_module( HMODULE hModule, LPCWSTR filename )\r
+{\r
+    WINE_MODREF *wm;\r
+    const WCHAR *p;\r
+    const IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader(hModule);\r
+#if 0\r
+    PLIST_ENTRY entry, mark;\r
+#endif\r
+\r
+    if (!(wm = malloc (sizeof(*wm)))) return NULL;\r
+\r
+    wm->nDeps    = 0;\r
+    wm->deps     = NULL;\r
+\r
+    wm->ldr.BaseAddress   = hModule;\r
+    wm->ldr.EntryPoint    = NULL;\r
+    wm->ldr.SizeOfImage   = nt->OptionalHeader.SizeOfImage;\r
+    wm->ldr.Flags         = LDR_DONT_RESOLVE_REFS;\r
+    wm->ldr.LoadCount     = 1;\r
+    wm->ldr.TlsIndex      = -1;\r
+    wm->ldr.SectionHandle = NULL;\r
+    wm->ldr.CheckSum      = 0;\r
+    wm->ldr.TimeDateStamp = 0;\r
+    wm->ldr.ActivationContext = 0;\r
+\r
+    wcscpy (wm->ldr.FullDllName, filename);\r
+    if ((p = wcsrchr( wm->ldr.FullDllName, L'\\' ))) p++;\r
+    else p = wm->ldr.FullDllName;\r
+    wcscpy (wm->ldr.BaseDllName, p );\r
+\r
+    if ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && !is_dll_native_subsystem( hModule, nt, p ))\r
+    {\r
+        wm->ldr.Flags |= LDR_IMAGE_IS_DLL;\r
+        if (nt->OptionalHeader.AddressOfEntryPoint)\r
+            wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;\r
+    }\r
+\r
+#if 0\r
+    InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,\r
+                   &wm->ldr.InLoadOrderModuleList);\r
+\r
+    /* insert module in MemoryList, sorted in increasing base addresses */\r
+    mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;\r
+    for (entry = mark->Flink; entry != mark; entry = entry->Flink)\r
+    {\r
+        if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)\r
+            break;\r
+    }\r
+    entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;\r
+    wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;\r
+    wm->ldr.InMemoryOrderModuleList.Flink = entry;\r
+    entry->Blink = &wm->ldr.InMemoryOrderModuleList;\r
+\r
+    /* wait until init is called for inserting into this list */\r
+    wm->ldr.InInitializationOrderModuleList.Flink = NULL;\r
+    wm->ldr.InInitializationOrderModuleList.Blink = NULL;\r
+#endif\r
+\r
+    modrefs[nr_modrefs++] = wm;\r
+\r
+    return wm;\r
+}\r
+\r
+\r
+static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,\r
+                                 DWORD flags, WINE_MODREF** pwm )\r
+{\r
+  void *module;\r
+  HANDLE mapping;\r
+  LARGE_INTEGER size;\r
+  SIZE_T len = 0;\r
+  WINE_MODREF *wm;\r
+  NTSTATUS status;\r
+\r
+  TRACE("Trying native dll %S\n", name);\r
+  \r
+  size.QuadPart = 0;\r
+  status = MyNtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,\r
+                             NULL, &size, PAGE_READONLY, SEC_IMAGE, file );\r
+  if (status != STATUS_SUCCESS) return status;\r
+  \r
+  module = NULL;\r
+  status = MyNtMapViewOfSection( mapping, NtCurrentProcess(),\r
+                                &module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );\r
+  CloseHandle( mapping );\r
+  if (status < 0) return status;\r
+  \r
+  /* create the MODREF */\r
+  \r
+  if (!(wm = alloc_module( module, name ))) return STATUS_NO_MEMORY;\r
+  \r
+  /* fixup imports */\r
+  \r
+  if (!(flags & DONT_RESOLVE_DLL_REFERENCES))\r
+    {\r
+#if 1\r
+      return (STATUS_NOT_IMPLEMENTED);\r
+#else\r
+      if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS)\r
+        {\r
+#if 0\r
+         /* the module has only be inserted in the load & memory order lists */\r
+         RemoveEntryList(&wm->ldr.InLoadOrderModuleList);\r
+         RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);\r
+         \r
+         /* FIXME: there are several more dangling references\r
+          * left. Including dlls loaded by this dll before the\r
+          * failed one. Unrolling is rather difficult with the\r
+          * current structure and we can leave them lying\r
+          * around with no problems, so we don't care.\r
+          * As these might reference our wm, we don't free it.\r
+          */\r
+#endif\r
+         return status;\r
+        }\r
+#endif\r
+    }\r
+  \r
+  TRACE( "Loaded %S at %p: native\n", wm->ldr.FullDllName, module );\r
+  \r
+  wm->ldr.LoadCount = 1;\r
+  *pwm = wm;\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname,\r
+                               WCHAR *filename, ULONG *size, WINE_MODREF **pwm, HANDLE *handle )\r
+{\r
+  HMODULE hnd = GetModuleHandle (NULL);\r
+  int len;\r
+  \r
+  assert (handle);\r
+  assert (*size == MAX_PATH);\r
+  \r
+  if (libname[0] == L'/' || libname[0] == L'\\')\r
+    {\r
+      wcscpy (filename, libname);\r
+    }\r
+  else\r
+    {\r
+      len = GetModuleFileName (hnd, filename, MAX_PATH);\r
+      filename[len++] = L'\\';\r
+      wcscpy (&filename[len], libname);\r
+    }\r
+  TRACE( "opening %S\n", filename);\r
+  \r
+  if (handle)\r
+    {\r
+      *handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL,\r
+                           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );\r
+      TRACE ("find_dll_file: 0x%p (0x%x)\n", *handle, GetFileSize (*handle, NULL));\r
+    }\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_MODREF** pwm )\r
+{\r
+    WCHAR filename[MAX_PATH];\r
+    ULONG size;\r
+    HANDLE handle = 0;\r
+    NTSTATUS nts;\r
+\r
+    TRACE( "looking for %S in %S\n", libname, load_path ? load_path : L"default path" );\r
+\r
+    *pwm = NULL;\r
+    size = MAX_PATH;\r
+    find_dll_file( load_path, libname, filename, &size, pwm, &handle );\r
+    \r
+    if (!handle)\r
+      nts = STATUS_DLL_NOT_FOUND;\r
+    else\r
+      nts = load_native_dll( load_path, filename, handle, flags, pwm );\r
+    \r
+    if (nts == STATUS_SUCCESS)\r
+      {\r
+        /* Initialize DLL just loaded */\r
+        TRACE("Loaded module %S at %p\n", filename, (*pwm)->ldr.BaseAddress);\r
+        if (handle)\r
+         CloseHandle( handle );\r
+        return nts;\r
+      }\r
+    \r
+    TRACE("Failed to load module %S; status=%x\n", libname, nts);\r
+    if (handle)\r
+      CloseHandle( handle );\r
+    return nts;\r
+}\r
+\r
+\r
+NTSTATUS MyLdrLoadDll(LPCWSTR path_name, DWORD flags,\r
+                     LPCWSTR libname, HMODULE* hModule)\r
+{\r
+  WINE_MODREF *wm;\r
+  NTSTATUS nts;\r
+\r
+  /* Support for dll path removed.  */\r
+  nts = load_dll( path_name, libname, flags, &wm );\r
+\r
+  /* For now.  */\r
+  assert (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS);\r
+#if 0\r
+  if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))\r
+    {\r
+      nts = process_attach( wm, NULL );\r
+      if (nts != STATUS_SUCCESS)\r
+        {\r
+         LdrUnloadDll(wm->ldr.BaseAddress);\r
+         wm = NULL;\r
+        }\r
+    }\r
+#endif\r
+  *hModule = (wm) ? wm->ldr.BaseAddress : NULL;\r
+\r
+  return nts;\r
+}\r
+\r
+\r
+\r
+/***********************************************************************\r
+ *           LdrProcessRelocationBlock  (NTDLL.@)\r
+ *\r
+ * Apply relocations to a given page of a mapped PE image.\r
+ */\r
+IMAGE_BASE_RELOCATION * MyLdrProcessRelocationBlock( void *page, UINT count,\r
+                                                    USHORT *relocs, INT_PTR delta )\r
+{\r
+  while (count--)\r
+    {\r
+      USHORT offset = *relocs & 0xfff;\r
+      int type = *relocs >> 12;\r
+      switch(type)\r
+        {\r
+        case IMAGE_REL_BASED_ABSOLUTE:\r
+         break;\r
+#if 1\r
+        case IMAGE_REL_BASED_HIGH:\r
+         *(short *)((char *)page + offset) += HIWORD(delta);\r
+         break;\r
+        case IMAGE_REL_BASED_LOW:\r
+         *(short *)((char *)page + offset) += LOWORD(delta);\r
+         break;\r
+        case IMAGE_REL_BASED_HIGHLOW:\r
+         *(int *)((char *)page + offset) += delta;\r
+         break;\r
+#else\r
+        case IMAGE_REL_BASED_DIR64:\r
+         *(INT_PTR *)((char *)page + offset) += delta;\r
+         break;\r
+#endif\r
+        default:\r
+         TRACE("Unknown/unsupported fixup type %x.\n", type);\r
+         return NULL;\r
+        }\r
+      relocs++;\r
+    }\r
+  return (IMAGE_BASE_RELOCATION *)relocs;  /* return address of next block */\r
+}\r
+\r
+\r
+void MyLdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,\r
+                          ULONG_PTR unknown3, ULONG_PTR unknown4 )\r
+{\r
+  static const WCHAR globalflagW[] = {'G','l','o','b','a','l','F','l','a','g',0};\r
+  NTSTATUS status;\r
+  WINE_MODREF *wm;\r
+  LPCWSTR load_path = NULL;\r
+  PEB *peb = current_peb();\r
+  IMAGE_NT_HEADERS *nt = MyRtlImageNtHeader( peb->ImageBaseAddress );\r
+  void (*_kernel_start) (void *ptr) = kernel_start;\r
+\r
+#if 0\r
+  if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */\r
+#endif\r
+\r
+  /* allocate the modref for the main exe (if not already done) */\r
+  wm = get_modref( peb->ImageBaseAddress );\r
+  assert( wm );\r
+  if (wm->ldr.Flags & LDR_IMAGE_IS_DLL)\r
+    {\r
+      TRACE("%S is a dll, not an executable\n", wm->ldr.FullDllName );\r
+      exit(1);\r
+    }\r
+\r
+  //  peb->ProcessParameters->ImagePathName = wm->ldr.FullDllName;\r
+  //  version_init( wm->ldr.FullDllName );\r
+\r
+  //  LdrQueryImageFileExecutionOptions( &peb->ProcessParameters->ImagePathName, globalflagW,\r
+  //                                REG_DWORD, &peb->NtGlobalFlag, sizeof(peb->NtGlobalFlag), NULL );\r
+\r
+  /* the main exe needs to be the first in the load order list */\r
+  //  RemoveEntryList( &wm->ldr.InLoadOrderModuleList );\r
+  //  InsertHeadList( &peb->LdrData->InLoadOrderModuleList, &wm->ldr.InLoadOrderModuleList );\r
+\r
+  //  if ((status = virtual_alloc_thread_stack( NtCurrentTeb(), 0, 0 )) != STATUS_SUCCESS) goto error;\r
+  //  if ((status = server_init_process_done()) != STATUS_SUCCESS) goto error;\r
+\r
+  //  actctx_init();\r
+  //  load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer;\r
+  if ((status = fixup_imports( wm, load_path )) != STATUS_SUCCESS) goto error;\r
+  //  if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto error;\r
+  //  if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto error;\r
+  //  heap_set_debug_flags( GetProcessHeap() );\r
+\r
+#if 0\r
+  /* FIXME: This may be interesting at some point.  */\r
+  status = wine_call_on_stack( attach_process_dlls, wm, NtCurrentTeb()->Tib.StackBase );\r
+  if (status != STATUS_SUCCESS) goto error;\r
+#endif\r
+\r
+  //  virtual_release_address_space( nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE );\r
+  //  virtual_clear_thread_stack();\r
+  //  wine_switch_to_stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );\r
+  // stack( start_process, kernel_start, NtCurrentTeb()->Tib.StackBase );\r
+  _kernel_start (peb);\r
+\r
+ error:\r
+  TRACE( "Main exe initialization for %S failed, status %x\n",\r
+        wm->ldr.FullDllName, status);\r
+        //      peb->ProcessParameters->ImagePathName, status );\r
+  //  NtTerminateProcess( GetCurrentProcess(), status );\r
+  exit (1);\r
+}\r