[NTDLL]
[reactos.git] / reactos / dll / ntdll / ldr / ldrapi.c
index cf9b5d2..e44cd79 100644 (file)
 /* INCLUDES *****************************************************************/
 
 #include <ntdll.h>
+
 #define NDEBUG
 #include <debug.h>
 
 /* GLOBALS *******************************************************************/
 
+LIST_ENTRY LdrpUnloadHead;
 LONG LdrpLoaderLockAcquisitonCount;
-BOOLEAN LdrpShowRecursiveLoads;
+BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads;
 UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
+ULONG AlternateResourceModuleCount;
 
 /* FUNCTIONS *****************************************************************/
 
+NTSTATUS
+NTAPI
+LdrFindCreateProcessManifest(IN ULONG Flags,
+                             IN PVOID Image,
+                             IN PVOID IdPath,
+                             IN ULONG IdPathLength,
+                             IN PVOID OutDataEntry)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+LdrDestroyOutOfProcessImage(IN PVOID Image)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+LdrCreateOutOfProcessImage(IN ULONG Flags,
+                           IN HANDLE ProcessHandle,
+                           IN HANDLE DllHandle,
+                           IN PVOID Unknown3)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+LdrAccessOutOfProcessResource(IN PVOID Unknown,
+                              IN PVOID Image,
+                              IN PVOID Unknown1,
+                              IN PVOID Unknown2,
+                              IN PVOID Unknown3)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+VOID
+NTAPI
+LdrSetDllManifestProber(IN PVOID ProberFunction)
+{
+    UNIMPLEMENTED;
+}
+
+BOOLEAN
+NTAPI
+LdrAlternateResourcesEnabled(VOID)
+{
+    /* ReactOS does not support this */
+    return FALSE;
+}
+
+FORCEINLINE
+ULONG_PTR
+LdrpMakeCookie(VOID)
+{
+    /* Generate a cookie */
+    return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) |
+                        (_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount) & 0xFFFF);
+}
+
 /*
  * @implemented
  */
