- Update NDK with proper (when possible) RTL structure names that were previously...
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
index c0700f6..1c9240d 100644 (file)
@@ -1,50 +1,77 @@
-/* $Id: utils.c,v 1.57 2002/10/01 19:27:20 chorns Exp $
- * 
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
- * FILE:            lib/ntdll/ldr/startup.c
+ * 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
- *     - any more ??
+ *      - 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,40 +82,333 @@ 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");
+}
 
 
 /***************************************************************************
- * NAME                                                                LOCAL
- *     LdrAdjustDllName
+ * NAME                                                         LOCAL
+ *      LdrAdjustDllName
  *
  * DESCRIPTION
- *     Adjusts the name of a dll to a fully qualified name.
+ *      Adjusts the name of a dll to a fully qualified name.
  *
  * ARGUMENTS
- *     FullDllName:    Pointer to caller supplied storage for the fully
- *                     qualified dll name.
- *     DllName:        Pointer to the dll name.
- *     BaseName:       TRUE:  Only the file name is passed to FullDllName
- *                     FALSE: The full path is preserved in FullDllName
+ *      FullDllName:    Pointer to caller supplied storage for the fully
+ *                      qualified dll name.
+ *      DllName:        Pointer to the dll name.
+ *      BaseName:       TRUE:  Only the file name is passed to FullDllName
+ *                      FALSE: The full path is preserved in FullDllName
  *
  * RETURN VALUE
- *     None
+ *      None
  *
  * REVISIONS
  *
  * NOTE
- *     A given path is not affected by the adjustment, but the file
- *     name only:
- *       ntdll      --> ntdll.dll
- *       ntdll.     --> ntdll
- *       ntdll.xyz  --> ntdll.xyz
+ *      A given path is not affected by the adjustment, but the file
+ *      name only:
+ *        ntdll      --> ntdll.dll
+ *        ntdll.     --> ntdll
+ *        ntdll.xyz  --> ntdll.xyz
  */
-
 static VOID
 LdrAdjustDllName (PUNICODE_STRING FullDllName,
-                 PUNICODE_STRING DllName,
-                 BOOLEAN BaseName)
+                  PUNICODE_STRING DllName,
+                  BOOLEAN BaseName)
 {
    WCHAR Buffer[MAX_PATH];
    ULONG Length;
@@ -97,237 +417,252 @@ LdrAdjustDllName (PUNICODE_STRING FullDllName,
 
    Length = DllName->Length / sizeof(WCHAR);
 
-   if (BaseName == TRUE)
+   if (BaseName)
      {
-       /* get the base dll name */
-       Pointer = DllName->Buffer + Length;
-       Extension = Pointer;
-
-       do
-         {
-            --Pointer;
-         }
-       while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
-
-       Pointer++;
-       Length = Extension - Pointer;
-       memmove (Buffer, Pointer, Length * sizeof(WCHAR));
-       Buffer[Length] = L'\0';
+        /* get the base dll name */
+        Pointer = DllName->Buffer + Length;
+        Extension = Pointer;
+
+        do
+          {
+             --Pointer;
+          }
+        while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
+
+        Pointer++;
+        Length = Extension - Pointer;
+        memmove (Buffer, Pointer, Length * sizeof(WCHAR));
+        Buffer[Length] = L'\0';
      }
    else
      {
-       /* get the full dll name */
-       memmove (Buffer, DllName->Buffer, DllName->Length);
-       Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
+        /* get the full dll name */
+        memmove (Buffer, DllName->Buffer, DllName->Length);
+        Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
      }
 
    /* Build the DLL's absolute name */
    Extension = wcsrchr (Buffer, L'.');
    if ((Extension != NULL) && (*Extension == L'.'))
      {
-       /* with extension - remove dot if it's the last character */
-       if (Buffer[Length - 1] == L'.')
-                       Length--;
-       Buffer[Length] = 0;
+        /* with extension - remove dot if it's the last character */
+        if (Buffer[Length - 1] == L'.')
+                        Length--;
+        Buffer[Length] = 0;
      }
    else
      {
-       /* name without extension - assume that it is .dll */
-       memmove (Buffer + Length, L".dll", 10);
+        /* name without extension - assume that it is .dll */
+        memmove (Buffer + Length, L".dll", 10);
      }
 
-   RtlCreateUnicodeString (FullDllName,
-                          Buffer);
+   RtlCreateUnicodeString(FullDllName, Buffer);
 }
 
-PLDR_MODULE
-LdrAddModuleEntry(PVOID ImageBase, PIMAGE_NT_HEADERS NTHeaders,
-                 PWSTR FullDosName)
+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 */
       Module->LoadCount = 1;
-    }
-  else
-    {
+    } else {
       /*
        * 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;
 
   RtlCreateUnicodeString (&Module->FullDllName,
-                         FullDosName);
+                          FullDosName);
   RtlCreateUnicodeString (&Module->BaseDllName,
-                         wcsrchr(FullDosName, L'\\') + 1);
+                          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 */
+                 &Module->InLoadOrderModuleList);
+  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)
 {
-  WCHAR                        SearchPathBuffer[MAX_PATH];
-  WCHAR                        FullDosName[MAX_PATH];
-  UNICODE_STRING               AdjustedName;
-  UNICODE_STRING               FullNtFileName;
-  OBJECT_ATTRIBUTES    FileObjectAttributes;
-  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)
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+
+  DPRINT("LdrpMapKnownDll() called\n");
+
+  if (LdrpKnownDllsDirHandle == NULL)
     {
-      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
-      return STATUS_SUCCESS;
+      DPRINT("Invalid 'KnownDlls' directory\n");
+      return STATUS_UNSUCCESSFUL;
     }
