Check for failed allocations. Spotted by Martin Bealby.
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
index ed66e36..76cabd3 100644 (file)
@@ -1,50 +1,77 @@
-/* $Id: utils.c,v 1.61 2003/04/18 08:28:31 gvg Exp $
- * 
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            lib/ntdll/ldr/utils.c
  * PURPOSE:         Process startup for PE executables
  * PROGRAMMERS:     Jean Michault
  *                  Rex Jolliff (rex@lvcablemodem.com)
+ *                  Hartmut Birr
  */
 
 /*
  * TODO:
- *      - Fix calling of entry points
  *      - Handle loading flags correctly
+ *      - Handle errors correctly (unload dll's)
+ *      - Implement a faster way to find modules (hash table)
  *      - any more ??
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <reactos/config.h>
-#include <ddk/ntddk.h>
-#include <windows.h>
-#include <string.h>
-#include <wchar.h>
-#include <ntdll/ldr.h>
-#include <ntos/minmax.h>
+#include <ntdll.h>
+#define NDEBUG
+#include <debug.h>
+
+#define LDRP_PROCESS_CREATION_TIME 0x8000000
 
+/* GLOBALS *******************************************************************/
 
-#ifdef DBG_NTDLL_LDR_UTILS
-#define NDEBUG
+#ifdef NDEBUG
+#if defined(__GNUC__)
+#define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
+#else
+#endif /* __GNUC__ */
+#else
+#define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
 #endif
-#include <ntdll/ntdll.h>
+
+typedef struct _TLS_DATA
+{
+   PVOID StartAddressOfRawData;
+   DWORD TlsDataSize;
+   DWORD TlsZeroSize;
+   PIMAGE_TLS_CALLBACK TlsAddressOfCallBacks;
+   PLDR_DATA_TABLE_ENTRY Module;
+} TLS_DATA, *PTLS_DATA;
+
+static PTLS_DATA LdrpTlsArray = NULL;
+static ULONG LdrpTlsCount = 0;
+static ULONG LdrpTlsSize = 0;
+static HANDLE LdrpKnownDllsDirHandle = NULL;
+static UNICODE_STRING LdrpKnownDllPath = {0, 0, NULL};
+static PLDR_DATA_TABLE_ENTRY LdrpLastModule = NULL;
+extern PLDR_DATA_TABLE_ENTRY ExeModule;
 
 /* PROTOTYPES ****************************************************************/
 
-static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_MODULE *Module);
+static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_DATA_TABLE_ENTRY *Module, BOOLEAN Ref);
 static PVOID LdrFixupForward(PCHAR ForwardName);
 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
-
+static NTSTATUS LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
+                               IN ULONG LoadFlags,
+                               IN PUNICODE_STRING Name,
+                               OUT PLDR_DATA_TABLE_ENTRY *Module,
+                               OUT PVOID *BaseAddress OPTIONAL);
+static NTSTATUS LdrpAttachProcess(VOID);
+static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
 
 /* FUNCTIONS *****************************************************************/
 
-
-#ifdef DBG
+#if defined(DBG) || defined(KDBG)
 
 VOID
-LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
+LdrpLoadUserModuleSymbols(PLDR_DATA_TABLE_ENTRY LdrModule)
 {
   NtSystemDebugControl(
     DebugDbgLoadSymbols,
@@ -55,7 +82,301 @@ LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
     NULL);
 }
 
-#endif /* DBG */
+#endif /* DBG || KDBG */
+
+BOOLEAN
+LdrMappedAsDataFile(PVOID *BaseAddress)
+{
+  if (0 != ((DWORD_PTR) *BaseAddress & (PAGE_SIZE - 1)))
+    {
+      *BaseAddress = (PVOID) ((DWORD_PTR) *BaseAddress & ~ ((DWORD_PTR) PAGE_SIZE - 1));
+      return TRUE;
+    }
+
+   return FALSE;
+}
+
+static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
+{
+   LONG LoadCount;
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   LoadCount = Module->LoadCount;
+   if (Module->LoadCount > 0 && Module->LoadCount != 0xFFFF)
+     {
+       Module->LoadCount--;
+     }
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+   return LoadCount;
+}
+
+static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEAN Locked)
+{
+   LONG LoadCount;
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   LoadCount = Module->LoadCount;
+   if (Module->LoadCount != 0xFFFF)
+     {
+       Module->LoadCount++;
+     }
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+   return LoadCount;
+}
+
+static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size, BOOLEAN Locked)
+{
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   Module->TlsIndex = (SHORT)LdrpTlsCount;
+   LdrpTlsCount++;
+   LdrpTlsSize += Size;
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+}
+
+static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
+{
+   PIMAGE_TLS_CALLBACK TlsCallback;
+   if (Module->TlsIndex != 0xFFFF && Module->LoadCount == 0xFFFF)
+     {
+       TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
+       if (TlsCallback)
+         {
+           while (*TlsCallback)
+             {
+               TRACE_LDR("%wZ - Calling tls callback at %x\n",
+                         &Module->BaseDllName, TlsCallback);
+               TlsCallback(Module->DllBase, dwReason, NULL);
+               TlsCallback = (PIMAGE_TLS_CALLBACK)((ULONG_PTR)TlsCallback + sizeof(PVOID));
+             }
+         }
+     }
+}
+
+static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PVOID lpReserved)
+{
+   if (!(Module->Flags & LDRP_IMAGE_DLL) ||
+       Module->EntryPoint == 0)
+     {
+       return TRUE;
+     }
+   LdrpTlsCallback(Module, dwReason);
+   return  ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
+}
+
+static NTSTATUS
+LdrpInitializeTlsForThread(VOID)
+{
+   PVOID* TlsPointers;
+   PTLS_DATA TlsInfo;
+   PVOID TlsData;
+   ULONG i;
+   PTEB Teb = NtCurrentTeb();
+
+   DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
+
+   Teb->StaticUnicodeString.Length = 0;
+   Teb->StaticUnicodeString.MaximumLength = sizeof(Teb->StaticUnicodeBuffer);
+   Teb->StaticUnicodeString.Buffer = Teb->StaticUnicodeBuffer;
+
+   if (LdrpTlsCount > 0)
+     {
+       TlsPointers = RtlAllocateHeap(RtlGetProcessHeap(),
+                                     0,
+                                     LdrpTlsCount * sizeof(PVOID) + LdrpTlsSize);
+       if (TlsPointers == NULL)
+         {
+           DPRINT1("failed to allocate thread tls data\n");
+           return STATUS_NO_MEMORY;
+         }
+
+       TlsData = (PVOID)((ULONG_PTR)TlsPointers + LdrpTlsCount * sizeof(PVOID));
+       Teb->ThreadLocalStoragePointer = TlsPointers;
+
+       TlsInfo = LdrpTlsArray;
+       for (i = 0; i < LdrpTlsCount; i++, TlsInfo++)
+         {
+           TRACE_LDR("Initialize tls data for %wZ\n", &TlsInfo->Module->BaseDllName);
+           TlsPointers[i] = TlsData;
+           if (TlsInfo->TlsDataSize)
+             {
+               memcpy(TlsData, TlsInfo->StartAddressOfRawData, TlsInfo->TlsDataSize);
+               TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsDataSize);
+             }
+           if (TlsInfo->TlsZeroSize)
+             {
+               memset(TlsData, 0, TlsInfo->TlsZeroSize);
+               TlsData = (PVOID)((ULONG_PTR)TlsData + TlsInfo->TlsZeroSize);
+             }
+         }
+     }
+   DPRINT("LdrpInitializeTlsForThread() done\n");
+   return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpInitializeTlsForProccess(VOID)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_DATA_TABLE_ENTRY Module;
+   PIMAGE_TLS_DIRECTORY TlsDirectory;
+   PTLS_DATA TlsData;
+   ULONG Size;
+
+   DPRINT("LdrpInitializeTlsForProccess() called for %wZ\n", &ExeModule->BaseDllName);
+
+   if (LdrpTlsCount > 0)
+     {
+       LdrpTlsArray = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      0,
+                                      LdrpTlsCount * sizeof(TLS_DATA));
+       if (LdrpTlsArray == NULL)
+         {
+           DPRINT1("Failed to allocate global tls data\n");
+           return STATUS_NO_MEMORY;
+         }
+
+       ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+       Entry = ModuleListHead->Flink;
+       while (Entry != ModuleListHead)
+         {
+           Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
+           if (Module->LoadCount == 0xFFFF &&
+               Module->TlsIndex != 0xFFFF)
+             {
+               TlsDirectory = (PIMAGE_TLS_DIRECTORY)
+                                 RtlImageDirectoryEntryToData(Module->DllBase,
+                                                              TRUE,
+                                                              IMAGE_DIRECTORY_ENTRY_TLS,
+                                                              &Size);
+               ASSERT(Module->TlsIndex < LdrpTlsCount);
+               TlsData = &LdrpTlsArray[Module->TlsIndex];
+               TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
+               TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
+               TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
+               if (TlsDirectory->AddressOfCallBacks)
+                 TlsData->TlsAddressOfCallBacks = *(PIMAGE_TLS_CALLBACK*)TlsDirectory->AddressOfCallBacks;
+               else
+                 TlsData->TlsAddressOfCallBacks = NULL;
+               TlsData->Module = Module;
+#if 0
+               DbgPrint("TLS directory for %wZ\n", &Module->BaseDllName);
+               DbgPrint("StartAddressOfRawData: %x\n", TlsDirectory->StartAddressOfRawData);
+               DbgPrint("EndAddressOfRawData:   %x\n", TlsDirectory->EndAddressOfRawData);
+               DbgPrint("SizeOfRawData:         %d\n", TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData);
+               DbgPrint("AddressOfIndex:        %x\n", TlsDirectory->AddressOfIndex);
+               DbgPrint("AddressOfCallBacks:    %x (%x)\n", TlsDirectory->AddressOfCallBacks, *TlsDirectory->AddressOfCallBacks);
+               DbgPrint("SizeOfZeroFill:        %d\n", TlsDirectory->SizeOfZeroFill);
+               DbgPrint("Characteristics:       %x\n", TlsDirectory->Characteristics);
+#endif
+               /*
+                * FIXME:
+                *   Is this region allways writable ?
+                */
+               *(PULONG)TlsDirectory->AddressOfIndex = Module->TlsIndex;
+             }
+           Entry = Entry->Flink;
+        }
+    }
+  DPRINT("LdrpInitializeTlsForProccess() done\n");
+  return STATUS_SUCCESS;
+}
+
+VOID
+LdrpInitLoader(VOID)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING LinkTarget;
+  UNICODE_STRING Name;
+  HANDLE LinkHandle;
+  ULONG Length;
+  NTSTATUS Status;
+
+  DPRINT("LdrpInitLoader() called for %wZ\n", &ExeModule->BaseDllName);
+
+  /* Get handle to the 'KnownDlls' directory */
+  RtlInitUnicodeString(&Name,
+                       L"\\KnownDlls");
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &Name,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  Status = NtOpenDirectoryObject(&LdrpKnownDllsDirHandle,
+                                 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
+                                 &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NtOpenDirectoryObject() failed (Status %lx)\n", Status);
+      LdrpKnownDllsDirHandle = NULL;
+      return;
+    }
+
+  /* Allocate target name string */
+  LinkTarget.Length = 0;
+  LinkTarget.MaximumLength = MAX_PATH * sizeof(WCHAR);
+  LinkTarget.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      0,
+                                      MAX_PATH * sizeof(WCHAR));
+  if (LinkTarget.Buffer == NULL)
+    {
+      NtClose(LdrpKnownDllsDirHandle);
+      LdrpKnownDllsDirHandle = NULL;
+      return;
+    }
+
+  RtlInitUnicodeString(&Name,
+                       L"KnownDllPath");
+  InitializeObjectAttributes(&ObjectAttributes,
+                             &Name,
+                             OBJ_CASE_INSENSITIVE | OBJ_OPENLINK,
+                             LdrpKnownDllsDirHandle,
+                             NULL);
+  Status = NtOpenSymbolicLinkObject(&LinkHandle,
+                                    SYMBOLIC_LINK_ALL_ACCESS,
+                                    &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      RtlFreeUnicodeString(&LinkTarget);
+      NtClose(LdrpKnownDllsDirHandle);
+      LdrpKnownDllsDirHandle = NULL;
+      return;
+    }
+
+  Status = NtQuerySymbolicLinkObject(LinkHandle,
+                                     &LinkTarget,
+                                     &Length);
+  NtClose(LinkHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      RtlFreeUnicodeString(&LinkTarget);
+      NtClose(LdrpKnownDllsDirHandle);
+      LdrpKnownDllsDirHandle = NULL;
+    }
+
+  RtlCreateUnicodeString(&LdrpKnownDllPath,
+                         LinkTarget.Buffer);
+
+  RtlFreeUnicodeString(&LinkTarget);
+
+  DPRINT("LdrpInitLoader() done\n");
+}
 
 
 /***************************************************************************
@@ -84,7 +405,6 @@ LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
  *        ntdll.     --> ntdll
  *        ntdll.xyz  --> ntdll.xyz
  */
-
 static VOID
 LdrAdjustDllName (PUNICODE_STRING FullDllName,
                   PUNICODE_STRING DllName,
@@ -97,7 +417,7 @@ LdrAdjustDllName (PUNICODE_STRING FullDllName,
 
    Length = DllName->Length / sizeof(WCHAR);
 
-   if (BaseName == TRUE)
+   if (BaseName)
      {
         /* get the base dll name */
         Pointer = DllName->Buffer + Length;
@@ -139,18 +459,21 @@ LdrAdjustDllName (PUNICODE_STRING FullDllName,
    RtlCreateUnicodeString(FullDllName, Buffer);
 }
 
-PLDR_MODULE
-LdrAddModuleEntry(PVOID ImageBase, PIMAGE_NT_HEADERS NTHeaders,
+PLDR_DATA_TABLE_ENTRY
+LdrAddModuleEntry(PVOID ImageBase,
+                  PIMAGE_NT_HEADERS NTHeaders,
                   PWSTR FullDosName)
 {
-  PLDR_MODULE           Module;
-  Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE));
-  assert(Module);
-  Module->BaseAddress = (PVOID)ImageBase;
-  Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
+  PLDR_DATA_TABLE_ENTRY Module;
+
+  Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_DATA_TABLE_ENTRY));
+  ASSERT(Module);
+  memset(Module, 0, sizeof(LDR_DATA_TABLE_ENTRY));
+  Module->DllBase = (PVOID)ImageBase;
+  Module->EntryPoint = (PVOID)NTHeaders->OptionalHeader.AddressOfEntryPoint;
   if (Module->EntryPoint != 0)
-    Module->EntryPoint += (ULONG)Module->BaseAddress;
-  Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
+    Module->EntryPoint = (PVOID)((ULONG_PTR)Module->EntryPoint + (ULONG_PTR)Module->DllBase);
+  Module->SizeOfImage = LdrpGetResidentSize(NTHeaders);
   if (NtCurrentPeb()->Ldr->Initialized == TRUE)
     {
       /* loading while app is running */
@@ -160,10 +483,11 @@ LdrAddModuleEntry(PVOID ImageBase, PIMAGE_NT_HEADERS NTHeaders,
        * loading while app is initializing
        * dll must not be unloaded
        */
-      Module->LoadCount = -1;
+      Module->LoadCount = 0xFFFF;
     }
 
-  Module->TlsIndex = 0;
+  Module->Flags = 0;
+  Module->TlsIndex = -1;
   Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
   Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
 
@@ -172,157 +496,173 @@ LdrAddModuleEntry(PVOID ImageBase, PIMAGE_NT_HEADERS NTHeaders,
   RtlCreateUnicodeString (&Module->BaseDllName,
                           wcsrchr(FullDosName, L'\\') + 1);
   DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
-  
-  /* FIXME: aquire loader lock */
+
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
   InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
                  &Module->InLoadOrderModuleList);
-  InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
-                 &Module->InInitializationOrderModuleList);
-  /* FIXME: release loader lock */
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
 
   return(Module);
 }
 
