add current directory to default search path so programs can find their own dlls
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
index 0d2d9e5..19e639b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: utils.c,v 1.20 1999/12/13 22:04:34 dwelch Exp $
+/* $Id: utils.c,v 1.47 2001/09/01 19:36:30 rex Exp $
  * 
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
@@ -8,25 +8,31 @@
  *                  Rex Jolliff (rex@lvcablemodem.com)
  */
 
+/*
+ * TODO:
+ *     - Fix calling of entry points
+ *     - Handle loading flags correctly
+ *     - any more ??
+ */
+
 /* INCLUDES *****************************************************************/
 
 #include <reactos/config.h>
-#define WIN32_NO_STATUS
-#define WIN32_NO_PEHDR
-#include <windows.h>
 #include <ddk/ntddk.h>
-#include <pe.h>
+#include <windows.h>
 #include <string.h>
-#include <internal/string.h>
 #include <wchar.h>
 #include <ntdll/ldr.h>
+#include <ntos/minmax.h>
+#include <napi/shared_data.h>
+
 
 #ifdef DBG_NTDLL_LDR_UTILS
 #define NDEBUG
 #endif
 #include <ntdll/ntdll.h>
 
-/* FUNCTIONS *****************************************************************/
+/* PROTOTYPES ****************************************************************/
 
 
 /* Type for a DLL's entry point */
@@ -34,259 +40,410 @@ typedef
 WINBOOL
 STDCALL
 (* PDLLMAIN_FUNC) (
-       HANDLE  hInst, 
+       HANDLE  hInst,
        ULONG   ul_reason_for_call,
        LPVOID  lpReserved
        );
 
-static
-NTSTATUS
-LdrFindDll (PDLL* Dll,PCHAR    Name);
+static NTSTATUS LdrFindDll(PLDR_MODULE *Dll,PUNICODE_STRING Name);
+static PVOID LdrFixupForward(PCHAR ForwardName);
+static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
 
-/**********************************************************************
- * NAME
- *     LdrLoadDll
+
+/* FUNCTIONS *****************************************************************/
+
+
+#ifdef KDBG
+
+VOID LdrLoadModuleSymbols(PLDR_MODULE ModuleObject)
+{
+  NtSystemDebugControl(
+    0xffffffff,
+    (PVOID)ModuleObject,
+    0,
+    NULL,
+    0,
+    NULL);
+}
+
+#endif /* KDBG */
+
+
+/***************************************************************************
+ * 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;
-       PEPFUNC                 DllStartupAddr;
-       ULONG                   ImageSize;
-       ULONG                   InitialViewSize;
-       PVOID                   ImageBase;
-       HANDLE                  FileHandle;
-       HANDLE                  SectionHandle;
-       PDLLMAIN_FUNC           Entrypoint;
-
-       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
-        */
+   WCHAR Buffer[MAX_PATH];
+   ULONG Length;
+   PWCHAR Extension;
+   PWCHAR Pointer;
 
-       if ( strncmp(Name,"\\??\\",3) != 0 ) {
-       
-               strcat(fqname, Name);
-       }
-       else
-               strncpy(fqname, Name, 256);
+   Length = DllName->Length / sizeof(WCHAR);
 
-       DPRINT("fqname \"%s\"\n", fqname);
-       /*
-        * Open the DLL's image file.
-        */
+   if (BaseName == TRUE)
+     {
+       /* get the base dll name */
+       Pointer = DllName->Buffer + Length;
+       Extension = Pointer;
 
-   if (LdrFindDll(Dll, Name) == STATUS_SUCCESS)
-     return STATUS_SUCCESS;
+       do
+         {
+            --Pointer;
+         }
+       while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
 
+       Pointer++;
+       Length = Extension - Pointer;
+       memmove (Buffer, Pointer, Length * sizeof(WCHAR));
+     }
+   else
+     {
+       /* get the full dll name */
+       memmove (Buffer, DllName->Buffer, DllName->Length);
+     }
 
-       RtlInitAnsiString(
-               & AnsiString,
-               fqname
-               );
-       RtlAnsiStringToUnicodeString(
-               & UnicodeString,
-               & AnsiString,
-               TRUE
-               );
+   /* 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);
+     }
 
-       InitializeObjectAttributes(
-               & FileObjectAttributes,
-               & UnicodeString,
-               0,
-               NULL,
-               NULL
-               );
+   RtlCreateUnicodeString (FullDllName,
+                          Buffer);
+}
 
-       DPRINT("Opening dll \"%s\"\n", fqname);
-       
-       Status = ZwOpenFile(
-                       & FileHandle,
-                       FILE_ALL_ACCESS,
-                       & FileObjectAttributes, 
-                       NULL,
-                       0,
-                       0
-                       );
-       if (!NT_SUCCESS(Status))
-       {
-               dprintf("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;
+/***************************************************************************
+ * NAME                                                                EXPORTED
+ *     LdrLoadDll
+ *
+ * DESCRIPTION
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ *
+ * REVISIONS
+ *
+ * NOTE
+ *
+ */
 