@@ -34,19 +104,17 @@ LdrUnlockLoaderLock(IN ULONG Flags,
     DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
 
     /* Check for valid flags */
-    if (Flags & ~1)
+    if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
     {
         /* Flags are invalid, check how to fail */
-        if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
+        if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
         {
             /* The caller wants us to raise status */
             RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
         }
-        else
-        {
-           /* A normal failure */
-            return STATUS_INVALID_PARAMETER_1;
-        }
+
+        /* A normal failure */
+        return STATUS_INVALID_PARAMETER_1;
     }
 
     /* If we don't have a cookie, just return */
@@ -59,20 +127,18 @@ LdrUnlockLoaderLock(IN ULONG Flags,
         DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
 
         /* Invalid cookie, check how to fail */
-        if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
+        if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
         {
             /* The caller wants us to raise status */
             RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
         }
-        else
-        {
-            /* A normal failure */
-            return STATUS_INVALID_PARAMETER_2;
-        }
+
+        /* A normal failure */
+        return STATUS_INVALID_PARAMETER_2;
     }
 
     /* Ready to release the lock */
-    if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
+    if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
     {
         /* Do a direct leave */
         RtlLeaveCriticalSection(&LdrpLoaderLock);
@@ -103,17 +169,16 @@ LdrUnlockLoaderLock(IN ULONG Flags,
 NTSTATUS
 NTAPI
 LdrLockLoaderLock(IN ULONG Flags,
-                  OUT PULONG Result OPTIONAL,
-                  OUT PULONG Cookie OPTIONAL)
+                  OUT PULONG Disposition OPTIONAL,
+                  OUT PULONG_PTR Cookie OPTIONAL)
 {
-    LONG OldCount;
     NTSTATUS Status = STATUS_SUCCESS;
     BOOLEAN InInit = LdrpInLdrInit;
 
-    DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Result, Cookie);
+    DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie);
 
     /* Zero out the outputs */
-    if (Result) *Result = 0;
+    if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID;
     if (Cookie) *Cookie = 0;
 
     /* Validate the flags */
@@ -146,7 +211,7 @@ LdrLockLoaderLock(IN ULONG Flags,
     }
 
     /* If the flag is set, make sure we have a valid pointer to use */
-    if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Result))
+    if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition))
     {
         /* No pointer to return the data to */
         if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
@@ -172,13 +237,13 @@ LdrLockLoaderLock(IN ULONG Flags,
             if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
             {
                 /* It's locked */
-                *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
-                goto Quickie;
+                *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
             }
             else
             {
                 /* It worked */
-                *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                *Cookie = LdrpMakeCookie();
             }
         }
         else
@@ -187,14 +252,9 @@ LdrLockLoaderLock(IN ULONG Flags,
             RtlEnterCriticalSection(&LdrpLoaderLock);
 
             /* See if result was requested */
-            if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+            if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+            *Cookie = LdrpMakeCookie();
         }
-
-        /* Increase the acquisition count */
-        OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
-
-        /* Generate a cookie */
-        *Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
     }
     else
     {
@@ -208,13 +268,13 @@ LdrLockLoaderLock(IN ULONG Flags,
                 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
                 {
                     /* It's locked */
-                    *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
-                    _SEH2_YIELD(return STATUS_SUCCESS);
+                    *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
                 }
                 else
                 {
                     /* It worked */
-                    *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                    *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                    *Cookie = LdrpMakeCookie();
                 }
             }
             else
@@ -223,14 +283,9 @@ LdrLockLoaderLock(IN ULONG Flags,
                 RtlEnterCriticalSection(&LdrpLoaderLock);
 
                 /* See if result was requested */
-                if (Result) *Result = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
+                *Cookie = LdrpMakeCookie();
             }
-
-            /* Increase the acquisition count */
-            OldCount = _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
-
-            /* Generate a cookie */
-            *Cookie = (((ULONG)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) | OldCount;
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -240,7 +295,7 @@ LdrLockLoaderLock(IN ULONG Flags,
         _SEH2_END;
     }
 
-Quickie:
+    /* Return status */
     return Status;
 }
 
@@ -249,6 +304,7 @@ Quickie:
  */
 NTSTATUS
 NTAPI
+DECLSPEC_HOTPATCH
 LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
            IN PULONG DllCharacteristics OPTIONAL,
            IN PUNICODE_STRING DllName,
@@ -263,10 +319,8 @@ LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
     PTEB Teb = NtCurrentTeb();
 
     /* Initialize the strings */
-    RtlInitUnicodeString(&DllString2, NULL);
-    DllString1.Buffer = StringBuffer;
-    DllString1.Length = 0;
-    DllString1.MaximumLength = sizeof(StringBuffer);
+    RtlInitEmptyUnicodeString(&DllString1, StringBuffer, sizeof(StringBuffer));
+    RtlInitEmptyUnicodeString(&DllString2, NULL, 0);
 
     /* Check if the SxS Assemblies specify another file */
     Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
@@ -288,32 +342,29 @@ LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
     else if (Status != STATUS_SXS_KEY_NOT_FOUND)
     {
         /* Unrecoverable SxS failure; did we get a string? */
-        if (DllString2.Buffer)
-        {
-            /* Free the string */
-            RtlFreeUnicodeString(&DllString2);
-            return Status;
-        }
+        if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
+        return Status;
     }
 
     /* Lock the loader lock */
     LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
 
     /* Check if there's a TLD DLL being loaded */
-    if ((OldTldDll = LdrpTopLevelDllBeingLoaded))
+    OldTldDll = LdrpTopLevelDllBeingLoaded;
+    if (OldTldDll)
     {
         /* This is a recursive load, do something about it? */
-        if (ShowSnaps || LdrpShowRecursiveLoads)
+        if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads))
         {
             /* Print out debug messages */
-            DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
+            DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
                     Teb->RealClientId.UniqueProcess,
                     Teb->RealClientId.UniqueThread);