-  
-  *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("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 %lx)\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)
     {
-      DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
-      if (Module->LoadCount != -1)
-       Module->LoadCount++;
-      *BaseAddress = Module->BaseAddress;
+      FullDosName->Length = 0;
+      FullDosName->MaximumLength = 0;
       return STATUS_SUCCESS;
     }
-  DPRINT("Loading \"%wZ\"\n", Name);
-  
+
+  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                 DosName[MAX_PATH];
+  UNICODE_STRING        FullNtFileName;
+  OBJECT_ATTRIBUTES     FileObjectAttributes;
+  HANDLE                FileHandle;
+  char                  BlockBuffer [1024];
+  PIMAGE_DOS_HEADER     DosHeader;
+  PIMAGE_NT_HEADERS     NTHeaders;
+  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,
-                         NULL,
-                         MAX_PATH,
-                         FullDosName,
-                         NULL) == 0)
+                          DllName->Buffer,
+                          NULL,
+                          MAX_PATH,
+                          DosName,
+                          NULL) == 0)
     return STATUS_DLL_NOT_FOUND;
-  
-  DPRINT("FullDosName %S\n", FullDosName);
-  
-  RtlFreeUnicodeString (&AdjustedName);
-  
-  if (!RtlDosPathNameToNtPathName_U (FullDosName,
-                                    &FullNtFileName,
-                                    NULL,
-                                    NULL))
+
+
+  if (!RtlDosPathNameToNtPathName_U (DosName,
+                                     &FullNtFileName,
+                                     NULL,
+                                     NULL))
     return STATUS_DLL_NOT_FOUND;
-  
+
   DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
-  
+
   InitializeObjectAttributes(&FileObjectAttributes,
-                            &FullNtFileName,
-                            0,
-                            NULL,
-                            NULL);
-  
+                             &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", 
-              &FullNtFileName, Status);
+      DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
+               &FullNtFileName, Status);
       RtlFreeUnicodeString (&FullNtFileName);
       return Status;
     }
   RtlFreeUnicodeString (&FullNtFileName);
-  
-  Status = ZwReadFile(FileHandle,
-                     0,
-                     0,
-                     0,
-                     0,
-                     BlockBuffer,
-                     sizeof(BlockBuffer),
-                     0,
-                     0);
+
+  Status = NtReadFile(FileHandle,
+                      NULL,
+                      NULL,
+                      NULL,
+                      &IoStatusBlock,
+                      BlockBuffer,
+                      sizeof(BlockBuffer),
+                      NULL,
+                      NULL);
   if (!NT_SUCCESS(Status))
     {
       DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
-      ZwClose(FileHandle);
+      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;
@@ -335,119 +670,98 @@ 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,
-                          SECTION_ALL_ACCESS,
-                          NULL,
-                          NULL,
-                          PAGE_READWRITE,
-                          SEC_COMMIT | SEC_IMAGE,
-                          FileHandle);
+  Status = NtCreateSection(SectionHandle,
+                           SECTION_ALL_ACCESS,
+                           NULL,
+                           NULL,
+                           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);
       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
+  RtlCreateUnicodeString(FullDosName,
+                         DosName);
+
+  return Status;
+}
+
 
-  LdrpLoadUserModuleSymbols(Module);
 
-#endif /* DBG */
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrLoadDll
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
+            IN ULONG LoadFlags,
+            IN PUNICODE_STRING Name,
+            OUT PVOID *BaseAddress OPTIONAL)
+{
+  NTSTATUS              Status;
+  PLDR_DATA_TABLE_ENTRY           Module;
+
+  TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
+            Name,
+            SearchPath ? " from " : "",
+            SearchPath ? SearchPath : L"");
 
-  /* initialize dll */
-  if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
-      IMAGE_FILE_DLL)
+  if (Name == NULL)
     {
-      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))
-           {
-             DPRINT("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);
-       }
+      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+      return STATUS_SUCCESS;
     }
 
-  *BaseAddress = Module->BaseAddress;
-  return STATUS_SUCCESS;
+  *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
+ * NAME                                                         EXPORTED
+ *      LdrFindEntryForAddress
  *
  * DESCRIPTION
  *
@@ -459,50 +773,57 @@ LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
  *
  * NOTE
  *
