change a few #ifdefs to allow loading of SYM files for user modules in DBG builds
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
index f18476b..c6dcf4a 100644 (file)
@@ -1,11 +1,20 @@
-/* $Id: utils.c,v 1.28 2000/08/05 18:01:51 dwelch Exp $
+/* $Id: utils.c,v 1.102 2004/12/15 03:00:33 royce Exp $
  * 
  * 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:
+ *      - Handle loading flags correctly
+ *      - Handle errors correctly (unload dll's)
+ *      - Implement a faster way to find modules (hash table)
+ *      - any more ??
  */
 
 /* INCLUDES *****************************************************************/
 #include <ntdll/ldr.h>
 #include <ntos/minmax.h>
 
+#define LDRP_PROCESS_CREATION_TIME 0x8000000
+
 #ifdef DBG_NTDLL_LDR_UTILS
 #define NDEBUG
 #endif
 #include <ntdll/ntdll.h>
 
+/* GLOBALS *******************************************************************/
+
+typedef struct _TLS_DATA
+{
+   PVOID StartAddressOfRawData;
+   DWORD TlsDataSize;
+   DWORD TlsZeroSize;
+   PIMAGE_TLS_CALLBACK TlsAddressOfCallBacks;
+   PLDR_MODULE 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_MODULE LdrpLastModule = NULL;
+extern ULONG NtGlobalFlag;
+extern PLDR_MODULE ExeModule;
+
+/* PROTOTYPES ****************************************************************/
+
+static NTSTATUS LdrFindEntryForName(PUNICODE_STRING Name, PLDR_MODULE *Module, BOOL 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_MODULE *Module);
+static NTSTATUS LdrpAttachProcess(VOID);
+static VOID LdrpDetachProcess(BOOL UnloadAll);
+
 /* FUNCTIONS *****************************************************************/
 
+#if defined(DBG) || defined(KDBG)
 
-/* Type for a DLL's entry point */
-typedef
-WINBOOL
-STDCALL
-(* PDLLMAIN_FUNC) (
-       HANDLE  hInst, 
-       ULONG   ul_reason_for_call,
-       LPVOID  lpReserved
-       );
+VOID
+LdrpLoadUserModuleSymbols(PLDR_MODULE LdrModule)
+{
+  NtSystemDebugControl(
+    DebugDbgLoadSymbols,
+    (PVOID)LdrModule,
+    0,
+    NULL,
+    0,
+    NULL);
+}
 
-static
-NTSTATUS
-LdrFindDll (PDLL* Dll,PCHAR    Name);
+#endif /* DBG || KDBG */
 
-/**********************************************************************
- * NAME
- *     LdrLoadDll
+static inline LONG LdrpDecrementLoadCount(PLDR_MODULE Module, BOOL Locked)
+{
+   LONG LoadCount;
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   LoadCount = Module->LoadCount;
+   if (Module->LoadCount > 0)
+     {
+       Module->LoadCount--;
+     }
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+   return LoadCount;
+}
+
+static inline LONG LdrpIncrementLoadCount(PLDR_MODULE Module, BOOL Locked)
+{
+   LONG LoadCount;
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   LoadCount = Module->LoadCount;
+   if (Module->LoadCount >= 0)
+     {
+       Module->LoadCount++;
+     }
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+   return LoadCount;
+}
+
+static inline VOID LdrpAcquireTlsSlot(PLDR_MODULE Module, ULONG Size, BOOL Locked)
+{
+   if (!Locked)
+     {
+       RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   Module->TlsIndex = (SHORT)LdrpTlsCount;
+   LdrpTlsCount++;
+   LdrpTlsSize += Size;
+   if (!Locked)
+     {
+       RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+     }
+}
+
+static inline VOID LdrpTlsCallback(PLDR_MODULE Module, ULONG dwReason)
+{
+   PIMAGE_TLS_CALLBACK TlsCallback;
+   if (Module->TlsIndex >= 0 && Module->LoadCount == -1)
+     {
+       TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
+       if (TlsCallback)
+         {
+           while (*TlsCallback)
+             {
+               TRACE_LDR("%wZ - Calling tls callback at %x\n",
+                         &Module->BaseDllName, TlsCallback);
+               TlsCallback(Module->BaseAddress, dwReason, NULL);
+               TlsCallback++;
+             }
+         }
+     }
+}
+
+static BOOL LdrpCallDllEntry(PLDR_MODULE Module, DWORD dwReason, PVOID lpReserved)
+{
+   if (!(Module->Flags & IMAGE_DLL) ||
+       Module->EntryPoint == 0)
+     {
+       return TRUE;
+     }
+   LdrpTlsCallback(Module, dwReason);
+   return  ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->BaseAddress, dwReason, lpReserved);
+}
+
+static NTSTATUS
+LdrpInitializeTlsForThread(VOID)
+{
+   PVOID* TlsPointers;
+   PTLS_DATA TlsInfo;
+   PVOID TlsData;
+   ULONG i;
+
+   DPRINT("LdrpInitializeTlsForThread() called for %wZ\n", &ExeModule->BaseDllName);
+
+   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)TlsPointers + LdrpTlsCount * sizeof(PVOID);
+       NtCurrentTeb()->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 += TlsInfo->TlsDataSize;
+             }
+           if (TlsInfo->TlsZeroSize)
+             {
+               memset(TlsData, 0, TlsInfo->TlsZeroSize);
+               TlsData += TlsInfo->TlsZeroSize;
+             }
+         }
+     }
+   DPRINT("LdrpInitializeTlsForThread() done\n");
+   return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+LdrpInitializeTlsForProccess(VOID)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+   PIMAGE_TLS_DIRECTORY TlsDirectory;
+   PTLS_DATA TlsData;
+
+   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_MODULE, InLoadOrderModuleList);
+           if (Module->LoadCount == -1 &&
+               Module->TlsIndex >= 0)
+             {
+               TlsDirectory = (PIMAGE_TLS_DIRECTORY)
+                                 RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                              TRUE,
+                                                              IMAGE_DIRECTORY_ENTRY_TLS,
+                                                              NULL);
+               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 = *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;
+               CHECKPOINT1;
+             }
+           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
  *
  * DESCRIPTION
+ *      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
  *
  * RETURN VALUE
+ *      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
  */
-
-NTSTATUS LdrLoadDll (PDLL* Dll,
-                    PCHAR      Name)
+static VOID
+LdrAdjustDllName (PUNICODE_STRING FullDllName,
+                  PUNICODE_STRING DllName,
+                  BOOLEAN BaseName)
 {
-       char                    fqname [255] = "\\??\\C:\\reactos\\system32\\";
-       ANSI_STRING             AnsiString;
-       UNICODE_STRING          UnicodeString;
-       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;
-
-       if ( Dll == NULL )
-               return -1;
-
-       if ( Name == NULL ) {
-               *Dll = &LdrDllListHead;
-               return STATUS_SUCCESS;
-       }
-
-       DPRINT("LdrLoadDll(Base %x, Name \"%s\")\n", Dll, Name);
-
-       /*
-        * Build the DLL's absolute name
-        */
-
-       if ( strncmp(Name,"\\??\\",3) != 0 ) {
-       
-               strcat(fqname, Name);
-       }
-       else
-               strncpy(fqname, Name, 256);
-
-       DPRINT("fqname \"%s\"\n", fqname);
-       /*
-        * Open the DLL's image file.
-        */
-
-   if (LdrFindDll(Dll, Name) == STATUS_SUCCESS)
-     return STATUS_SUCCESS;
+   WCHAR Buffer[MAX_PATH];
+   ULONG Length;
+   PWCHAR Extension;
+   PWCHAR Pointer;
+
+   Length = DllName->Length / sizeof(WCHAR);
 
+   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';
+     }
+   else
+     {
+        /* get the full dll name */
+        memmove (Buffer, DllName->Buffer, DllName->Length);
+        Buffer[DllName->Length / sizeof(WCHAR)] = L'\0';
+     }
 
-       RtlInitAnsiString(
-               & AnsiString,
-               fqname
-               );
-       RtlAnsiStringToUnicodeString(
-               & UnicodeString,
-               & AnsiString,
-               TRUE
-               );
-
-       InitializeObjectAttributes(
-               & FileObjectAttributes,
-               & UnicodeString,
-               0,
-               NULL,
-               NULL
-               );
-
-       DPRINT("Opening dll \"%s\"\n", fqname);
-       
-       Status = ZwOpenFile(
-                       & FileHandle,
-                       FILE_ALL_ACCESS,
-                       & FileObjectAttributes, 
-                       NULL,
-                       0,
-                       0
-                       );
-       if (!NT_SUCCESS(Status))
-       {
-               DbgPrint("Dll open of %s failed: Status = 0x%08x\n", 
-                      fqname, Status);
-               return Status;
-       }
-       Status = ZwReadFile(
-                       FileHandle,
-                       0,
-                       0,
-                       0,
-                       0,
-                       BlockBuffer,
-                       sizeof BlockBuffer,
-                       0,
-                       0
-                       );
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
-               ZwClose(FileHandle);
-               return Status;
-       }
-       /*
-        * Overlay DOS and NT headers structures to the 
-        * buffer with DLL's header raw data.
-        */
-       DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
-       NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
-       /*
-        * Check it is a PE image file.
-        */
-       if (    (DosHeader->e_magic != IMAGE_DOS_MAGIC)
-               || (DosHeader->e_lfanew == 0L)
-//             || (*(PULONG)((PUCHAR)BlockBuffer + DosHeader->e_lfanew) != IMAGE_PE_MAGIC)
-               || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC)
-               )
-       {
-               DPRINT("NTDLL format invalid\n");
-               ZwClose(FileHandle);
-       
-               return STATUS_UNSUCCESSFUL;
-       }
-
-//     NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
-       ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
-       ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
-
-       DPRINT("ImageBase 0x%08x\n", ImageBase);
-       
-       /*
-        * Create a section for NTDLL.
-        */
-       Status = ZwCreateSection(
-                       & SectionHandle,
-                       SECTION_ALL_ACCESS,
-                       NULL,
-                       NULL,
-                       PAGE_READWRITE,
-                       MEM_COMMIT,
-                       FileHandle
-                       );
-       if (!NT_SUCCESS(Status))
-       {
-               DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
-               ZwClose(FileHandle);
-               return Status;
-       }
-       /*
-        * Map the NTDLL into the process.
-        */
-       InitialViewSize =
-               DosHeader->e_lfanew
-               + sizeof (IMAGE_NT_HEADERS)
-               + sizeof (IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
-       Status = ZwMapViewOfSection(
-                       SectionHandle,
-                       NtCurrentProcess(),
-                       (PVOID*)&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);
-
-       (*Dll) = RtlAllocateHeap(
-                       RtlGetProcessHeap(),
-                       0,
-                       sizeof (DLL)
-                       );
-       (*Dll)->Headers = NTHeaders;
-       (*Dll)->BaseAddress = (PVOID)ImageBase;
-       (*Dll)->Next = LdrDllListHead.Next;
-       (*Dll)->Prev = & LdrDllListHead;
-       (*Dll)->ReferenceCount = 1;
-       LdrDllListHead.Next->Prev = (*Dll);
-       LdrDllListHead.Next = (*Dll);
-
-
-   if (((*Dll)->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
-       IMAGE_FILE_DLL)
+   /* 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;
+     }
+   else
      {
+        /* name without extension - assume that it is .dll */
+        memmove (Buffer + Length, L".dll", 10);
+     }
 
-               Entrypoint =
-               (PDLLMAIN_FUNC) LdrPEStartup(
-                                       ImageBase,
-                                       SectionHandle
-                                       );
-               if (Entrypoint != NULL)
-               {
-                       DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-                       if (FALSE == Entrypoint(
-                               Dll,
-                               DLL_PROCESS_ATTACH,
-                               NULL
-                               ))
-                       {
-                               DPRINT("NTDLL.LDR: DLL \"%s\" failed to initialize\n", fqname);
-                               /* FIXME: should clean up and fail */
-                       }
-                       else
-                       {
-                               DPRINT("NTDLL.LDR: DLL \"%s\" initialized successfully\n", fqname);
-                       }
-               }
-               else
-               {
-                       DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%s\"\n", fqname);
-               }
-       }
-       return STATUS_SUCCESS;
+   RtlCreateUnicodeString(FullDllName, Buffer);
 }
 