-            DPRINT1("[%lx, %lx]      Previous DLL being loaded \"%wZ\"\n",
+            DPRINT1("[%p, %p]      Previous DLL being loaded \"%wZ\"\n",
                     Teb->RealClientId.UniqueProcess,
                     Teb->RealClientId.UniqueThread,
                     OldTldDll);
-            DPRINT1("[%lx, %lx]      DLL being requested \"%wZ\"\n",
+            DPRINT1("[%p, %p]      DLL being requested \"%wZ\"\n",
                     Teb->RealClientId.UniqueProcess,
                     Teb->RealClientId.UniqueThread,
                     DllName);
@@ -321,13 +372,13 @@ LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
             /* Was it initializing too? */
             if (!LdrpCurrentDllInitializer)
             {
-                DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
+                DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
                         Teb->RealClientId.UniqueProcess,
                         Teb->RealClientId.UniqueThread);
             }
             else
             {
-                DPRINT1("[%lx, %lx]      DLL whose initializer was currently running \"%wZ\"\n",
+                DPRINT1("[%p, %p]      DLL whose initializer was currently running \"%wZ\"\n",
                         Teb->ClientId.UniqueProcess,
                         Teb->ClientId.UniqueThread,
                         &LdrpCurrentDllInitializer->BaseDllName);
@@ -345,9 +396,22 @@ LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
                          DllName,
                          BaseAddress,
                          TRUE);
-
-    /* Set it to success just to be sure */
-    Status = STATUS_SUCCESS;
+    if (NT_SUCCESS(Status))
+    {
+        Status = STATUS_SUCCESS;
+    }
+    else if ((Status != STATUS_NO_SUCH_FILE) &&
+             (Status != STATUS_DLL_NOT_FOUND) &&
+             (Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
+             (Status != STATUS_DLL_INIT_FAILED))
+    {
+        DbgPrintEx(DPFLTR_LDR_ID,
+                   DPFLTR_WARNING_LEVEL,
+                   "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
+                   __FUNCTION__,
+                   DllName,
+                   Status);
+    }
 
     /* Restore the old TLD DLL */
     LdrpTopLevelDllBeingLoaded = OldTldDll;
@@ -381,6 +445,29 @@ LdrFindEntryForAddress(PVOID Address,
     /* Nothing to do */
     if (!Ldr) return STATUS_NO_MORE_ENTRIES;
 
+    /* Get the current entry */
+    LdrEntry = Ldr->EntryInProgress;
+    if (LdrEntry)
+    {
+        /* Get the NT Headers */
+        NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
+        if (NtHeader)
+        {
+            /* Get the Image Base */
+            DllBase = (ULONG_PTR)LdrEntry->DllBase;
+            DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
+
+            /* Check if they match */
+            if (((ULONG_PTR)Address >= DllBase) &&
+                ((ULONG_PTR)Address < DllEnd))
+            {
+                /* Return it */
+                *Module = LdrEntry;
+                return STATUS_SUCCESS;
+            }
+        }
+    }
+
     /* Loop the module list */
     ListHead = &Ldr->InMemoryOrderModuleList;
     NextEntry = ListHead->Flink;
@@ -388,7 +475,8 @@ LdrFindEntryForAddress(PVOID Address,
     {
         /* Get the entry and NT Headers */
         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
-        if ((NtHeader = RtlImageNtHeader(LdrEntry->DllBase)))
+        NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
+        if (NtHeader)
         {
             /* Get the Image Base */
             DllBase = (ULONG_PTR)LdrEntry->DllBase;
@@ -409,6 +497,11 @@ LdrFindEntryForAddress(PVOID Address,
     }
 
     /* Nothing found */
+    DbgPrintEx(DPFLTR_LDR_ID,
+               DPFLTR_WARNING_LEVEL,
+               "LDR: %s() exiting 0x%08lx\n",
+               __FUNCTION__,
+               STATUS_NO_MORE_ENTRIES);
     return STATUS_NO_MORE_ENTRIES;
 }
 
@@ -423,31 +516,36 @@ LdrGetDllHandleEx(IN ULONG Flags,
                   IN PUNICODE_STRING DllName,
                   OUT PVOID *DllHandle OPTIONAL)
 {
-    NTSTATUS Status = STATUS_DLL_NOT_FOUND;
+    NTSTATUS Status;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
-    UNICODE_STRING RedirectName, DllString1;
-    UNICODE_STRING RawDllName;
-    PUNICODE_STRING pRedirectName = &RedirectName;
-    PUNICODE_STRING CompareName;
+    UNICODE_STRING RedirectName, DllString1, RawDllName;
+    PUNICODE_STRING pRedirectName, CompareName;
     PWCHAR p1, p2, p3;
-    BOOLEAN Locked = FALSE;
-    BOOLEAN RedirectedDll = FALSE;
-    ULONG Cookie;
-    ULONG LoadFlag;
+    BOOLEAN Locked, RedirectedDll;
+    ULONG_PTR Cookie;
+    ULONG LoadFlag, Length;
 
     /* Initialize the strings */
-    RtlInitUnicodeString(&DllString1, NULL);
-    RtlInitUnicodeString(&RawDllName, NULL);
+    RtlInitEmptyUnicodeString(&DllString1, NULL, 0);
+    RtlInitEmptyUnicodeString(&RawDllName, NULL, 0);
     RedirectName = *DllName;
+    pRedirectName = &RedirectName;
+
+    /* Initialize state */
+    RedirectedDll = Locked = FALSE;
+    LdrEntry = NULL;
+    Cookie = 0;
 
     /* Clear the handle */
     if (DllHandle) *DllHandle = NULL;
 
-    /* Check for a valid flag */
-    if ((Flags & ~3) || (!DllHandle && !(Flags & 2)))
+    /* Check for a valid flag combination */
+    if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) ||
+        (!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN)))
     {
         DPRINT1("Flags are invalid or no DllHandle given\n");
-        return STATUS_INVALID_PARAMETER;
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
     }
 
     /* If not initializing */
@@ -455,6 +553,9 @@ LdrGetDllHandleEx(IN ULONG Flags,
     {
         /* Acquire the lock */
         Status = LdrLockLoaderLock(0, NULL, &Cookie);
+        if (!NT_SUCCESS(Status)) goto Quickie;
+
+        /* Remember we own it */
         Locked = TRUE;
     }
 
@@ -480,6 +581,13 @@ LdrGetDllHandleEx(IN ULONG Flags,
         /* Unrecoverable SxS failure; */
         goto Quickie;
     }
+    else
+    {
+        ASSERT(pRedirectName == &RedirectName);
+    }
+
+    /* Set default failure code */
+    Status = STATUS_DLL_NOT_FOUND;
 
     /* Use the cache if we can */
     if (LdrpGetModuleHandleCache)
@@ -488,28 +596,24 @@ LdrGetDllHandleEx(IN ULONG Flags,
         if (RedirectedDll)
         {
             /* Check the flag */
-            if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
-            {
-                /* Use the right name */
-                CompareName = &LdrpGetModuleHandleCache->FullDllName;
-            }
-            else
+            if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
             {
                 goto DontCompare;
             }
+
+            /* Use the right name */
+            CompareName = &LdrpGetModuleHandleCache->FullDllName;
         }
         else
         {
             /* Check the flag */
-            if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
-            {
-                /* Use the right name */
-                CompareName = &LdrpGetModuleHandleCache->BaseDllName;
-            }
-            else
+            if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
             {
                 goto DontCompare;
             }
+
+            /* Use the right name */
+            CompareName = &LdrpGetModuleHandleCache->BaseDllName;
         }
 
         /* Check if the name matches */
@@ -522,17 +626,15 @@ LdrGetDllHandleEx(IN ULONG Flags,
 
             /* Return success */
             Status = STATUS_SUCCESS;
-
-            goto FoundEntry;
+            goto Quickie;
         }
     }
 
 DontCompare:
     /* Find the name without the extension */
     p1 = pRedirectName->Buffer;
-    p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
-StartLoop:
     p2 = NULL;
+    p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
     while (p1 != p3)
     {
         if (*p1++ == L'.')
@@ -541,48 +643,47 @@ StartLoop:
         }
         else if (*p1 == L'\\')
         {
-            goto StartLoop;
+            p2 = NULL;
         }
     }
 
     /* Check if no extension was found or if we got a slash */
-    if (!p2 || *p2 == L'\\' || *p2 == L'/')
+    if (!(p2) || (*p2 == L'\\') || (*p2 == L'/'))
     {
         /* Check that we have space to add one */
-        if (pRedirectName->Length + LdrApiDefaultExtension.Length >= MAXLONG)
+        Length = pRedirectName->Length +
+                 LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
+        if (Length >= UNICODE_STRING_MAX_BYTES)
         {
             /* No space to add the extension */
-            return STATUS_NAME_TOO_LONG;
+            Status = STATUS_NAME_TOO_LONG;
+            goto Quickie;
         }
 
         /* Setup the string */
-        RawDllName.MaximumLength = pRedirectName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
-        RawDllName.Length = RawDllName.MaximumLength - sizeof(UNICODE_NULL);
+        RawDllName.MaximumLength = Length;
+        ASSERT(Length >= sizeof(UNICODE_NULL));
         RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                             0,
                                             RawDllName.MaximumLength);
+        if (!RawDllName.Buffer)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Quickie;
+        }
 
-        /* Copy the buffer */
-        RtlMoveMemory(RawDllName.Buffer,
-                      pRedirectName->Buffer,
-                      pRedirectName->Length);
-
-        /* Add extension */
-        RtlMoveMemory((PVOID)((ULONG_PTR)RawDllName.Buffer + pRedirectName->Length),
-                      LdrApiDefaultExtension.Buffer,
-                      LdrApiDefaultExtension.Length);
-
-        /* Null terminate */
-        RawDllName.Buffer[RawDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+        /* Copy the string and add extension */
+        RtlCopyUnicodeString(&RawDllName, pRedirectName);
+        RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension);
     }
     else
     {
         /* Check if there's something in the name */
-        if (pRedirectName->Length)
+        Length = pRedirectName->Length;
+        if (Length)
         {
             /* Check and remove trailing period */
-            if (pRedirectName->Buffer[(pRedirectName->Length - 2) /
-                sizeof(WCHAR)] == '.')
+            if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.')
             {
                 /* Decrease the size */
                 pRedirectName->Length -= sizeof(WCHAR);
@@ -591,24 +692,23 @@ StartLoop:
 
         /* Setup the string */
         RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR);
-        RawDllName.Length = pRedirectName->Length;
         RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                             0,
                                             RawDllName.MaximumLength);
+        if (!RawDllName.Buffer)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Quickie;
+        }
 
-        /* Copy the buffer */
-        RtlMoveMemory(RawDllName.Buffer,
-                      pRedirectName->Buffer,
-                      pRedirectName->Length);
-
-        /* Null terminate */
-        RawDllName.Buffer[RawDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+        /* Copy the string */
+        RtlCopyUnicodeString(&RawDllName, pRedirectName);
     }
 
     /* Display debug string */
     if (ShowSnaps)
     {
-        DPRINT1("LDR: LdrGetDllHandle, searching for %wZ from %ws\n",
+        DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
                 &RawDllName,
                 DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"");
     }
@@ -631,46 +731,41 @@ StartLoop:
         /* Make sure to NULL this */
         LdrEntry = NULL;
     }
-FoundEntry:
-    DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
+Quickie:
+    /* The success path must have a valid loader entry */
+    ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status));
 