-/***************************************************************************
- * NAME                                                         EXPORTED
- *      LdrLoadDll
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- *
- * NOTE
- *
- */
 
-NTSTATUS STDCALL
-LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
-            IN ULONG LoadFlags,
-            IN PUNICODE_STRING Name,
-            OUT PVOID *BaseAddress OPTIONAL)
+static NTSTATUS
+LdrpMapKnownDll(IN PUNICODE_STRING DllName,
+                OUT PUNICODE_STRING FullDosName,
+                OUT PHANDLE SectionHandle)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+
+  DPRINT("LdrpMapKnownDll() called\n");
+
+  if (LdrpKnownDllsDirHandle == NULL)
+    {
+      DPRINT("Invalid 'KnownDlls' directory\n");
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                             DllName,
+                             OBJ_CASE_INSENSITIVE,
+                             LdrpKnownDllsDirHandle,
+                             NULL);
+  Status = NtOpenSection(SectionHandle,
+                         SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
+                         &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NtOpenSection() failed for '%wZ' (Status 0x%08lx)\n", DllName, Status);
+      return Status;
+    }
+
+  FullDosName->Length = LdrpKnownDllPath.Length + DllName->Length + sizeof(WCHAR);
+  FullDosName->MaximumLength = FullDosName->Length + sizeof(WCHAR);
+  FullDosName->Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                        0,
+                                        FullDosName->MaximumLength);
+  if (FullDosName->Buffer == NULL)
+    {
+      FullDosName->Length = 0;
+      FullDosName->MaximumLength = 0;
+      return STATUS_SUCCESS;
+    }
+
+  wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
+  wcscat(FullDosName->Buffer, L"\\");
+  wcscat(FullDosName->Buffer, DllName->Buffer);
+
+  DPRINT("FullDosName '%wZ'\n", FullDosName);
+
+  DPRINT("LdrpMapKnownDll() done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
+                    IN PUNICODE_STRING DllName,
+                    OUT PUNICODE_STRING FullDosName,
+                    IN BOOLEAN MapAsDataFile,
+                    OUT PHANDLE SectionHandle)
 {
   WCHAR                 SearchPathBuffer[MAX_PATH];
-  WCHAR                 FullDosName[MAX_PATH];
-  UNICODE_STRING        AdjustedName;
+  WCHAR                 DosName[MAX_PATH];
   UNICODE_STRING        FullNtFileName;
   OBJECT_ATTRIBUTES     FileObjectAttributes;
+  HANDLE                FileHandle;
   char                  BlockBuffer [1024];
   PIMAGE_DOS_HEADER     DosHeader;
-  NTSTATUS              Status;
   PIMAGE_NT_HEADERS     NTHeaders;
-  ULONG                 ImageSize;
-  ULONG                 InitialViewSize;
-  PVOID                 ImageBase;
-  HANDLE                FileHandle;
-  HANDLE                SectionHandle;
-  PDLLMAIN_FUNC         Entrypoint = NULL;
-  PLDR_MODULE           Module;
-  
-  if (Name == NULL)
-    {
-      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
-      return STATUS_SUCCESS;
-    }
-  
-  *BaseAddress = NULL;
-  
-  DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
-         Name, BaseAddress);
-  
-  /* adjust the full dll name */
-  LdrAdjustDllName (&AdjustedName,
-                    Name,
-                    FALSE);
-  DPRINT("AdjustedName: %wZ\n", &AdjustedName);
-  
-  /*
-   * Test if dll is already loaded.
-   */
-  if (LdrFindEntryForName(&AdjustedName, &Module) == STATUS_SUCCESS)
-    {
-      DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
-      if (Module->LoadCount != -1)
-        Module->LoadCount++;
-      *BaseAddress = Module->BaseAddress;
-      return STATUS_SUCCESS;
-    }
-  DPRINT("Loading \"%wZ\"\n", Name);
+  IO_STATUS_BLOCK       IoStatusBlock;
+  NTSTATUS              Status;
+  ULONG                 len;
+
+  DPRINT("LdrpMapDllImageFile() called\n");
 
   if (SearchPath == NULL)
     {
-      SearchPath = SearchPathBuffer;
-      wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
+      /* get application running path */
+
+      wcscpy (SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer);
+
+      len = wcslen (SearchPathBuffer);
+
+      while (len && SearchPathBuffer[len - 1] != L'\\')
+           len--;
+
+      if (len) SearchPathBuffer[len-1] = L'\0';
+
+      wcscat (SearchPathBuffer, L";");
+
+      wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
       wcscat (SearchPathBuffer, L"\\system32;");
       wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
       wcscat (SearchPathBuffer, L";.");
+
+      SearchPath = SearchPathBuffer;
     }
 
-  DPRINT("SearchPath %S\n", SearchPath);
-  
   if (RtlDosSearchPath_U (SearchPath,
-                          AdjustedName.Buffer,
+                          DllName->Buffer,
                           NULL,
                           MAX_PATH,
-                          FullDosName,
+                          DosName,
                           NULL) == 0)
     return STATUS_DLL_NOT_FOUND;
-  
-  DPRINT("FullDosName %S\n", FullDosName);
-  
-  RtlFreeUnicodeString (&AdjustedName);
-  
-  if (!RtlDosPathNameToNtPathName_U (FullDosName,
+
+
+  if (!RtlDosPathNameToNtPathName_U (DosName,
                                      &FullNtFileName,
                                      NULL,
                                      NULL))
     return STATUS_DLL_NOT_FOUND;
-  
+
   DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
-  
+
   InitializeObjectAttributes(&FileObjectAttributes,
                              &FullNtFileName,
                              0,
                              NULL,
                              NULL);
-  
+
   DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
-  
-  Status = ZwOpenFile(&FileHandle,
-                      FILE_ALL_ACCESS,
-                      &FileObjectAttributes, 
-                      NULL,
-                      0,
-                      0);
+
+  Status = NtOpenFile(&FileHandle,
+                      GENERIC_READ|SYNCHRONIZE,
+                      &FileObjectAttributes,
+                      &IoStatusBlock,
+                      FILE_SHARE_READ,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
   if (!NT_SUCCESS(Status))
     {
-      DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n", 
+      DPRINT1("Dll open of %wZ failed: Status = 0x%08lx\n",
                &FullNtFileName, Status);
       RtlFreeUnicodeString (&FullNtFileName);
       return Status;
     }
   RtlFreeUnicodeString (&FullNtFileName);
-  
-  Status = ZwReadFile(FileHandle,
-                      0,
-                      0,
-                      0,
-                      0,
+
+  Status = NtReadFile(FileHandle,
+                      NULL,
+                      NULL,
+                      NULL,
+                      &IoStatusBlock,
                       BlockBuffer,
                       sizeof(BlockBuffer),
-                      0,
-                      0);
+                      NULL,
+                      NULL);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
-      ZwClose(FileHandle);
+      DPRINT("Dll header read failed: Status = 0x%08lx\n", Status);
+      NtClose(FileHandle);
       return Status;
     }
   /*
-   * Overlay DOS and NT headers structures to the 
+   * Overlay DOS and NT headers structures to the
    * buffer with DLL's header raw data.
    */
   DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
@@ -330,119 +670,45 @@ LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
   /*
    * Check it is a PE image file.
    */
-  if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
+  if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
       || (DosHeader->e_lfanew == 0L)
-      || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
+      || (*(PULONG)(NTHeaders) != IMAGE_NT_SIGNATURE))
     {
       DPRINT("NTDLL format invalid\n");
-      ZwClose(FileHandle);
-      
+      NtClose(FileHandle);
+
       return STATUS_UNSUCCESSFUL;
     }
-  
-  ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
-  ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
-  
-  DPRINT("ImageBase 0x%08x\n", ImageBase);
-        
+
   /*
    * Create a section for dll.
    */
-  Status = ZwCreateSection(&SectionHandle,
+  Status = NtCreateSection(SectionHandle,
                            SECTION_ALL_ACCESS,
                            NULL,
                            NULL,
-                           PAGE_READWRITE,
-                           SEC_COMMIT | SEC_IMAGE,
+                           PAGE_READONLY,
+                           SEC_COMMIT | (MapAsDataFile ? 0 : SEC_IMAGE),
                            FileHandle);
+  NtClose(FileHandle);
+
   if (!NT_SUCCESS(Status))
     {
-      DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
-      ZwClose(FileHandle);
+      DPRINT("NTDLL create section failed: Status = 0x%08lx\n", Status);
       return Status;
     }
-  
-  /*
-   * Map the dll into the process.
-   */
-  InitialViewSize = 0;
-  ImageBase = 0;
-  Status = ZwMapViewOfSection(SectionHandle,
-                              NtCurrentProcess(),
-                              &ImageBase,
-                              0,
-                              InitialViewSize,
-                              NULL,
-                              &InitialViewSize,
-                              0,
-                              MEM_COMMIT,
-                              PAGE_READWRITE);
-  if (!NT_SUCCESS(Status))
-    {
-      DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n", Status);
-      ZwClose(FileHandle);
-      return(Status);
-    }
-  ZwClose(FileHandle);
-
-  /* relocate dll and fixup import table */
-  if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
-      IMAGE_FILE_DLL)
-    {
-      Entrypoint =
-        (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle, &Module,
-                                     FullDosName);
-      if (Entrypoint == NULL)
-        {
-          return(STATUS_UNSUCCESSFUL);
-        }
-    }
-  
-#ifdef DBG
-
-  LdrpLoadUserModuleSymbols(Module);
 
-#endif /* DBG */
-
-  /* initialize dll */
-  if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
-      IMAGE_FILE_DLL)
-    {
-      if (Module->EntryPoint != 0)
-        {
-          Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
-          
-          DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-          if (FALSE == Entrypoint(Module->BaseAddress,
-                                  DLL_PROCESS_ATTACH,
-                                  NULL))
-            {
-             /* Do this as a DPRINT1 for now, until clean up and fail implemented */
-              DPRINT1("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
-                     &Module->BaseDllName);
-              /* FIXME: should clean up and fail */
-            }
-          else
-            {
-              DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
-                     &Module->BaseDllName);
-            }
-        }
-      else
-        {
-          DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
-                 &Module->BaseDllName);
-        }
-    }
+  RtlCreateUnicodeString(FullDosName,
+                         DosName);
 
-  *BaseAddress = Module->BaseAddress;
-  return STATUS_SUCCESS;
+  return Status;
 }
 
 
+
 /***************************************************************************
  * NAME                                                         EXPORTED
- *      LdrFindEntryForAddress
+ *      LdrLoadDll
  *
  * DESCRIPTION
  *
@@ -454,35 +720,94 @@ LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
  *
  * NOTE
  *
+ * @implemented
  */
-NTSTATUS STDCALL
-LdrFindEntryForAddress(PVOID Address,
-                       PLDR_MODULE *Module)
+NTSTATUS NTAPI
+LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
+            IN ULONG LoadFlags,
+            IN PUNICODE_STRING Name,
+            OUT PVOID *BaseAddress OPTIONAL)
 {
-  PLIST_ENTRY ModuleListHead;
-  PLIST_ENTRY Entry;
-  PLDR_MODULE ModulePtr;
+  NTSTATUS              Status;
+  PLDR_DATA_TABLE_ENTRY           Module;
 
-  DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address);
+  TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
+            Name,
+            SearchPath ? " from " : "",
+            SearchPath ? SearchPath : L"");
 
-  if (NtCurrentPeb()->Ldr == NULL)
-    return(STATUS_NO_MORE_ENTRIES);
+  if (Name == NULL)
+    {
+      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+      return STATUS_SUCCESS;
+    }
 
-  ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-  Entry = ModuleListHead->Flink;
-  if (Entry == ModuleListHead)
-    return(STATUS_NO_MORE_ENTRIES);
+  *BaseAddress = NULL;
+
+  Status = LdrpLoadModule(SearchPath, LoadFlags, Name, &Module, BaseAddress);
+  if (NT_SUCCESS(Status) && 0 == (LoadFlags & LOAD_LIBRARY_AS_DATAFILE))
+    {
+      RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+      Status = LdrpAttachProcess();
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      if (NT_SUCCESS(Status))
+        {
+          *BaseAddress = Module->DllBase;
+        }
+   }
+  return Status;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrFindEntryForAddress
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrFindEntryForAddress(PVOID Address,
+                       PLDR_DATA_TABLE_ENTRY *Module)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_DATA_TABLE_ENTRY ModulePtr;
+
+  DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
+
+  if (NtCurrentPeb()->Ldr == NULL)
+    return(STATUS_NO_MORE_ENTRIES);
+
+  RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+  ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+  Entry = ModuleListHead->Flink;
+  if (Entry == ModuleListHead)
+    {
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      return(STATUS_NO_MORE_ENTRIES);
+    }
 
   while (Entry != ModuleListHead)
     {
-      ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+      ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
-      DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->BaseAddress);
+      DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->DllBase);
 
-      if ((Address >= ModulePtr->BaseAddress) &&
-          (Address <= (ModulePtr->BaseAddress + ModulePtr->SizeOfImage)))
+      if ((Address >= ModulePtr->DllBase) &&
+          ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage)))
         {
           *Module = ModulePtr;
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
           return(STATUS_SUCCESS);
         }
 
@@ -491,6 +816,7 @@ LdrFindEntryForAddress(PVOID Address,
 
   DPRINT("Failed to find module entry.\n");
 
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
   return(STATUS_NO_MORE_ENTRIES);
 }
 