+PLDR_MODULE
+LdrAddModuleEntry(PVOID ImageBase,
+                  PIMAGE_NT_HEADERS NTHeaders,
+                  PWSTR FullDosName)
+{
+  PLDR_MODULE Module;
+
+  Module = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof (LDR_MODULE));
+  assert(Module);
+  memset(Module, 0, sizeof(LDR_MODULE));
+  Module->BaseAddress = (PVOID)ImageBase;
+  Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
+  if (Module->EntryPoint != 0)
+    Module->EntryPoint += (ULONG)Module->BaseAddress;
+  Module->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
+  if (NtCurrentPeb()->Ldr->Initialized == TRUE)
+    {
+      /* loading while app is running */
+      Module->LoadCount = 1;
+    } else {
+      /*
+       * loading while app is initializing
+       * dll must not be unloaded
+       */
+      Module->LoadCount = -1;
+    }
+
+  Module->Flags = 0;
+  Module->TlsIndex = -1;
+  Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
+  Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
+
+  RtlCreateUnicodeString (&Module->FullDllName,
+                          FullDosName);
+  RtlCreateUnicodeString (&Module->BaseDllName,
+                          wcsrchr(FullDosName, L'\\') + 1);
+  DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
+
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+  InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
+                 &Module->InLoadOrderModuleList);
+  RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+
+  return(Module);
+}
 
-/**********************************************************************
- * NAME                                                                LOCAL
- *     LdrFindDll
+
+static NTSTATUS
+LdrpMapKnownDll(IN PUNICODE_STRING DllName,
+                OUT PUNICODE_STRING FullDosName,
+                OUT PHANDLE SectionHandle)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS Status;
+
+  DPRINT("LdrpMapKnownDll() called\n");
+
+  if (LdrpKnownDllsDirHandle == NULL)
+    {
+      DPRINT("Invalid 'KnownDlls' directory\n");
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  DPRINT("LdrpKnownDllPath '%wZ'\n", &LdrpKnownDllPath);
+
+  InitializeObjectAttributes(&ObjectAttributes,
+                             DllName,
+                             OBJ_CASE_INSENSITIVE,
+                             LdrpKnownDllsDirHandle,
+                             NULL);
+  Status = NtOpenSection(SectionHandle,
+                         SECTION_MAP_READ | SECTION_MAP_WRITE | SECTION_MAP_EXECUTE,
+                         &ObjectAttributes);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NtOpenSection() failed for '%wZ' (Status %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)
+    {
+      FullDosName->Length = 0;
+      FullDosName->MaximumLength = 0;
+      return STATUS_SUCCESS;
+    }
+
+  wcscpy(FullDosName->Buffer, LdrpKnownDllPath.Buffer);
+  wcscat(FullDosName->Buffer, L"\\");
+  wcscat(FullDosName->Buffer, DllName->Buffer);
+
+  DPRINT("FullDosName '%wZ'\n", FullDosName);
+
+  DPRINT("LdrpMapKnownDll() done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+LdrpMapDllImageFile(IN PWSTR SearchPath OPTIONAL,
+                    IN PUNICODE_STRING DllName,
+                    OUT PUNICODE_STRING FullDosName,
+                    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;
+  PVOID                 ImageBase;
+  ULONG                 ImageSize;
+  IO_STATUS_BLOCK       IoStatusBlock;
+  NTSTATUS              Status;
+  ULONG                 len;
+
+  DPRINT("LdrpMapDllImageFile() called\n");
+
+  if (SearchPath == NULL)
+    {
+      /* 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;
+    }
+
+  if (RtlDosSearchPath_U (SearchPath,
+                          DllName->Buffer,
+                          NULL,
+                          MAX_PATH,
+                          DosName,
+                          NULL) == 0)
+    return STATUS_DLL_NOT_FOUND;
+
+
+  if (!RtlDosPathNameToNtPathName_U (DosName,
+                                     &FullNtFileName,
+                                     NULL,
+                                     NULL))
+    return STATUS_DLL_NOT_FOUND;
+
+  DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
+
+  InitializeObjectAttributes(&FileObjectAttributes,
+                             &FullNtFileName,
+                             0,
+                             NULL,
+                             NULL);
+
+  DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
+
+  Status = NtOpenFile(&FileHandle,
+                      GENERIC_READ|SYNCHRONIZE,
+                      &FileObjectAttributes,
+                      &IoStatusBlock,
+                      0,
+                      FILE_SYNCHRONOUS_IO_NONALERT);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("Dll open of %wZ failed: Status = 0x%08x\n",
+               &FullNtFileName, Status);
+      RtlFreeUnicodeString (&FullNtFileName);
+      return Status;
+    }
+  RtlFreeUnicodeString (&FullNtFileName);
+
+  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);
+      NtClose(FileHandle);
+      return Status;
+    }
+  /*
+   * Overlay DOS and NT headers structures to the
+   * buffer with DLL's header raw data.
+   */
+  DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
+  NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
+  /*
+   * Check it is a PE image file.
+   */
+  if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
+      || (DosHeader->e_lfanew == 0L)
+      || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
+    {
+      DPRINT("NTDLL format invalid\n");
+      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 = NtCreateSection(SectionHandle,
+                           SECTION_ALL_ACCESS,
+                           NULL,
+                           NULL,
+                           PAGE_READWRITE,
+                           SEC_COMMIT | SEC_IMAGE,
+                           FileHandle);
+  NtClose(FileHandle);
+
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
+      return Status;
+    }
+
+  RtlCreateUnicodeString(FullDosName,
+                         DosName);
+
+  return Status;
+}
+
+
+
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrLoadDll
  *
  * DESCRIPTION
  *