-    /* Check if we got an entry */
-    if (LdrEntry)
+    /* Check if we got an entry and success */
+    DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
+    if ((LdrEntry) && (NT_SUCCESS(Status)))
     {
-        /* Check for success */
-        if (NT_SUCCESS(Status))
+        /* Check if the DLL is locked */
+        if ((LdrEntry->LoadCount != 0xFFFF) &&
+            !(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT))
         {
-            /* Check if the DLL is locked */
-            if (LdrEntry->LoadCount != -1)
+            /* Check what to do with the load count */
+            if (Flags & LDR_GET_DLL_HANDLE_EX_PIN)
             {
-                /* Check what flag we got */
-                if (!(Flags & 1))
-                {
-                    /* Check what to do with the load count */
-                    if (Flags & 2)
-                    {
-                        /* Pin it */
-                        LdrEntry->LoadCount = -1;
-                        LoadFlag = LDRP_UPDATE_PIN;
-                    }
-                    else
-                    {
-                        /* Increase the load count */
-                        LdrEntry->LoadCount++;
-                        LoadFlag = LDRP_UPDATE_REFCOUNT;
-                    }
-
-                    /* Update the load count now */
-                    LdrpUpdateLoadCount2(LdrEntry, LoadFlag);
-                    LdrpClearLoadInProgress();
-                }
+                /* Pin it */
+                LdrEntry->LoadCount = 0xFFFF;
+                LoadFlag = LDRP_UPDATE_PIN;
+            }
+            else
+            {
+                /* Increase the load count */
+                LdrEntry->LoadCount++;
+                LoadFlag = LDRP_UPDATE_REFCOUNT;
             }
 
-            /* Check if the caller is requesting the handle */
-            if (DllHandle) *DllHandle = LdrEntry->DllBase;
+            /* Update the load count now */
+            LdrpUpdateLoadCount2(LdrEntry, LoadFlag);
+            LdrpClearLoadInProgress();
         }
+
+        /* Check if the caller is requesting the handle */
+        if (DllHandle) *DllHandle = LdrEntry->DllBase;
     }