-       DPRINT("ImageBase 0x%08x\n", ImageBase);
+NTSTATUS STDCALL
+LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
+           IN ULONG LoadFlags,
+           IN PUNICODE_STRING Name,
+           OUT PVOID *BaseAddress OPTIONAL)
+{
+  WCHAR                        SearchPathBuffer[MAX_PATH];
+  WCHAR                        FullDosName[MAX_PATH];
+  UNICODE_STRING               AdjustedName;
+  UNICODE_STRING               FullNtFileName;
+  OBJECT_ATTRIBUTES    FileObjectAttributes;
+  char                 BlockBuffer [1024];
+  PIMAGE_DOS_HEADER    DosHeader;
+  NTSTATUS             Status;
+  PIMAGE_NT_HEADERS    NTHeaders;
+  ULONG                        ImageSize;
+  ULONG                        InitialViewSize;
+  PVOID                        ImageBase;
+  HANDLE                       FileHandle;
+  HANDLE                       SectionHandle;
+  PDLLMAIN_FUNC                Entrypoint = NULL;
+  PLDR_MODULE          Module;
+  
+  if (Name == NULL)
+    {
+      *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+      return STATUS_SUCCESS;
+    }
+  
+  *BaseAddress = NULL;
+  
+  DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
+        Name, BaseAddress);
+  
+  /* adjust the full dll name */
+  LdrAdjustDllName (&AdjustedName,
+                   Name,
+                   FALSE);
+  DPRINT("AdjustedName: %wZ\n", &AdjustedName);
+  
+  /*
+   * Test if dll is already loaded.
+   */
+  if (LdrFindDll(&Module, &AdjustedName) == STATUS_SUCCESS)
+    {
+      DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
+      if (Module->LoadCount != -1)
+       Module->LoadCount++;
+      *BaseAddress = Module->BaseAddress;
+      return STATUS_SUCCESS;
+    }
+  DPRINT("Loading \"%wZ\"\n", Name);
+  
+  if (SearchPath == NULL)
+    {
+      PKUSER_SHARED_DATA SharedUserData = 
+       (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
+      
+      SearchPath = SearchPathBuffer;
+      wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
+      wcscat (SearchPathBuffer, L"\\system32;");
+      wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
+      wcscat (SearchPathBuffer, L";.");
+    }
+
+  DPRINT("SearchPath %S\n", SearchPath);
+  
+  if (RtlDosSearchPath_U (SearchPath,
+                         AdjustedName.Buffer,
+                         NULL,
+                         MAX_PATH,
+                         FullDosName,
+                         NULL) == 0)
+    return STATUS_DLL_NOT_FOUND;
+  
+  DPRINT("FullDosName %S\n", FullDosName);
+  
+  RtlFreeUnicodeString (&AdjustedName);
+  
+  if (!RtlDosPathNameToNtPathName_U (FullDosName,
+                                    &FullNtFileName,
+                                    NULL,
+                                    NULL))
+    return STATUS_DLL_NOT_FOUND;
+  
+  DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
+  
+  InitializeObjectAttributes(&FileObjectAttributes,
+                            &FullNtFileName,
+                            0,
+                            NULL,
+                            NULL);
+  
+  DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
+  
+  Status = ZwOpenFile(&FileHandle,
+                     FILE_ALL_ACCESS,
+                     &FileObjectAttributes, 
+                     NULL,
+                     0,
+                     0);
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n", 
+              &FullNtFileName, Status);
+      RtlFreeUnicodeString (&FullNtFileName);
+      return Status;
+    }
+  RtlFreeUnicodeString (&FullNtFileName);
+  
+  Status = ZwReadFile(FileHandle,
+                     0,
+                     0,
+                     0,
+                     0,
+                     BlockBuffer,
+                     sizeof(BlockBuffer),
+                     0,
+                     0);
+  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)(NTHeaders) != IMAGE_PE_MAGIC))
+    {
+      DPRINT("NTDLL format invalid\n");
+      ZwClose(FileHandle);
+      
+      return STATUS_UNSUCCESSFUL;
+    }
+  
+  ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
+  ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
+  
+  DPRINT("ImageBase 0x%08x\n", ImageBase);
        
-       DllStartupAddr =
-               (PEPFUNC) (
-                       ImageBase
-                       + NTHeaders->OptionalHeader.AddressOfEntryPoint
-                       );
-       /*
-        * Create a section for NTDLL.
-        */
-       Status = ZwCreateSection(
-                       & SectionHandle,
-                       SECTION_ALL_ACCESS,
-                       NULL,
-                       NULL,
-                       PAGE_READWRITE,
-                       MEM_COMMIT,
-                       FileHandle
-                       );
-       if (!NT_SUCCESS(Status))
+  /*
+   * Create a section for dll.
+   */
+  Status = ZwCreateSection(&SectionHandle,
+                          SECTION_ALL_ACCESS,
+                          NULL,
+                          NULL,
+                          PAGE_READWRITE,
+                          SEC_COMMIT | SEC_IMAGE,
+                          FileHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
+      ZwClose(FileHandle);
+      return Status;
+    }
+  
+  /*
+   * Map the dll into the process.
+   */
+  InitialViewSize = 0;
+  ImageBase = 0;
+  Status = ZwMapViewOfSection(SectionHandle,
+                             NtCurrentProcess(),
+                             &ImageBase,
+                             0,
+                             InitialViewSize,
+                             NULL,
+                             &InitialViewSize,
+                             0,
+                             MEM_COMMIT,
+                             PAGE_READWRITE);
+  if (!NT_SUCCESS(Status))
+    {
+      DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
+              Status);
+      ZwClose(FileHandle);
+               return(Status);
+    }
+  ZwClose(FileHandle);
+
+  /* relocate dll and fixup import table */
+  if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
+      IMAGE_FILE_DLL)
+    {
+      Entrypoint =
+       (PDLLMAIN_FUNC) LdrPEStartup(ImageBase, SectionHandle);
+    }
+  
+  /* build module entry */
+  Module = RtlAllocateHeap(RtlGetProcessHeap(),
+                          0,
+                          sizeof (LDR_MODULE));
+  Module->BaseAddress = (PVOID)ImageBase;
+  Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
+  if (Module->EntryPoint != 0)
+    Module->EntryPoint += (ULONG)Module->BaseAddress;
+  Module->SizeOfImage = ImageSize;
+  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->TlsIndex = 0;
+  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);
+  
+  /* FIXME: aquire loader lock */
+  InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
+                &Module->InLoadOrderModuleList);
+  InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
+                &Module->InInitializationOrderModuleList);
+  /* FIXME: release loader lock */
+
+#ifdef KDBG
+  LdrLoadModuleSymbols(Module);
+#endif /* KDBG */
+
+  /* initialize dll */
+  if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
+      IMAGE_FILE_DLL)
+    {
+      if (Module->EntryPoint != 0)
        {
-               DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
-               ZwClose(FileHandle);
-               return Status;
+         Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+         
+         DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+         if (FALSE == Entrypoint(Module->BaseAddress,
+                                 DLL_PROCESS_ATTACH,
+                                 NULL))
+           {
+             DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
+                    &Module->BaseDllName);
+             /* FIXME: should clean up and fail */
+           }
+         else
+           {
+             DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
+                    &Module->BaseDllName);
+           }
        }