@@ -291,61 +709,215 @@ NTSTATUS LdrLoadDll (PDLL* Dll,
  *
  * NOTE
  *
+ * @implemented
  */
-static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
+NTSTATUS STDCALL
+LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
+            IN ULONG LoadFlags,
+            IN PUNICODE_STRING Name,
+            OUT PVOID *BaseAddress OPTIONAL)
 {
-   PIMAGE_EXPORT_DIRECTORY     ExportDir;
-   DLL                 * current;
-   PIMAGE_OPTIONAL_HEADER      OptionalHeader;
+  NTSTATUS              Status;
+  PLDR_MODULE           Module;
+
+  TRACE_LDR("LdrLoadDll, loading %wZ%s%S\n",
+            Name,
+            SearchPath ? " from " : "",
+            SearchPath ? SearchPath : L"");
+
+  if (Name == NULL)
+    {
+      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+      return STATUS_SUCCESS;
+    }
+
+  *BaseAddress = NULL;
+
+  Status = LdrpLoadModule(SearchPath, LoadFlags, Name, &Module);
+  if (NT_SUCCESS(Status))
+    {
+      RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+      Status = LdrpAttachProcess();
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      if (NT_SUCCESS(Status))
+        {
+          *BaseAddress = Module->BaseAddress;
+        }
+   }
+  return Status;
+}
 
 
-   DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name);
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrFindEntryForAddress
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrFindEntryForAddress(PVOID Address,
+                       PLDR_MODULE *Module)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_MODULE ModulePtr;
 
-   current = & LdrDllListHead;
+  DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
 
-   // NULL is the current process
+  if (NtCurrentPeb()->Ldr == NULL)
+    return(STATUS_NO_MORE_ENTRIES);
 
-   if ( Name == NULL )
-     {
-       *Dll = current;
-       return STATUS_SUCCESS;
-     }
+  RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+  ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+  Entry = ModuleListHead->Flink;
+  if (Entry == ModuleListHead)
+    {
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      return(STATUS_NO_MORE_ENTRIES);
+    }
 