-Quickie:
+
     /* Free string if needed */
     if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1);
 
@@ -683,7 +778,11 @@ Quickie:
     }
 
     /* Release lock */
-    if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+    if (Locked)
+    {
+        LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS,
+                            Cookie);
+    }
 
     /* Return */
     return Status;
@@ -700,7 +799,7 @@ LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
                 OUT PVOID *DllHandle)
 {
     /* Call the newer API */
-    return LdrGetDllHandleEx(TRUE,
+    return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT,
                              DllPath,
                              DllCharacteristics,
                              DllName,
@@ -733,19 +832,21 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
 {
     FILE_STANDARD_INFORMATION FileStandardInfo;
     PIMAGE_IMPORT_DESCRIPTOR ImportData;
-    PIMAGE_SECTION_HEADER LastSection;
+    PIMAGE_SECTION_HEADER LastSection = NULL;
     IO_STATUS_BLOCK IoStatusBlock;
     PIMAGE_NT_HEADERS NtHeader;
     HANDLE SectionHandle;
-    SIZE_T ViewSize = 0;
-    PVOID ViewBase = NULL;
-    BOOLEAN Result;
+    SIZE_T ViewSize;
+    PVOID ViewBase;
+    BOOLEAN Result, NoActualCheck;
     NTSTATUS Status;
     PVOID ImportName;
     ULONG Size;
-
     DPRINT("LdrVerifyImageMatchesChecksum() called\n");
 
+    /* If the handle has the magic KnownDll flag, skip actual checksums */
+    NoActualCheck = ((ULONG_PTR)FileHandle & 1);
+
     /* Create the section */
     Status = NtCreateSection(&SectionHandle,
                              SECTION_MAP_EXECUTE,
@@ -761,6 +862,8 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
     }
 
     /* Map the section */
+    ViewSize = 0;
+    ViewBase = NULL;
     Status = NtMapViewOfSection(SectionHandle,
                                 NtCurrentProcess(),
                                 &ViewBase,
@@ -795,13 +898,22 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
     /* Protect with SEH */
     _SEH2_TRY
     {
-        /* Verify the checksum */
-        Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
-                                                     ViewSize,
-                                                     FileStandardInfo.EndOfFile.LowPart);
+        /* Check if this is the KnownDll hack */
+        if (NoActualCheck)
+        {
+            /* Don't actually do it */
+            Result = TRUE;
+        }
+        else
+        {
+            /* Verify the checksum */
+            Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
+                                                         FileStandardInfo.EndOfFile.LowPart,
+                                                         FileStandardInfo.EndOfFile.LowPart);
+        }
 
         /* Check if a callback was supplied */
-        if (Result && Callback)
+        if ((Result) && (Callback))
         {
             /* Get the NT Header */
             NtHeader = RtlImageNtHeader(ViewBase);
@@ -850,14 +962,14 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
     NtClose(SectionHandle);
 
     /* Return status */
-    return !Result ? STATUS_IMAGE_CHECKSUM_MISMATCH : Status;
+    return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH;
 }
 
 NTSTATUS
 NTAPI
 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,
                                    IN ULONG Reserved,
-                                   IN PRTL_PROCESS_MODULES ModuleInformation,
+                                   OUT PRTL_PROCESS_MODULES ModuleInformation,
                                    IN ULONG Size,
                                    OUT PULONG ReturnedSize OPTIONAL)
 {
@@ -875,21 +987,21 @@ LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,
     /* Acquire loader lock */
     RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
 
-    /* Check if we were given enough space */
-    if (Size < UsedSize)
-    {
-        Status = STATUS_INFO_LENGTH_MISMATCH;
-    }
-    else
-    {
-        ModuleInformation->NumberOfModules = 0;
-        ModulePtr = &ModuleInformation->Modules[0];
-        Status = STATUS_SUCCESS;
-    }
-
-    /* Traverse the list of modules */
     _SEH2_TRY
     {
+        /* Check if we were given enough space */
+        if (Size < UsedSize)
+        {
+            Status = STATUS_INFO_LENGTH_MISMATCH;
+        }
+        else
+        {
+            ModuleInformation->NumberOfModules = 0;
+            ModulePtr = &ModuleInformation->Modules[0];
+            Status = STATUS_SUCCESS;
+        }
+
+        /* Traverse the list of modules */
         ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
         Entry = ModuleListHead->Flink;
 
@@ -991,9 +1103,14 @@ LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation,
     return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize);
 }
 
+/*
+ * @implemented
+ */
 NTSTATUS
 NTAPI
-LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVOID Context)
+LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag,
+                          IN PLDR_ENUM_CALLBACK EnumProc,
+                          IN PVOID Context)
 {
     PLIST_ENTRY ListHead, ListEntry;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
@@ -1002,7 +1119,7 @@ LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVO
     BOOLEAN Stop = FALSE;
 
     /* Check parameters */
-    if (ReservedFlag || !EnumProc) return STATUS_INVALID_PARAMETER;
+    if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER;
 
     /* Acquire the loader lock */
     Status = LdrLockLoaderLock(0, NULL, &Cookie);
@@ -1053,4 +1170,469 @@ LdrEnumerateLoadedModules(BOOLEAN ReservedFlag, PLDR_ENUM_CALLBACK EnumProc, PVO
     return STATUS_SUCCESS;
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    NTSTATUS Status;
+    BOOLEAN LockHeld;
+    ULONG_PTR Cookie;
+    DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
+
+    /* Don't do it during shutdown */
+    if (LdrpShutdownInProgress) return STATUS_SUCCESS;
+
+    /* Check if we should grab the lock */
+    LockHeld = FALSE;
+    if (!LdrpInLdrInit)
+    {
+        /* Grab the lock */
+        Status = LdrLockLoaderLock(0, NULL, &Cookie);
+        if (!NT_SUCCESS(Status)) return Status;
+        LockHeld = TRUE;
+    }
+
+    /* Make sure the DLL is valid and get its entry */
+    Status = STATUS_DLL_NOT_FOUND;
+    if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+    {
+        /* Get if it has a TLS slot */
+        if (!LdrEntry->TlsIndex)
+        {
+            /* It doesn't, so you're allowed to call this */
+            LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
+            Status = STATUS_SUCCESS;
+        }
+    }
+
+    /* Check if the lock was held */
+    if (LockHeld)
+    {
+        /* Release it */
+        LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+    }
+
+    /* Return the status */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrAddRefDll(IN ULONG Flags,
+             IN PVOID BaseAddress)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Cookie;
+    BOOLEAN Locked = FALSE;
+
+    /* Check for invalid flags */
+    if (Flags & ~(LDR_ADDREF_DLL_PIN))
+    {
+        /* Fail with invalid parameter status if so */
+        Status = STATUS_INVALID_PARAMETER;
+        goto quickie;
+    }
+
+    /* Acquire the loader lock if not in init phase */
+    if (!LdrpInLdrInit)
+    {
+        /* Acquire the lock */
+        Status = LdrLockLoaderLock(0, NULL, &Cookie);
+        if (!NT_SUCCESS(Status)) goto quickie;
+        Locked = TRUE;
+    }
+
+    /* Get this module's data table entry */
+    if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+    {
+        if (!LdrEntry)
+        {
+            /* Shouldn't happen */
+            Status = STATUS_INTERNAL_ERROR;
+            goto quickie;
+        }
+
+        /* If this is not a pinned module */
+        if (LdrEntry->LoadCount != 0xFFFF)
+        {
+            /* Update its load count */
+            if (Flags & LDR_ADDREF_DLL_PIN)
+            {
+                /* Pin it by setting load count to -1 */
+                LdrEntry->LoadCount = 0xFFFF;
+                LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN);
+            }
+            else
+            {
+                /* Increase its load count by one */
+                LdrEntry->LoadCount++;
+                LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
+            }
+
+            /* Clear load in progress */
+            LdrpClearLoadInProgress();
+        }
+    }
+    else
+    {
+        /* There was an error getting this module's handle, return invalid param status */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+quickie:
+    /* Check for error case */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Print debug information */
+        if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) &&
+                            (Status != STATUS_DLL_NOT_FOUND) &&
+                            (Status != STATUS_OBJECT_NAME_NOT_FOUND)))
+        {
+            DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress, Status);
+        }
+    }
+
+    /* Release the lock if needed */
+    if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrUnloadDll(IN PVOID BaseAddress)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PPEB Peb = NtCurrentPeb();
+    PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry;
+    PVOID EntryPoint;
+    PLIST_ENTRY NextEntry;
+    LIST_ENTRY UnloadList;
+    RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
+    PVOID CorImageData;
+    ULONG ComSectionSize;
+
+    /* Get the LDR Lock */
+    if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock);
+
+    /* Increase the unload count */
+    LdrpActiveUnloadCount++;
+
+    /* Skip unload */
+    if (LdrpShutdownInProgress) goto Quickie;
+
+    /* Make sure the DLL is valid and get its entry */
+    if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
+    {
+        Status = STATUS_DLL_NOT_FOUND;
+        goto Quickie;
+    }
+
+    /* Check the current Load Count */
+    if (LdrEntry->LoadCount != 0xFFFF)
+    {
+        /* Decrease it */
+        LdrEntry->LoadCount--;
+
+        /* If it's a dll */
+        if (LdrEntry->Flags & LDRP_IMAGE_DLL)
+        {
+            /* Set up the Act Ctx */
+            ActCtx.Size = sizeof(ActCtx);
+            ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
+            RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
+
+            /* Activate the ActCtx */
+            RtlActivateActivationContextUnsafeFast(&ActCtx,
+                                                   LdrEntry->EntryPointActivationContext);
+
+            /* Update the load count */
+            LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT);
+
+            /* Release the context */
+            RtlDeactivateActivationContextUnsafeFast(&ActCtx);
+        }
+    }
+    else
+    {
+        /* The DLL is locked */
+        goto Quickie;
+    }
+
+    /* Show debug message */
+    if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n");
+
+    /* Check if this is our only unload and initialize the list if so */
+    if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead);
+
+    /* Loop the modules to build the list */
+    NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink;
+    while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList)
+    {
+        /* Get the entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InInitializationOrderModuleList);
+        NextEntry = NextEntry->Blink;
+
+        /* Remove flag */
+        LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
+
+        /* If the load count is now 0 */
+        if (!LdrEntry->LoadCount)
+        {
+            /* Show message */
+            if (ShowSnaps)
+            {
+                DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
+                        LdrpActiveUnloadCount,
+                        LdrEntry->BaseDllName.Buffer,
+                        LdrEntry->FullDllName.Buffer,
+                        (ULONG)LdrEntry->LoadCount,
+                        LdrEntry->EntryPoint);
+            }
+
+            /* FIXME: Call Shim Engine and notify */
+
+            /* Unlink it */
+            CurrentEntry = LdrEntry;
+            RemoveEntryList(&CurrentEntry->InInitializationOrderModuleList);
+            RemoveEntryList(&CurrentEntry->InMemoryOrderModuleList);
+            RemoveEntryList(&CurrentEntry->HashLinks);
+
+            /* If there's more then one active unload */
+            if (LdrpActiveUnloadCount > 1)
+            {
+                /* Flush the cached DLL handle and clear the list */
+                LdrpLoadedDllHandleCache = NULL;
+                CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
+            }
+
+            /* Add the entry on the unload list */
+            InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks);
+        }
+    }
+
+    /* Only call the entrypoints once */
+    if (LdrpActiveUnloadCount > 1) goto Quickie;
+
+    /* Now loop the unload list and create our own */
+    InitializeListHead(&UnloadList);
+    CurrentEntry = NULL;
+    NextEntry = LdrpUnloadHead.Flink;
+    while (NextEntry != &LdrpUnloadHead)
+    {
+        /* Get the current entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
+
+        /* FIXME: Log the Unload Event */
+        //LdrpRecordUnloadEvent(LdrEntry);
+
+        /* Set the entry and clear it from the list */
+        CurrentEntry = LdrEntry;
+        LdrpLoadedDllHandleCache = NULL;
+        CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
+
+        /* Move it from the global to the local list */
+        RemoveEntryList(&CurrentEntry->HashLinks);
+        InsertTailList(&UnloadList, &CurrentEntry->HashLinks);
+
+        /* Get the entrypoint */
+        EntryPoint = LdrEntry->EntryPoint;
+
+        /* Check if we should call it */
+        if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED))
+        {
+            /* Show message */
+            if (ShowSnaps)
+            {
+                DPRINT1("LDR: Calling deinit %p\n", EntryPoint);
+            }
+
+            /* Set up the Act Ctx */
+            ActCtx.Size = sizeof(ActCtx);
+            ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
+            RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
+
+            /* Activate the ActCtx */
+            RtlActivateActivationContextUnsafeFast(&ActCtx,
+                                                   LdrEntry->EntryPointActivationContext);
+
+            /* Call the entrypoint */
+            LdrpCallInitRoutine(LdrEntry->EntryPoint,
+                                LdrEntry->DllBase,
+                                DLL_PROCESS_DETACH,
+                                NULL);
+
+            /* Release the context */
+            RtlDeactivateActivationContextUnsafeFast(&ActCtx);
+        }
+
+        /* Remove it from the list */
+        RemoveEntryList(&CurrentEntry->InLoadOrderLinks);
+        CurrentEntry = NULL;
+        NextEntry = LdrpUnloadHead.Flink;
+    }
+
+    /* Now loop our local list */
+    NextEntry = UnloadList.Flink;
+    while (NextEntry != &UnloadList)
+    {
+        /* Get the entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
+        NextEntry = NextEntry->Flink;
+        CurrentEntry = LdrEntry;
+
+        /* Notify Application Verifier */
+        if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
+        {
+            DPRINT1("We don't support Application Verifier yet\n");
+        }
+
+        /* Show message */
+        if (ShowSnaps)
+        {
+            DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer);
+        }
+
+        /* Check if this is a .NET executable */
+        CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+                                                    TRUE,
+                                                    IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
+                                                    &ComSectionSize);
+        if (CorImageData)
+        {
+            /* FIXME */
+            DPRINT1(".NET Images are not supported yet\n");
+        }
+
+        /* Check if we should unmap*/
+        if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP))
+        {
+            /* Unmap the DLL */
+            Status = NtUnmapViewOfSection(NtCurrentProcess(),
+                                          CurrentEntry->DllBase);
+            ASSERT(NT_SUCCESS(Status));
+        }
+
+        /* Unload the alternate resource module, if any */
+        LdrUnloadAlternateResourceModule(CurrentEntry->DllBase);
+
+        /* FIXME: Send shutdown notification */
+        //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
+
+        /* Check if a Hotpatch is active */
+        if (LdrEntry->PatchInformation)
+        {
+            /* FIXME */
+            DPRINT1("We don't support Hotpatching yet\n");
+        }
+
+        /* Deallocate the Entry */
+        LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry);
+
+        /* If this is the cached entry, invalidate it */
+        if (LdrpGetModuleHandleCache == CurrentEntry)
+        {
+            LdrpGetModuleHandleCache = NULL;
+        }
+    }
+
+Quickie:
+    /* Decrease unload count */
+    LdrpActiveUnloadCount--;
+    if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock);
+
+    /* Return to caller */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+RtlDllShutdownInProgress(VOID)
+{
+    /* Return the internal global */
+    return LdrpShutdownInProgress;
+}
+
+/*
+ * @implemented
+ */
+PIMAGE_BASE_RELOCATION
+NTAPI
+LdrProcessRelocationBlock(IN ULONG_PTR Address,
+                          IN ULONG Count,
+                          IN PUSHORT TypeOffset,
+                          IN LONG_PTR Delta)
+{
+    return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
+}
+
+/* FIXME: Add to ntstatus.mc */
+#define STATUS_MUI_FILE_NOT_FOUND        ((NTSTATUS)0xC00B0001L)
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrLoadAlternateResourceModule(IN PVOID Module,
+                               IN PWSTR Buffer)
+{
+    /* Is MUI Support enabled? */
+    if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS;
+
+    UNIMPLEMENTED;
+    return STATUS_MUI_FILE_NOT_FOUND;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
+{
+    ULONG_PTR Cookie;
+
+    /* Acquire the loader lock */
+    LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
+
+    /* Check if there's any alternate resources loaded */
+    if (AlternateResourceModuleCount)
+    {
+        UNIMPLEMENTED;
+    }
+
+    /* Release the loader lock */
+    LdrUnlockLoaderLock(1, Cookie);
+
+    /* All done */
+    return TRUE;
+}
+
+/*
+ * @unimplemented
+ */
+BOOLEAN
+NTAPI
+LdrFlushAlternateResourceModules(VOID)
+{
+    UNIMPLEMENTED;
+    return FALSE;
+}
+
 /* EOF */