-       /*
-        * 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))
+      else
        {
-               dprintf("NTDLL.LDR: map view of section failed (Status %x)\n",
-                      Status);
-               ZwClose(FileHandle);
-               return(Status);
+         DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
+                &Module->BaseDllName);
        }
-       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)
-     {
-
-               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;
+  *BaseAddress = Module->BaseAddress;
+  return STATUS_SUCCESS;
 }
 
 
-/**********************************************************************
+/***************************************************************************
  * NAME                                                                LOCAL
  *     LdrFindDll
  *
@@ -301,60 +458,47 @@ NTSTATUS LdrLoadDll (PDLL* Dll,
  * NOTE
  *
  */
-static NTSTATUS LdrFindDll(PDLL* Dll, PCHAR Name)
+static NTSTATUS LdrFindDll(PLDR_MODULE *Dll, PUNICODE_STRING Name)
 {
-   PIMAGE_EXPORT_DIRECTORY     ExportDir;
-   DLL                 * current;
-   PIMAGE_OPTIONAL_HEADER      OptionalHeader;
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
 
+   DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name);
 
-   DPRINT("NTDLL.LdrFindDll(Name %s)\n", Name);
-
-   current = & LdrDllListHead;
+   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+   Entry = ModuleListHead->Flink;
 
    // NULL is the current process
-
    if ( Name == NULL )
      {
-       *Dll = current;
+       *Dll = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
        return STATUS_SUCCESS;
      }
 
-   do
+   while (Entry != ModuleListHead)
      {
-       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)
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+       DPRINT("Scanning %wZ %wZ\n", &Module->BaseDllName, Name);
+
+       if (RtlCompareUnicodeString(&Module->BaseDllName, Name, TRUE) == 0)
          {
-            *Dll = current;
-            current->ReferenceCount++;
+            *Dll = Module;
             return STATUS_SUCCESS;
          }
-       
-       current = current->Next;
-       
-     } while (current != & LdrDllListHead);
 
-   DPRINT("Failed to find dll %s\n",Name);
+       Entry = Entry->Flink;
+     }
 
-   return -1;
-}
+   DPRINT("Failed to find dll %wZ\n", Name);
 
+   return STATUS_UNSUCCESSFUL;
+}
 
 /**********************************************************************
- * NAME
- *     LdrMapSections
+ * NAME                                                                LOCAL
+ *     LdrFixupForward
  *
  * DESCRIPTION
  *
@@ -367,50 +511,48 @@ 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;
+   UNICODE_STRING FunctionName;
+   NTSTATUS Status;
+   PCHAR p;
+   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);
+       *p = 0;
+
+       DPRINT("Dll: %s  Function: %s\n", NameBuffer, p+1);
+       RtlCreateUnicodeStringFromAsciiz (&DllName,
+                                         NameBuffer);
+
+       Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
        if (!NT_SUCCESS(Status))
          {
-            DPRINT("Failed to map section");
-            return(Status);
+            Status = LdrLoadDll(NULL,
+                                0,
+                                &DllName,
+                                &BaseAddress);
+            if (!NT_SUCCESS(Status))
+              {
+                 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
+                 RtlFreeUnicodeString (&DllName);
+                 return NULL;
+              }
          }
+
+       RtlFreeUnicodeString (&DllName);
+       DPRINT("BaseAddress: %p\n", BaseAddress);
+       
+       return LdrGetExportByName(BaseAddress, p+1, -1);
      }
-   return STATUS_SUCCESS;
+
+   return NULL;
 }
 
 
@@ -429,10 +571,9 @@ NTSTATUS LdrMapSections(HANDLE                     ProcessHandle,
  * NOTE
  *
  */