+ * @implemented
  */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 LdrFindEntryForAddress(PVOID Address,
-                      PLDR_MODULE *Module)
+                       PLDR_DATA_TABLE_ENTRY *Module)
 {
   PLIST_ENTRY ModuleListHead;
   PLIST_ENTRY Entry;
-  PLDR_MODULE ModulePtr;
+  PLDR_DATA_TABLE_ENTRY ModulePtr;
 
-  DPRINT("NTDLL.LdrFindEntryForAddress(Address %p)\n", Address);
+  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)
-    return(STATUS_NO_MORE_ENTRIES);
+    {
+      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)))
-       {
-         *Module = ModulePtr;
-         return(STATUS_SUCCESS);
-       }
+      if ((Address >= ModulePtr->DllBase) &&
+          ((ULONG_PTR)Address <= ((ULONG_PTR)ModulePtr->DllBase + ModulePtr->SizeOfImage)))
+        {
+          *Module = ModulePtr;
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+          return(STATUS_SUCCESS);
+        }
 
       Entry = Entry->Flink;
     }
 
   DPRINT("Failed to find module entry.\n");
 
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
   return(STATUS_NO_MORE_ENTRIES);
 }
 
 
 /***************************************************************************
- * NAME                                                                LOCAL
- *     LdrFindEntryForName
+ * NAME                                                         LOCAL
+ *      LdrFindEntryForName
  *
  * DESCRIPTION
  *
@@ -517,52 +838,97 @@ 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);
     }
 
-  while (Entry != ModuleListHead)
-    {
-      ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+  LdrAdjustDllName (&AdjustedName, Name, FALSE);
 
-      DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, Name);
+  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 (RtlCompareUnicodeString(&ModulePtr->BaseDllName, Name, TRUE) == 0)
-       {
-         *Module = ModulePtr;
-         return(STATUS_SUCCESS);
-       }
+  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_DATA_TABLE_ENTRY, InLoadOrderModuleList);
+
+      DPRINT("Scanning %wZ %wZ\n", &ModulePtr->BaseDllName, &AdjustedName);
+
+      if ((! ContainsPath &&
+           0 == RtlCompareUnicodeString(&ModulePtr->BaseDllName, &AdjustedName, TRUE)) ||
+          (ContainsPath &&
+           0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
+        {
+          *Module = LdrpLastModule = ModulePtr;
+          if (Ref && ModulePtr->LoadCount != 0xFFFF)
+            {
+              ModulePtr->LoadCount++;
+            }
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+          RtlFreeUnicodeString(&AdjustedName);
+          return(STATUS_SUCCESS);
+        }
 
       Entry = Entry->Flink;
     }
 
   DPRINT("Failed to find dll %wZ\n", Name);
-
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+  RtlFreeUnicodeString(&AdjustedName);
   return(STATUS_NO_MORE_ENTRIES);
 }
 
 /**********************************************************************
- * NAME                                                                LOCAL
- *     LdrFixupForward
+ * NAME                                                         LOCAL
+ *      LdrFixupForward
  *
  * DESCRIPTION
  *
@@ -580,40 +946,46 @@ 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);
    p = strchr(NameBuffer, '.');
    if (p != NULL)
      {
-       *p = 0;
-
-       DPRINT("Dll: %s  Function: %s\n", NameBuffer, p+1);
-       RtlCreateUnicodeStringFromAsciiz (&DllName,
-                                         NameBuffer);
-
-       Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
-       if (!NT_SUCCESS(Status))
-         {
-            Status = LdrLoadDll(NULL,
-                                0,
-                                &DllName,
-                                &BaseAddress);
-            if (!NT_SUCCESS(Status))
-              {
-                 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
-                 RtlFreeUnicodeString (&DllName);
-                 return NULL;
-              }
-         }
-
-       RtlFreeUnicodeString (&DllName);
-       DPRINT("BaseAddress: %p\n", BaseAddress);
-       
-       return LdrGetExportByName(BaseAddress, p+1, -1);
+        *p = 0;
+
+        DPRINT("Dll: %s  Function: %s\n", NameBuffer, p+1);
+        RtlCreateUnicodeStringFromAsciiz (&DllName,
+                                          NameBuffer);
+
+        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,
+                                 LDRP_PROCESS_CREATION_TIME,
+                                 &DllName,
+                                 &BaseAddress);
+             if (NT_SUCCESS(Status))
+               {
+                 Status = LdrFindEntryForName (&DllName, &Module, FALSE);
+               }
+          }
+        RtlFreeUnicodeString (&DllName);
+        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;
@@ -621,9 +993,9 @@ LdrFixupForward(PCHAR ForwardName)
 
 
 /**********************************************************************
- * NAME                                                                LOCAL
- *     LdrGetExportByOrdinal
- *     
+ * NAME                                                         LOCAL
+ *      LdrGetExportByOrdinal
+ *
  * DESCRIPTION
  *
  * ARGUMENTS
@@ -637,44 +1009,52 @@ LdrFixupForward(PCHAR ForwardName)
  */
 static PVOID
 LdrGetExportByOrdinal (
-       PVOID   BaseAddress,
-       ULONG   Ordinal
-       )
+        PVOID   BaseAddress,
+        ULONG   Ordinal
+        )
 {
-       PIMAGE_EXPORT_DIRECTORY ExportDir;
-       PDWORD                  * ExFunctions;
-       USHORT                  * ExOrdinals;
-
-       ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-               RtlImageDirectoryEntryToData (BaseAddress,
-                                             TRUE,
-                                             IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                             NULL);
-
-
-       ExOrdinals = (USHORT *)
-               RVA(
-                       BaseAddress,
-                       ExportDir->AddressOfNameOrdinals
-                       );
-       ExFunctions = (PDWORD *)
-               RVA(
-                       BaseAddress,
-                       ExportDir->AddressOfFunctions
-                       );
-       DbgPrint(
-               "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
-               Ordinal,
-               ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
-               );
-       return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
+        PIMAGE_EXPORT_DIRECTORY ExportDir;
+        ULONG                   ExportDirSize;
+        PDWORD                  * ExFunctions;
+        PVOID                   Function;
+
+        ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+                RtlImageDirectoryEntryToData (BaseAddress,
+                                              TRUE,
+                                              IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                              &ExportDirSize);
+
+
+        ExFunctions = (PDWORD *)
+                RVA(
+                        BaseAddress,
+                        ExportDir->AddressOfFunctions
+                        );
+        DPRINT(
+                "LdrGetExportByOrdinal(Ordinal %d) = %p\n",
+                Ordinal,
+                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
- *     
+ * NAME                                                         LOCAL
+ *      LdrGetExportByName
+ *
  * DESCRIPTION
  *
  * ARGUMENTS
@@ -684,143 +1064,141 @@ LdrGetExportByOrdinal (
  * REVISIONS
  *
  * NOTE
+ *  AddressOfNames and AddressOfNameOrdinals are paralell tables,
+ *  both with NumberOfNames entries.
  *
  */
 static PVOID
 LdrGetExportByName(PVOID BaseAddress,
-                  PUCHAR SymbolName,
-                  WORD Hint)
+                   PUCHAR SymbolName,
+                   WORD Hint)
 {
-   PIMAGE_EXPORT_DIRECTORY     ExportDir;
-   PDWORD                      * ExFunctions;
-   PDWORD                      * ExNames;
-   USHORT                      * ExOrdinals;
-   ULONG                       i;
-   PVOID                       ExName;
-   ULONG                       Ordinal;
-   PVOID                       Function;
-   ULONG minn, maxn;
+   PIMAGE_EXPORT_DIRECTORY      ExportDir;
+   PDWORD                       * ExFunctions;
+   PDWORD                       * ExNames;
+   USHORT                       * ExOrdinals;
+   PVOID                        ExName;
+   ULONG                        Ordinal;
+   PVOID                        Function;
+   LONG minn, maxn;
    ULONG ExportDirSize;
-   
+
    DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
-   
+
    ExportDir = (PIMAGE_EXPORT_DIRECTORY)
      RtlImageDirectoryEntryToData(BaseAddress,
-                                 TRUE,
-                                 IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                 &ExportDirSize);
+                                  TRUE,
+                                  IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                  &ExportDirSize);
    if (ExportDir == NULL)
      {
-       DbgPrint("LdrGetExportByName(): no export directory!\n");
-       return NULL;
+        DPRINT1("LdrGetExportByName(): no export directory!\n");
+        return NULL;
      }
-   
+
+
+   //The symbol names may be missing entirely
+   if (ExportDir->AddressOfNames == 0)
+   {
+      DPRINT("LdrGetExportByName(): symbol names missing entirely\n");
+      return NULL;
+   }
+
    /*
     * Get header pointers
     */
    ExNames = (PDWORD *)RVA(BaseAddress,
-                          ExportDir->AddressOfNames);
+                           ExportDir->AddressOfNames);
    ExOrdinals = (USHORT *)RVA(BaseAddress,
-                             ExportDir->AddressOfNameOrdinals);
+                              ExportDir->AddressOfNameOrdinals);
    ExFunctions = (PDWORD *)RVA(BaseAddress,
-                              ExportDir->AddressOfFunctions);
-   
+                               ExportDir->AddressOfFunctions);
+
    /*
     * Check the hint first
     */