@@ -512,38 +838,82 @@ LdrFindEntryForAddress(PVOID Address,
  */
 static NTSTATUS
 LdrFindEntryForName(PUNICODE_STRING Name,
-                    PLDR_MODULE *Module)
+                    PLDR_DATA_TABLE_ENTRY *Module,
+                    BOOLEAN Ref)
 {
   PLIST_ENTRY ModuleListHead;
   PLIST_ENTRY Entry;
-  PLDR_MODULE ModulePtr;
+  PLDR_DATA_TABLE_ENTRY ModulePtr;
+  BOOLEAN ContainsPath;
+  UNICODE_STRING AdjustedName;
+  unsigned i;
 
-  DPRINT("NTDLL.LdrFindEntryForName(Name %wZ)\n", Name);
+  DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
 
   if (NtCurrentPeb()->Ldr == NULL)
     return(STATUS_NO_MORE_ENTRIES);
 
+  RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
   Entry = ModuleListHead->Flink;
   if (Entry == ModuleListHead)
-    return(STATUS_NO_MORE_ENTRIES);
+    {
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      return(STATUS_NO_MORE_ENTRIES);
+    }
 
   // NULL is the current process
   if (Name == NULL)
     {
-      *Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+      *Module = ExeModule;
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
       return(STATUS_SUCCESS);
     }
 
+  LdrAdjustDllName (&AdjustedName, Name, FALSE);
+
+  ContainsPath = (AdjustedName.Length >= 2 * sizeof(WCHAR) && L':' == AdjustedName.Buffer[1]);
+  for (i = 0; ! ContainsPath && i < AdjustedName.Length / sizeof(WCHAR); i++)
+    {
+      ContainsPath = L'\\' == AdjustedName.Buffer[i] ||
+                     L'/' == AdjustedName.Buffer[i];
+    }
+
+  if (LdrpLastModule)
+    {
+      if ((! ContainsPath &&
+           0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
+          (ContainsPath &&
+           0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
+        {
+          *Module = LdrpLastModule;
+          if (Ref && (*Module)->LoadCount != 0xFFFF)
+            {
+              (*Module)->LoadCount++;
+            }
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+          RtlFreeUnicodeString(&AdjustedName);
+          return(STATUS_SUCCESS);
+        }
+    }
   while (Entry != ModuleListHead)
     {
-      ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+      ModulePtr = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
-      DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, Name);
+      DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
 
-      if (RtlCompareUnicodeString(&ModulePtr->BaseDllName, Name, TRUE) == 0)
+      if ((! ContainsPath &&
+           0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
+          (ContainsPath &&
+           0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
         {
-          *Module = ModulePtr;
+          *Module = LdrpLastModule = ModulePtr;
+          if (Ref && ModulePtr->LoadCount != 0xFFFF)
+            {
+              ModulePtr->LoadCount++;
+            }
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+          RtlFreeUnicodeString(&AdjustedName);
           return(STATUS_SUCCESS);
         }
 
@@ -551,7 +921,8 @@ LdrFindEntryForName(PUNICODE_STRING Name,
     }
 
   DPRINT("Failed to find dll %wZ\n", Name);
-
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+  RtlFreeUnicodeString(&AdjustedName);
   return(STATUS_NO_MORE_ENTRIES);
 }
 
@@ -575,9 +946,9 @@ LdrFixupForward(PCHAR ForwardName)
 {
    CHAR NameBuffer[128];
    UNICODE_STRING DllName;
-   UNICODE_STRING FunctionName;
    NTSTATUS Status;
    PCHAR p;
+   PLDR_DATA_TABLE_ENTRY Module;
    PVOID BaseAddress;
 
    strcpy(NameBuffer, ForwardName);
@@ -590,25 +961,31 @@ LdrFixupForward(PCHAR ForwardName)
         RtlCreateUnicodeStringFromAsciiz (&DllName,
                                           NameBuffer);
 
-        Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
+        Status = LdrFindEntryForName (&DllName, &Module, FALSE);
+        /* FIXME:
+         *   The caller (or the image) is responsible for loading of the dll, where the function is forwarded.
+         */
         if (!NT_SUCCESS(Status))
           {
              Status = LdrLoadDll(NULL,
-                                 0,
+                                 LDRP_PROCESS_CREATION_TIME,
                                  &DllName,
                                  &BaseAddress);
-             if (!NT_SUCCESS(Status))
+             if (NT_SUCCESS(Status))
                {
-                  DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
-                  RtlFreeUnicodeString (&DllName);
-                  return NULL;
+                 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
                }
           }
-
         RtlFreeUnicodeString (&DllName);
-        DPRINT("BaseAddress: %p\n", BaseAddress);
-        
-        return LdrGetExportByName(BaseAddress, p+1, -1);
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("LdrFixupForward: failed to load %s\n", NameBuffer);
+            return NULL;
+          }
+
+        DPRINT("BaseAddress: %p\n", Module->DllBase);
+
+        return LdrGetExportByName(Module->DllBase, (PUCHAR)(p+1), -1);
      }
 
    return NULL;
@@ -618,7 +995,7 @@ LdrFixupForward(PCHAR ForwardName)
 /**********************************************************************
  * NAME                                                         LOCAL
  *      LdrGetExportByOrdinal
- *      
+ *
  * DESCRIPTION
  *
  * ARGUMENTS
@@ -637,39 +1014,47 @@ LdrGetExportByOrdinal (
         )
 {
         PIMAGE_EXPORT_DIRECTORY ExportDir;
+        ULONG                   ExportDirSize;
         PDWORD                  * ExFunctions;
-        USHORT                  * ExOrdinals;
+        PVOID                   Function;
 
         ExportDir = (PIMAGE_EXPORT_DIRECTORY)
                 RtlImageDirectoryEntryToData (BaseAddress,
                                               TRUE,
                                               IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                              NULL);
+                                              &ExportDirSize);
 
 
-        ExOrdinals = (USHORT *)
-                RVA(
-                        BaseAddress,
-                        ExportDir->AddressOfNameOrdinals
-                        );
         ExFunctions = (PDWORD *)
                 RVA(
                         BaseAddress,
                         ExportDir->AddressOfFunctions
                         );
-        DbgPrint(
-                "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
+        DPRINT(
+                "LdrGetExportByOrdinal(Ordinal %lu) = %p\n",
                 Ordinal,
                 RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
                 );
-        return(RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] ));
+
+        Function = (0 != ExFunctions[Ordinal - ExportDir->Base]
+                    ? RVA(BaseAddress, ExFunctions[Ordinal - ExportDir->Base] )
+                    : NULL);
+
+        if (((ULONG)Function >= (ULONG)ExportDir) &&
+            ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+          {
+             DPRINT("Forward: %s\n", (PCHAR)Function);
+             Function = LdrFixupForward((PCHAR)Function);
+          }
+
+        return Function;
 }
 
 
 /**********************************************************************
  * NAME                                                         LOCAL
  *      LdrGetExportByName
- *      
+ *
  * DESCRIPTION
  *
  * ARGUMENTS
@@ -679,7 +1064,7 @@ LdrGetExportByOrdinal (
  * REVISIONS
  *
  * NOTE
- *  AddressOfNames and AddressOfNameOrdinals are paralell tables, 
+ *  AddressOfNames and AddressOfNameOrdinals are paralell tables,
  *  both with NumberOfNames entries.
  *
  */
@@ -692,15 +1077,14 @@ LdrGetExportByName(PVOID BaseAddress,
    PDWORD                       * ExFunctions;
    PDWORD                       * ExNames;
    USHORT                       * ExOrdinals;
-   ULONG                        i;
    PVOID                        ExName;
    ULONG                        Ordinal;
    PVOID                        Function;
-   ULONG minn, maxn;
+   LONG minn, maxn;
    ULONG ExportDirSize;
-   
-   DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
-   
+
+   DPRINT("LdrGetExportByName %p %s %hu\n", BaseAddress, SymbolName, Hint);
+
    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
      RtlImageDirectoryEntryToData(BaseAddress,
                                   TRUE,
@@ -708,7 +1092,7 @@ LdrGetExportByName(PVOID BaseAddress,
                                   &ExportDirSize);
    if (ExportDir == NULL)
      {
-        DbgPrint("LdrGetExportByName(): no export directory!\n");
+        DPRINT1("LdrGetExportByName(): no export directory!\n");
         return NULL;
      }
 
@@ -716,7 +1100,7 @@ LdrGetExportByName(PVOID BaseAddress,
    //The symbol names may be missing entirely
    if (ExportDir->AddressOfNames == 0)
    {
-      DPRINT("LdrGetExportByName(): symbol names missing entirely\n");  
+      DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
       return NULL;
    }
 
@@ -729,14 +1113,14 @@ LdrGetExportByName(PVOID BaseAddress,
                               ExportDir->AddressOfNameOrdinals);
    ExFunctions = (PDWORD *)RVA(BaseAddress,
                                ExportDir->AddressOfFunctions);
-   
+
    /*
     * Check the hint first
     */
    if (Hint < ExportDir->NumberOfNames)
      {
         ExName = RVA(BaseAddress, ExNames[Hint]);
-        if (strcmp(ExName, SymbolName) == 0)
+        if (strcmp(ExName, (PCHAR)SymbolName) == 0)
           {
              Ordinal = ExOrdinals[Hint];
              Function = RVA(BaseAddress, ExFunctions[Ordinal]);
@@ -745,26 +1129,31 @@ LdrGetExportByName(PVOID BaseAddress,
                {
                   DPRINT("Forward: %s\n", (PCHAR)Function);
                   Function = LdrFixupForward((PCHAR)Function);
+                  if (Function == NULL)
+                    {
+                      DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
+                    }
+                  return Function;
                }
              if (Function != NULL)
                return Function;
           }
      }
-   
+
    /*
-    * Try a binary search first
+    * Binary search
     */
    minn = 0;
-   maxn = ExportDir->NumberOfNames;
+   maxn = ExportDir->NumberOfNames - 1;
    while (minn <= maxn)
      {
-        ULONG mid;
+        LONG mid;
         LONG res;
 
         mid = (minn + maxn) / 2;
 
         ExName = RVA(BaseAddress, ExNames[mid]);
-        res = strcmp(ExName, SymbolName);
+        res = strcmp(ExName, (PCHAR)SymbolName);
         if (res == 0)
           {
              Ordinal = ExOrdinals[mid];
@@ -774,6 +1163,11 @@ LdrGetExportByName(PVOID BaseAddress,
                {
                   DPRINT("Forward: %s\n", (PCHAR)Function);
                   Function = LdrFixupForward((PCHAR)Function);
+                  if (Function == NULL)
+                    {
+                      DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
+                    }
+                  return Function;
                }
              if (Function != NULL)
                return Function;
@@ -792,40 +1186,19 @@ LdrGetExportByName(PVOID BaseAddress,
              minn = mid + 1;
           }
      }
-   
-   /*
-    * Fall back on a linear search
-    */
-   DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
-   for (i = 0; i < ExportDir->NumberOfNames; i++)
-     {
-        ExName = RVA(BaseAddress, ExNames[i]);
-        if (strcmp(ExName,SymbolName) == 0)
-          {
-             Ordinal = ExOrdinals[i];
-             Function = RVA(BaseAddress, ExFunctions[Ordinal]);
-             DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
-             if (((ULONG)Function >= (ULONG)ExportDir) &&
-                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
-               {
-                  DPRINT("Forward: %s\n", (PCHAR)Function);
-                  Function = LdrFixupForward((PCHAR)Function);
-               }
-             return Function;
-          }
-     }
-   DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
-   return NULL;
+
+   DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
+   return (PVOID)NULL;
 }
 
 
 /**********************************************************************
  * NAME                                                         LOCAL
  *      LdrPerformRelocations
- *      
+ *
  * DESCRIPTION
  *      Relocate a DLL's memory image.
- *      
+ *
  * ARGUMENTS
  *
  * RETURN VALUE
@@ -835,143 +1208,396 @@ LdrGetExportByName(PVOID BaseAddress,
  * NOTE
  *
  */
-static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS        NTHeaders,
-                                       PVOID                    ImageBase)
+static NTSTATUS
+LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
+                      PVOID ImageBase)
 {
-  USHORT                        NumberOfEntries;
-  PUSHORT                       pValue16;
-  ULONG                 RelocationRVA;
-  ULONG                 Delta32;
-  ULONG                 Offset;
-  PULONG                        pValue32;
-  PRELOCATION_DIRECTORY RelocationDir;
-  PRELOCATION_ENTRY     RelocationBlock;
-  int                   i;
   PIMAGE_DATA_DIRECTORY RelocationDDir;
-  ULONG OldProtect;
+  PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
+  ULONG Count, ProtectSize, OldProtect, OldProtect2;
+  PVOID Page, ProtectPage, ProtectPage2;
+  PUSHORT TypeOffset;
+  ULONG_PTR Delta;
   NTSTATUS Status;
-  PIMAGE_SECTION_HEADER Sections;
-  ULONG MaxExtend;
-  ULONG LastOffset;
-
-  Sections = 
-    (PIMAGE_SECTION_HEADER)((PVOID)NTHeaders + sizeof(IMAGE_NT_HEADERS));
-  MaxExtend = 0;
-  for (i = 0; i < NTHeaders->FileHeader.NumberOfSections; i++)
+
+  if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
     {
-      if (!(Sections[i].Characteristics & IMAGE_SECTION_NOLOAD))
-        {
-          ULONG Extend;
-          Extend = 
-            (ULONG)(Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize);
-          MaxExtend = max(MaxExtend, Extend);
-        }
+      return STATUS_UNSUCCESSFUL;
     }
-  
-  RelocationDDir = 
+
+  RelocationDDir =
     &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
-  RelocationRVA = RelocationDDir->VirtualAddress;
-   
-  if (RelocationRVA)
+
+  if (RelocationDDir->VirtualAddress == 0 || RelocationDDir->Size == 0)
     {
-      RelocationDir = 
-        (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
+      return STATUS_SUCCESS;
+    }
 
-      while (RelocationDir->SizeOfBlock)
-        {
-          if (RelocationDir->VirtualAddress > MaxExtend)
-            {
-              RelocationRVA += RelocationDir->SizeOfBlock;
-              RelocationDir = 
-                (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
-              continue;
-            }
+  ProtectSize = PAGE_SIZE;
+  Delta = (ULONG_PTR)ImageBase - NTHeaders->OptionalHeader.ImageBase;
+  RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
+                  RelocationDDir->VirtualAddress);
+  RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)ImageBase +
+                  RelocationDDir->VirtualAddress + RelocationDDir->Size);
 
-          Delta32 = (ULONG)(ImageBase - NTHeaders->OptionalHeader.ImageBase);
-          RelocationBlock = 
-            (PRELOCATION_ENTRY) (RelocationRVA + ImageBase + 
-                                 sizeof (RELOCATION_DIRECTORY));          
-          NumberOfEntries = 
-            RelocationDir->SizeOfBlock - sizeof (RELOCATION_DIRECTORY);
-          NumberOfEntries = NumberOfEntries / sizeof (RELOCATION_ENTRY);
+  while (RelocationDir < RelocationEnd &&
+         RelocationDir->SizeOfBlock > 0)
+    {
+      Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+              sizeof(USHORT);
+      Page = (PVOID)((ULONG_PTR)ImageBase + (ULONG_PTR)RelocationDir->VirtualAddress);
+      TypeOffset = (PUSHORT)(RelocationDir + 1);
+
+      /* Unprotect the page(s) we're about to relocate. */
+      ProtectPage = Page;
+      Status = NtProtectVirtualMemory(NtCurrentProcess(),
+                                      &ProtectPage,
+                                      &ProtectSize,
+                                      PAGE_READWRITE,
+                                      &OldProtect);
+      if (!NT_SUCCESS(Status))
+        {
+          DPRINT1("Failed to unprotect relocation target.\n");
+          return Status;
+        }
 
+      if (RelocationDir->VirtualAddress + PAGE_SIZE <
+          NTHeaders->OptionalHeader.SizeOfImage)
+        {
+          ProtectPage2 = (PVOID)((ULONG_PTR)ProtectPage + PAGE_SIZE);
           Status = NtProtectVirtualMemory(NtCurrentProcess(),
-                                          ImageBase + 
-                                          RelocationDir->VirtualAddress,
-                                          PAGE_SIZE,
+                                          &ProtectPage2,
+                                          &ProtectSize,
                                           PAGE_READWRITE,
-                                          &OldProtect);
-          if (!NT_SUCCESS(Status))
-            {
-              DPRINT1("Failed to unprotect relocation target.\n");
-              return(Status);
-            }
-                
-          for (i = 0; i < NumberOfEntries; i++)
-            {
-              Offset = (RelocationBlock[i].TypeOffset & 0xfff);
-              Offset += (ULONG)(RelocationDir->VirtualAddress + ImageBase);
-
-              /*
-               * What kind of relocations should we perform
-               * for the current entry?
-               */
-              switch (RelocationBlock[i].TypeOffset >> 12)
-                {
-                case TYPE_RELOC_ABSOLUTE:
-                  break;
-                  
-                case TYPE_RELOC_HIGH:
-                  pValue16 = (PUSHORT)Offset;
-                  *pValue16 += Delta32 >> 16;
-                  break;
-                  
-                case TYPE_RELOC_LOW:
-                  pValue16 = (PUSHORT)Offset;
-                  *pValue16 += Delta32 & 0xffff;
-                  break;
-                  
-                case TYPE_RELOC_HIGHLOW:
-                  pValue32 = (PULONG)Offset;
-                  *pValue32 += Delta32;
-                  break;
-                          
-                case TYPE_RELOC_HIGHADJ:
-                  /* FIXME: do the highadjust fixup  */
-                  DPRINT("TYPE_RELOC_HIGHADJ fixup not implemented, sorry\n");
-                  return(STATUS_UNSUCCESSFUL);
-                  
-                default:
-                  DPRINT("unexpected fixup type\n");
-                  return STATUS_UNSUCCESSFUL;
-                }             
-            }
-
-          Status = NtProtectVirtualMemory(NtCurrentProcess(),
-                                          ImageBase + 
-                                          RelocationDir->VirtualAddress,
-                                          PAGE_SIZE,
-                                          OldProtect,
-                                          &OldProtect);
+                                          &OldProtect2);
           if (!NT_SUCCESS(Status))
             {
-              DPRINT1("Failed to protect relocation target.\n");
-              return(Status);
+              DPRINT1("Failed to unprotect relocation target (2).\n");
+              NtProtectVirtualMemory(NtCurrentProcess(),
+                                     &ProtectPage,
+                                     &ProtectSize,
+                                     OldProtect,
+                                     &OldProtect);
+              return Status;
             }
+        }
+      else
+        {
+          ProtectPage2 = NULL;
+        }
 
-          RelocationRVA += RelocationDir->SizeOfBlock;
-          RelocationDir = 
-            (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
+      RelocationDir = LdrProcessRelocationBlock(Page,
+                                                Count,
+                                                TypeOffset,
+                                                Delta);
+      if (RelocationDir == NULL)
+        return STATUS_UNSUCCESSFUL;
+
+      /* Restore old page protection. */
+      NtProtectVirtualMemory(NtCurrentProcess(),
+                             &ProtectPage,
+                             &ProtectSize,
+                             OldProtect,
+                             &OldProtect);
+
+      if (ProtectPage2 != NULL)
+        {
+          NtProtectVirtualMemory(NtCurrentProcess(),
+                                 &ProtectPage2,
+                                 &ProtectSize,
+                                 OldProtect2,
+                                 &OldProtect2);
         }
     }
+
   return STATUS_SUCCESS;
 }
 
+static NTSTATUS
+LdrpGetOrLoadModule(PWCHAR SerachPath,
+                    PCHAR Name,
+                    PLDR_DATA_TABLE_ENTRY* Module,
+                    BOOLEAN Load)
+{
+   UNICODE_STRING DllName;
+   NTSTATUS Status;
+
+   DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
+
+   RtlCreateUnicodeStringFromAsciiz (&DllName, Name);
+
+   Status = LdrFindEntryForName (&DllName, Module, Load);
+   if (Load && !NT_SUCCESS(Status))
+     {
+       Status = LdrpLoadModule(SerachPath,
+                               NtCurrentPeb()->Ldr->Initialized ? 0 : LDRP_PROCESS_CREATION_TIME,
+                               &DllName,
+                               Module,
+                               NULL);
+       if (NT_SUCCESS(Status))
+         {
+           Status = LdrFindEntryForName (&DllName, Module, FALSE);
+         }
+       if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("failed to load %wZ\n", &DllName);
+         }
+     }
+   RtlFreeUnicodeString (&DllName);
+   return Status;
+}
+
+static NTSTATUS
+LdrpProcessImportDirectoryEntry(PLDR_DATA_TABLE_ENTRY Module,
+                                PLDR_DATA_TABLE_ENTRY ImportedModule,
+                                PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory)
+{
+   NTSTATUS Status;
+   PVOID* ImportAddressList;
+   PULONG FunctionNameList;
+   PVOID IATBase;
+   ULONG OldProtect;
+   ULONG Ordinal;
+   ULONG IATSize;
+
+   if (ImportModuleDirectory == NULL || ImportModuleDirectory->Name == 0)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   /* Get the import address list. */
+   ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+
+   /* Get the list of functions to import. */
+   if (ImportModuleDirectory->OriginalFirstThunk != 0)
+     {
+       FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
+     }
+   else
+     {
+       FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+     }
+
+   /* Get the size of IAT. */
+   IATSize = 0;
+   while (FunctionNameList[IATSize] != 0L)
+     {
+       IATSize++;
+     }
+
+   /* Unprotect the region we are about to write into. */
+   IATBase = (PVOID)ImportAddressList;
+   IATSize *= sizeof(PVOID*);
+   Status = NtProtectVirtualMemory(NtCurrentProcess(),
+                                   &IATBase,
+                                   &IATSize,
+                                   PAGE_READWRITE,
+                                   &OldProtect);
+   if (!NT_SUCCESS(Status))
+     {
+       DPRINT1("Failed to unprotect IAT.\n");
+       return(Status);
+     }
+
+   /* Walk through function list and fixup addresses. */
+   while (*FunctionNameList != 0L)
+     {
+       if ((*FunctionNameList) & 0x80000000)
+         {
+           Ordinal = (*FunctionNameList) & 0x7fffffff;
+           *ImportAddressList = LdrGetExportByOrdinal(ImportedModule->DllBase, Ordinal);
+           if ((*ImportAddressList) == NULL)
+             {
+               DPRINT1("Failed to import #%ld from %wZ\n", Ordinal, &ImportedModule->FullDllName);
+               return STATUS_UNSUCCESSFUL;
+             }
+         }
+       else
+         {
+           IMAGE_IMPORT_BY_NAME *pe_name;
+           pe_name = RVA(Module->DllBase, *FunctionNameList);
+           *ImportAddressList = LdrGetExportByName(ImportedModule->DllBase, pe_name->Name, pe_name->Hint);
+           if ((*ImportAddressList) == NULL)
+             {
+               DPRINT1("Failed to import %s from %wZ\n", pe_name->Name, &ImportedModule->FullDllName);
+               return STATUS_UNSUCCESSFUL;
+             }
+         }
+       ImportAddressList++;
+       FunctionNameList++;
+     }
+
+   /* Protect the region we are about to write into. */
+   Status = NtProtectVirtualMemory(NtCurrentProcess(),
+                                   &IATBase,
+                                   &IATSize,
+                                   OldProtect,
+                                   &OldProtect);
+   if (!NT_SUCCESS(Status))
+     {
+       DPRINT1("Failed to protect IAT.\n");
+       return(Status);
+     }
+
+   return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpProcessImportDirectory(
+   PLDR_DATA_TABLE_ENTRY Module,
+   PLDR_DATA_TABLE_ENTRY ImportedModule,
+   PCHAR ImportedName)
+{
+   NTSTATUS Status;
+   PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+   PCHAR Name;
+   ULONG Size;
+
+   DPRINT("LdrpProcessImportDirectory(%p '%wZ', '%s')\n",
+          Module, &Module->BaseDllName, ImportedName);
+
+
+   ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+                             RtlImageDirectoryEntryToData(Module->DllBase,
+                                                          TRUE,
+                                                          IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                          &Size);
+   if (ImportModuleDirectory == NULL)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   while (ImportModuleDirectory->Name)
+     {
+       Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
+       if (0 == _stricmp(Name, ImportedName))
+         {
+           Status = LdrpProcessImportDirectoryEntry(Module,
+                                                    ImportedModule,
+                                                    ImportModuleDirectory);
+           if (!NT_SUCCESS(Status))
+             {
+               return Status;
+             }
+         }
+       ImportModuleDirectory++;
+     }
+
+
+   return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+LdrpAdjustImportDirectory(PLDR_DATA_TABLE_ENTRY Module,
+                          PLDR_DATA_TABLE_ENTRY ImportedModule,
+                          PCHAR ImportedName)
+{
+   PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+   NTSTATUS Status;
+   PVOID* ImportAddressList;
+   PVOID Start;
+   PVOID End;
+   PULONG FunctionNameList;
+   PVOID IATBase;
+   ULONG OldProtect;
+   ULONG Offset;
+   ULONG IATSize;
+   PIMAGE_NT_HEADERS NTHeaders;
+   PCHAR Name;
+   ULONG Size;
+
+   DPRINT("LdrpAdjustImportDirectory(Module %p '%wZ', %p '%wZ', '%s')\n",
+          Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
+
+   ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+                              RtlImageDirectoryEntryToData(Module->DllBase,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                           &Size);
+   if (ImportModuleDirectory == NULL)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   while (ImportModuleDirectory->Name)
+     {
+       Name = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
+       if (0 == _stricmp(Name, (PCHAR)ImportedName))
+         {
+
+           /* Get the import address list. */
+           ImportAddressList = (PVOID *)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+
+           /* Get the list of functions to import. */
+           if (ImportModuleDirectory->OriginalFirstThunk != 0)
+             {
+               FunctionNameList = (PULONG) ((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->OriginalFirstThunk);
+             }
+           else
+             {
+               FunctionNameList = (PULONG)((ULONG_PTR)Module->DllBase + (ULONG_PTR)ImportModuleDirectory->FirstThunk);
+             }
+
+           /* Get the size of IAT. */
+           IATSize = 0;
+           while (FunctionNameList[IATSize] != 0L)
+             {
+               IATSize++;
+             }
+
+           /* Unprotect the region we are about to write into. */
+           IATBase = (PVOID)ImportAddressList;
+           IATSize *= sizeof(PVOID*);
+           Status = NtProtectVirtualMemory(NtCurrentProcess(),
+                                           &IATBase,
+                                           &IATSize,
+                                           PAGE_READWRITE,
+                                           &OldProtect);
+           if (!NT_SUCCESS(Status))
+             {
+               DPRINT1("Failed to unprotect IAT.\n");
+               return(Status);
+             }
+
+           NTHeaders = RtlImageNtHeader (ImportedModule->DllBase);
+           Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
+           End = (PVOID)((ULONG_PTR)Start + ImportedModule->SizeOfImage);
+           Offset = (ULONG)((ULONG_PTR)ImportedModule->DllBase - (ULONG_PTR)Start);
+
+           /* Walk through function list and fixup addresses. */
+           while (*FunctionNameList != 0L)
+             {
+               if (*ImportAddressList >= Start && *ImportAddressList < End)
+                 {
+                   (*ImportAddressList) = (PVOID)((ULONG_PTR)(*ImportAddressList) + Offset);
+                 }
+               ImportAddressList++;
+               FunctionNameList++;
+             }
+
+           /* Protect the region we are about to write into. */
+           Status = NtProtectVirtualMemory(NtCurrentProcess(),
+                                           &IATBase,
+                                           &IATSize,
+                                           OldProtect,
+                                           &OldProtect);
+           if (!NT_SUCCESS(Status))
+             {
+               DPRINT1("Failed to protect IAT.\n");
+               return(Status);
+             }
+         }
+       ImportModuleDirectory++;
+     }
+   return STATUS_SUCCESS;
+}
+
 
 /**********************************************************************
  * NAME                                                         LOCAL
  *      LdrFixupImports
- *      
+ *
  * DESCRIPTION
  *      Compute the entry point for every symbol the DLL imports
  *      from other modules.
@@ -985,155 +1611,227 @@ static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS        NTHeaders,
  * NOTE
  *
  */
-static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS       NTHeaders,
-                                PVOID                   ImageBase)
+static NTSTATUS
+LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
+                IN PLDR_DATA_TABLE_ENTRY Module)
 {
-   PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
-   ULONG Ordinal;
-   PVOID BaseAddress;
+   PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+   PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectoryCurrent;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
+   PIMAGE_TLS_DIRECTORY TlsDirectory;
+   ULONG TlsSize = 0;
    NTSTATUS Status;
-   ULONG IATSize;
-   
-   DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders, 
-           ImageBase);
-   
+   PLDR_DATA_TABLE_ENTRY ImportedModule;
+   PCHAR ImportedName;
+   ULONG Size;
+
+   DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
+
+   /* Check for tls data */
+   TlsDirectory = (PIMAGE_TLS_DIRECTORY)
+                     RtlImageDirectoryEntryToData(Module->DllBase,
+                                                  TRUE,
+                                                  IMAGE_DIRECTORY_ENTRY_TLS,
+                                                  &Size);
+   if (TlsDirectory)
+     {
+       TlsSize = TlsDirectory->EndAddressOfRawData
+                   - TlsDirectory->StartAddressOfRawData
+                   + TlsDirectory->SizeOfZeroFill;
+       if (TlsSize > 0 &&
+           NtCurrentPeb()->Ldr->Initialized)
+         {
+           TRACE_LDR("Trying to load dynamicly %wZ which contains a tls directory\n",
+                     &Module->BaseDllName);
+           return STATUS_UNSUCCESSFUL;
+         }
+     }
    /*
     * Process each import module.
     */
-   ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
-                               ImageBase + NTHeaders->OptionalHeader
-                                 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
-                             .VirtualAddress);
-   DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
+   ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+                              RtlImageDirectoryEntryToData(Module->DllBase,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                           &Size);
+
+   BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
+                              RtlImageDirectoryEntryToData(Module->DllBase,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
+                                                           &Size);
+
+   if (BoundImportDescriptor != NULL && ImportModuleDirectory == NULL)
+     {
+       DPRINT1("%wZ has only a bound import directory\n", &Module->BaseDllName);
+       return STATUS_UNSUCCESSFUL;
+     }
+   if (BoundImportDescriptor)
+     {
+       DPRINT("BoundImportDescriptor %p\n", BoundImportDescriptor);
 
-   while (ImportModuleDirectory->dwRVAModuleName)
+       BoundImportDescriptorCurrent = BoundImportDescriptor;
+       while (BoundImportDescriptorCurrent->OffsetModuleName)
+         {
+           ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
+           TRACE_LDR("%wZ bound to %s\n", &Module->BaseDllName, ImportedName);
+           Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
+           if (!NT_SUCCESS(Status))
+             {
+               DPRINT1("failed to load %s\n", ImportedName);
+               return Status;
+             }
+           if (Module == ImportedModule)
+             {
+               LdrpDecrementLoadCount(Module, FALSE);
+             }
+           if (ImportedModule->TimeDateStamp != BoundImportDescriptorCurrent->TimeDateStamp)
+             {
+               TRACE_LDR("%wZ has stale binding to %wZ\n",
+                         &Module->BaseDllName, &ImportedModule->BaseDllName);
+               Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
+               if (!NT_SUCCESS(Status))
+                 {
+                   DPRINT1("failed to import %s\n", ImportedName);
+                   return Status;
+                 }
+             }
+           else
+             {
+               BOOLEAN WrongForwarder;
+               WrongForwarder = FALSE;
+               if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
+                 {
+                   TRACE_LDR("%wZ has stale binding to %s\n",
+                             &Module->BaseDllName, ImportedName);
+                 }
+               else
+                 {
+                   TRACE_LDR("%wZ has correct binding to %wZ\n",
+                           &Module->BaseDllName, &ImportedModule->BaseDllName);
+                 }
+               if (BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs)
+                 {
+                   PIMAGE_BOUND_FORWARDER_REF BoundForwarderRef;
+                   ULONG i;
+                   PLDR_DATA_TABLE_ENTRY ForwarderModule;
+                   PCHAR ForwarderName;
+
+                   BoundForwarderRef = (PIMAGE_BOUND_FORWARDER_REF)(BoundImportDescriptorCurrent + 1);
+                   for (i = 0; i < BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs; i++, BoundForwarderRef++)
+                     {
+                       ForwarderName = (PCHAR)BoundImportDescriptor + BoundForwarderRef->OffsetModuleName;
+                       TRACE_LDR("%wZ bound to %s via forwardes from %s\n",
+                                 &Module->BaseDllName, ForwarderName, ImportedName);
+                       Status = LdrpGetOrLoadModule(SearchPath, ForwarderName, &ForwarderModule, TRUE);
+                       if (!NT_SUCCESS(Status))
+                         {
+                           DPRINT1("failed to load %s\n", ForwarderName);
+                           return Status;
+                         }
+                       if (Module == ImportedModule)
+                         {
+                           LdrpDecrementLoadCount(Module, FALSE);
+                         }
+                       if (ForwarderModule->TimeDateStamp != BoundForwarderRef->TimeDateStamp ||
+                           ForwarderModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
+                         {
+                           TRACE_LDR("%wZ has stale binding to %s\n",
+                                     &Module->BaseDllName, ForwarderName);
+                           WrongForwarder = TRUE;
+                         }
+                       else
+                         {
+                           TRACE_LDR("%wZ has correct binding to %s\n",
+                                     &Module->BaseDllName, ForwarderName);
+                         }
+                     }
+                 }
+               if (WrongForwarder ||
+                   ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
+                 {
+                   Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
+                   if (!NT_SUCCESS(Status))
+                     {
+                       DPRINT1("failed to import %s\n", ImportedName);
+                       return Status;
+                     }
+                 }
+               else if (ImportedModule->Flags & LDRP_IMAGE_NOT_AT_BASE)
+                 {
+                   TRACE_LDR("Adjust imports for %s from %wZ\n",
+                             ImportedName, &Module->BaseDllName);
+                   Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
+                   if (!NT_SUCCESS(Status))
+                   {
+                     DPRINT1("failed to adjust import entries for %s\n", ImportedName);
+                     return Status;
+                   }
+                 }
+               else if (WrongForwarder)
+                 {
+                   /*
+                    * FIXME:
+                    *   Update only forwarders
+                    */
+                   TRACE_LDR("Stale BIND %s from %wZ\n",
+                             ImportedName, &Module->BaseDllName);
+                   Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
+                   if (!NT_SUCCESS(Status))
+                     {
+                       DPRINT1("faild to import %s\n", ImportedName);
+                       return Status;
+                     }
+                 }
+               else
+                 {
+                   /* nothing to do */
+                 }
+             }
+           BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
+         }
+     }
+   else if (ImportModuleDirectory)
      {
-        PVOID   * ImportAddressList;
-        PULONG  FunctionNameList;
-        UNICODE_STRING DllName;
-        DWORD   pName;
-        WORD    pHint;
-        PVOID   IATBase;
-        ULONG   OldProtect;
+       DPRINT("ImportModuleDirectory %p\n", ImportModuleDirectory);
 
-        DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
-               (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
+       ImportModuleDirectoryCurrent = ImportModuleDirectory;
+       while (ImportModuleDirectoryCurrent->Name)
+         {
+           ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
+           TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
+
+           Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
+           if (!NT_SUCCESS(Status))
+             {
+               DPRINT1("failed to load %s\n", ImportedName);
+               return Status;
+             }
+           if (Module == ImportedModule)
+             {
+               LdrpDecrementLoadCount(Module, FALSE);
+             }
+
+           TRACE_LDR("Initializing imports for %wZ from %s\n",
+                     &Module->BaseDllName, ImportedName);
+           Status = LdrpProcessImportDirectoryEntry(Module, ImportedModule, ImportModuleDirectoryCurrent);
+           if (!NT_SUCCESS(Status))
+             {
+               DPRINT1("failed to import %s\n", ImportedName);
+               return Status;
+             }
+           ImportModuleDirectoryCurrent++;
+         }
+     }
 
-        RtlCreateUnicodeStringFromAsciiz (&DllName,
-                  (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
+   if (TlsDirectory && TlsSize > 0)
+     {
+       LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
+     }
 
-        Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
-        if (!NT_SUCCESS(Status))
-          {
-             Status = LdrLoadDll(NULL,
-                                 0,
-                                 &DllName,
-                                 &BaseAddress);
-             RtlFreeUnicodeString (&DllName);
-             if (!NT_SUCCESS(Status))
-               {
-                  DbgPrint("LdrFixupImports:failed to load %s\n"
-                        ,(PCHAR)(ImageBase 
-                                + ImportModuleDirectory->dwRVAModuleName));
-
-                  return Status;
-               }
-          }
-
-        /*
-         * Get the import address list.
-         */
-        ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
-                        + ImportModuleDirectory->dwRVAFunctionAddressList);
-        
-        /*
-         * Get the list of functions to import.
-         */
-        if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
-          {
-             FunctionNameList = (PULONG) (
-                                          ImageBase
-                                          + ImportModuleDirectory->dwRVAFunctionNameList
-                                          );
-          }
-        else
-          {
-             FunctionNameList = 
-               (PULONG)(ImageBase 
-                        + ImportModuleDirectory->dwRVAFunctionAddressList);
-          }
-
-        /*
-         * Get the size of IAT.
-         */
-        IATSize = 0;
-        while (FunctionNameList[IATSize] != 0L)
-          {
-            IATSize++;
-          }
-
-        /*
-         * Unprotect the region we are about to write into.
-         */
-        IATBase = (PVOID)ImportAddressList;
-        Status = NtProtectVirtualMemory(NtCurrentProcess(),
-                                        IATBase,
-                                        IATSize * sizeof(PVOID*),
-                                        PAGE_READWRITE,
-                                        &OldProtect);
-        if (!NT_SUCCESS(Status))
-          {
-            DbgPrint("LDR: Failed to unprotect IAT.\n");
-            return(Status);
-          }
-
-        /*
-         * Walk through function list and fixup addresses.
-         */
-        while (*FunctionNameList != 0L)
-          {
-             if ((*FunctionNameList) & 0x80000000)
-               {
-                  Ordinal = (*FunctionNameList) & 0x7fffffff;
-                  *ImportAddressList = 
-                    LdrGetExportByOrdinal(BaseAddress,
-                                          Ordinal);
-               }
-             else
-               {
-                  pName = (DWORD) (ImageBase + *FunctionNameList + 2);
-                  pHint = *(PWORD)(ImageBase + *FunctionNameList);
-
-                  *ImportAddressList = 
-                    LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
-                  if ((*ImportAddressList) == NULL)
-                    {
-                       DbgPrint("Failed to import %s\n", pName);
-                       return STATUS_UNSUCCESSFUL;
-                    }
-               }
-             ImportAddressList++;
-             FunctionNameList++;
-          }
-
-        /*
-         * Protect the region we are about to write into.
-         */
-        Status = NtProtectVirtualMemory(NtCurrentProcess(),
-                                        IATBase,
-                                        IATSize * sizeof(PVOID*),
-                                        OldProtect,
-                                        &OldProtect);
-        if (!NT_SUCCESS(Status))
-          {
-            DbgPrint("LDR: Failed to protect IAT.\n");
-            return(Status);
-          }
-
-        ImportModuleDirectory++;
-     }
-   return STATUS_SUCCESS;
-}
+   return STATUS_SUCCESS;
+}
 
 
 /**********************************************************************
@@ -1141,19 +1839,18 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS       NTHeaders,
  *      LdrPEStartup
  *
  * DESCRIPTION
- *      1. Map the DLL's sections into memory.
- *      2. Relocate, if needed the DLL.
- *      3. Fixup any imported symbol.
- *      4. Compute the DLL's entry point.
+ *      1. Relocate, if needed the EXE.
+ *      2. Fixup any imported symbol.
+ *      3. Compute the EXE's entry point.
  *
  * ARGUMENTS
  *      ImageBase
- *              Address at which the DLL's image
+ *              Address at which the EXE's image
  *              is loaded.
- *              
+ *
  *      SectionHandle
  *              Handle of the section that contains
- *              the DLL's image.
+ *              the EXE's image.
  *
  * RETURN VALUE
  *      NULL on error; otherwise the entry point
@@ -1162,27 +1859,29 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS       NTHeaders,
  * REVISIONS
  *
  * NOTE
- *
+ *      04.01.2004 hb Previous this function was used for all images (dll + exe).
+ *                    Currently the function is only used for the exe.
  */
 PEPFUNC LdrPEStartup (PVOID  ImageBase,
                       HANDLE SectionHandle,
-                      PLDR_MODULE* Module,
+                      PLDR_DATA_TABLE_ENTRY* Module,
                       PWSTR FullDosName)
 {
    NTSTATUS             Status;
    PEPFUNC              EntryPoint = NULL;
    PIMAGE_DOS_HEADER    DosHeader;
    PIMAGE_NT_HEADERS    NTHeaders;
+   PLDR_DATA_TABLE_ENTRY tmpModule;
 
-   DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
-           ImageBase, (ULONG)SectionHandle);
+   DPRINT("LdrPEStartup(ImageBase %p SectionHandle %p)\n",
+           ImageBase, SectionHandle);
 
    /*
     * Overlay DOS and WNT headers structures
     * to the DLL's image.
     */
    DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
-   NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
+   NTHeaders = (PIMAGE_NT_HEADERS) ((ULONG_PTR)ImageBase + DosHeader->e_lfanew);
 
    /*
     * If the base address is different from the
@@ -1191,11 +1890,11 @@ PEPFUNC LdrPEStartup (PVOID  ImageBase,
     */
    if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
      {
-       DbgPrint("LDR: Performing relocations\n");
+       DPRINT("LDR: Performing relocations\n");
        Status = LdrPerformRelocations(NTHeaders, ImageBase);
        if (!NT_SUCCESS(Status))
          {
-           DbgPrint("LdrPerformRelocations() failed\n");
+           DPRINT1("LdrPerformRelocations() failed\n");
            return NULL;
          }
      }
@@ -1203,597 +1902,724 @@ PEPFUNC LdrPEStartup (PVOID  ImageBase,
    if (Module != NULL)
      {
        *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
+       (*Module)->SectionPointer = SectionHandle;
+     }
+   else
+     {
+       Module = &tmpModule;
+       Status = LdrFindEntryForAddress(ImageBase, Module);
+       if (!NT_SUCCESS(Status))
+         {
+           return NULL;
+         }
+     }
+
+   if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
+     {
+       (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
      }
 
    /*
     * If the DLL's imports symbols from other
     * modules, fixup the imported calls entry points.
     */
-   if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
-       .VirtualAddress != 0)
+   DPRINT("About to fixup imports\n");
+   Status = LdrFixupImports(NULL, *Module);
+   if (!NT_SUCCESS(Status))
      {
-        DPRINT("About to fixup imports\n");
-        Status = LdrFixupImports(NTHeaders, ImageBase);
-        if (!NT_SUCCESS(Status))
-          {
-             DbgPrint("LdrFixupImports() failed\n");
-             return NULL;
-          }
-        DPRINT("Fixup done\n");
+       DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
+       return NULL;
+     }
+   DPRINT("Fixup done\n");
+   RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+   Status = LdrpInitializeTlsForProccess();
+   if (NT_SUCCESS(Status))
+     {
+       Status = LdrpAttachProcess();
+     }
+   if (NT_SUCCESS(Status))
+     {
+       LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
+     }
+
+
+   RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+   if (!NT_SUCCESS(Status))
+     {
+       return NULL;
      }
 
    /*
     * Compute the DLL's entry point's address.
     */
-   DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
-   DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
+   DPRINT("ImageBase = %p\n", ImageBase);
+   DPRINT("AddressOfEntryPoint = 0x%lx\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
    if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
      {
-        EntryPoint = (PEPFUNC) (ImageBase
+        EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
                            + NTHeaders->OptionalHeader.AddressOfEntryPoint);
      }
-   DPRINT("LdrPEStartup() = %x\n",EntryPoint);
+   DPRINT("LdrPEStartup() = %p\n",EntryPoint);
    return EntryPoint;
 }
 
-
-NTSTATUS STDCALL
-LdrUnloadDll (IN PVOID BaseAddress)
+static NTSTATUS
+LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
+               IN ULONG LoadFlags,
+               IN PUNICODE_STRING Name,
+               PLDR_DATA_TABLE_ENTRY *Module,
+               PVOID *BaseAddress OPTIONAL)
 {
-   PIMAGE_NT_HEADERS NtHeaders;
-   PDLLMAIN_FUNC Entrypoint;
-   PLIST_ENTRY ModuleListHead;
-   PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
-   NTSTATUS Status;
-
-   if (BaseAddress == NULL)
-     return STATUS_SUCCESS;
-
-   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-   Entry = ModuleListHead->Flink;
-
-   while (Entry != ModuleListHead)
-     {
-        Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
-        if (Module->BaseAddress == BaseAddress)
+    UNICODE_STRING AdjustedName;
+    UNICODE_STRING FullDosName;
+    NTSTATUS Status;
+    PLDR_DATA_TABLE_ENTRY tmpModule;
+    HANDLE SectionHandle;
+    ULONG ViewSize;
+    PVOID ImageBase;
+    PIMAGE_NT_HEADERS NtHeaders;
+    BOOLEAN MappedAsDataFile;
+
+    if (Module == NULL)
+      {
+        Module = &tmpModule;
+      }
+    /* adjust the full dll name */
+    LdrAdjustDllName(&AdjustedName, Name, FALSE);
+
+    DPRINT("%wZ\n", &AdjustedName);
+
+    MappedAsDataFile = FALSE;
+    /* Test if dll is already loaded */
+    Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
+    if (NT_SUCCESS(Status))
+      {
+        RtlFreeUnicodeString(&AdjustedName);
+        if (NULL != BaseAddress)
           {
-             if (Module->LoadCount == -1)
-               {
-                  /* never unload this dll */
-                  return STATUS_SUCCESS;
-               }
-             else if (Module->LoadCount > 1)
-               {
-                  Module->LoadCount--;
-                  return STATUS_SUCCESS;
-               }
-
-             NtHeaders = RtlImageNtHeader (Module->BaseAddress);
-             if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
-               {
-                  if (Module->EntryPoint != 0)
-                    {
-                       Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
-                       DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-                       Entrypoint(Module->BaseAddress,
-                                  DLL_PROCESS_DETACH,
-                                  NULL);
-                    }
-                  else
-                    {
-                       DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
-                    }
-               }
-             Status = ZwUnmapViewOfSection (NtCurrentProcess (),
-                                            Module->BaseAddress);
-             ZwClose (Module->SectionHandle);
-
-             /* remove the module entry from the list */
-             RtlFreeUnicodeString (&Module->FullDllName);
-             RtlFreeUnicodeString (&Module->BaseDllName);
-             RemoveEntryList (Entry);
-             RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
-
-             return Status;
+            *BaseAddress = (*Module)->DllBase;
           }
-
-        Entry = Entry->Flink;
-     }
-
-   DPRINT("NTDLL.LDR: Dll not found\n")
-
-   return STATUS_UNSUCCESSFUL;
+      }
+    else
+      {
+        /* Open or create dll image section */
+        Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
+        if (!NT_SUCCESS(Status))
+          {
+            MappedAsDataFile = (0 != (LoadFlags & LOAD_LIBRARY_AS_DATAFILE));
+            Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName,
+                                         MappedAsDataFile, &SectionHandle);
+          }
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
+            RtlFreeUnicodeString(&AdjustedName);
+            return Status;
+          }
+        RtlFreeUnicodeString(&AdjustedName);
+        /* Map the dll into the process */
+        ViewSize = 0;
+        ImageBase = 0;
+        Status = NtMapViewOfSection(SectionHandle,
+                                    NtCurrentProcess(),
+                                    &ImageBase,
+                                    0,
+                                    0,
+                                    NULL,
+                                    &ViewSize,
+                                    0,
+                                    MEM_COMMIT,
+                                    PAGE_READONLY);
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("map view of section failed (Status 0x%08lx)\n", Status);
+            RtlFreeUnicodeString(&FullDosName);
+            NtClose(SectionHandle);
+            return(Status);
+          }
+        if (NULL != BaseAddress)
+          {
+            *BaseAddress = ImageBase;
+          }
+        /* Get and check the NT headers */
+        NtHeaders = RtlImageNtHeader(ImageBase);
+        if (NtHeaders == NULL)
+          {
+            DPRINT1("RtlImageNtHeaders() failed\n");
+            NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
+            NtClose (SectionHandle);
+            RtlFreeUnicodeString(&FullDosName);
+            return STATUS_UNSUCCESSFUL;
+          }
+        DPRINT("Mapped %wZ at %x\n", &FullDosName, ImageBase);
+        if (MappedAsDataFile)
+          {
+            ASSERT(NULL != BaseAddress);
+            if (NULL != BaseAddress)
+              {
+                *BaseAddress = (PVOID) ((char *) *BaseAddress + 1);
+              }
+            *Module = NULL;
+            RtlFreeUnicodeString(&FullDosName);
+            NtClose(SectionHandle);
+            return STATUS_SUCCESS;
+          }
+        /* If the base address is different from the
+         * one the DLL is actually loaded, perform any
+         * relocation. */
+        if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
+          {
+            DPRINT1("Relocating (%lx -> %p) %wZ\n",
+              NtHeaders->OptionalHeader.ImageBase, ImageBase, &FullDosName);
+            Status = LdrPerformRelocations(NtHeaders, ImageBase);
+            if (!NT_SUCCESS(Status))
+              {
+                DPRINT1("LdrPerformRelocations() failed\n");
+                NtUnmapViewOfSection (NtCurrentProcess (), ImageBase);
+                NtClose (SectionHandle);
+                RtlFreeUnicodeString(&FullDosName);
+                return STATUS_UNSUCCESSFUL;
+              }
+          }
+        *Module = LdrAddModuleEntry(ImageBase, NtHeaders, FullDosName.Buffer);
+        (*Module)->SectionPointer = SectionHandle;
+        if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
+          {
+            (*Module)->Flags |= LDRP_IMAGE_NOT_AT_BASE;
+          }
+        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
+          {
+            (*Module)->Flags |= LDRP_IMAGE_DLL;
+          }
+        /* fixup the imported calls entry points */
+        Status = LdrFixupImports(SearchPath, *Module);
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
+            return Status;
+          }
+#if defined(DBG) || defined(KDBG)
+        LdrpLoadUserModuleSymbols(*Module);
+#endif /* DBG || KDBG */
+        RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+        InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
+                       &(*Module)->InInitializationOrderModuleList);
+        RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+      }
+    return STATUS_SUCCESS;
 }
 
-#if 0 /*MOVED_TO_FILE_RES_C*/
-
-NTSTATUS STDCALL
-LdrFindResource_U(PVOID BaseAddress,
-                  PLDR_RESOURCE_INFO ResourceInfo,
-                  ULONG Level,
-                  PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
+static NTSTATUS
+LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
+                 BOOLEAN Unload)
 {
-   PIMAGE_RESOURCE_DIRECTORY ResDir;
-   PIMAGE_RESOURCE_DIRECTORY ResBase;
-   PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
-   NTSTATUS Status = STATUS_SUCCESS;
-   ULONG EntryCount;
-   PWCHAR ws;
-   ULONG i;
-   ULONG Id;
-
-   DPRINT ("LdrFindResource_U()\n");
+   PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
+   PCHAR ImportedName;
+   PLDR_DATA_TABLE_ENTRY ImportedModule;
+   NTSTATUS Status;
+   LONG LoadCount;
+   ULONG Size;
 
-   /* Get the pointer to the resource directory */
-   ResDir = (PIMAGE_RESOURCE_DIRECTORY)
-        RtlImageDirectoryEntryToData (BaseAddress,
-                                      TRUE,
-                                      IMAGE_DIRECTORY_ENTRY_RESOURCE,
-                                      &i);
-   if (ResDir == NULL)
+   if (Unload)
      {
-        return STATUS_RESOURCE_DATA_NOT_FOUND;
+       RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
      }
 
-   DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
+   LoadCount = LdrpDecrementLoadCount(Module, Unload);
 
-   ResBase = ResDir;
+   TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
 
-   /* Let's go into resource tree */
-   for (i = 0; i < Level; i++)
+   if (LoadCount == 0)
      {
-        DPRINT("ResDir: %x\n", (ULONG)ResDir);
-        Id = ((PULONG)ResourceInfo)[i];
-        EntryCount = ResDir->NumberOfNamedEntries;
-        ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
-        DPRINT("ResEntry %x\n", (ULONG)ResEntry);
-        if (Id & 0xFFFF0000)
-          {
-             /* Resource name is a unicode string */
-             for (; EntryCount--; ResEntry++)
-               {
-                  /* Scan entries for equal name */
-                  if (ResEntry->Name & 0x80000000)
+       /* ?????????????????? */
+     }
+   else if (LoadCount == 1)
+     {
+       BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
+                                 RtlImageDirectoryEntryToData(Module->DllBase,
+                                                              TRUE,
+                                                              IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
+                                                              &Size);
+       if (BoundImportDescriptor)
+        {
+          /* dereferencing all imported modules, use the bound import descriptor */
+          BoundImportDescriptorCurrent = BoundImportDescriptor;
+          while (BoundImportDescriptorCurrent->OffsetModuleName)
+            {
+              ImportedName = (PCHAR)BoundImportDescriptor + BoundImportDescriptorCurrent->OffsetModuleName;
+              TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
+              Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
+              if (!NT_SUCCESS(Status))
+                {
+                  DPRINT1("unable to found imported modul %s\n", ImportedName);
+                }
+              else
+                {
+                  if (Module != ImportedModule)
                     {
-                       ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
-                       if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
-                           wcslen((PWCHAR)Id) == (int)*ws )
+                      Status = LdrpUnloadModule(ImportedModule, FALSE);
+                      if (!NT_SUCCESS(Status))
+                        {
+                          DPRINT1("unable to unload %s\n", ImportedName);
+                        }
+                    }
+                }
+              BoundImportDescriptorCurrent++;
+            }
+         }
+       else
+         {
+           ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)
+                                      RtlImageDirectoryEntryToData(Module->DllBase,
+                                                                   TRUE,
+                                                                   IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                                   &Size);
+           if (ImportModuleDirectory)
+             {
+               /* dereferencing all imported modules, use the import descriptor */
+               while (ImportModuleDirectory->Name)
+                 {
+                   ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectory->Name;
+                   TRACE_LDR("%wZ trys to unload %s\n", &Module->BaseDllName, ImportedName);
+                   Status = LdrpGetOrLoadModule(NULL, ImportedName, &ImportedModule, FALSE);
+                   if (!NT_SUCCESS(Status))
+                     {
+                       DPRINT1("unable to found imported modul %s\n", ImportedName);
+                     }
+                   else
+                     {
+                       if (Module != ImportedModule)
                          {
-                            goto found;
+                           Status = LdrpUnloadModule(ImportedModule, FALSE);
+                           if (!NT_SUCCESS(Status))
+                             {
+                               DPRINT1("unable to unload %s\n", ImportedName);
+                             }
                          }
-                    }
-               }
-          }
-        else
-          {
-             /* We use ID number instead of string */
-             ResEntry += EntryCount;
-             EntryCount = ResDir->NumberOfIdEntries;
-             for (; EntryCount--; ResEntry++)
-               {
-                  /* Scan entries for equal name */
-                  if (ResEntry->Name == Id)
-                    {
-                     DPRINT("ID entry found %x\n", Id);
-                     goto found;
-                    }
-               }
-          }
-        DPRINT("Error %lu\n", i);
-
-          switch (i)
-          {
-             case 0:
-                return STATUS_RESOURCE_TYPE_NOT_FOUND;
-
-             case 1:
-                return STATUS_RESOURCE_NAME_NOT_FOUND;
-
-             case 2:
-                if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
-                  {
-                     /* Use the first available language */
-                     ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
-                     break;
-                  }
-                return STATUS_RESOURCE_LANG_NOT_FOUND;
-
-             case 3:
-                return STATUS_RESOURCE_DATA_NOT_FOUND;
-
-             default:
-                return STATUS_INVALID_PARAMETER;
-          }
-found:;
-        ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
-                (ResEntry->OffsetToData & 0x7FFFFFFF));
+                     }
+                   ImportModuleDirectory++;
+                 }
+             }
+         }
      }
-   DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
 
-   if (ResourceDataEntry)
+   if (Unload)
      {
-        *ResourceDataEntry = (PVOID)ResDir;
+       LdrpDetachProcess(FALSE);
+       RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
      }
+   return STATUS_SUCCESS;
 
-  return Status;
 }
 
-
-NTSTATUS STDCALL
-LdrAccessResource(IN  PVOID BaseAddress,
-                  IN  PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
-                  OUT PVOID *Resource OPTIONAL,
-                  OUT PULONG Size OPTIONAL)
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrUnloadDll (IN PVOID BaseAddress)
 {
-   PIMAGE_SECTION_HEADER Section;
-   PIMAGE_NT_HEADERS NtHeader;
-   ULONG SectionRva;
-   ULONG SectionVa;
-   ULONG DataSize;
-   ULONG Offset = 0;
-   ULONG Data;
-
-   Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
-                                               TRUE,
-                                               IMAGE_DIRECTORY_ENTRY_RESOURCE,
-                                               &DataSize);
-   if (Data == 0)
-        return STATUS_RESOURCE_DATA_NOT_FOUND;
-
-   if ((ULONG)BaseAddress & 1)
-     {
-        /* loaded as ordinary file */
-        NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
-        Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
-        Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
-        if (Section == NULL)
-          {
-             return STATUS_RESOURCE_DATA_NOT_FOUND;
-          }
+   PLDR_DATA_TABLE_ENTRY Module;
+   NTSTATUS Status;
 
-        if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
-          {
-             SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
-             SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
-             Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
-          }
-     }
+   if (BaseAddress == NULL)
+     return STATUS_SUCCESS;
 
-   if (Resource)
+   if (LdrMappedAsDataFile(&BaseAddress))
      {
-        *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
+       Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
      }
-
-   if (Size)
+   else
      {
-        *Size = ResourceDataEntry->Size;
+       Status = LdrFindEntryForAddress(BaseAddress, &Module);
+       if (NT_SUCCESS(Status))
+         {
+           TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
+           Status = LdrpUnloadModule(Module, TRUE);
+         }
      }
 
-   return STATUS_SUCCESS;
+   return Status;
 }
 