-
-PVOID
+static PVOID
 LdrGetExportByOrdinal (
-       PDLL    Module,
+       PVOID   BaseAddress,
        ULONG   Ordinal
        )
 {
@@ -440,25 +581,24 @@ LdrGetExportByOrdinal (
        PDWORD                  * ExFunctions;
        USHORT                  * ExOrdinals;
 
-       ExportDir = (
-               Module->BaseAddress
-               + (Module->Headers->OptionalHeader
-                       .DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]
-                               .VirtualAddress
-                               )
-               );
+       ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+               RtlImageDirectoryEntryToData (BaseAddress,
+                                             TRUE,
+                                             IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                             NULL);
+
 
        ExOrdinals = (USHORT *)
                RVA(
-                       Module->BaseAddress,
+                       BaseAddress,
                        ExportDir->AddressOfNameOrdinals
                        );
        ExFunctions = (PDWORD *)
                RVA(
-                       Module->BaseAddress,
+                       BaseAddress,
                        ExportDir->AddressOfFunctions
                        );
-       dprintf(
+       DbgPrint(
                "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
                Ordinal,
                ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
@@ -482,76 +622,131 @@ LdrGetExportByOrdinal (
  * NOTE
  *
  */
-
-PVOID
-LdrGetExportByName (
-       PDLL    Module,
-       PUCHAR  SymbolName
-       )
+static PVOID
+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]));
-               }
-       }
+   PIMAGE_EXPORT_DIRECTORY     ExportDir;
+   PDWORD                      * ExFunctions;
+   PDWORD                      * ExNames;
+   USHORT                      * ExOrdinals;
+   ULONG                       i;
+   PVOID                       ExName;
+   ULONG                       Ordinal;
+   PVOID                       Function;
+   ULONG 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)
+     {
+       DbgPrint("LdrGetExportByName(): no export directory!\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->NumberOfFunctions)
+     {
+       ExName = RVA(BaseAddress, ExNames[Hint]);
+       if (strcmp(ExName, SymbolName) == 0)
+         {
+            Ordinal = ExOrdinals[Hint];
+            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+            if (((ULONG)Function >= (ULONG)ExportDir) &&
+                ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+              {
+                 DPRINT("Forward: %s\n", (PCHAR)Function);
+                 Function = LdrFixupForward((PCHAR)Function);
+              }
+            if (Function != NULL)
+              return Function;
+         }
+     }
+   
+   /*
+    * Try a binary search first
+    */
+   minn = 0;
+   maxn = ExportDir->NumberOfFunctions;
+   while (minn <= maxn)
+     {
+       ULONG mid;
+       LONG res;
 
-       dprintf("LdrGetExportByName() = failed to find %s\n",SymbolName);
+       mid = (minn + maxn) / 2;
 
-       return NULL;
+       ExName = RVA(BaseAddress, ExNames[mid]);
+       res = strcmp(ExName, SymbolName);
+       if (res == 0)
+         {
+            Ordinal = ExOrdinals[mid];
+            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+            if (((ULONG)Function >= (ULONG)ExportDir) &&
+                ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+              {
+                 DPRINT("Forward: %s\n", (PCHAR)Function);
+                 Function = LdrFixupForward((PCHAR)Function);
+              }
+            if (Function != NULL)
+              return Function;
+         }
+       else if (minn == maxn)
+         {
+            DPRINT("LdrGetExportByName(): binary search failed\n");
+            break;
+         }
+       else if (res > 0)
+         {
+            maxn = mid - 1;
+         }
+       else
+         {
+            minn = mid + 1;
+         }
+     }
+   
+   /*
+    * Fall back on a linear search
+    */
+   DPRINT("LdrGetExportByName(): Falling back on a linear search of export table\n");
+   for (i = 0; i < ExportDir->NumberOfFunctions; i++)
+     {
+       ExName = RVA(BaseAddress, ExNames[i]);
+       if (strcmp(ExName,SymbolName) == 0)
+         {
+            Ordinal = ExOrdinals[i];
+            Function = RVA(BaseAddress, ExFunctions[Ordinal]);
+            DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
+            if (((ULONG)Function >= (ULONG)ExportDir) &&
+                ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
+              {
+                 DPRINT("Forward: %s\n", (PCHAR)Function);
+                 Function = LdrFixupForward((PCHAR)Function);
+              }
+            return Function;
+         }
+     }
+   DbgPrint("LdrGetExportByName(): failed to find %s\n",SymbolName);
+   return NULL;
 }
 
 
@@ -571,105 +766,99 @@ LdrGetExportByName (
  * NOTE
  *
  */
-static
-NTSTATUS
-LdrPerformRelocations (
-       PIMAGE_NT_HEADERS       NTHeaders,
-       PVOID                   ImageBase
-       )
+static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS       NTHeaders,
+                                      PVOID                    ImageBase)
 {
-       USHORT                  NumberOfEntries;
-       PUSHORT                 pValue16;
-       ULONG                   RelocationRVA;
-       ULONG                   Delta32;
-       ULONG                   Offset;
-       PULONG                  pValue32;
-       PRELOCATION_DIRECTORY   RelocationDir;
-       PRELOCATION_ENTRY       RelocationBlock;
-       int                     i;
-
-
-       RelocationRVA =
-               NTHeaders->OptionalHeader
-                       .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
-                               .VirtualAddress;
-       if (RelocationRVA)
+   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);
+          RelocationDir = (PRELOCATION_DIRECTORY)
+            ((PCHAR)ImageBase + RelocationRVA);
 
-               while (RelocationDir->SizeOfBlock)
-               {
-                       Delta32 = (unsigned long) (
-                               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) (
+          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
-                               );
-               }
+                                                        + RelocationRVA
+                                                        );
+            }
        }
-       return STATUS_SUCCESS;
+   return STATUS_SUCCESS;
 }
 
 
@@ -693,10 +882,10 @@ LdrPerformRelocations (
 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS      NTHeaders,
                                PVOID                   ImageBase)
 {
-   PIMAGE_IMPORT_MODULE_DIRECTORY      ImportModuleDirectory;
-   ULONG                               Ordinal;
-   PDLL                                Module;
-   NTSTATUS                    Status;
+   PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
+   ULONG Ordinal;
+   PVOID BaseAddress;
+   NTSTATUS Status;
    
    DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders, 
           ImageBase);
@@ -709,24 +898,39 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
                                 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
                             .VirtualAddress);
    DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