-   if (Hint < ExportDir->NumberOfFunctions)
+   if (Hint < ExportDir->NumberOfNames)
      {
-       ExName = RVA(BaseAddress, ExNames[Hint]);
-       if (strcmp(ExName, SymbolName) == 0)
-         {
-            Ordinal = ExOrdinals[Hint];
-            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
-            if (((ULONG)Function >= (ULONG)ExportDir) &&
-                ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
-              {
-                 DPRINT("Forward: %s\n", (PCHAR)Function);
-                 Function = LdrFixupForward((PCHAR)Function);
-              }
-            if (Function != NULL)
-              return Function;
-         }
+        ExName = RVA(BaseAddress, ExNames[Hint]);
+        if (strcmp(ExName, (PCHAR)SymbolName) == 0)
+          {
+             Ordinal = ExOrdinals[Hint];
+             Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+             if (((ULONG)Function >= (ULONG)ExportDir) &&
+                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+               {
+                  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->NumberOfFunctions;
+   maxn = ExportDir->NumberOfNames - 1;
    while (minn <= maxn)
      {
-       ULONG mid;
-       LONG res;
-
-       mid = (minn + maxn) / 2;
-
-       ExName = RVA(BaseAddress, ExNames[mid]);
-       res = strcmp(ExName, SymbolName);
-       if (res == 0)
-         {
-            Ordinal = ExOrdinals[mid];
-            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
-            if (((ULONG)Function >= (ULONG)ExportDir) &&
-                ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
-              {
-                 DPRINT("Forward: %s\n", (PCHAR)Function);
-                 Function = LdrFixupForward((PCHAR)Function);
-              }
-            if (Function != NULL)
-              return Function;
-         }
-       else if (minn == maxn)
-         {
-            DPRINT("LdrGetExportByName(): binary search failed\n");
-            break;
-         }
-       else if (res > 0)
-         {
-            maxn = mid - 1;
-         }
-       else
-         {
-            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->NumberOfFunctions; 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;
-         }
+        LONG mid;
+        LONG res;
+
+        mid = (minn + maxn) / 2;
+
+        ExName = RVA(BaseAddress, ExNames[mid]);
+        res = strcmp(ExName, (PCHAR)SymbolName);
+        if (res == 0)
+          {
+             Ordinal = ExOrdinals[mid];
+             Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+             if (((ULONG)Function >= (ULONG)ExportDir) &&
+                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+               {
+                  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;
+          }
+        else if (minn == maxn)
+          {
+             DPRINT("LdrGetExportByName(): binary search failed\n");
+             break;
+          }
+        else if (res > 0)
+          {
+             maxn = mid - 1;
+          }
+        else
+          {
+             minn = mid + 1;
+          }
      }
-   DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
-   return NULL;
+
+   DPRINT1("LdrGetExportByName(): failed to find %s\n",SymbolName);
+   return (PVOID)NULL;
 }
 
 
 /**********************************************************************
- * NAME                                                                LOCAL
- *     LdrPerformRelocations
- *     
+ * NAME                                                         LOCAL
+ *      LdrPerformRelocations
+ *
  * DESCRIPTION
- *     Relocate a DLL's memory image.
- *     
+ *      Relocate a DLL's memory image.
+ *
  * ARGUMENTS
  *
  * RETURN VALUE
@@ -830,344 +1208,670 @@ 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)
+    {
+      return STATUS_SUCCESS;
+    }
+
+  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);
+
+  while (RelocationDir < RelocationEnd &&
+         RelocationDir->SizeOfBlock > 0)
     {
-      RelocationDir = 
-       (PRELOCATION_DIRECTORY)((PCHAR)ImageBase + RelocationRVA);
-
-      while (RelocationDir->SizeOfBlock)
-       {
-         if (RelocationDir->VirtualAddress > MaxExtend)
-           {
-             RelocationRVA += RelocationDir->SizeOfBlock;
-             RelocationDir = 
-               (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
-             continue;
-           }
-
-         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);
-
-         Status = NtProtectVirtualMemory(NtCurrentProcess(),
-                                         ImageBase + 
-                                         RelocationDir->VirtualAddress,
-                                         PAGE_SIZE,
-                                         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);
-         if (!NT_SUCCESS(Status))
-           {
-             DPRINT1("Failed to protect relocation target.\n");
-             return(Status);
-           }
-
-         RelocationRVA += RelocationDir->SizeOfBlock;
-         RelocationDir = 
-           (PRELOCATION_DIRECTORY) (ImageBase + RelocationRVA);
-       }
+      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(),
+                                          &ProtectPage2,
+                                          &ProtectSize,
+                                          PAGE_READWRITE,
+                                          &OldProtect2);
+          if (!NT_SUCCESS(Status))
+            {
+              DPRINT1("Failed to unprotect relocation target (2).\n");
+              NtProtectVirtualMemory(NtCurrentProcess(),
+                                     &ProtectPage,
+                                     &ProtectSize,
+                                     OldProtect,
+                                     &OldProtect);
+              return Status;
+            }
+        }
+      else
+        {
+          ProtectPage2 = NULL;
+        }
+
+      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;
 
-/**********************************************************************
- * NAME                                                                LOCAL
- *     LdrFixupImports
- *     
- * DESCRIPTION
- *     Compute the entry point for every symbol the DLL imports
- *     from other modules.
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
+   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(%x '%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 %x '%wZ', %x '%wZ', %x '%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.
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
  * REVISIONS
  *
  * 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 %x, Module %x)\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 %x\n", BoundImportDescriptor);
+
+       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)
+     {
+       DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
+
+       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++;
+         }
+     }
 
-   while (ImportModuleDirectory->dwRVAModuleName)
+   if (TlsDirectory && TlsSize > 0)
      {
-       PVOID   * ImportAddressList;
-       PULONG  FunctionNameList;
-       UNICODE_STRING DllName;
-       DWORD   pName;
-       WORD    pHint;
-       PVOID   IATBase;
-       ULONG   OldProtect;
-
-       DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
-              (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
-
-       RtlCreateUnicodeStringFromAsciiz (&DllName,
-                 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
-
-       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++;
+       LdrpAcquireTlsSlot(Module, TlsSize, FALSE);
      }
+
    return STATUS_SUCCESS;
 }
 
 
 /**********************************************************************
  * NAME
- *     LdrPEStartup
+ *      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
- *             is loaded.
- *             
- *     SectionHandle
- *             Handle of the section that contains
- *             the DLL's image.
+ *      ImageBase
+ *              Address at which the EXE's image
+ *              is loaded.
+ *
+ *      SectionHandle
+ *              Handle of the section that contains
+ *              the EXE's image.
  *
  * RETURN VALUE
- *     NULL on error; otherwise the entry point
- *     to call for initializing the DLL.
+ *      NULL on error; otherwise the entry point
+ *      to call for initializing the DLL.
  *
  * 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,
-                     PWSTR FullDosName)
+                      HANDLE SectionHandle,
+                      PLDR_DATA_TABLE_ENTRY* Module,
+                      PWSTR FullDosName)
 {
-   NTSTATUS            Status;
-   PEPFUNC             EntryPoint = NULL;
-   PIMAGE_DOS_HEADER   DosHeader;
-   PIMAGE_NT_HEADERS   NTHeaders;
+   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);
@@ -1177,7 +1881,7 @@ PEPFUNC LdrPEStartup (PVOID  ImageBase,
     * 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
@@ -1186,35 +1890,63 @@ 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");
-          return NULL;
-        }
+         {
+           DPRINT1("LdrPerformRelocations() failed\n");
+           return NULL;
+         }
      }
 
    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;
      }
 
    /*
@@ -1224,586 +1956,670 @@ PEPFUNC LdrPEStartup (PVOID  ImageBase,
    DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
    if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
      {
-       EntryPoint = (PEPFUNC) (ImageBase
-                          + NTHeaders->OptionalHeader.AddressOfEntryPoint);
+        EntryPoint = (PEPFUNC) ((ULONG_PTR)ImageBase
+                           + NTHeaders->OptionalHeader.AddressOfEntryPoint);
      }
    DPRINT("LdrPEStartup() = %x\n",EntryPoint);
    return EntryPoint;
 }
 
+static NTSTATUS
+LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
+               IN ULONG LoadFlags,
+               IN PUNICODE_STRING Name,
+               PLDR_DATA_TABLE_ENTRY *Module,
+               PVOID *BaseAddress OPTIONAL)
+{
+    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)
+          {
+            *BaseAddress = (*Module)->DllBase;
+          }
+      }
+    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 %x)\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 (%x -> %x) %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;
+}
 
-NTSTATUS STDCALL
-LdrUnloadDll (IN PVOID BaseAddress)
+static NTSTATUS
+LdrpUnloadModule(PLDR_DATA_TABLE_ENTRY Module,
+                 BOOLEAN Unload)
 {
-   PIMAGE_NT_HEADERS NtHeaders;
-   PDLLMAIN_FUNC Entrypoint;
-   PLIST_ENTRY ModuleListHead;
-   PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
+   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;
 
-   if (BaseAddress == NULL)
-     return STATUS_SUCCESS;
-
-   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-   Entry = ModuleListHead->Flink;
-
-   while (Entry != ModuleListHead)
+   if (Unload)
      {
-       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
-       if (Module->BaseAddress == 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;
-         }
-
-       Entry = Entry->Flink;
+       RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
      }
 
-   DPRINT("NTDLL.LDR: Dll not found\n")
-
-   return STATUS_UNSUCCESSFUL;
-}
-
+   LoadCount = LdrpDecrementLoadCount(Module, Unload);
 
-NTSTATUS STDCALL
-LdrFindResource_U(PVOID BaseAddress,
-                  PLDR_RESOURCE_INFO ResourceInfo,
-                  ULONG Level,
-                  PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
-{
-   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;
+   TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
 
-   DPRINT ("LdrFindResource_U()\n");
-
-   /* Get the pointer to the resource directory */
-   ResDir = (PIMAGE_RESOURCE_DIRECTORY)
-       RtlImageDirectoryEntryToData (BaseAddress,
-                                     TRUE,
-                                     IMAGE_DIRECTORY_ENTRY_RESOURCE,
-                                     &i);
-   if (ResDir == NULL)
+   if (LoadCount == 0)
      {
-       return STATUS_RESOURCE_DATA_NOT_FOUND;
+       /* ?????????????????? */
      }
-
-   DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
-
-   ResBase = ResDir;
-
-   /* Let's go into resource tree */
-   for (i = 0; i < Level; i++)
+   else if (LoadCount == 1)
      {
-       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)
-                   {
-                      ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
-                      if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
-                          wcslen((PWCHAR)Id) == (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 == 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));
+       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)
+                    {
+                      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)
+                         {
+                           Status = LdrpUnloadModule(ImportedModule, FALSE);
+                           if (!NT_SUCCESS(Status))
+                             {
+                               DPRINT1("unable to unload %s\n", ImportedName);
+                             }
+                         }
+                     }
+                   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;
-         }
-
-       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;
-         }
-     }
+   PLDR_DATA_TABLE_ENTRY Module;
+   NTSTATUS Status;
 
-   if (Resource)
+   if (BaseAddress == NULL)
+     return STATUS_SUCCESS;
+
+   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;
 }
 
-
-NTSTATUS STDCALL
-LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
 {
-   PLIST_ENTRY ModuleListHead;
-   PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
-   NTSTATUS Status;
-
-   DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
-         BaseAddress);
-
-   Status = STATUS_DLL_NOT_FOUND;
-
-   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-   Entry = ModuleListHead->Flink;
-
-   while (Entry != ModuleListHead)
-     {
-       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
-
-       DPRINT("BaseDllName %wZ BaseAddress %x\n",
-              &Module->BaseDllName,
-              Module->BaseAddress);
-
-       if (Module->BaseAddress == BaseAddress)
-         {
-            if (Module->TlsIndex == 0)
-              {
-                Module->Flags |= 0x00040000;
-                Status = STATUS_SUCCESS;
-              }
-            return Status;
-         }
-
-       Entry = Entry->Flink;
-     }
+    PLIST_ENTRY ModuleListHead;
+    PLIST_ENTRY Entry;
+    PLDR_DATA_TABLE_ENTRY Module;
+    NTSTATUS Status;
+
+    DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\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_DATA_TABLE_ENTRY, InLoadOrderModuleList);
+
+        DPRINT("BaseDllName %wZ BaseAddress %x\n", &Module->BaseDllName, Module->DllBase);
+
+        if (Module->DllBase == BaseAddress)
+          {
+            if (Module->TlsIndex == 0xFFFF)
+              {
+                Module->Flags |= LDRP_DONT_CALL_FOR_THREADS;
+                Status = STATUS_SUCCESS;
+              }
+            break;
+          }
+        Entry = Entry->Flink;
+      }
+    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+    return Status;
+}
 