-   do
-     {
-       OptionalHeader = & current->Headers->OptionalHeader;
-       ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-         OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-         .VirtualAddress;
-       ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-         ((ULONG)ExportDir + (ULONG)current->BaseAddress);
-       
-       DPRINT("Scanning  %x %x %x\n",ExportDir->Name,
-              current->BaseAddress,
-              (ExportDir->Name + current->BaseAddress));
-       DPRINT("Scanning %s %s\n",
-              ExportDir->Name + current->BaseAddress, Name);
-       
-       if (_stricmp(ExportDir->Name + current->BaseAddress, Name) == 0)
-         {
-            *Dll = current;
-            current->ReferenceCount++;
-            return STATUS_SUCCESS;
-         }
-       
-       current = current->Next;
-       
-     } while (current != & LdrDllListHead);
-
-   DPRINT("Failed to find dll %s\n",Name);
-
-   return -1;
+  while (Entry != ModuleListHead)
+    {
+      ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+      DPRINT("Scanning %wZ at %p\n", &ModulePtr->BaseDllName, ModulePtr->BaseAddress);
+
+      if ((Address >= ModulePtr->BaseAddress) &&
+          (Address <= (ModulePtr->BaseAddress + 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
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
+static NTSTATUS
+LdrFindEntryForName(PUNICODE_STRING Name,
+                    PLDR_MODULE *Module,
+                    BOOL Ref)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_MODULE ModulePtr;
+  BOOLEAN ContainsPath;
+  UNICODE_STRING AdjustedName;
+  unsigned i;
+
+  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)
+    {
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      return(STATUS_NO_MORE_ENTRIES);
+    }
+
+  // NULL is the current process
+  if (Name == NULL)
+    {
+      *Module = ExeModule;
+      RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+      return(STATUS_SUCCESS);
+    }
+
+  LdrAdjustDllName (&AdjustedName, Name, FALSE);
+
+  ContainsPath = (AdjustedName.Length >= 2 * sizeof(WCHAR) && L':' == AdjustedName.Buffer[1]);
+  for (i = 0; ! ContainsPath && i < AdjustedName.Length / sizeof(WCHAR); i++)
+    {
+      ContainsPath = L'\\' == AdjustedName.Buffer[i] ||
+                     L'/' == AdjustedName.Buffer[i];
+    }
+
+  if (LdrpLastModule)
+    {
+      if ((! ContainsPath &&
+           0 == RtlCompareUnicodeString(&LdrpLastModule->BaseDllName, &AdjustedName, TRUE)) ||
+          (ContainsPath &&
+           0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
+        {
+          *Module = LdrpLastModule;
+          if (Ref && (*Module)->LoadCount != -1)
+            {
+              (*Module)->LoadCount++;
+            }
+          RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+          RtlFreeUnicodeString(&AdjustedName);
+          return(STATUS_SUCCESS);
+        }
+    }
+  while (Entry != ModuleListHead)
+    {
+      ModulePtr = CONTAINING_RECORD(Entry, LDR_MODULE, 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 != -1)
+            {
+              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
- *     LdrMapSections
+ * NAME                                                         LOCAL
+ *      LdrFixupForward
  *
  * DESCRIPTION
  *
@@ -358,57 +930,61 @@ static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
  * NOTE
  *
  */
-NTSTATUS LdrMapSections(HANDLE                 ProcessHandle,
-                       PVOID                   ImageBase,
-                       HANDLE                  SectionHandle,
-                       PIMAGE_NT_HEADERS       NTHeaders)
+static PVOID
+LdrFixupForward(PCHAR ForwardName)
 {
-   ULONG               i;
-   NTSTATUS    Status;
-   
-   
-   for (i = 0; (i < NTHeaders->FileHeader.NumberOfSections); i++)
+   CHAR NameBuffer[128];
+   UNICODE_STRING DllName;
+   NTSTATUS Status;
+   PCHAR p;
+   PLDR_MODULE Module;
+   PVOID BaseAddress;
+
+   strcpy(NameBuffer, ForwardName);
+   p = strchr(NameBuffer, '.');
+   if (p != NULL)
      {
-       PIMAGE_SECTION_HEADER   Sections;
-       LARGE_INTEGER           Offset; 
-       ULONG                   Base;
-       ULONG Size;
-       
-       Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(ImageBase);
-       Base = (ULONG) (Sections[i].VirtualAddress + ImageBase);
-       Offset.u.LowPart = Sections[i].PointerToRawData;
-       Offset.u.HighPart = 0;
-       
-       Size = max(Sections[i].Misc.VirtualSize, Sections[i].SizeOfRawData);
-       
-       DPRINT("Mapping section %d offset %x base %x size %x\n",
-               i, Offset.u.LowPart, Base, Sections[i].Misc.VirtualSize);
-       DPRINT("Size %x\n", Sections[i].SizeOfRawData);
-       
-       Status = ZwMapViewOfSection(SectionHandle,
-                                   ProcessHandle,
-                                   (PVOID*)&Base,
-                                   0,
-                                   Size,
-                                   &Offset,
-                                   (PULONG)&Size,
-                                   0,
-                                   MEM_COMMIT,
-                                   PAGE_READWRITE);
-       if (!NT_SUCCESS(Status))
-         {
-            DPRINT("Failed to map section");
-            return(Status);
-         }
+        *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->BaseAddress);
+
+        return LdrGetExportByName(Module->BaseAddress, p+1, -1);
      }
-   return STATUS_SUCCESS;
+
+   return NULL;
 }
 
 
 /**********************************************************************
- * NAME                                                                LOCAL
- *     LdrGetExportByOrdinal
- *     
+ * NAME                                                         LOCAL
+ *      LdrGetExportByOrdinal
+ *
  * DESCRIPTION
  *
  * ARGUMENTS
@@ -420,48 +996,54 @@ NTSTATUS LdrMapSections(HANDLE                    ProcessHandle,
  * NOTE
  *
  */
-
 static PVOID
 LdrGetExportByOrdinal (
-       PDLL    Module,
-       ULONG   Ordinal
-       )
+        PVOID   BaseAddress,
+        ULONG   Ordinal
+        )
 {
-       PIMAGE_EXPORT_DIRECTORY ExportDir;
-       PDWORD                  * ExFunctions;
-       USHORT                  * ExOrdinals;
-
-       ExportDir = (
-               Module->BaseAddress
-               + (Module->Headers->OptionalHeader
-                       .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-                               .VirtualAddress
-                               )
-               );
-
-       ExOrdinals = (USHORT *)
-               RVA(
-                       Module->BaseAddress,
-                       ExportDir->AddressOfNameOrdinals
-                       );
-       ExFunctions = (PDWORD *)
-               RVA(
-                       Module->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) = %x\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
@@ -471,88 +1053,167 @@ LdrGetExportByOrdinal (
  * REVISIONS
  *
  * NOTE
+ *  AddressOfNames and AddressOfNameOrdinals are paralell tables,
+ *  both with NumberOfNames entries.
  *
  */
-
 static PVOID
-LdrGetExportByName (
-       PDLL    Module,
-       PUCHAR  SymbolName
-       )
+LdrGetExportByName(PVOID BaseAddress,
+                   PUCHAR SymbolName,
+                   WORD Hint)
 {
-       PIMAGE_EXPORT_DIRECTORY ExportDir;
-       PDWORD                  * ExFunctions;
-       PDWORD                  * ExNames;
-       USHORT                  * ExOrdinals;
-       ULONG                   i;
-       PVOID                   ExName;
-       ULONG                   Ordinal;
-
-//     DPRINT(
-//             "LdrFindExport(Module %x, SymbolName %s)\n",
-//             Module,
-//             SymbolName
-//             );
-
-       ExportDir = (
-               Module->BaseAddress
-               + (Module->Headers->OptionalHeader
-                       .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-                               .VirtualAddress
-                               )
-               );
-       /*
-        * Get header pointers
-        */
-       ExNames = (PDWORD *)
-               RVA(
-                       Module->BaseAddress,
-                       ExportDir->AddressOfNames
-                       );
-       ExOrdinals = (USHORT *)
-               RVA(
-                       Module->BaseAddress,
-                       ExportDir->AddressOfNameOrdinals
-                       );
-       ExFunctions = (PDWORD *)
-               RVA(
-                       Module->BaseAddress,
-                       ExportDir->AddressOfFunctions
-                       );
-       for (   i = 0;
-               ( i < ExportDir->NumberOfFunctions);
-               i++
-               )
-       {
-               ExName = RVA(
-                               Module->BaseAddress,
-                               ExNames[i]
-                               );
-//             DPRINT(
-//                     "Comparing '%s' '%s'\n",
-//                     ExName,
-//                     SymbolName
-//                     );
-               if (strcmp(ExName,SymbolName) == 0)
-               {
-                       Ordinal = ExOrdinals[i];
-                       return(RVA(Module->BaseAddress, ExFunctions[Ordinal]));
-               }
-       }
-
-       DbgPrint("LdrGetExportByName() = failed to find %s\n",SymbolName);
-
-       return NULL;
+   PIMAGE_EXPORT_DIRECTORY      ExportDir;
+   PDWORD                       * ExFunctions;
+   PDWORD                       * ExNames;
+   USHORT                       * ExOrdinals;
+   ULONG                        i;
+   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);
+   if (ExportDir == 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);
+   ExOrdinals = (USHORT *)RVA(BaseAddress,
+                              ExportDir->AddressOfNameOrdinals);
+   ExFunctions = (PDWORD *)RVA(BaseAddress,
+                               ExportDir->AddressOfFunctions);
+
+   /*
+    * Check the hint first
+    */
+   if (Hint < ExportDir->NumberOfNames)
+     {
+        ExName = RVA(BaseAddress, ExNames[Hint]);
+        if (strcmp(ExName, SymbolName) == 0)
+          {
+             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
+    */
+   minn = 0;
+   maxn = ExportDir->NumberOfNames - 1;
+   while (minn <= maxn)
+     {
+        LONG 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)
+                    {
+                      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;
+          }
+     }
+
+   /*
+    * Fall back on a linear search
+    */
+   DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
+   for (i = 0; i < ExportDir->NumberOfNames; i++)
+     {
+        ExName = RVA(BaseAddress, ExNames[i]);
+        if (strcmp(ExName,SymbolName) == 0)
+          {
+             Ordinal = ExOrdinals[i];
+             Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+             DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
+             if (((ULONG)Function >= (ULONG)ExportDir) &&
+                 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+               {
+                  DPRINT("Forward: %s\n", (PCHAR)Function);
+                  Function = LdrFixupForward((PCHAR)Function);
+               }
+             if (Function == NULL)
+               {
+                 break;
+               }
+             return Function;
+          }
+     }
+   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
@@ -562,109 +1223,396 @@ LdrGetExportByName (
  * NOTE
  *
  */
-static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS       NTHeaders,
-                                      PVOID                    ImageBase)
+static NTSTATUS
+LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders,
+                      PVOID ImageBase)
+{
+  PIMAGE_DATA_DIRECTORY RelocationDDir;
+  PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
+  ULONG Count, ProtectSize, OldProtect, OldProtect2;
+  PVOID Page, ProtectPage, ProtectPage2;
+  PUSHORT TypeOffset;
+  ULONG_PTR Delta;
+  NTSTATUS Status;
+
+  if (NTHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
+    {
+      return STATUS_UNSUCCESSFUL;
+    }
+
+  RelocationDDir =
+    &NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+  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)
+    {
+      Count = (RelocationDir->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+              sizeof(USHORT);
+      Page = ImageBase + 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 = 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_MODULE* Module,
+                    BOOL Load)
+{
+   UNICODE_STRING DllName;
+   NTSTATUS Status;
+
+   DPRINT("LdrpGetOrLoadModule() called for %s\n", Name);
+
+   RtlCreateUnicodeStringFromAsciiz (&DllName, Name);
+
+   Status = LdrFindEntryForName (&DllName, Module, Load);
+   if (Load && !NT_SUCCESS(Status))
+     {
+       Status = LdrpLoadModule(SerachPath,
+                               NtCurrentPeb()->Ldr->Initialized ? 0 : LDRP_PROCESS_CREATION_TIME,
+                               &DllName,
+                               Module);
+       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_MODULE Module,
+                                PLDR_MODULE ImportedModule,
+                                PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory)
 {
-   USHORT                      NumberOfEntries;
-   PUSHORT                     pValue16;
-   ULONG                       RelocationRVA;
-   ULONG                       Delta32;
-   ULONG                       Offset;
-   PULONG                      pValue32;
-   PRELOCATION_DIRECTORY       RelocationDir;
-   PRELOCATION_ENTRY   RelocationBlock;
-   int                 i;
-
-
-   RelocationRVA = NTHeaders->OptionalHeader
-     .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
-     .VirtualAddress;
-   
-   if (RelocationRVA)
-       {
-          RelocationDir = (PRELOCATION_DIRECTORY)
-            ((PCHAR)ImageBase + RelocationRVA);
-
-          while (RelocationDir->SizeOfBlock)
-            {
-               Delta32 = (ULONG)(ImageBase - 
-                                 NTHeaders->OptionalHeader.ImageBase);
-               RelocationBlock = (PRELOCATION_ENTRY) (
-                                                      RelocationRVA
-                                                      + ImageBase
-                                                      + sizeof (RELOCATION_DIRECTORY)
-                                                      );
-               NumberOfEntries = (
-                                  RelocationDir->SizeOfBlock
-                                  - sizeof (RELOCATION_DIRECTORY)
-                                  )
-                 / sizeof (RELOCATION_ENTRY);
-               
-               for (   i = 0;
-                    (i < NumberOfEntries);
-                    i++
-                    )
-                 {
-                    Offset = (
-                              RelocationBlock[i].TypeOffset
-                              & 0xfff
-                              )
-                      + RelocationDir->VirtualAddress;
-                    /*
-                     * 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) (ImageBase + Offset);
-                         *pValue16 += Delta32 >> 16;
-                         break;
-                         
-                       case TYPE_RELOC_LOW:
-                         pValue16 = (PUSHORT)(ImageBase + Offset);
-                         *pValue16 += Delta32 & 0xffff;
-                         break;
-                         
-                       case TYPE_RELOC_HIGHLOW:
-                         pValue32 = (PULONG) (ImageBase + 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;
-                      }
-                 }
-               RelocationRVA += RelocationDir->SizeOfBlock;
-               RelocationDir = (PRELOCATION_DIRECTORY) (
-                               ImageBase
-                                                        + RelocationRVA
-                                                        );
-            }
-       }
+   NTSTATUS Status;
+   PVOID* ImportAddressList;
+   PULONG FunctionNameList;
+   PVOID IATBase;
+   ULONG OldProtect;
+   ULONG Ordinal;
+   ULONG IATSize;
+
+   if (ImportModuleDirectory == NULL || ImportModuleDirectory->dwRVAModuleName == 0)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   /* Get the import address list. */
+   ImportAddressList = (PVOID *)(Module->BaseAddress + ImportModuleDirectory->dwRVAFunctionAddressList);
+
+   /* Get the list of functions to import. */
+   if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
+     {
+       FunctionNameList = (PULONG) (Module->BaseAddress + ImportModuleDirectory->dwRVAFunctionNameList);
+     }
+   else
+     {
+       FunctionNameList = (PULONG)(Module->BaseAddress + 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;
+   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->BaseAddress, 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->BaseAddress, *FunctionNameList);
+           *ImportAddressList = LdrGetExportByName(ImportedModule->BaseAddress, 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_MODULE Module,
+   PLDR_MODULE ImportedModule,
+   PCHAR ImportedName)
+{
+   NTSTATUS Status;
+   PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
+   PCHAR Name;
+
+   DPRINT("LdrpProcessImportDirectory(%x '%wZ', '%s')\n",
+          Module, &Module->BaseDllName, ImportedName);
+
+
+   ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
+                             RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                          TRUE,
+                                                          IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                          NULL);
+   if (ImportModuleDirectory == NULL)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   while (ImportModuleDirectory->dwRVAModuleName)
+     {
+       Name = (PCHAR)Module->BaseAddress + ImportModuleDirectory->dwRVAModuleName;
+       if (0 == _stricmp(Name, ImportedName))
+         {
+           Status = LdrpProcessImportDirectoryEntry(Module,
+                                                    ImportedModule,
+                                                    ImportModuleDirectory);
+           if (!NT_SUCCESS(Status))
+             {
+               return Status;
+             }
+         }
+       ImportModuleDirectory++;
+     }
+
+
+   return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+LdrpAdjustImportDirectory(PLDR_MODULE Module,
+                          PLDR_MODULE ImportedModule,
+                          PUCHAR ImportedName)
+{
+   PIMAGE_IMPORT_MODULE_DIRECTORY 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;
+
+   DPRINT("LdrpAdjustImportDirectory(Module %x '%wZ', %x '%wZ', %x '%s')\n",
+          Module, &Module->BaseDllName, ImportedModule, &ImportedModule->BaseDllName, ImportedName);
+
+   ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
+                              RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                           NULL);
+   if (ImportModuleDirectory == NULL)
+     {
+       return STATUS_UNSUCCESSFUL;
+     }
+
+   while (ImportModuleDirectory->dwRVAModuleName)
+     {
+       Name = (PCHAR)Module->BaseAddress + ImportModuleDirectory->dwRVAModuleName;
+       if (0 == _stricmp(Name, ImportedName))
+         {
+
+           /* Get the import address list. */
+           ImportAddressList = (PVOID *)(Module->BaseAddress + ImportModuleDirectory->dwRVAFunctionAddressList);
+
+           /* Get the list of functions to import. */
+           if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
+             {
+               FunctionNameList = (PULONG) (Module->BaseAddress + ImportModuleDirectory->dwRVAFunctionNameList);
+             }
+           else
+             {
+               FunctionNameList = (PULONG)(Module->BaseAddress + 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;
+           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->BaseAddress);
+           Start = (PVOID)NTHeaders->OptionalHeader.ImageBase;
+           End = Start + ImportedModule->SizeOfImage;
+           Offset = ImportedModule->BaseAddress - Start;
+
+           /* Walk through function list and fixup addresses. */
+           while (*FunctionNameList != 0L)
+             {
+               if (*ImportAddressList >= Start && *ImportAddressList < End)
+                 {
+                   (*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
- *     
+ * NAME                                                         LOCAL
+ *      LdrFixupImports
+ *
  * DESCRIPTION
- *     Compute the entry point for every symbol the DLL imports
- *     from other modules.
+ *      Compute the entry point for every symbol the DLL imports
+ *      from other modules.
  *
  * ARGUMENTS
  *
@@ -675,148 +1623,269 @@ static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS       NTHeaders,
  * NOTE
  *
  */
-static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS      NTHeaders,
-                               PVOID                   ImageBase)
+static NTSTATUS
+LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
+                IN PLDR_MODULE Module)
 {
    PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
-   ULONG Ordinal;
-   PDLL        Module;
+   PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectoryCurrent;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
+   PIMAGE_TLS_DIRECTORY TlsDirectory;
+   ULONG TlsSize = 0;
    NTSTATUS Status;
-   
-   DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders, 
-          ImageBase);
-   
+   PLDR_MODULE ImportedModule;
+   PCHAR ImportedName;
+
+   DPRINT("LdrFixupImports(SearchPath %x, Module %x)\n", SearchPath, Module);
+
+   /* Check for tls data */
+   TlsDirectory = (PIMAGE_TLS_DIRECTORY)
+                     RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                  TRUE,
+                                                  IMAGE_DIRECTORY_ENTRY_TLS,
+                                                  NULL);
+   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);
-   
-   while (ImportModuleDirectory->dwRVAModuleName)
+   ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)
+                              RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                           NULL);
+
+   BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
+                              RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                           TRUE,
+                                                           IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
+                                                           NULL);
+
+   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
+             {
+               BOOL WrongForwarder;
+               WrongForwarder = FALSE;
+               if (ImportedModule->Flags & 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_MODULE ForwarderModule;
+                   PUCHAR 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 & 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 & 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 & IMAGE_NOT_AT_BASE)
+                 {
+                   TRACE_LDR("Adjust imports for %s from %wZ\n",
+                             ImportedName, &Module->BaseDllName);
+                   Status = LdrpAdjustImportDirectory(Module, ImportedModule, ImportedName);
+                   if (!NT_SUCCESS(Status))
+                   {
+                     DPRINT1("failed to adjust import entries for %s\n", ImportedName);
+                     return Status;
+                   }
+                 }
+               else if (WrongForwarder)
+                 {
+                   /*
+                    * FIXME:
+                    *   Update only forwarders
+                    */
+                   TRACE_LDR("Stale BIND %s from %wZ\n",
+                             ImportedName, &Module->BaseDllName);
+                   Status = LdrpProcessImportDirectory(Module, ImportedModule, ImportedName);
+                   if (!NT_SUCCESS(Status))
+                     {
+                       DPRINT1("faild to import %s\n", ImportedName);
+                       return Status;
+                     }
+                 }
+               else
+                 {
+                   /* nothing to do */
+                 }
+             }
+           BoundImportDescriptorCurrent += BoundImportDescriptorCurrent->NumberOfModuleForwarderRefs + 1;
+         }
+     }
+   else if (ImportModuleDirectory)
      {
-       PVOID   * ImportAddressList; 
-       PULONG  FunctionNameList;
-       DWORD   pName;
-       PWORD   pHint;
-       
-       DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
-              (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
-       
-       Status = LdrLoadDll(&Module,
-                           (PCHAR)(ImageBase
-                                   +ImportModuleDirectory->dwRVAModuleName));
-       if (!NT_SUCCESS(Status))
-         {
-            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
-                                         );
-         }
-       /*
-        * Walk through function list and fixup addresses.
-        */
-       while (*FunctionNameList != 0L)
-         {
-            if ((*FunctionNameList) & 0x80000000)
-              {
-                 Ordinal = (*FunctionNameList) & 0x7fffffff;
-                               *ImportAddressList = 
-                   LdrGetExportByOrdinal(
-                                         Module,
-                                         Ordinal
-                                         );
-              }
-            else
-              {
-                 pName = (DWORD) (
-                                  ImageBase
-                                  + *FunctionNameList
-                                  + 2
-                                  );
-                 pHint = (PWORD) (
-                                  ImageBase
-                                  + *FunctionNameList
-                                               );
-                 
-                 *ImportAddressList =
-                   LdrGetExportByName(
-                                               Module,
-                                      (PUCHAR) pName
-                                      );
-                 if ((*ImportAddressList) == NULL)
-                   {
-                                  DbgPrint("Failed to import %s\n", pName);
-                      return STATUS_UNSUCCESSFUL;
-                   }
-              }
-                       ImportAddressList++;
-            FunctionNameList++;
-         }
-       ImportModuleDirectory++;
+       DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
+
+       ImportModuleDirectoryCurrent = ImportModuleDirectory;
+       while (ImportModuleDirectoryCurrent->dwRVAModuleName)
+         {
+           ImportedName = (PCHAR)Module->BaseAddress + ImportModuleDirectoryCurrent->dwRVAModuleName;
+           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++;
+         }
      }
+
+   if (TlsDirectory && TlsSize > 0)
+     {
+       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)
+PEPFUNC LdrPEStartup (PVOID  ImageBase,
+                      HANDLE SectionHandle,
+                      PLDR_MODULE* 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_MODULE tmpModule;
+
+   DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
+           ImageBase, (ULONG)SectionHandle);
 
    /*
     * Overlay DOS and WNT headers structures
@@ -824,18 +1893,7 @@ PEPFUNC LdrPEStartup (PVOID       ImageBase,
     */
    DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
    NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
-   
-   /*
-    * Initialize image sections.
-    */
-   if (SectionHandle != NULL)
-     {
-       LdrMapSections(NtCurrentProcess(),
-                      ImageBase,
-                      SectionHandle,
-                      NTHeaders);
-     }
-   
+
    /*
     * If the base address is different from the
     * one the DLL is actually loaded, perform any
@@ -843,304 +1901,1169 @@ PEPFUNC LdrPEStartup (PVOID   ImageBase,
     */
    if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
      {
-       Status = LdrPerformRelocations(NTHeaders, ImageBase);
-       if (!NT_SUCCESS(Status))
-         {
-            DbgPrint("LdrPerformRelocations() failed\n");
-            return NULL;
-         }
+       DPRINT("LDR: Performing relocations\n");
+       Status = LdrPerformRelocations(NTHeaders, ImageBase);
+       if (!NT_SUCCESS(Status))
+         {
+           DPRINT1("LdrPerformRelocations() failed\n");
+           return NULL;
+         }
+     }
+
+   if (Module != NULL)
+     {
+       *Module = LdrAddModuleEntry(ImageBase, NTHeaders, FullDosName);
+       (*Module)->SectionHandle = SectionHandle;
+     }
+   else
+     {
+       Module = &tmpModule;
+       Status = LdrFindEntryForAddress(ImageBase, Module);
+       if (!NT_SUCCESS(Status))
+         {
+           return NULL;
+         }
+     }
+
+   if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
+     {
+       (*Module)->Flags |= 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))
+     {
+       DPRINT1("LdrFixupImports() failed for %wZ\n", &(*Module)->BaseDllName);
+       return NULL;
+     }
+   DPRINT("Fixup done\n");
+   RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+   Status = LdrpInitializeTlsForProccess();
+   if (NT_SUCCESS(Status))
      {
-       DPRINT("About to fixup imports\n");
-       Status = LdrFixupImports(NTHeaders, ImageBase);
-       if (!NT_SUCCESS(Status))
-         {
-            DbgPrint("LdrFixupImports() failed\n");
-            return NULL;
-         }
+       Status = LdrpAttachProcess();
      }
-   
+   if (NT_SUCCESS(Status))
+     {
+       LdrpTlsCallback(*Module, DLL_PROCESS_ATTACH);
+     }
+
+
+   RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
+   if (!NT_SUCCESS(Status))
+     {
+       CHECKPOINT1;
+       return NULL;
+     }
+
    /*
     * Compute the DLL's entry point's address.
     */
+   DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
+   DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
    if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
      {
-       EntryPoint = (PEPFUNC) (ImageBase
-                          + NTHeaders->OptionalHeader.AddressOfEntryPoint);
+        EntryPoint = (PEPFUNC) (ImageBase
+                           + NTHeaders->OptionalHeader.AddressOfEntryPoint);
      }
    DPRINT("LdrPEStartup() = %x\n",EntryPoint);
    return EntryPoint;
 }
 
-NTSTATUS LdrUnloadDll(PDLL Dll)
+static NTSTATUS
+LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
+               IN ULONG LoadFlags,
+               IN PUNICODE_STRING Name,
+               PLDR_MODULE *Module)
 {
-   PDLLMAIN_FUNC               Entrypoint;
-   NTSTATUS            Status;
+    UNICODE_STRING AdjustedName;
+    UNICODE_STRING FullDosName;
+    NTSTATUS Status;
+    PLDR_MODULE tmpModule;
+    HANDLE SectionHandle;
+    ULONG ViewSize;
+    PVOID ImageBase;
+    PIMAGE_NT_HEADERS NtHeaders;
+
+    if (Module == NULL)
+      {
+        Module = &tmpModule;
+      }
+    /* adjust the full dll name */
+    LdrAdjustDllName(&AdjustedName, Name, FALSE);
+
+    DPRINT("%wZ\n", &AdjustedName);
+
+    /* Test if dll is already loaded */
+    Status = LdrFindEntryForName(&AdjustedName, Module, TRUE);
+    if (NT_SUCCESS(Status))
+      {
+        RtlFreeUnicodeString(&AdjustedName);
+      }
+    else
+      {
+        /* Open or create dll image section */
+        Status = LdrpMapKnownDll(&AdjustedName, &FullDosName, &SectionHandle);
+        if (!NT_SUCCESS(Status))
+          {
+            Status = LdrpMapDllImageFile(SearchPath, &AdjustedName, &FullDosName, &SectionHandle);
+          }
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("Failed to create or open dll section of '%wZ' (Status %lx)\n", &AdjustedName, Status);
+            RtlFreeUnicodeString(&AdjustedName);
+            RtlFreeUnicodeString(&FullDosName);
+            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_READWRITE);
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("map view of section failed (Status %x)\n", Status);
+            RtlFreeUnicodeString(&FullDosName);
+            NtClose(SectionHandle);
+            return(Status);
+          }
+        /* 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;
+          }
+        /* 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)->SectionHandle = SectionHandle;
+        if (ImageBase != (PVOID) NtHeaders->OptionalHeader.ImageBase)
+          {
+            (*Module)->Flags |= IMAGE_NOT_AT_BASE;
+          }
+        if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL)
+          {
+            (*Module)->Flags |= IMAGE_DLL;
+          }
+        /* fixup the imported calls entry points */
+        Status = LdrFixupImports(SearchPath, *Module);
+        if (!NT_SUCCESS(Status))
+          {
+            DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
+            return Status;
+          }
+#if defined(DBG) || defined(KDBG)
+        LdrpLoadUserModuleSymbols(*Module);
+#endif /* DBG || KDBG */
+        RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
+        InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
+                       &(*Module)->InInitializationOrderModuleList);
+        RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+      }
+    return STATUS_SUCCESS;
+}
 
-   if ( Dll == NULL || Dll == &LdrDllListHead )
-     return -1;
+static NTSTATUS
+LdrpUnloadModule(PLDR_MODULE Module,
+                 BOOL Unload)
+{
+   PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptor;
+   PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportDescriptorCurrent;
+   PCHAR ImportedName;
+   PLDR_MODULE ImportedModule;
+   NTSTATUS Status;
+   LONG LoadCount;
 
 
-   if ( Dll->ReferenceCount > 1 )
+   if (Unload)
      {
-       Dll->ReferenceCount--;
-       return STATUS_SUCCESS;
+       RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
      }
 
-   if (( Dll->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ) {
-
-      Entrypoint = (PDLLMAIN_FUNC) LdrPEStartup(Dll->BaseAddress,
-                                               Dll->SectionHandle);
-      if (Entrypoint != NULL)
-       {
-          DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
-          if (FALSE == Entrypoint(Dll,
-                                  DLL_PROCESS_DETACH,
-                                  NULL))
-            {
-               DPRINT("NTDLL.LDR: DLL failed to detach\n");
-               return -1;
-            }
-          else
-            {
-               DPRINT("NTDLL.LDR: DLL  detached successfully\n");
-            }
-       }
-      else
-       {
-          DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
-       }
-      
-   }
-   Status = ZwUnmapViewOfSection(NtCurrentProcess(),
-                                Dll->BaseAddress);
+   LoadCount = LdrpDecrementLoadCount(Module, Unload);
 
-   ZwClose(Dll->SectionHandle);
+   TRACE_LDR("Unload %wZ, LoadCount %d\n", &Module->BaseDllName, LoadCount);
+
+   if (LoadCount == 0)
+     {
+       /* ?????????????????? */
+       CHECKPOINT1;
+     }
+   else if (LoadCount == 1)
+     {
+       BoundImportDescriptor = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)
+                                 RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                              TRUE,
+                                                              IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
+                                                              NULL);
+       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_MODULE_DIRECTORY)
+                                      RtlImageDirectoryEntryToData(Module->BaseAddress,
+                                                                   TRUE,
+                                                                   IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                                   NULL);
+           if (ImportModuleDirectory)
+             {
+               /* dereferencing all imported modules, use the import descriptor */
+               while (ImportModuleDirectory->dwRVAModuleName)
+                 {
+                   ImportedName = (PCHAR)Module->BaseAddress + ImportModuleDirectory->dwRVAModuleName;
+                   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++;
+                 }
+             }
+         }
+     }
+
+   if (Unload)
+     {
+       LdrpDetachProcess(FALSE);
+       RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+     }
+   return STATUS_SUCCESS;
 
-   return Status;
 }
 
-static IMAGE_RESOURCE_DIRECTORY_ENTRY * LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY *ResourceDir, LPCWSTR ResourceName, ULONG Offset)
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrUnloadDll (IN PVOID BaseAddress)
 {
+   PLDR_MODULE Module;
+   NTSTATUS Status;
 
+   if (BaseAddress == NULL)
+     return STATUS_SUCCESS;
 
-       WORD    NumberOfNamedEntries;
-       WORD    NumberOfIdEntries;
-       WORD    Entries;
-       ULONG   Length;
-
-       if ( (((ULONG)ResourceDir) & 0xF0000000) != 0 ) {
-               return (IMAGE_RESOURCE_DIRECTORY_ENTRY *)NULL;
-       }
-
-
-       NumberOfIdEntries = ResourceDir->NumberOfIdEntries;
-       NumberOfNamedEntries = ResourceDir->NumberOfNamedEntries;
-       if ( (  NumberOfIdEntries + NumberOfNamedEntries) == 0) {
-               return &ResourceDir->DirectoryEntries[0];
-       }
-
-       if ( HIWORD(ResourceName) != 0 ) {
-               Length = wcslen(ResourceName);
-               Entries = ResourceDir->NumberOfNamedEntries;
-               do {
-                       IMAGE_RESOURCE_DIR_STRING_U *DirString;
-
-                       Entries--;
-                       DirString =  (IMAGE_RESOURCE_DIR_STRING_U *)(((ULONG)ResourceDir->DirectoryEntries[Entries].Name &  (~0xF0000000)) + Offset);
-                       
-                       if ( DirString->Length == Length && wcscmp(DirString->NameString, ResourceName ) == 0 ) {
-                               return  &ResourceDir->DirectoryEntries[Entries];
-                       }
-               } while (Entries > 0);
-       }
-       else {
-                       Entries = ResourceDir->NumberOfIdEntries + ResourceDir->NumberOfNamedEntries;
-                       do {
-                               Entries--;
-
-                               if ( (LPWSTR)ResourceDir->DirectoryEntries[Entries].Name == ResourceName ) {
-                                       return &ResourceDir->DirectoryEntries[Entries];
-                               }
-                       } while (Entries > ResourceDir->NumberOfNamedEntries);
-               
-       }
-
-       
-
-       return NULL;
-               
+   Status = LdrFindEntryForAddress(BaseAddress, &Module);
+   if (NT_SUCCESS(Status))
+     {
+       TRACE_LDR("LdrUnloadDll, , unloading %wZ\n", &Module->BaseDllName);
+       Status = LdrpUnloadModule(Module, TRUE);
+     }
+   return Status;
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+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;
+    RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+    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 == -1)
+              {
+                Module->Flags |= DONT_CALL_FOR_THREAD;
+                Status = STATUS_SUCCESS;
+              }
+            break;
+          }
+        Entry = Entry->Flink;
+      }
+    RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+    return Status;
+}
 