-   
+
    while (ImportModuleDirectory->dwRVAModuleName)
      {
-       PVOID   * ImportAddressList; 
+       PVOID   * ImportAddressList;
        PULONG  FunctionNameList;
+       UNICODE_STRING DllName;
        DWORD   pName;
-       PWORD   pHint;
-       
+       WORD    pHint;
+
        DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
               (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
-       
-       Status = LdrLoadDll(&Module,
-                           (PCHAR)(ImageBase
-                                   +ImportModuleDirectory->dwRVAModuleName));
+
+       RtlCreateUnicodeStringFromAsciiz (&DllName,
+                 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
+
+       Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
        if (!NT_SUCCESS(Status))
          {
-            return Status;
+            Status = LdrLoadDll(NULL,
+                                0,
+                                &DllName,
+                                &BaseAddress);
+            RtlFreeUnicodeString (&DllName);
+            if (!NT_SUCCESS(Status))
+              {
+                 DbgPrint("LdrFixupImports:failed to load %s\n"
+                       ,(PCHAR)(ImageBase 
+                               + ImportModuleDirectory->dwRVAModuleName));
+
+                 return Status;
+              }
          }
+
        /*
         * Get the import address list.
         */
@@ -745,10 +949,9 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS  NTHeaders,
          }
        else
          {
-            FunctionNameList = (PULONG) (
-                                         ImageBase
-                                         + ImportModuleDirectory->dwRVAFunctionAddressList
-                                         );
+            FunctionNameList = 
+              (PULONG)(ImageBase 
+                       + ImportModuleDirectory->dwRVAFunctionAddressList);
          }
        /*
         * Walk through function list and fixup addresses.
@@ -758,36 +961,24 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
             if ((*FunctionNameList) & 0x80000000)
               {
                  Ordinal = (*FunctionNameList) & 0x7fffffff;
-                               *ImportAddressList = 
-                   LdrGetExportByOrdinal(
-                                         Module,
-                                         Ordinal
-                                         );
+                 *ImportAddressList = 
+                   LdrGetExportByOrdinal(BaseAddress,
+                                         Ordinal);
               }
             else
               {
-                 pName = (DWORD) (
-                                  ImageBase
-                                  + *FunctionNameList
-                                  + 2
-                                  );
-                 pHint = (PWORD) (
-                                  ImageBase
-                                  + *FunctionNameList
-                                               );
-                 
-                 *ImportAddressList =
-                   LdrGetExportByName(
-                                               Module,
-                                      (PUCHAR) pName
-                                      );
+                 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
+                 pHint = *(PWORD)(ImageBase + *FunctionNameList);
+
+                 *ImportAddressList = 
+                   LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
                  if ((*ImportAddressList) == NULL)
                    {
-                                  dprintf("Failed to import %s\n", pName);
+                      DbgPrint("Failed to import %s\n", pName);
                       return STATUS_UNSUCCESSFUL;
                    }
               }
-                       ImportAddressList++;
+            ImportAddressList++;
             FunctionNameList++;
          }
        ImportModuleDirectory++;
@@ -824,14 +1015,16 @@ static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS        NTHeaders,
  * NOTE
  *
  */
-PEPFUNC LdrPEStartup (PVOID    ImageBase,
-                     HANDLE    SectionHandle)
+PEPFUNC LdrPEStartup (PVOID  ImageBase,
+                     HANDLE SectionHandle)
 {
    NTSTATUS            Status;
-   PEPFUNC                     EntryPoint;
+   PEPFUNC             EntryPoint = NULL;
    PIMAGE_DOS_HEADER   DosHeader;
    PIMAGE_NT_HEADERS   NTHeaders;
-   
+
+   DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
+           ImageBase, (ULONG)SectionHandle);
 
    /*
     * Overlay DOS and WNT headers structures
@@ -839,15 +1032,7 @@ PEPFUNC LdrPEStartup (PVOID       ImageBase,
     */
    DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
    NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
-   
-   /*
-    * Initialize image sections.
-    */
-   LdrMapSections(NtCurrentProcess(),
-                 ImageBase,
-                 SectionHandle,
-                 NTHeaders);
-   
+
    /*
     * If the base address is different from the
     * one the DLL is actually loaded, perform any
@@ -855,14 +1040,15 @@ PEPFUNC LdrPEStartup (PVOID      ImageBase,
     */
    if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
      {
-       Status = LdrPerformRelocations(NTHeaders, ImageBase);
-       if (!NT_SUCCESS(Status))
-         {
-            dprintf("LdrPerformRelocations() failed\n");
-            return NULL;
-         }
+       DbgPrint("LDR: Performing relocations\n");
+       Status = LdrPerformRelocations(NTHeaders, ImageBase);
+       if (!NT_SUCCESS(Status))
+        {
+          DbgPrint("LdrPerformRelocations() failed\n");
+          return NULL;
+        }
      }
-   
+
    /*
     * If the DLL's imports symbols from other
     * modules, fixup the imported calls entry points.
@@ -874,215 +1060,602 @@ PEPFUNC LdrPEStartup (PVOID    ImageBase,
        Status = LdrFixupImports(NTHeaders, ImageBase);
        if (!NT_SUCCESS(Status))
          {
-            dprintf("LdrFixupImports() failed\n");
+            DbgPrint("LdrFixupImports() failed\n");
             return NULL;
          }
+       DPRINT("Fixup done\n");
      }
-   
+
    /*
     * Compute the DLL's entry point's address.
     */
-   EntryPoint = (PEPFUNC) (ImageBase
+   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);
+     }
    DPRINT("LdrPEStartup() = %x\n",EntryPoint);
    return EntryPoint;
 }
 