-   return Status;
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
+                IN PULONG DllCharacteristics,
+                IN PUNICODE_STRING DllName,
+                OUT PVOID *DllHandle)
+{
+    PLDR_DATA_TABLE_ENTRY Module;
+    NTSTATUS Status;
+
+    TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n",
+               DllName, DllPath ? DllPath : L"");
+
+    /* NULL is the current executable */
+    if (DllName == NULL)
+      {
+        *DllHandle = ExeModule->DllBase;
+        DPRINT("BaseAddress %x\n", *DllHandle);
+        return STATUS_SUCCESS;
+      }
+
+    Status = LdrFindEntryForName(DllName, &Module, FALSE);
+    if (NT_SUCCESS(Status))
+      {
+        *DllHandle = Module->DllBase;
+        return STATUS_SUCCESS;
+      }
+
+    DPRINT("Failed to find dll %wZ\n", DllName);
+    *DllHandle = NULL;
+    return STATUS_DLL_NOT_FOUND;
 }
 
 
-NTSTATUS STDCALL
-LdrFindResourceDirectory_U (IN PVOID BaseAddress,
-                            WCHAR **name,
-                            DWORD level,
-                            OUT PVOID *addr)
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+LdrGetProcedureAddress (IN PVOID BaseAddress,
+                        IN PANSI_STRING Name,
+                        IN ULONG Ordinal,
+                        OUT PVOID *ProcedureAddress)
 {
-   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)
+   if (Name && Name->Length)
      {
-       return STATUS_RESOURCE_DATA_NOT_FOUND;
+       TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
      }