-#endif /*MOVED_TO_FILE_RES_C*/
-
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
 {
     PLIST_ENTRY ModuleListHead;
     PLIST_ENTRY Entry;
-    PLDR_MODULE Module;
+    PLDR_DATA_TABLE_ENTRY Module;
     NTSTATUS Status;
 
-    DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n", BaseAddress);
+    DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
 
     Status = STATUS_DLL_NOT_FOUND;
+    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
     ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
     Entry = ModuleListHead->Flink;
-    while (Entry != ModuleListHead) {
-        Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+    while (Entry != ModuleListHead)
+      {
+        Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
-        DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->BaseAddress);
+        DPRINT("BaseDllName %wZ BaseAddress %p\n", &Module->BaseDllName, Module->DllBase);
 
-        if (Module->BaseAddress == BaseAddress) {
-            if (Module->TlsIndex == 0) {
-                Module->Flags |= 0x00040000;
+        if (Module->DllBase == BaseAddress)
+          {
+            if (Module->TlsIndex == 0xFFFF)
+              {
+                Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
                 Status = STATUS_SUCCESS;
-            }
-            return Status;
-        }
+              }
+            break;
+          }
         Entry = Entry->Flink;
-    }
+      }
+    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
     return Status;
 }
 
-#if 0 /*MOVED_TO_FILE_RES_C*/
-
-NTSTATUS STDCALL
-LdrFindResourceDirectory_U (IN PVOID BaseAddress,
-                            WCHAR **name,
-                            DWORD level,
-                            OUT PVOID *addr)
-{
-   PIMAGE_RESOURCE_DIRECTORY ResDir;
-   PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
-   ULONG EntryCount;
-   ULONG i;
-   NTSTATUS Status = STATUS_SUCCESS;
-   WCHAR *ws;
-
-   /* Get the pointer to the resource directory */
-   ResDir = (PIMAGE_RESOURCE_DIRECTORY)
-        RtlImageDirectoryEntryToData (BaseAddress,
-                                      TRUE,
-                                      IMAGE_DIRECTORY_ENTRY_RESOURCE,
-                                      &i);
-   if (ResDir == NULL)
-     {
-        return STATUS_RESOURCE_DATA_NOT_FOUND;
-     }
-
-   /* Let's go into resource tree */
-   for (i = 0; i < level; i++, name++)
-     {
-        EntryCount = ResDir->NumberOfNamedEntries;
-        ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
-        if ((ULONG)(*name) & 0xFFFF0000)
-          {
-             /* Resource name is a unicode string */
-             for (; EntryCount--; ResEntry++)
-               {
-                  /* Scan entries for equal name */
-                  if (ResEntry->Name & 0x80000000)
-                    {
-                       ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
-                       if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
-                         {
-                            goto found;
-                         }
-                    }
-               }
-          }
-        else
-          {
-             /* We use ID number instead of string */
-             ResEntry += EntryCount;
-             EntryCount = ResDir->NumberOfIdEntries;
-             for (; EntryCount--; ResEntry++)
-               {
-                  /* Scan entries for equal name */
-                  if (ResEntry->Name == (ULONG)(*name))
-                     goto found;
-               }
-          }
-
-          switch (i)
-          {
-             case 0:
-                return STATUS_RESOURCE_TYPE_NOT_FOUND;
-
-             case 1:
-                return STATUS_RESOURCE_NAME_NOT_FOUND;
-
-             case 2:
-                Status = STATUS_RESOURCE_LANG_NOT_FOUND;
-                /* Just use first language entry */
-                if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
-                  {
-                     ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
-                     break;
-                  }
-                return Status;
-
-             case 3:
-                return STATUS_RESOURCE_DATA_NOT_FOUND;
-
-             default:
-                return STATUS_INVALID_PARAMETER;
-          }
-found:;
-        ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
-     }
-
-   if (addr)
-     {
-        *addr = (PVOID)ResDir;
-     }
-
-  return Status;
-}
-
-#endif /*MOVED_TO_FILE_RES_C*/
-
-NTSTATUS
-STDCALL
-LdrGetDllHandle(IN ULONG Unknown1,
-                IN ULONG Unknown2,
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
+                IN PULONG DllCharacteristics,
                 IN PUNICODE_STRING DllName,
-                OUT PVOID* BaseAddress)
+                OUT PVOID *DllHandle)
 {
-    UNICODE_STRING FullDllName;
-    PLIST_ENTRY ModuleListHead;
-    PLIST_ENTRY Entry;
-    PLDR_MODULE Module;
+    PLDR_DATA_TABLE_ENTRY Module;
+    NTSTATUS Status;
 
-    DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
-           Unknown1, Unknown2, DllName, BaseAddress);
+    TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
+               DllName, DllPath ? DllPath : L"");
 
     /* NULL is the current executable */