-NTSTATUS LdrUnloadDll(PDLL Dll)
+
+NTSTATUS STDCALL
+LdrUnloadDll (IN PVOID BaseAddress)
 {
-   PDLLMAIN_FUNC               Entrypoint;
-   NTSTATUS            Status;
+   PIMAGE_NT_HEADERS NtHeaders;
+   PDLLMAIN_FUNC Entrypoint;
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+   NTSTATUS Status;
+
+   if (BaseAddress == NULL)
+     return STATUS_SUCCESS;
 
-   if ( Dll == NULL || Dll == &LdrDllListHead )
-     return -1;
+   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+   Entry = ModuleListHead->Flink;
 
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+       if (Module->BaseAddress == BaseAddress)
+         {
+            if (Module->LoadCount == -1)
+              {
+                 /* never unload this dll */
+                 return STATUS_SUCCESS;
+              }
+            else if (Module->LoadCount > 1)
+              {
+                 Module->LoadCount--;
+                 return STATUS_SUCCESS;
+              }
 
-   if ( Dll->ReferenceCount > 1 )
+            NtHeaders = RtlImageNtHeader (Module->BaseAddress);
+            if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
+              {
+                 if (Module->EntryPoint != 0)
+                   {
+                      Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+                      DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+                      Entrypoint(Module->BaseAddress,
+                                 DLL_PROCESS_DETACH,
+                                 NULL);
+                   }
+                 else
+                   {
+                      DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
+                   }
+              }
+            Status = ZwUnmapViewOfSection (NtCurrentProcess (),
+                                           Module->BaseAddress);
+            ZwClose (Module->SectionHandle);
+
+            /* remove the module entry from the list */
+            RtlFreeUnicodeString (&Module->FullDllName);
+            RtlFreeUnicodeString (&Module->BaseDllName);
+            RemoveEntryList (Entry);
+            RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
+
+            return Status;
+         }
+
+       Entry = Entry->Flink;
+     }
+
+   DPRINT("NTDLL.LDR: Dll not found\n")
+
+   return STATUS_UNSUCCESSFUL;
+}
+
+
+NTSTATUS STDCALL
+LdrFindResource_U(PVOID BaseAddress,
+                  PLDR_RESOURCE_INFO ResourceInfo,
+                  ULONG Level,
+                  PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
+{
+   PIMAGE_RESOURCE_DIRECTORY ResDir;
+   PIMAGE_RESOURCE_DIRECTORY ResBase;
+   PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
+   NTSTATUS Status = STATUS_SUCCESS;
+   ULONG EntryCount;
+   PWCHAR ws;
+   ULONG i;
+   ULONG Id;
+
+   DPRINT ("LdrFindResource_U()\n");
+
+   /* Get the pointer to the resource directory */
+   ResDir = (PIMAGE_RESOURCE_DIRECTORY)
+       RtlImageDirectoryEntryToData (BaseAddress,
+                                     TRUE,
+                                     IMAGE_DIRECTORY_ENTRY_RESOURCE,
+                                     &i);
+   if (ResDir == NULL)
      {
-       Dll->ReferenceCount--;
-       return STATUS_SUCCESS;
+       return STATUS_RESOURCE_DATA_NOT_FOUND;
      }
 
-   if (( Dll->Headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ) {
+   DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
 
-      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);
+   ResBase = ResDir;
 
-   ZwClose(Dll->SectionHandle);
+   /* Let's go into resource tree */
+   for (i = 0; i < Level; i++)
+     {
+       DPRINT("ResDir: %x\n", (ULONG)ResDir);
+       Id = ((PULONG)ResourceInfo)[i];
+       EntryCount = ResDir->NumberOfNamedEntries;
+       ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+       DPRINT("ResEntry %x\n", (ULONG)ResEntry);
+       if (Id & 0xFFFF0000)
+         {
+            /* Resource name is a unicode string */
+            for (; EntryCount--; ResEntry++)
+              {
+                 /* Scan entries for equal name */
+                 if (ResEntry->Name & 0x80000000)
+                   {
+                      ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
+                      if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
+                          wcslen((PWCHAR)Id) == (int)*ws )
+                        {
+                           goto found;
+                        }
+                   }
+              }
+         }
+       else
+         {
+            /* We use ID number instead of string */
+            ResEntry += EntryCount;
+            EntryCount = ResDir->NumberOfIdEntries;
+            for (; EntryCount--; ResEntry++)
+              {
+                 /* Scan entries for equal name */
+                 if (ResEntry->Name == Id)
+                   {
+                    DPRINT("ID entry found %x\n", Id);
+                    goto found;
+                   }
+              }
+         }
+       DPRINT("Error %lu\n", i);
 
-   return Status;
+         switch (i)
+         {
+            case 0:
+               return STATUS_RESOURCE_TYPE_NOT_FOUND;
+
+            case 1:
+               return STATUS_RESOURCE_NAME_NOT_FOUND;
+
+            case 2:
+               if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
+                 {
+                    /* Use the first available language */
+                    ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
+                    break;
+                 }
+               return STATUS_RESOURCE_LANG_NOT_FOUND;
+
+            case 3:
+               return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+            default:
+               return STATUS_INVALID_PARAMETER;
+         }
+found:;
+       ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
+               (ResEntry->OffsetToData & 0x7FFFFFFF));
+     }
+   DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
+
+   if (ResourceDataEntry)
+     {
+       *ResourceDataEntry = (PVOID)ResDir;
+     }
+
+  return Status;
 }
 
-static IMAGE_RESOURCE_DIRECTORY_ENTRY * LdrGetNextEntry(IMAGE_RESOURCE_DIRECTORY *ResourceDir, LPCWSTR ResourceName, ULONG Offset)
+
+NTSTATUS STDCALL
+LdrAccessResource(IN  PVOID BaseAddress,
+                  IN  PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
+                  OUT PVOID *Resource OPTIONAL,
+                  OUT PULONG Size OPTIONAL)
 {
+   PIMAGE_SECTION_HEADER Section;
+   PIMAGE_NT_HEADERS NtHeader;
+   ULONG SectionRva;
+   ULONG SectionVa;
+   ULONG DataSize;
+   ULONG Offset = 0;
+   ULONG Data;
+
+   Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
+                                              TRUE,
+                                              IMAGE_DIRECTORY_ENTRY_RESOURCE,
+                                              &DataSize);
+   if (Data == 0)
+       return STATUS_RESOURCE_DATA_NOT_FOUND;
+
+   if ((ULONG)BaseAddress & 1)
+     {
+       /* loaded as ordinary file */
+       NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
+       Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+       Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+       if (Section == NULL)
+         {
+            return STATUS_RESOURCE_DATA_NOT_FOUND;
+         }
 
+       if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
+         {
+            SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
+            SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
+            Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
+         }
+     }
 