-
-   /* Let's go into resource tree */
-   for (i = 0; i < level; i++, name++)
+   else
      {
-       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);
+       TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
      }
 
-   if (addr)
+   DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
+          BaseAddress, Name, Ordinal, ProcedureAddress);
+
+   if (Name && Name->Length)
      {
-       *addr = (PVOID)ResDir;
+       /* by name */
+       *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
+       if (*ProcedureAddress != NULL)
+         {
+           return STATUS_SUCCESS;
+         }
+       DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
      }
-
-  return Status;
+   else
+     {
+       /* by ordinal */
+       Ordinal &= 0x0000FFFF;
+       *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
+       if (*ProcedureAddress)
+         {
+           return STATUS_SUCCESS;
+         }
+       DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
+     }
+   return STATUS_PROCEDURE_NOT_FOUND;
 }
 
-
-NTSTATUS STDCALL
-LdrGetDllHandle (IN ULONG Unknown1,
-                 IN ULONG Unknown2,
-                 IN PUNICODE_STRING DllName,
-                 OUT PVOID *BaseAddress)
+/**********************************************************************
+ * 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)
 {
-   UNICODE_STRING FullDllName;
    PLIST_ENTRY ModuleListHead;
    PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
+   PLDR_DATA_TABLE_ENTRY Module;
+   static ULONG CallingCount = 0;
 
-   DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
-          Unknown1, Unknown2, DllName, BaseAddress);
-
-   /* NULL is the current executable */
-   if ( DllName == NULL )
-     {
-       *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
-       DPRINT("BaseAddress %x\n", *BaseAddress);
-       return STATUS_SUCCESS;
-     }
+   DPRINT("LdrpDetachProcess() called for %wZ\n",
+           &ExeModule->BaseDllName);
 