-    if (DllName == NULL) {
-        *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
-        DPRINT("BaseAddress %x\n", *BaseAddress);
+    if (DllName == NULL)
+      {
+        *DllHandle = ExeModule->DllBase;
+        DPRINT("BaseAddress 0x%lx\n", *DllHandle);
         return STATUS_SUCCESS;
-    }
-    LdrAdjustDllName(&FullDllName, DllName, TRUE);
-
-    DPRINT("FullDllName %wZ\n", &FullDllName);
-
-    ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-    Entry = ModuleListHead->Flink;
-    while (Entry != ModuleListHead) {
-        Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
-
-        DPRINT("EntryPoint %x\n", Module->EntryPoint);
-        DPRINT("Comparing %wZ and %wZ\n", &Module->BaseDllName, &FullDllName);
-
-        if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE)) {
-             RtlFreeUnicodeString(&FullDllName);
-             *BaseAddress = Module->BaseAddress;
-             DPRINT("BaseAddress %x\n", *BaseAddress);
-             return STATUS_SUCCESS;
-        }
-        Entry = Entry->Flink;
-    }
+      }
 
-    DPRINT("Failed to find dll %wZ\n", &FullDllName);
+    Status = LdrFindEntryForName(DllName, &Module, FALSE);
+    if (NT_SUCCESS(Status))
+      {
+        *DllHandle = Module->DllBase;
+        return STATUS_SUCCESS;
+      }
 