-       WORD    NumberOfNamedEntries;
-       WORD    NumberOfIdEntries;
-       WORD    Entries;
-       ULONG   Length;
+   if (Resource)
+     {
+       *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
+     }
 
-       if ( (((ULONG)ResourceDir) & 0xF0000000) != 0 ) {
-               return (IMAGE_RESOURCE_DIRECTORY_ENTRY *)NULL;
-       }
+   if (Size)
+     {
+       *Size = ResourceDataEntry->Size;
+     }
 
+   return STATUS_SUCCESS;
+}
 
-       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);
-               
-       }
+NTSTATUS STDCALL
+LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+   NTSTATUS Status;
 
-       
+   DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
+         BaseAddress);
 
-       return NULL;
-               
+   Status = STATUS_DLL_NOT_FOUND;
+
+   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+   Entry = ModuleListHead->Flink;
+
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
+
+       DPRINT("BaseDllName %wZ BaseAddress %x\n",
+              &Module->BaseDllName,
+              Module->BaseAddress);
+
+       if (Module->BaseAddress == BaseAddress)
+         {
+            if (Module->TlsIndex == 0)
+              {
+                Module->Flags |= 0x00040000;
+                Status = STATUS_SUCCESS;
+              }
+            return Status;
+         }
+
+       Entry = Entry->Flink;
+     }
+
+   return Status;
 }
 
 
+NTSTATUS STDCALL
+LdrFindResourceDirectory_U (IN PVOID BaseAddress,
+                            WCHAR **name,
+                            DWORD level,
+                            OUT PVOID *addr)
+{
+   PIMAGE_RESOURCE_DIRECTORY ResDir;
+   PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
+   ULONG EntryCount;
+   ULONG i;
+   NTSTATUS Status = STATUS_SUCCESS;
+   WCHAR *ws;
+
+   /* Get the pointer to the resource directory */
+   ResDir = (PIMAGE_RESOURCE_DIRECTORY)
+       RtlImageDirectoryEntryToData (BaseAddress,
+                                     TRUE,
+                                     IMAGE_DIRECTORY_ENTRY_RESOURCE,
+                                     &i);
+   if (ResDir == NULL)
+     {
+       return STATUS_RESOURCE_DATA_NOT_FOUND;
+     }
+
+   /* Let's go into resource tree */
+   for (i = 0; i < level; i++, name++)
+     {
+       EntryCount = ResDir->NumberOfNamedEntries;
+       ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
+       if ((ULONG)(*name) & 0xFFFF0000)
+         {
+            /* Resource name is a unicode string */
+            for (; EntryCount--; ResEntry++)
+              {
+                 /* Scan entries for equal name */
+                 if (ResEntry->Name & 0x80000000)
+                   {
+                      ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
+                      if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
+                        {
+                           goto found;
+                        }
+                   }
+              }
+         }
+       else
+         {
+            /* We use ID number instead of string */
+            ResEntry += EntryCount;
+            EntryCount = ResDir->NumberOfIdEntries;
+            for (; EntryCount--; ResEntry++)
+              {
+                 /* Scan entries for equal name */
+                 if (ResEntry->Name == (ULONG)(*name))
+                    goto found;
+              }
+         }
+
+         switch (i)
+         {
+            case 0:
+               return STATUS_RESOURCE_TYPE_NOT_FOUND;
+
+            case 1:
+               return STATUS_RESOURCE_NAME_NOT_FOUND;
+
+            case 2:
+               Status = STATUS_RESOURCE_LANG_NOT_FOUND;
+               /* Just use first language entry */
+               if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
+                 {
+                    ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
+                    break;
+                 }
+               return Status;
+
+            case 3:
+               return STATUS_RESOURCE_DATA_NOT_FOUND;
 
-NTSTATUS LdrFindResource_U(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY **ResourceDataEntry,LPCWSTR ResourceName, ULONG ResourceType,ULONG Language)
+            default:
+               return STATUS_INVALID_PARAMETER;
+         }
+found:;
+       ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
+     }
+
+   if (addr)
+     {
+       *addr = (PVOID)ResDir;
+     }
+
+  return Status;
+}
+
+
+NTSTATUS STDCALL
+LdrGetDllHandle (IN ULONG Unknown1,
+                 IN ULONG Unknown2,
+                 IN PUNICODE_STRING DllName,
+                 OUT PVOID *BaseAddress)
 {
-       IMAGE_RESOURCE_DIRECTORY *ResourceTypeDir;
-       IMAGE_RESOURCE_DIRECTORY *ResourceNameDir;
-       IMAGE_RESOURCE_DIRECTORY *ResourceLangDir;
+   UNICODE_STRING FullDllName;
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
 
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceTypeDirEntry;
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceNameDirEntry;
-       IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceLangDirEntry;
+   DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
+          Unknown1, Unknown2, DllName, BaseAddress);
 
-       PIMAGE_OPTIONAL_HEADER  OptionalHeader;
+   /* NULL is the current executable */
+   if ( DllName == NULL )
+     {
+       *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
+       DPRINT("BaseAddress %x\n", *BaseAddress);
+       return STATUS_SUCCESS;
+     }
 
+   LdrAdjustDllName (&FullDllName,
+                    DllName,
+                    TRUE);
 
+   DPRINT("FullDllName %wZ\n",
+         &FullDllName);
 
-       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);
+   ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
+   Entry = ModuleListHead->Flink;
 
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
 