-   LdrAdjustDllName (&FullDllName,
-                    DllName,
-                    TRUE);
-
-   DPRINT("FullDllName %wZ\n",
-         &FullDllName);
-
-   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
-   Entry = ModuleListHead->Flink;
+   CallingCount++;
 
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Blink;
    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;
+       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("Failed to find dll %wZ\n", &FullDllName);
-   RtlFreeUnicodeString (&FullDllName);
-   *BaseAddress = NULL;
-   return STATUS_DLL_NOT_FOUND;
+   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);
+
+               RtlFreeUnicodeString (&Module->FullDllName);
+               RtlFreeUnicodeString (&Module->BaseDllName);
+
+               RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
+             }
+         }
+     }
+   CallingCount--;
+   DPRINT("LdrpDetachProcess() done\n");
 }
 
-
-NTSTATUS STDCALL
-LdrGetProcedureAddress (IN PVOID BaseAddress,
-                        IN PANSI_STRING Name,
-                        IN ULONG Ordinal,
-                        OUT PVOID *ProcedureAddress)
+/**********************************************************************
+ * 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)
 {
-   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);
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_DATA_TABLE_ENTRY Module;
+   BOOLEAN Result;
+   NTSTATUS Status = STATUS_SUCCESS;
 
-   DPRINT("ExportDir %x i %lu\n", ExportDir, i);
+   DPRINT("LdrpAttachProcess() called for %wZ\n",
+          &ExeModule->BaseDllName);
 
-   if (!ExportDir || !i || !ProcedureAddress)
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Flink;
+   while (Entry != ModuleListHead)
      {
-       return STATUS_INVALID_PARAMETER;
+       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;
      }
 
-   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);
-     }
-   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);
-  }
+   DPRINT("LdrpAttachProcess() done\n");
 
-   return STATUS_PROCEDURE_NOT_FOUND;
+   return Status;
 }
 
-
-NTSTATUS STDCALL
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
 LdrShutdownProcess (VOID)
 {
-   PLIST_ENTRY ModuleListHead;
-   PLIST_ENTRY Entry;
-   PLDR_MODULE Module;
+  LdrpDetachProcess(TRUE);
+  return STATUS_SUCCESS;
+}
 
-   DPRINT("LdrShutdownProcess() called\n");
+/*
+ * @implemented
+ */
 