-    RtlFreeUnicodeString(&FullDllName);
-    *BaseAddress = NULL;
+    DPRINT("Failed to find dll %wZ\n", DllName);
+    *DllHandle = NULL;
     return STATUS_DLL_NOT_FOUND;
 }
 
 
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
 LdrGetProcedureAddress (IN PVOID BaseAddress,
                         IN PANSI_STRING Name,
                         IN ULONG Ordinal,
                         OUT PVOID *ProcedureAddress)
 {
-   PIMAGE_EXPORT_DIRECTORY ExportDir;
-   PUSHORT OrdinalPtr;
-   PULONG NamePtr;
-   PULONG AddressPtr;
-   ULONG i = 0;
-
-   DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
-          BaseAddress, Name, Ordinal, ProcedureAddress);
-
-   /* Get the pointer to the export directory */
-   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-                RtlImageDirectoryEntryToData (BaseAddress,
-                                              TRUE,
-                                              IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                              &i);
-
-   DPRINT("ExportDir %x i %lu\n", ExportDir, i);
-
-   if (!ExportDir || !i || !ProcedureAddress)
+   if (Name && Name->Length)
      {
-        return STATUS_INVALID_PARAMETER;
+       TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
      }
+   else
+     {
+       TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
+     }
+
+   DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
+          BaseAddress, Name, Ordinal, ProcedureAddress);
 