-
-NTSTATUS LdrFindResource_U(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY **ResourceDataEntry,LPCWSTR ResourceName, ULONG ResourceType,ULONG Language)
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrGetDllHandle(IN PWCHAR Path OPTIONAL,
+                IN ULONG Unknown2,
+                IN PUNICODE_STRING DllName,
+                OUT PVOID* BaseAddress)
 {
-       IMAGE_RESOURCE_DIRECTORY *ResourceTypeDir;
-       IMAGE_RESOURCE_DIRECTORY *ResourceNameDir;
-       IMAGE_RESOURCE_DIRECTORY *ResourceLangDir;
+    PLDR_MODULE Module;
+    NTSTATUS Status;
+
+    TRACE_LDR("LdrGetDllHandle, searching for %wZ from %S\n", DllName, Path ? Path : L"");
+
+    /* NULL is the current executable */
+    if (DllName == NULL)
+      {
+        *BaseAddress = ExeModule->BaseAddress;
+        DPRINT("BaseAddress %x\n", *BaseAddress);
+        return STATUS_SUCCESS;
+      }
+
+    Status = LdrFindEntryForName(DllName, &Module, FALSE);
+    if (NT_SUCCESS(Status))
+      {
+        *BaseAddress = Module->BaseAddress;
+        return STATUS_SUCCESS;
+      }
+
+    DPRINT("Failed to find dll %wZ\n", DllName);
+    *BaseAddress = NULL;
+    return STATUS_DLL_NOT_FOUND;
+}
 
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceTypeDirEntry;
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceNameDirEntry;
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceLangDirEntry;
 