-       Offset = (ULONG)ResourceTypeDir;
+       DPRINT("EntryPoint %x\n", Module->EntryPoint);
+       DPRINT("Comparing %wZ and %wZ\n",
+              &Module->BaseDllName,
+              &FullDllName);
 
-       ResourceTypeDirEntry = LdrGetNextEntry(ResourceTypeDir, (LPWSTR)ResourceType, Offset);
-       
-       if ( ResourceTypeDirEntry != NULL ) {
-               ResourceNameDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceTypeDirEntry->OffsetToData & (~0xF0000000)) + Offset);
+       if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE))
+         {
+            RtlFreeUnicodeString (&FullDllName);
+            *BaseAddress = Module->BaseAddress;
+            DPRINT("BaseAddress %x\n", *BaseAddress);
+            return STATUS_SUCCESS;
+         }
 
-               ResourceNameDirEntry = LdrGetNextEntry(ResourceNameDir, ResourceName, Offset);
+       Entry = Entry->Flink;
+     }
 
-               if ( ResourceNameDirEntry != NULL ) {
-               
-                       ResourceLangDir = (IMAGE_RESOURCE_DIRECTORY*)((ResourceNameDirEntry->OffsetToData & (~0xF0000000)) + Offset);
-
-                       ResourceLangDirEntry = LdrGetNextEntry(ResourceLangDir, (LPWSTR)Language, Offset);
-                       if ( ResourceLangDirEntry != NULL ) {
-
-                               *ResourceDataEntry = (IMAGE_RESOURCE_DATA_ENTRY *)(ResourceLangDirEntry->OffsetToData +
-                                                                       (ULONG)ResourceTypeDir);
-                               return STATUS_SUCCESS;
-                       }
-                       else {
-                               return -1;
-                       }
-               }       
-               else {
-                               return -1;      
-               }
-                       
-       }
+   DPRINT("Failed to find dll %wZ\n", &FullDllName);
+   RtlFreeUnicodeString (&FullDllName);
+   *BaseAddress = NULL;
+   return STATUS_DLL_NOT_FOUND;
+}
+
+
+NTSTATUS STDCALL
+LdrGetProcedureAddress (IN PVOID BaseAddress,
+                        IN PANSI_STRING Name,
+                        IN ULONG Ordinal,
+                        OUT PVOID *ProcedureAddress)
+{
+   PIMAGE_EXPORT_DIRECTORY ExportDir;
+   PUSHORT OrdinalPtr;
+   PULONG NamePtr;
+   PULONG AddressPtr;
+   ULONG i = 0;
 
-       return -1;
+   DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
+          BaseAddress, Name, Ordinal, ProcedureAddress);
 
+   /* Get the pointer to the export directory */
+   ExportDir = (PIMAGE_EXPORT_DIRECTORY)
+               RtlImageDirectoryEntryToData (BaseAddress,
+                                             TRUE,
+                                             IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                             &i);
+
+   DPRINT("ExportDir %x i %lu\n", ExportDir, i);
+
+   if (!ExportDir || !i || !ProcedureAddress)
+     {
+       return STATUS_INVALID_PARAMETER;
+     }
+
+   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;
 }
 
-NTSTATUS LdrAccessResource(DLL *Dll, IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry, void **Data)
+
+NTSTATUS STDCALL
+LdrShutdownProcess (VOID)
 {
-       PIMAGE_SECTION_HEADER   Sections;
-       int i;
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
 
-       if ( Data == NULL )
-               return -1;
+   DPRINT("LdrShutdownProcess() called\n");
 
-       if ( ResourceDataEntry == NULL )
-               return -1;
+   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
 
-       if ( Dll == NULL )
-               return -1;
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Blink;
 
-       Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(Dll->BaseAddress);
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+
+       DPRINT("  Unloading %S\n",
+              &Module->BaseDllName);
+       // PJS: only detach from static dlls, they should FreeLibrary() any dlls that
+       // they loaded dynamically, and when the last reference is gone, that lib will
+       // be detached.  
+       if (Module->EntryPoint != 0 && Module->LoadCount == -1)
+         {
+            PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
 
-       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;
-       }
+            DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+            Entrypoint (Module->BaseAddress,
+                        DLL_PROCESS_DETACH,
+                        NULL);
+         }
 
-       if ( i == Dll->Headers->FileHeader.NumberOfSections ) {
-               *Data = NULL;
-               return -1;
-       }
+       Entry = Entry->Blink;
+     }
 
-       *Data = (void *)(((ULONG)Dll->BaseAddress + ResourceDataEntry->OffsetToData - (ULONG)Sections[i].VirtualAddress) +
-                                  (ULONG)Sections[i].PointerToRawData);
+   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
 
+   DPRINT("LdrShutdownProcess() done\n");
 
-       return STATUS_SUCCESS;
+   return STATUS_SUCCESS;
+}
+
+
+NTSTATUS STDCALL
+LdrShutdownThread (VOID)
+{
+   PLIST_ENTRY ModuleListHead;
+   PLIST_ENTRY Entry;
+   PLDR_MODULE Module;
+
+   DPRINT("LdrShutdownThread() called\n");
+
+   RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
+
+   ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
+   Entry = ModuleListHead->Blink;
+
+   while (Entry != ModuleListHead)
+     {
+       Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
+
+       DPRINT("  Unloading %wZ\n",
+              &Module->BaseDllName);
+
+       if (Module->EntryPoint != 0)
+         {
+            PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
+
+            DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
+            Entrypoint (Module->BaseAddress,
+                        DLL_THREAD_DETACH,
+                        NULL);
+         }
+
+       Entry = Entry->Blink;
+     }
+
+   RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
+
+   DPRINT("LdrShutdownThread() done\n");
+
+   return STATUS_SUCCESS;
 }
 
 /* EOF */