-   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+NTSTATUS
+LdrpAttachThread (VOID)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_DATA_TABLE_ENTRY Module;
+  NTSTATUS Status;
 
-   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
-   Entry = ModuleListHead->Blink;
+  DPRINT("LdrpAttachThread() called for %wZ\n",
+         &ExeModule->BaseDllName);
 
-   while (Entry != ModuleListHead)
-     {
-       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
-
-       DPRINT("  Unloading %S\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;
-
-            DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-            Entrypoint (Module->BaseAddress,
-                        DLL_PROCESS_DETACH,
-                        NULL);
-         }
-
-       Entry = Entry->Blink;
-     }
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
 
-   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+  Status = LdrpInitializeTlsForThread();
 
-   DPRINT("LdrShutdownProcess() done\n");
+  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);
+    }
 
-   return STATUS_SUCCESS;
+  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);
-
-       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;
+       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 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;
@@ -1811,8 +2627,8 @@ LdrShutdownThread (VOID)
 
 
 /***************************************************************************
- * NAME                                                                EXPORTED
- *     LdrQueryProcessModuleInformation
+ * NAME                                                         EXPORTED
+ *      LdrQueryProcessModuleInformation
  *
  * DESCRIPTION
  *
@@ -1823,17 +2639,18 @@ LdrShutdownThread (VOID)
  * REVISIONS
  *
  * NOTE
+ *
+ * @implemented
  */
-NTSTATUS STDCALL
-LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
-                                IN ULONG Size OPTIONAL,
-                                OUT PULONG ReturnedSize)
-
+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;
@@ -1859,42 +2676,41 @@ 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);
+             &Module->FullDllName);
 
       if (UsedSize > Size)
-       {
-         Status = STATUS_INFO_LENGTH_MISMATCH;
-       }
+        {
+          Status = STATUS_INFO_LENGTH_MISMATCH;
+        }
       else if (ModuleInformation != NULL)
-       {
-         ModulePtr->Unknown0 = 0;      // FIXME: ??
-         ModulePtr->Unknown1 = 0;      // FIXME: ??
-         ModulePtr->BaseAddress = Module->BaseAddress;
-         ModulePtr->SizeOfImage = Module->SizeOfImage;
-         ModulePtr->Flags = Module->Flags;
-         ModulePtr->Unknown2 = 0;      // FIXME: load order index ??
-         ModulePtr->Unknown3 = 0;      // FIXME: ??
-         ModulePtr->LoadCount = Module->LoadCount;
-
-         AnsiString.Length = 0;
-         AnsiString.MaximumLength = 256;
-         AnsiString.Buffer = ModulePtr->ModuleName;
-         RtlUnicodeStringToAnsiString(&AnsiString,
-                                      &Module->FullDllName,
-                                      FALSE);
-         p = strrchr(ModulePtr->ModuleName, '\\');
-         if (p != NULL)
-           ModulePtr->PathLength = p - ModulePtr->ModuleName + 1;
-         else
-           ModulePtr->PathLength = 0;
-
-         ModulePtr++;
-         ModuleInformation->ModuleCount++;
-       }
-      UsedSize += sizeof(MODULE_ENTRY);
+        {
+          ModulePtr->Reserved[0] = ModulePtr->Reserved[1] = 0;      // FIXME: ??
+          ModulePtr->Base = Module->DllBase;
+          ModulePtr->Size = Module->SizeOfImage;
+          ModulePtr->Flags = Module->Flags;
+          ModulePtr->Index = 0;      // FIXME: index ??
+          ModulePtr->Unknown = 0;      // FIXME: ??
+          ModulePtr->LoadCount = Module->LoadCount;
+
+          AnsiString.Length = 0;
+          AnsiString.MaximumLength = 256;
+          AnsiString.Buffer = ModulePtr->ImageName;
+          RtlUnicodeStringToAnsiString(&AnsiString,
+                                       &Module->FullDllName,
+                                       FALSE);
+          p = strrchr(ModulePtr->ImageName, '\\');
+          if (p != NULL)
+            ModulePtr->ModuleNameOffset = p - ModulePtr->ImageName + 1;
+          else
+            ModulePtr->ModuleNameOffset = 0;
+
+          ModulePtr++;
+          ModuleInformation->ModuleCount++;
+        }
+      UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
 
       Entry = Entry->Flink;
     }
@@ -1909,4 +2725,393 @@ 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);
+
+  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;
+        }
+
+      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 */