-   AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
    if (Name && Name->Length)
      {
-        /* by name */
-        OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
-        NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
-        for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
-          {
-             if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
-               {
-                  *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
-                  return STATUS_SUCCESS;
-               }
-          }
-        DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
+       /* by name */
+       *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
+       if (*ProcedureAddress != NULL)
+         {
+           return STATUS_SUCCESS;
+         }
+       DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
      }
    else
      {
-        /* by ordinal */
-        Ordinal &= 0x0000FFFF;
-        if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
-          {
-             *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
-             return STATUS_SUCCESS;
-          }
-        DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
-  }
-
+       /* by ordinal */
+       Ordinal &= 0x0000FFFF;
+       *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
+       if (*ProcedureAddress)
+         {
+           return STATUS_SUCCESS;
+         }
+       DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
+     }
    return STATUS_PROCEDURE_NOT_FOUND;
 }
 
-
-NTSTATUS STDCALL
-LdrShutdownProcess (VOID)
+/**********************************************************************
+ * NAME                                                         LOCAL
+ *      LdrpDetachProcess
+ *
+ * DESCRIPTION
+ *      Unload dll's which are no longer referenced from others dll's
+ *
+ * ARGUMENTS
+ *      none
+ *
+ * RETURN VALUE
+ *      none
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *      The loader lock must be held on enty.
+ */
+static VOID
+LdrpDetachProcess(BOOLEAN UnloadAll)
 {
    PLIST_ENTRY ModuleListHead;
    PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
+   PLDR_DATA_TABLE_ENTRY Module;
+   static ULONG CallingCount = 0;
 
-   DPRINT("LdrShutdownProcess() called\n");
+   DPRINT("LdrpDetachProcess() called for %wZ\n",
+           &ExeModule->BaseDllName);
 
-   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+   CallingCount++;
 
    ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
    Entry = ModuleListHead->Blink;
-
    while (Entry != ModuleListHead)
      {
-        Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
-
-        DPRINT("  Unloading %wZ\n",
-               &Module->BaseDllName);
-        // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
-        // they loaded dynamically, and when the last reference is gone, that lib will
-        // be detached.  
-        if (Module->EntryPoint != 0 && Module->LoadCount == -1)
-          {
-             PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+       if (((UnloadAll && Module->LoadCount == 0xFFFF) || Module->LoadCount == 0) &&
+           Module->Flags & LDRP_ENTRY_PROCESSED &&
+           !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
+         {
+           Module->Flags |= LDRP_UNLOAD_IN_PROGRESS;
+           if (Module == LdrpLastModule)
+             {
+               LdrpLastModule = NULL;
+             }
+           if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED)
+             {
+               TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
+                         &Module->BaseDllName, Module->EntryPoint);
+               LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(Module->LoadCount == 0xFFFF ? 1 : 0));
+             }
+           else
+             {
+               TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
+             }
+           Entry = ModuleListHead->Blink;
+         }
+       else
+         {
+           Entry = Entry->Blink;
+         }
+     }
 
-             DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-             Entrypoint (Module->BaseAddress,
-                         DLL_PROCESS_DETACH,
-                         NULL);
-          }
+   if (CallingCount == 1)
+     {
+       Entry = ModuleListHead->Blink;
+       while (Entry != ModuleListHead)
+         {
+           Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+           Entry = Entry->Blink;
+           if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
+               ((UnloadAll && Module->LoadCount != 0xFFFF) || Module->LoadCount == 0))
+             {
+               /* remove the module entry from the list */
+               RemoveEntryList (&Module->InLoadOrderModuleList);
+               RemoveEntryList (&Module->InInitializationOrderModuleList);
+
+               NtUnmapViewOfSection (NtCurrentProcess (), Module->DllBase);
+               NtClose (Module->SectionPointer);
+
+               TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
 
-        Entry = Entry->Blink;
+               RtlFreeUnicodeString (&Module->FullDllName);
+               RtlFreeUnicodeString (&Module->BaseDllName);
+
+               RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
+             }
+         }
      }
+   CallingCount--;
+   DPRINT("LdrpDetachProcess() done\n");
+}
 
-   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+/**********************************************************************
+ * NAME                                                         LOCAL
+ *      LdrpAttachProcess
+ *
+ * DESCRIPTION
+ *      Initialize all dll's which are prepered for loading
+ *
+ * ARGUMENTS
+ *      none
+ *
+ * RETURN VALUE
+ *      status
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *      The loader lock must be held on entry.
+ *
+ */
+static NTSTATUS
+LdrpAttachProcess(VOID)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_DATA_TABLE_ENTRY Module;
+   BOOLEAN Result;
+   NTSTATUS Status = STATUS_SUCCESS;
 
-   DPRINT("LdrShutdownProcess() done\n");
+   DPRINT("LdrpAttachProcess() called for %wZ\n",
+          &ExeModule->BaseDllName);
 