-       PIMAGE_OPTIONAL_HEADER  OptionalHeader;
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrGetProcedureAddress (IN PVOID BaseAddress,
+                        IN PANSI_STRING Name,
+                        IN ULONG Ordinal,
+                        OUT PVOID *ProcedureAddress)
+{
+   if (Name && Name->Length)
+     {
+       TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
+     }
+   else
+     {
+       TRACE_LDR("LdrGetProcedureAddress by ORDINAL - %d\n", Ordinal);
+     }
 
+   DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
+          BaseAddress, Name, Ordinal, ProcedureAddress);
 
+   if (Name && Name->Length)
+     {
+       /* by name */
+       *ProcedureAddress = LdrGetExportByName(BaseAddress, Name->Buffer, 0xffff);
+       if (*ProcedureAddress != NULL)
+         {
+           return STATUS_SUCCESS;
+         }
+       DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
+     }
+   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;
+}
 
-       ULONG Offset;
-               
-       OptionalHeader = & Dll->Headers->OptionalHeader;
-       ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
-               OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
-       ResourceTypeDir = (PIMAGE_RESOURCE_DIRECTORY)
-               ((ULONG)ResourceTypeDir + (ULONG)Dll->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(BOOL UnloadAll)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+   static ULONG CallingCount = 0;
 
+   DPRINT("LdrpDetachProcess() called for %wZ\n",
+           &ExeModule->BaseDllName);
 
-       Offset = (ULONG)ResourceTypeDir;
+   CallingCount++;
 
-       ResourceTypeDirEntry = LdrGetNextEntry(ResourceTypeDir, (LPWSTR)ResourceType, Offset);
-       
-       if ( ResourceTypeDirEntry != NULL ) {
-               ResourceNameDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceTypeDirEntry->OffsetToData & (~0xF0000000)) + Offset);
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Blink;
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+       if (((UnloadAll && Module->LoadCount <= 0) || Module->LoadCount == 0) &&
+           Module->Flags & ENTRY_PROCESSED &&
+           !(Module->Flags & UNLOAD_IN_PROGRESS))
+         {
+           Module->Flags |= UNLOAD_IN_PROGRESS;
+           if (Module == LdrpLastModule)
+             {
+               LdrpLastModule = NULL;
+             }
+           if (Module->Flags & 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 == -1 ? 1 : 0));
+             }
+           else
+             {
+               TRACE_LDR("Unload %wZ\n", &Module->BaseDllName);
+             }
+           Entry = ModuleListHead->Blink;
+         }
+       else
+         {
+           Entry = Entry->Blink;
+         }
+     }
 
