- Revert r52573
[reactos.git] / dll / ntdll / ldr / ldrapi.c
index e08f4ca..7ba8792 100644 (file)
@@ -16,6 +16,8 @@
 /* GLOBALS *******************************************************************/
 
 LONG LdrpLoaderLockAcquisitonCount;
+BOOLEAN LdrpShowRecursiveLoads;
+UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
 
 /* FUNCTIONS *****************************************************************/
 
@@ -242,6 +244,480 @@ Quickie:
     return Status;
 }
 
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
+           IN PULONG DllCharacteristics OPTIONAL,
+           IN PUNICODE_STRING DllName,
+           OUT PVOID *BaseAddress)
+{
+    WCHAR StringBuffer[MAX_PATH];
+    UNICODE_STRING DllString1, DllString2;
+    BOOLEAN RedirectedDll = FALSE;
+    NTSTATUS Status;
+    ULONG Cookie;
+    PUNICODE_STRING OldTldDll;
+    PTEB Teb = NtCurrentTeb();
+
+    /* Initialize the strings */
+    RtlInitUnicodeString(&DllString2, NULL);
+    DllString1.Buffer = StringBuffer;
+    DllString1.Length = 0;
+    DllString1.MaximumLength = sizeof(StringBuffer);
+
+    /* Check if the SxS Assemblies specify another file */
+    Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
+                                                      DllName,
+                                                      &LdrApiDefaultExtension,
+                                                      &DllString1,
+                                                      &DllString2,
+                                                      &DllName,
+                                                      NULL,
+                                                      NULL,
+                                                      NULL);
+
+    /* Check success */
+    if (NT_SUCCESS(Status))
+    {
+        /* Let Ldrp know */
+        RedirectedDll = TRUE;
+    }
+    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;
+    }
+
+    /* 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))
+    {
+        /* This is a recursive load, do something about it? */
+        if (ShowSnaps || LdrpShowRecursiveLoads)
+        {
+            /* Print out debug messages */
+            DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
+                    Teb->RealClientId.UniqueProcess,
+                    Teb->RealClientId.UniqueThread);
+            DPRINT1("[%lx, %lx]      Previous DLL being loaded \"%wZ\"\n",
+                    Teb->RealClientId.UniqueProcess,
+                    Teb->RealClientId.UniqueThread,
+                    OldTldDll);
+            DPRINT1("[%lx, %lx]      DLL being requested \"%wZ\"\n",
+                    Teb->RealClientId.UniqueProcess,
+                    Teb->RealClientId.UniqueThread,
+                    DllName);
+
+            /* Was it initializing too? */
+            if (!LdrpCurrentDllInitializer)
+            {
+                DPRINT1("[%lx, %lx] 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",
+                        Teb->ClientId.UniqueProcess,
+                        Teb->ClientId.UniqueThread,
+                        &LdrpCurrentDllInitializer->BaseDllName);
+            }
+        }
+    }
+
+    /* Set this one as the TLD DLL being loaded*/
+    LdrpTopLevelDllBeingLoaded = DllName;
+
+    /* Load the DLL */
+    Status = LdrpLoadDll(RedirectedDll,
+                         SearchPath,
+                         DllCharacteristics,
+                         DllName,
+                         BaseAddress,
+                         TRUE);
+
+    /* Restore the old TLD DLL */
+    LdrpTopLevelDllBeingLoaded = OldTldDll;
+
+    /* Release the lock */
+    LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+
+    /* Do we have a redirect string? */
+    if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
+
+    /* Return */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrFindEntryForAddress(PVOID Address,
+                       PLDR_DATA_TABLE_ENTRY *Module)
+{
+    PLIST_ENTRY ListHead, NextEntry;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PIMAGE_NT_HEADERS NtHeader;
+    PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr;
+    ULONG_PTR DllBase, DllEnd;
+
+    DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
+
+    /* Nothing to do */
+    if (!Ldr) return STATUS_NO_MORE_ENTRIES;
+
+    /* Loop the module list */
+    ListHead = &Ldr->InMemoryOrderModuleList;
+    NextEntry = ListHead->Flink;
+    while (NextEntry != ListHead)
+    {
+        /* Get the entry and NT Headers */
+        LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
+        if ((NtHeader = RtlImageNtHeader(LdrEntry->DllBase)))
+        {
+            /* 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;
+            }
+
+            /* Next Entry */
+            NextEntry = NextEntry->Flink;
+        }
+    }
+
+    /* Nothing found */
+    return STATUS_NO_MORE_ENTRIES;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrGetDllHandleEx(IN ULONG Flags,
+                  IN PWSTR DllPath OPTIONAL,
+                  IN PULONG DllCharacteristics OPTIONAL,
+                  IN PUNICODE_STRING DllName,
+                  OUT PVOID *DllHandle OPTIONAL)
+{
+    NTSTATUS Status = STATUS_DLL_NOT_FOUND;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    UNICODE_STRING RedirectName, DllString1;
+    UNICODE_STRING RawDllName;
+    PUNICODE_STRING pRedirectName = &RedirectName;
+    PUNICODE_STRING CompareName;
+    PWCHAR p1, p2, p3;
+    BOOLEAN Locked = FALSE;
+    BOOLEAN RedirectedDll = FALSE;
+    ULONG Cookie;
+    ULONG LoadFlag;
+
+    /* Initialize the strings */
+    RtlInitUnicodeString(&DllString1, NULL);
+    RtlInitUnicodeString(&RawDllName, NULL);
+    RedirectName = *DllName;
+
+    /* Clear the handle */
+    if (DllHandle) *DllHandle = NULL;
+
+    /* Check for a valid flag */
+    if ((Flags & ~3) || (!DllHandle && !(Flags & 2)))
+    {
+        DPRINT1("Flags are invalid or no DllHandle given\n");
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* If not initializing */
+    if (!LdrpInLdrInit)
+    {
+        /* Acquire the lock */
+        Status = LdrLockLoaderLock(0, NULL, &Cookie);
+        Locked = TRUE;
+    }
+
+    /* Check if the SxS Assemblies specify another file */
+    Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
+                                                      pRedirectName,
+                                                      &LdrApiDefaultExtension,
+                                                      NULL,
+                                                      &DllString1,
+                                                      &pRedirectName,
+                                                      NULL,
+                                                      NULL,
+                                                      NULL);
+
+    /* Check success */
+    if (NT_SUCCESS(Status))
+    {
+        /* Let Ldrp know */
+        RedirectedDll = TRUE;
+    }
+    else if (Status != STATUS_SXS_KEY_NOT_FOUND)
+    {
+        /* Unrecoverable SxS failure; */
+        goto Quickie;
+    }
+
+    /* Use the cache if we can */
+    if (LdrpGetModuleHandleCache)
+    {
+        /* Check if we were redirected */
+        if (RedirectedDll)
+        {
+            /* Check the flag */
+            if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
+            {
+                /* Use the right name */
+                CompareName = &LdrpGetModuleHandleCache->FullDllName;
+            }
+            else
+            {
+                goto DontCompare;
+            }
+        }
+        else
+        {
+            /* Check the flag */
+            if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
+            {
+                /* Use the right name */
+                CompareName = &LdrpGetModuleHandleCache->BaseDllName;
+            }
+            else
+            {
+                goto DontCompare;
+            }
+        }
+
+        /* Check if the name matches */
+        if (RtlEqualUnicodeString(pRedirectName,
+                                  CompareName,
+                                  TRUE))
+        {
+            /* Skip the rest */
+            LdrEntry = LdrpGetModuleHandleCache;
+
+            /* Return success */
+            Status = STATUS_SUCCESS;
+
+            goto FoundEntry;
+        }
+    }
+
+DontCompare:
+    /* Find the name without the extension */
+    p1 = pRedirectName->Buffer;
+    p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
+StartLoop:
+    p2 = NULL;
+    while (p1 != p3)
+    {
+        if (*p1++ == L'.')
+        {
+            p2 = p1;
+        }
+        else if (*p1 == L'\\')
+        {
+            goto StartLoop;
+        }
+    }
+
+    /* Check if no extension was found or if we got a slash */
+    if (!p2 || *p2 == L'\\' || *p2 == L'/')
+    {
+        /* Check that we have space to add one */
+        if (pRedirectName->Length + LdrApiDefaultExtension.Length >= MAXLONG)
+        {
+            /* No space to add the extension */
+            return STATUS_NAME_TOO_LONG;
+        }
+
+        /* Setup the string */
+        RawDllName.MaximumLength = pRedirectName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
+        RawDllName.Length = RawDllName.MaximumLength - sizeof(UNICODE_NULL);
+        RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                            0,
+                                            RawDllName.MaximumLength);
+
+        /* 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;
+    }
+    else
+    {
+        /* Check if there's something in the name */
+        if (pRedirectName->Length)
+        {
+            /* Check and remove trailing period */
+            if (pRedirectName->Buffer[(pRedirectName->Length - 2) /
+                sizeof(WCHAR)] == '.')
+            {
+                /* Decrease the size */
+                pRedirectName->Length -= sizeof(WCHAR);
+            }
+        }
+
+        /* Setup the string */
+        RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR);
+        RawDllName.Length = pRedirectName->Length;
+        RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                            0,
+                                            RawDllName.MaximumLength);
+
+        /* Copy the buffer */
+        RtlMoveMemory(RawDllName.Buffer,
+                      pRedirectName->Buffer,
+                      pRedirectName->Length);
+
+        /* Null terminate */
+        RawDllName.Buffer[RawDllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+    }
+
+    /* Display debug string */
+    if (ShowSnaps)
+    {
+        DPRINT1("LDR: LdrGetDllHandle, searching for %wZ from %ws\n",
+                &RawDllName,
+                DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"");
+    }
+
+    /* Do the lookup */
+    if (LdrpCheckForLoadedDll(DllPath,
+                              &RawDllName,
+                              ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE,
+                              RedirectedDll,
+                              &LdrEntry))
+    {
+        /* Update cached entry */
+        LdrpGetModuleHandleCache = LdrEntry;
+
+        /* Return success */
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* Make sure to NULL this */
+        LdrEntry = NULL;
+    }
+FoundEntry:
+    DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
+
+    /* Check if we got an entry */
+    if (LdrEntry)
+    {
+        /* Check for success */
+        if (NT_SUCCESS(Status))
+        {
+            /* Check if the DLL is locked */
+            if (LdrEntry->LoadCount != -1)
+            {
+                /* 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();
+                }
+            }
+
+            /* Check if the caller is requesting the handle */
+            if (DllHandle) *DllHandle = LdrEntry->DllBase;
+        }
+    }
+Quickie:
+    /* Free string if needed */
+    if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1);
+
+    /* Free the raw DLL Name if needed */
+    if (RawDllName.Buffer)
+    {
+        /* Free the heap-allocated buffer */
+        RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer);
+        RawDllName.Buffer = NULL;
+    }
+
+    /* Release lock */
+    if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
+
+    /* Return */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
+                IN PULONG DllCharacteristics OPTIONAL,
+                IN PUNICODE_STRING DllName,
+                OUT PVOID *DllHandle)
+{
+    /* Call the newer API */
+    return LdrGetDllHandleEx(TRUE,
+                             DllPath,
+                             DllCharacteristics,
+                             DllName,
+                             DllHandle);
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+LdrGetProcedureAddress(IN PVOID BaseAddress,
+                       IN PANSI_STRING Name,
+                       IN ULONG Ordinal,
+                       OUT PVOID *ProcedureAddress)
+{
+    /* Call the internal routine and tell it to execute DllInit */
+    return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE);
+}
+
 /*
  * @implemented
  */
@@ -374,21 +850,6 @@ LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
     return !Result ? STATUS_IMAGE_CHECKSUM_MISMATCH : Status;
 }
 
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-LdrGetProcedureAddress_(IN PVOID BaseAddress,
-                       IN PANSI_STRING Name,
-                       IN ULONG Ordinal,
-                       OUT PVOID *ProcedureAddress)
-{
-    /* Call the internal routine and tell it to execute DllInit */
-    return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE);
-}
-
-
 NTSTATUS
 NTAPI
 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,