-   return STATUS_SUCCESS;
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Flink;
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+       if (!(Module->Flags & (LDRP_LOAD_IN_PROGRESS|LDRP_UNLOAD_IN_PROGRESS|LDRP_ENTRY_PROCESSED)))
+         {
+           Module->Flags |= LDRP_LOAD_IN_PROGRESS;
+           TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
+                     &Module->BaseDllName, Module->EntryPoint);
+           Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(Module->LoadCount == 0xFFFF ? 1 : 0));
+           if (!Result)
+             {
+               Status = STATUS_DLL_INIT_FAILED;
+               break;
+             }
+           if (Module->Flags & LDRP_IMAGE_DLL && Module->EntryPoint != 0)
+             {
+               Module->Flags |= LDRP_PROCESS_ATTACH_CALLED|LDRP_ENTRY_PROCESSED;
+             }
+           else
+             {
+               Module->Flags |= LDRP_ENTRY_PROCESSED;
+             }
+           Module->Flags &= ~LDRP_LOAD_IN_PROGRESS;
+         }
+       Entry = Entry->Flink;
+     }
+
+   DPRINT("LdrpAttachProcess() done\n");
+
+   return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrShutdownProcess (VOID)
+{
+  LdrpDetachProcess(TRUE);
+  return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+
+NTSTATUS
+LdrpAttachThread (VOID)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_DATA_TABLE_ENTRY Module;
+  NTSTATUS Status;
+
+  DPRINT("LdrpAttachThread() called for %wZ\n",
+         &ExeModule->BaseDllName);
+
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  Status = LdrpInitializeTlsForThread();
+
+  if (NT_SUCCESS(Status))
+    {
+      ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+      Entry = ModuleListHead->Flink;
+
+      while (Entry != ModuleListHead)
+        {
+          Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
+          if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
+              !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
+              !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
+            {
+              TRACE_LDR("%wZ - Calling entry point at %x for thread attaching\n",
+                        &Module->BaseDllName, Module->EntryPoint);
+              LdrpCallDllEntry(Module, DLL_THREAD_ATTACH, NULL);
+            }
+          Entry = Entry->Flink;
+        }
+
+      Entry = NtCurrentPeb()->Ldr->InLoadOrderModuleList.Flink;
+      Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
+      LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
+    }
+
+  RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  DPRINT("LdrpAttachThread() done\n");
+
+  return Status;
 }
 
 
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
 LdrShutdownThread (VOID)
 {
    PLIST_ENTRY ModuleListHead;
    PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
+   PLDR_DATA_TABLE_ENTRY Module;
 
-   DPRINT("LdrShutdownThread() called\n");
+   DPRINT("LdrShutdownThread() called for %wZ\n",
+          &ExeModule->BaseDllName);
 
    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
 
    ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
    Entry = ModuleListHead->Blink;
-
    while (Entry != ModuleListHead)
      {
-        Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+       Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
 
-        DPRINT("  Unloading %wZ\n",
-               &Module->BaseDllName);
-
-        if (Module->EntryPoint != 0)
-          {
-             PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
-
-             DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-             Entrypoint (Module->BaseAddress,
-                         DLL_THREAD_DETACH,
-                         NULL);
-          }
-
-        Entry = Entry->Blink;
+       if (Module->Flags & LDRP_PROCESS_ATTACH_CALLED &&
+           !(Module->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
+           !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
+         {
+           TRACE_LDR("%wZ - Calling entry point at %x for thread detaching\n",
+                     &Module->BaseDllName, Module->EntryPoint);
+           LdrpCallDllEntry(Module, DLL_THREAD_DETACH, NULL);
+         }
+       Entry = Entry->Blink;
      }
 
    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
 
+   if (LdrpTlsArray)
+     {
+       RtlFreeHeap (RtlGetProcessHeap(),  0, NtCurrentTeb()->ThreadLocalStoragePointer);
+     }
+
    DPRINT("LdrShutdownThread() done\n");
 
    return STATUS_SUCCESS;
@@ -1813,17 +2639,18 @@ LdrShutdownThread (VOID)
  * REVISIONS
  *
  * NOTE
+ *
+ * @implemented
  */
-NTSTATUS STDCALL
-LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
+NTSTATUS NTAPI
+LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation OPTIONAL,
                                  IN ULONG Size OPTIONAL,
                                  OUT PULONG ReturnedSize)
-
 {
   PLIST_ENTRY ModuleListHead;
   PLIST_ENTRY Entry;
-  PLDR_MODULE Module;
-  PMODULE_ENTRY ModulePtr = NULL;
+  PLDR_DATA_TABLE_ENTRY Module;
+  PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
   NTSTATUS Status = STATUS_SUCCESS;
   ULONG UsedSize = sizeof(ULONG);
   ANSI_STRING AnsiString;
@@ -1849,7 +2676,7 @@ LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTION
 
   while (Entry != ModuleListHead)
     {
-      Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+      Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
 
       DPRINT("  Module %wZ\n",
              &Module->FullDllName);
@@ -1860,31 +2687,30 @@ LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTION
         }
       else if (ModuleInformation != NULL)
         {
-          ModulePtr->Unknown0 = 0;      // FIXME: ??
-          ModulePtr->Unknown1 = 0;      // FIXME: ??
-          ModulePtr->BaseAddress = Module->BaseAddress;
-          ModulePtr->SizeOfImage = Module->SizeOfImage;
+          ModulePtr->Reserved[0] = ModulePtr->Reserved[1] = 0;      // FIXME: ??
+          ModulePtr->Base = Module->DllBase;
+          ModulePtr->Size = Module->SizeOfImage;
           ModulePtr->Flags = Module->Flags;
-          ModulePtr->Unknown2 = 0;      // FIXME: load order index ??
-          ModulePtr->Unknown3 = 0;      // FIXME: ??
+          ModulePtr->Index = 0;      // FIXME: index ??
+          ModulePtr->Unknown = 0;      // FIXME: ??
           ModulePtr->LoadCount = Module->LoadCount;
 
           AnsiString.Length = 0;
           AnsiString.MaximumLength = 256;
-          AnsiString.Buffer = ModulePtr->ModuleName;
+          AnsiString.Buffer = ModulePtr->ImageName;
           RtlUnicodeStringToAnsiString(&AnsiString,
                                        &Module->FullDllName,
                                        FALSE);
-          p = strrchr(ModulePtr->ModuleName, '\\');
+          p = strrchr(ModulePtr->ImageName, '\\');
           if (p != NULL)
-            ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
+            ModulePtr->ModuleNameOffset = p - ModulePtr->ImageName + 1;
           else
-            ModulePtr->PathLength = 0;
+            ModulePtr->ModuleNameOffset = 0;
 
           ModulePtr++;
           ModuleInformation->ModuleCount++;
         }
-      UsedSize += sizeof(MODULE_ENTRY);
+      UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
 
       Entry = Entry->Flink;
     }
@@ -1899,4 +2725,398 @@ LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTION
   return(Status);
 }
 
+
+static BOOLEAN
+LdrpCheckImageChecksum (IN PVOID BaseAddress,
+                        IN ULONG ImageSize)
+{
+  PIMAGE_NT_HEADERS Header;
+  PUSHORT Ptr;
+  ULONG Sum;
+  ULONG CalcSum;
+  ULONG HeaderSum;
+  ULONG i;
+
+  Header = RtlImageNtHeader (BaseAddress);
+  if (Header == NULL)
+    return FALSE;
+
+  HeaderSum = Header->OptionalHeader.CheckSum;
+  if (HeaderSum == 0)
+    return TRUE;
+
+   Sum = 0;
+   Ptr = (PUSHORT) BaseAddress;
+   for (i = 0; i < ImageSize / sizeof (USHORT); i++)
+     {
+      Sum += (ULONG)*Ptr;
+      if (HIWORD(Sum) != 0)
+        {
+          Sum = LOWORD(Sum) + HIWORD(Sum);
+        }
+      Ptr++;
+     }
+
+  if (ImageSize & 1)
+    {
+      Sum += (ULONG)*((PUCHAR)Ptr);
+      if (HIWORD(Sum) != 0)
+        {
+          Sum = LOWORD(Sum) + HIWORD(Sum);
+        }
+    }
+
+  CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
+
+  /* Subtract image checksum from calculated checksum. */
+  /* fix low word of checksum */
+  if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
+    {
+      CalcSum -= LOWORD(HeaderSum);
+    }
+  else
+    {
+      CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
+    }
+
+   /* fix high word of checksum */
+  if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
+    {
+      CalcSum -= HIWORD(HeaderSum);
+    }
+  else
+    {
+      CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
+    }
+
+  /* add file length */
+  CalcSum += ImageSize;
+
+  return (BOOLEAN)(CalcSum == HeaderSum);
+}
+
+/*
+ * Compute size of an image as it is actually present in virt memory
+ * (i.e. excluding NEVER_LOAD sections)
+ */
+ULONG
+LdrpGetResidentSize(PIMAGE_NT_HEADERS NTHeaders)
+{
+  PIMAGE_SECTION_HEADER SectionHeader;
+  unsigned SectionIndex;
+  ULONG ResidentSize;
+
+  SectionHeader = (PIMAGE_SECTION_HEADER)((char *) &NTHeaders->OptionalHeader
+                                          + NTHeaders->FileHeader.SizeOfOptionalHeader);
+  ResidentSize = 0;
+  for (SectionIndex = 0; SectionIndex < NTHeaders->FileHeader.NumberOfSections; SectionIndex++)
+    {
+      if (0 == (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE)
+          && ResidentSize < SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize)
+        {
+          ResidentSize = SectionHeader->VirtualAddress + SectionHeader->Misc.VirtualSize;
+        }
+      SectionHeader++;
+    }
+
+  return ResidentSize;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrVerifyImageMatchesChecksum
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
+                               ULONG Unknown1,
+                               ULONG Unknown2,
+                               ULONG Unknown3)
+{
+  FILE_STANDARD_INFORMATION FileInfo;
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE SectionHandle;
+  ULONG ViewSize;
+  PVOID BaseAddress;
+  BOOLEAN Result;
+  NTSTATUS Status;
+
+  DPRINT ("LdrVerifyImageMatchesChecksum() called\n");
+
+  Status = NtCreateSection (&SectionHandle,
+                            SECTION_MAP_READ,
+                            NULL,
+                            NULL,
+                            PAGE_READONLY,
+                            SEC_COMMIT,
+                            FileHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("NtCreateSection() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  ViewSize = 0;
+  BaseAddress = NULL;
+  Status = NtMapViewOfSection (SectionHandle,
+                               NtCurrentProcess (),
+                               &BaseAddress,
+                               0,
+                               0,
+                               NULL,
+                               &ViewSize,
+                               ViewShare,
+                               0,
+                               PAGE_READONLY);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
+      NtClose (SectionHandle);
+      return Status;
+    }
+
+  Status = NtQueryInformationFile (FileHandle,
+                                   &IoStatusBlock,
+                                   &FileInfo,
+                                   sizeof (FILE_STANDARD_INFORMATION),
+                                   FileStandardInformation);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("NtMapViewOfSection() failed (Status %lx)\n", Status);
+      NtUnmapViewOfSection (NtCurrentProcess (),
+                            BaseAddress);
+      NtClose (SectionHandle);
+      return Status;
+    }
+
+  Result = LdrpCheckImageChecksum (BaseAddress,
+                                   FileInfo.EndOfFile.u.LowPart);
+  if (Result == FALSE)
+    {
+      Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
+    }
+
+  NtUnmapViewOfSection (NtCurrentProcess (),
+                        BaseAddress);
+
+  NtClose (SectionHandle);
+
+  return Status;
+}
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrQueryImageFileExecutionOptions
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrQueryImageFileExecutionOptions (IN PUNICODE_STRING SubKey,
+                                   IN PCWSTR ValueName,
+                                   IN ULONG Type,
+                                   OUT PVOID Buffer,
+                                   IN ULONG BufferSize,
+                                   OUT PULONG ReturnedLength OPTIONAL)
+{
+  PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING ValueNameString;
+  UNICODE_STRING KeyName;
+  WCHAR NameBuffer[256];
+  HANDLE KeyHandle;
+  ULONG KeyInfoSize;
+  ULONG ResultSize;
+  PWCHAR Ptr;
+  NTSTATUS Status;
+
+  wcscpy (NameBuffer,
+          L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
+  Ptr = wcsrchr (SubKey->Buffer, L'\\');
+  if (Ptr == NULL)
+    {
+      Ptr = SubKey->Buffer;
+    }
+  else
+    {
+      Ptr++;
+    }
+  wcscat (NameBuffer, Ptr);
+  RtlInitUnicodeString (&KeyName,
+                        NameBuffer);
+
+  InitializeObjectAttributes (&ObjectAttributes,
+                              &KeyName,
+                              OBJ_CASE_INSENSITIVE,
+                              NULL,
+                              NULL);
+
+  Status = NtOpenKey (&KeyHandle,
+                      KEY_READ,
+                      &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32;
+  KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
+                             HEAP_ZERO_MEMORY,
+                             KeyInfoSize);
+  if (KeyInfo == NULL)
+    {
+      NtClose (KeyHandle);
+      return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+  RtlInitUnicodeString (&ValueNameString,
+                        (PWSTR)ValueName);
+  Status = NtQueryValueKey (KeyHandle,
+                            &ValueNameString,
+                            KeyValuePartialInformation,
+                            KeyInfo,
+                            KeyInfoSize,
+                            &ResultSize);
+  if (Status == STATUS_BUFFER_OVERFLOW)
+    {
+      KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
+      RtlFreeHeap (RtlGetProcessHeap(),
+                   0,
+                   KeyInfo);
+      KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
+                                 HEAP_ZERO_MEMORY,
+                                 KeyInfoSize);
+      if (KeyInfo == NULL)
+        {
+          NtClose (KeyHandle);
+          return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+      Status = NtQueryValueKey (KeyHandle,
+                                &ValueNameString,
+                                KeyValuePartialInformation,
+                                KeyInfo,
+                                KeyInfoSize,
+                                &ResultSize);
+    }
+  NtClose (KeyHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      if (KeyInfo != NULL)
+        {
+          RtlFreeHeap (RtlGetProcessHeap(),
+                       0,
+                       KeyInfo);
+        }
+      return Status;
+    }
+
+  if (KeyInfo->Type != Type)
+    {
+      RtlFreeHeap (RtlGetProcessHeap(),
+                   0,
+                   KeyInfo);
+      return STATUS_OBJECT_TYPE_MISMATCH;
+    }
+
+  ResultSize = BufferSize;
+  if (ResultSize < KeyInfo->DataLength)
+    {
+      Status = STATUS_BUFFER_OVERFLOW;
+    }
+  else
+    {
+      ResultSize = KeyInfo->DataLength;
+    }
+  RtlCopyMemory (Buffer,
+                 &KeyInfo->Data,
+                 ResultSize);
+
+  RtlFreeHeap (RtlGetProcessHeap(),
+               0,
+               KeyInfo);
+
+  if (ReturnedLength != NULL)
+    {
+      *ReturnedLength = ResultSize;
+    }
+
+  return Status;
+}
+
+
+PIMAGE_BASE_RELOCATION NTAPI
+LdrProcessRelocationBlock(IN PVOID Address,
+                         IN USHORT Count,
+                         IN PUSHORT TypeOffset,
+                         IN ULONG_PTR Delta)
+{
+  SHORT Offset;
+  USHORT Type;
+  USHORT i;
+  PUSHORT ShortPtr;
+  PULONG LongPtr;
+
+  for (i = 0; i < Count; i++)
+    {
+      Offset = *TypeOffset & 0xFFF;
+      Type = *TypeOffset >> 12;
+
+      switch (Type)
+        {
+          case IMAGE_REL_BASED_ABSOLUTE:
+            break;
+
+          case IMAGE_REL_BASED_HIGH:
+            ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
+            *ShortPtr += HIWORD(Delta);
+            break;
+
+          case IMAGE_REL_BASED_LOW:
+            ShortPtr = (PUSHORT)((ULONG_PTR)Address + Offset);
+            *ShortPtr += LOWORD(Delta);
+            break;
+
+          case IMAGE_REL_BASED_HIGHLOW:
+            LongPtr = (PULONG)((ULONG_PTR)Address + Offset);
+            *LongPtr += Delta;
+            break;
+
+          case IMAGE_REL_BASED_HIGHADJ:
+          case IMAGE_REL_BASED_MIPS_JMPADDR:
+          default:
+            DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
+            return NULL;
+        }
+
+      TypeOffset++;
+    }
+
+  return (PIMAGE_BASE_RELOCATION)TypeOffset;
+}
+
 /* EOF */