-               ResourceNameDirEntry = LdrGetNextEntry(ResourceNameDir, ResourceName, Offset);
+   if (CallingCount == 1)
+     {
+       Entry = ModuleListHead->Blink;
+       while (Entry != ModuleListHead)
+         {
+           Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+           Entry = Entry->Blink;
+           if (Module->Flags & UNLOAD_IN_PROGRESS &&
+               ((UnloadAll && Module->LoadCount >= 0) || Module->LoadCount == 0))
+             {
+               /* remove the module entry from the list */
+               RemoveEntryList (&Module->InLoadOrderModuleList);
+               RemoveEntryList (&Module->InInitializationOrderModuleList);
+
+               NtUnmapViewOfSection (NtCurrentProcess (), Module->BaseAddress);
+               NtClose (Module->SectionHandle);
+
+               TRACE_LDR("%wZ unloaded\n", &Module->BaseDllName);
+
+               RtlFreeUnicodeString (&Module->FullDllName);
+               RtlFreeUnicodeString (&Module->BaseDllName);
+
+               RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
+             }
+         }
+     }
+   CallingCount--;
+   DPRINT("LdrpDetachProcess() done\n");
+}
 
-               if ( ResourceNameDirEntry != NULL ) {
-               
-                       ResourceLangDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceNameDirEntry->OffsetToData & (~0xF0000000)) + Offset);
+/**********************************************************************
+ * NAME                                                         LOCAL
+ *      LdrpAttachProcess
+ *
+ * DESCRIPTION
+ *      Initialize all dll's which are prepered for loading
+ *
+ * ARGUMENTS
+ *      none
+ *
+ * RETURN VALUE
+ *      status
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *      The loader lock must be held on entry.
+ *
+ */
+static NTSTATUS
+LdrpAttachProcess(VOID)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+   BOOL Result;
+   NTSTATUS Status = STATUS_SUCCESS;
+
+   DPRINT("LdrpAttachProcess() called for %wZ\n",
+          &ExeModule->BaseDllName);
+
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Flink;
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+       if (!(Module->Flags & (LOAD_IN_PROGRESS|UNLOAD_IN_PROGRESS|ENTRY_PROCESSED)))
+         {
+           Module->Flags |= 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 == -1 ? 1 : 0));
+           if (!Result)
+             {
+               Status = STATUS_DLL_INIT_FAILED;
+               break;
+             }
+           if (Module->Flags & IMAGE_DLL && Module->EntryPoint != 0)
+             {
+               Module->Flags |= PROCESS_ATTACH_CALLED|ENTRY_PROCESSED;
+             }
+           else
+             {
+               Module->Flags |= ENTRY_PROCESSED;
+             }
+           Module->Flags &= ~LOAD_IN_PROGRESS;
+         }
+       Entry = Entry->Flink;
+     }
 
-                       ResourceLangDirEntry = LdrGetNextEntry(ResourceLangDir, (LPWSTR)Language, Offset);
-                       if ( ResourceLangDirEntry != NULL ) {
+   DPRINT("LdrpAttachProcess() done\n");
 
-                               *ResourceDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceLangDirEntry->OffsetToData +
-                                                                       (ULONG)ResourceTypeDir);
-                               return STATUS_SUCCESS;
-                       }
-                       else {
-                               return -1;
-                       }
-               }       
-               else {
-                               return -1;      
-               }
-                       
-       }
+   return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrShutdownProcess (VOID)
+{
+  LdrpDetachProcess(TRUE);
+  return STATUS_SUCCESS;
+}
 
-       return -1;
+/*
+ * @implemented
+ */
 
+NTSTATUS
+LdrpAttachThread (VOID)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_MODULE Module;
+  NTSTATUS Status;
+
+  DPRINT("LdrpAttachThread() called for %wZ\n",
+         &ExeModule->BaseDllName);
+
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  Status = LdrpInitializeTlsForThread();
+
+  if (NT_SUCCESS(Status))
+    {
+      ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+      Entry = ModuleListHead->Flink;
+
+      while (Entry != ModuleListHead)
+        {
+          Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+          if (Module->Flags & PROCESS_ATTACH_CALLED &&
+              !(Module->Flags & DONT_CALL_FOR_THREAD) &&
+              !(Module->Flags & 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_MODULE, InLoadOrderModuleList);
+      LdrpTlsCallback(Module, DLL_THREAD_ATTACH);
+    }
+
+  RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  DPRINT("LdrpAttachThread() done\n");
+
+  return Status;
 }
 
-NTSTATUS LdrAccessResource(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry, void **Data)
+
+/*
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrShutdownThread (VOID)
 {
-       PIMAGE_SECTION_HEADER   Sections;
-       int i;
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
 
-       if ( Data == NULL )
-               return -1;
+   DPRINT("LdrShutdownThread() called for %wZ\n",
+          &ExeModule->BaseDllName);
 
-       if ( ResourceDataEntry == NULL )
-               return -1;
+   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
 
-       if ( Dll == NULL )
-               return -1;
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Blink;
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+
+       if (Module->Flags & PROCESS_ATTACH_CALLED &&
+           !(Module->Flags & DONT_CALL_FOR_THREAD) &&
+           !(Module->Flags & 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;
+     }
 
-       Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(Dll->BaseAddress);
+   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
 
-       for (   i = 0;
-               (i < Dll->Headers->FileHeader.NumberOfSections);
-               i++
-               )
-       {
-               if (Sections[i].VirtualAddress <= ResourceDataEntry->OffsetToData 
-                       && Sections[i].VirtualAddress + Sections[i].Misc.VirtualSize > ResourceDataEntry->OffsetToData )
-                       break;
-       }
+   if (LdrpTlsArray)
+     {
+       RtlFreeHeap (RtlGetProcessHeap(),  0, NtCurrentTeb()->ThreadLocalStoragePointer);
+     }
 
-       if ( i == Dll->Headers->FileHeader.NumberOfSections ) {
-               *Data = NULL;
-               return -1;
-       }
+   DPRINT("LdrShutdownThread() done\n");
 
-       *Data = (void *)(((ULONG)Dll->BaseAddress + ResourceDataEntry->OffsetToData - (ULONG)Sections[i].VirtualAddress) +
-                                  (ULONG)Sections[i].PointerToRawData);
+   return STATUS_SUCCESS;
+}
 
 
-       return STATUS_SUCCESS;
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrQueryProcessModuleInformation
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS STDCALL
+LdrQueryProcessModuleInformation(IN PMODULE_INFORMATION ModuleInformation OPTIONAL,
+                                 IN ULONG Size OPTIONAL,
+                                 OUT PULONG ReturnedSize)
+{
+  PLIST_ENTRY ModuleListHead;
+  PLIST_ENTRY Entry;
+  PLDR_MODULE Module;
+  PDEBUG_MODULE_INFORMATION ModulePtr = NULL;
+  NTSTATUS Status = STATUS_SUCCESS;
+  ULONG UsedSize = sizeof(ULONG);
+  ANSI_STRING AnsiString;
+  PCHAR p;
+
+  DPRINT("LdrQueryProcessModuleInformation() called\n");
+
+  RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  if (ModuleInformation == NULL || Size == 0)
+    {
+      Status = STATUS_INFO_LENGTH_MISMATCH;
+    }
+  else
+    {
+      ModuleInformation->ModuleCount = 0;
+      ModulePtr = &ModuleInformation->ModuleEntry[0];
+      Status = STATUS_SUCCESS;
+    }
+
+  ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+  Entry = ModuleListHead->Flink;
+
+  while (Entry != ModuleListHead)
+    {
+      Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+      DPRINT("  Module %wZ\n",
+             &Module->FullDllName);
+
+      if (UsedSize > Size)
+        {
+          Status = STATUS_INFO_LENGTH_MISMATCH;
+        }
+      else if (ModuleInformation != NULL)
+        {
+          ModulePtr->Reserved[0] = ModulePtr->Reserved[1] = 0;      // FIXME: ??
+          ModulePtr->Base = Module->BaseAddress;
+          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(DEBUG_MODULE_INFORMATION);
+
+      Entry = Entry->Flink;
+    }
+
+  RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+  if (ReturnedSize != 0)
+    *ReturnedSize = UsedSize;
+
+  DPRINT("LdrQueryProcessModuleInformation() done\n");
+
+  return(Status);
 }
 
 
-NTSTATUS
-STDCALL
-LdrDisableThreadCalloutsForDll (
-       PVOID   IN      ImageBase,
-       BOOLEAN IN      Disable
-       )
+static BOOLEAN
+LdrpCheckImageChecksum (IN PVOID BaseAddress,
+                        IN ULONG ImageSize)
 {
-       return STATUS_NOT_IMPLEMENTED;
+  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);
 }
 
 
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrVerifyImageMatchesChecksum
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
 NTSTATUS STDCALL
-LdrGetProcedureAddress (IN PVOID BaseAddress,
-                        IN PANSI_STRING Name,
-                        IN ULONG Ordinal,
-                        OUT PVOID *ProcedureAddress)
+LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
+                               ULONG Unknown1,
+                               ULONG Unknown2,
+                               ULONG Unknown3)
 {
-   PIMAGE_EXPORT_DIRECTORY ExportDir;
-   PUSHORT OrdinalPtr;
-   PULONG NamePtr;
-   PULONG AddressPtr;
-   ULONG i = 0;
+  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_EXECUTE,
+                            NULL,
+                            NULL,
+                            PAGE_EXECUTE,
+                            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_EXECUTE);
+  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;
+}
 
-   /* Get the pointer to the export directory */
-   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
-               RtlImageDirectoryEntryToData (BaseAddress,
-                                             TRUE,
-                                             IMAGE_DIRECTORY_ENTRY_EXPORT,
-                                             &i);
 
-   if (!ExportDir || !i || !ProcedureAddress)
-     {
-       return STATUS_INVALID_PARAMETER;
-     }
+/***************************************************************************
+ * NAME                                                         EXPORTED
+ *      LdrQueryImageFileExecutionOptions
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ * @implemented
+ */
+NTSTATUS STDCALL
+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;
+}
 
-   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);
-  }
 
-   return STATUS_PROCEDURE_NOT_FOUND;
+PIMAGE_BASE_RELOCATION STDCALL
+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)(Address + Offset);
+            *ShortPtr += HIWORD(Delta);
+            break;
+
+          case IMAGE_REL_BASED_LOW:
+            ShortPtr = (PUSHORT)(Address + Offset);
+            *ShortPtr += LOWORD(Delta);
+            break;
+
+          case IMAGE_REL_BASED_HIGHLOW:
+            LongPtr = (PULONG)(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 */