Sync to trunk head (r42241)
[reactos.git] / reactos / dll / ntdll / ldr / utils.c
index 7b8ca8a..2753814 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-#define LDRP_PROCESS_CREATION_TIME 0x8000000
+#define LDRP_PROCESS_CREATION_TIME 0xffff
 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
 
 /* GLOBALS *******************************************************************/
 
 #ifdef NDEBUG
-#if defined(__GNUC__)
-#define TRACE_LDR(args...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); }
-#elif defined(_MSC_VER)
-#define TRACE_LDR(args, ...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
-#endif /* __GNUC__ */
-#else
-#define TRACE_LDR(args...) do { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(args); } while(0)
+#define TRACE_LDR(...) if (RtlGetNtGlobalFlags() & FLG_SHOW_LDR_SNAPS) { DbgPrint("(LDR:%s:%d) ",__FILE__,__LINE__); DbgPrint(__VA_ARGS__); }
 #endif
 
 typedef struct _TLS_DATA
@@ -69,7 +63,7 @@ static VOID LdrpDetachProcess(BOOLEAN UnloadAll);
 
 /* FUNCTIONS *****************************************************************/
 
-#if defined(DBG) || defined(KDBG)
+#if DBG || defined(KDBG)
 
 VOID
 LdrpLoadUserModuleSymbols(PLDR_DATA_TABLE_ENTRY LdrModule)
@@ -105,7 +99,7 @@ static __inline LONG LdrpDecrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEA
        RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
      }
    LoadCount = Module->LoadCount;
-   if (Module->LoadCount > 0 && Module->LoadCount != 0xFFFF)
+   if (Module->LoadCount > 0 && Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
      {
        Module->LoadCount--;
      }
@@ -124,7 +118,7 @@ static __inline LONG LdrpIncrementLoadCount(PLDR_DATA_TABLE_ENTRY Module, BOOLEA
        RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
      }
    LoadCount = Module->LoadCount;
-   if (Module->LoadCount != 0xFFFF)
+   if (Module->LoadCount != LDRP_PROCESS_CREATION_TIME)
      {
        Module->LoadCount++;
      }
@@ -153,7 +147,7 @@ static __inline VOID LdrpAcquireTlsSlot(PLDR_DATA_TABLE_ENTRY Module, ULONG Size
 static __inline VOID LdrpTlsCallback(PLDR_DATA_TABLE_ENTRY Module, ULONG dwReason)
 {
    PIMAGE_TLS_CALLBACK *TlsCallback;
-   if (Module->TlsIndex != 0xFFFF && Module->LoadCount == 0xFFFF)
+   if (Module->TlsIndex != 0xFFFF && Module->LoadCount == LDRP_PROCESS_CREATION_TIME)
      {
        TlsCallback = LdrpTlsArray[Module->TlsIndex].TlsAddressOfCallBacks;
        if (TlsCallback)
@@ -180,6 +174,112 @@ static BOOLEAN LdrpCallDllEntry(PLDR_DATA_TABLE_ENTRY Module, DWORD dwReason, PV
    return  ((PDLLMAIN_FUNC)Module->EntryPoint)(Module->DllBase, dwReason, lpReserved);
 }
 
+static PWSTR
+LdrpQueryAppPaths(IN PCWSTR ImageName)
+{
+    PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    WCHAR SearchPathBuffer[5*MAX_PATH];
+    UNICODE_STRING ValueNameString;
+    UNICODE_STRING KeyName;
+    WCHAR NameBuffer[MAX_PATH];
+    ULONG KeyInfoSize;
+    ULONG ResultSize;
+    PWCHAR Backslash;
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+    PWSTR Path = NULL;
+
+    _snwprintf(NameBuffer,
+              sizeof(NameBuffer) / sizeof(WCHAR),
+              L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s",
+              ImageName);
+
+    RtlInitUnicodeString(&KeyName, NameBuffer);
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    Status = NtOpenKey(&KeyHandle,
+                       KEY_READ,
+                       &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
+        return NULL;
+    }
+
+    KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR);
+
+    KeyInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, KeyInfoSize);
+    if (KeyInfo == NULL)
+    {
+        DPRINT("RtlAllocateHeap() failed\n");
+        NtClose(KeyHandle);
+        return NULL;
+    }
+
+    RtlInitUnicodeString(&ValueNameString,
+                         L"Path");
+
+    Status = NtQueryValueKey(KeyHandle,
+                             &ValueNameString,
+                             KeyValuePartialInformation,
+                             KeyInfo,
+                             KeyInfoSize,
+                             &ResultSize);
+
+    if (!NT_SUCCESS(Status))
+    {
+        NtClose(KeyHandle);
+        RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
+        return NULL;
+    }
+
+    RtlCopyMemory(SearchPathBuffer,
+                  &KeyInfo->Data,
+                  KeyInfo->DataLength);
+
+    /* Free KeyInfo memory, we won't need it anymore */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, KeyInfo);
+
+    /* Close the key handle */
+    NtClose(KeyHandle);
+
+    /* get application running path */
+    wcscat(SearchPathBuffer, L";");
+    wcscat(SearchPathBuffer, NtCurrentPeb()->ProcessParameters->ImagePathName.Buffer); // FIXME: Don't rely on it being NULL-terminated!!!
+
+    /* Remove trailing backslash */
+    Backslash = wcsrchr(SearchPathBuffer, L'\\');
+    if (Backslash) Backslash = L'\0';
+
+    wcscat(SearchPathBuffer, L";");
+
+    wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
+    wcscat(SearchPathBuffer, L"\\system32;");
+    wcscat(SearchPathBuffer, SharedUserData->NtSystemRoot);
+    wcscat(SearchPathBuffer, L";.");
+
+    /* Copy it to the heap allocd memory */
+    Path = RtlAllocateHeap(RtlGetProcessHeap(),
+                           0,
+                           wcslen(SearchPathBuffer) * sizeof(WCHAR));
+
+    if (!Path)
+    {
+        DPRINT1("RtlAllocateHeap() failed\n");
+        return NULL;
+    }
+
+    wcscpy(Path, SearchPathBuffer);
+
+    return Path;
+}
+
 static NTSTATUS
 LdrpInitializeTlsForThread(VOID)
 {
@@ -259,7 +359,7 @@ LdrpInitializeTlsForProccess(VOID)
        while (Entry != ModuleListHead)
          {
            Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
-           if (Module->LoadCount == 0xFFFF &&
+           if (Module->LoadCount == LDRP_PROCESS_CREATION_TIME &&
                Module->TlsIndex != 0xFFFF)
              {
                TlsDirectory = (PIMAGE_TLS_DIRECTORY)
@@ -269,7 +369,7 @@ LdrpInitializeTlsForProccess(VOID)
                                                               &Size);
                ASSERT(Module->TlsIndex < LdrpTlsCount);
                TlsData = &LdrpTlsArray[Module->TlsIndex];
-               TlsData->StartAddressOfRawData = (PVOID)(ULONG_PTR)TlsDirectory->StartAddressOfRawData;
+               TlsData->StartAddressOfRawData = (PVOID)TlsDirectory->StartAddressOfRawData;
                TlsData->TlsDataSize = TlsDirectory->EndAddressOfRawData - TlsDirectory->StartAddressOfRawData;
                TlsData->TlsZeroSize = TlsDirectory->SizeOfZeroFill;
                if (TlsDirectory->AddressOfCallBacks)
@@ -486,7 +586,7 @@ LdrAddModuleEntry(PVOID ImageBase,
        * loading while app is initializing
        * dll must not be unloaded
        */
-      Module->LoadCount = 0xFFFF;
+      Module->LoadCount = LDRP_PROCESS_CREATION_TIME;
     }
 
   Module->Flags = 0;
@@ -858,7 +958,6 @@ LdrFindEntryForName(PUNICODE_STRING Name,
   PLDR_DATA_TABLE_ENTRY ModulePtr;
   BOOLEAN ContainsPath;
   UNICODE_STRING AdjustedName;
-  unsigned i;
 
   DPRINT("LdrFindEntryForName(Name %wZ)\n", Name);
 
@@ -882,14 +981,8 @@ LdrFindEntryForName(PUNICODE_STRING Name,
       return(STATUS_SUCCESS);
     }
 
-  LdrAdjustDllName (&AdjustedName, Name, FALSE);
-
-  ContainsPath = (AdjustedName.Length >= 2 * sizeof(WCHAR) && L':' == AdjustedName.Buffer[1]);
-  for (i = 0; ! ContainsPath && i < AdjustedName.Length / sizeof(WCHAR); i++)
-    {
-      ContainsPath = L'\\' == AdjustedName.Buffer[i] ||
-                     L'/' == AdjustedName.Buffer[i];
-    }
+  ContainsPath = (Name->Length >= 2 * sizeof(WCHAR) && L':' == Name->Buffer[1]);
+  LdrAdjustDllName (&AdjustedName, Name, !ContainsPath);
 
   if (LdrpLastModule)
     {
@@ -899,7 +992,7 @@ LdrFindEntryForName(PUNICODE_STRING Name,
            0 == RtlCompareUnicodeString(&LdrpLastModule->FullDllName, &AdjustedName, TRUE)))
         {
           *Module = LdrpLastModule;
-          if (Ref && (*Module)->LoadCount != 0xFFFF)
+          if (Ref && (*Module)->LoadCount != LDRP_PROCESS_CREATION_TIME)
             {
               (*Module)->LoadCount++;
             }
@@ -920,7 +1013,7 @@ LdrFindEntryForName(PUNICODE_STRING Name,
            0 == RtlCompareUnicodeString(&ModulePtr->FullDllName, &AdjustedName, TRUE)))
         {
           *Module = LdrpLastModule = ModulePtr;
-          if (Ref && ModulePtr->LoadCount != 0xFFFF)
+          if (Ref && ModulePtr->LoadCount != LDRP_PROCESS_CREATION_TIME)
             {
               ModulePtr->LoadCount++;
             }
@@ -979,9 +1072,8 @@ LdrFixupForward(PCHAR ForwardName)
          */
         if (!NT_SUCCESS(Status))
           {
-             ULONG Flags = LDRP_PROCESS_CREATION_TIME;
              Status = LdrLoadDll(NULL,
-                                 &Flags,
+                                                                NULL,
                                  &DllName,
                                  &BaseAddress);
              if (NT_SUCCESS(Status))
@@ -1351,10 +1443,10 @@ LdrpGetOrLoadModule(PWCHAR SearchPath,
    if (Load && !NT_SUCCESS(Status))
      {
        Status = LdrpLoadModule(SearchPath,
-                               NtCurrentPeb()->Ldr->Initialized ? 0 : LDRP_PROCESS_CREATION_TIME,
+                                                          0,
                                &DllName,
                                Module,
-                               NULL);
+                                                          NULL);
        if (NT_SUCCESS(Status))
          {
            Status = LdrFindEntryForName (&DllName, Module, FALSE);
@@ -1684,6 +1776,7 @@ LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
    NTSTATUS Status;
    PLDR_DATA_TABLE_ENTRY ImportedModule;
    PCHAR ImportedName;
+   PWSTR ModulePath;
    ULONG Size;
 
    DPRINT("LdrFixupImports(SearchPath %S, Module %p)\n", SearchPath, Module);
@@ -1863,12 +1956,22 @@ LdrFixupImports(IN PWSTR SearchPath OPTIONAL,
            ImportedName = (PCHAR)Module->DllBase + ImportModuleDirectoryCurrent->Name;
            TRACE_LDR("%wZ imports functions from %s\n", &Module->BaseDllName, ImportedName);
 
+           if (SearchPath == NULL)
+           {
+                ModulePath = LdrpQueryAppPaths(Module->BaseDllName.Buffer);
+
+                Status = LdrpGetOrLoadModule(ModulePath, ImportedName, &ImportedModule, TRUE);
+                if (ModulePath != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, ModulePath);
+                if (NT_SUCCESS(Status)) goto Success;
+           }
+
            Status = LdrpGetOrLoadModule(SearchPath, ImportedName, &ImportedModule, TRUE);
            if (!NT_SUCCESS(Status))
              {
                DPRINT1("failed to load %s\n", ImportedName);
                return Status;
              }
+Success:
            if (Module == ImportedModule)
              {
                LdrpDecrementLoadCount(Module, FALSE);
@@ -2166,7 +2269,7 @@ LdrpLoadModule(IN PWSTR SearchPath OPTIONAL,
             DPRINT1("LdrFixupImports failed for %wZ, status=%x\n", &(*Module)->BaseDllName, Status);
             return Status;
           }
-#if defined(DBG) || defined(KDBG)
+#if DBG || defined(KDBG)
         LdrpLoadUserModuleSymbols(*Module);
 #endif /* DBG || KDBG */
         RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
@@ -2475,6 +2578,7 @@ LdrGetProcedureAddress (IN PVOID BaseAddress,
                         IN ULONG Ordinal,
                         OUT PVOID *ProcedureAddress)
 {
+   NTSTATUS Status = STATUS_PROCEDURE_NOT_FOUND;
    if (Name && Name->Length)
      {
        TRACE_LDR("LdrGetProcedureAddress by NAME - %Z\n", Name);
@@ -2487,28 +2591,37 @@ LdrGetProcedureAddress (IN PVOID BaseAddress,
    DPRINT("LdrGetProcedureAddress (BaseAddress %p Name %Z Ordinal %lu ProcedureAddress %p)\n",
           BaseAddress, Name, Ordinal, ProcedureAddress);
 
-   if (Name && Name->Length)
+   _SEH2_TRY
+   {
+     if (Name && Name->Length)
      {
        /* by name */
        *ProcedureAddress = LdrGetExportByName(BaseAddress, (PUCHAR)Name->Buffer, 0xffff);
        if (*ProcedureAddress != NULL)
          {
-           return STATUS_SUCCESS;
+           Status = STATUS_SUCCESS;
          }
        DPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
      }
-   else
+     else
      {
        /* by ordinal */
        Ordinal &= 0x0000FFFF;
        *ProcedureAddress = LdrGetExportByOrdinal(BaseAddress, (WORD)Ordinal);
        if (*ProcedureAddress)
          {
-           return STATUS_SUCCESS;
+           Status = STATUS_SUCCESS;
          }
        DPRINT("LdrGetProcedureAddress: Can't resolve symbol @%lu\n", Ordinal);
      }
-   return STATUS_PROCEDURE_NOT_FOUND;
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+       Status = STATUS_DLL_NOT_FOUND;
+   }
+   _SEH2_END;
+
+   return Status;
 }
 
 /**********************************************************************
@@ -2550,7 +2663,7 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
    while (Entry != ModuleListHead)
      {
        Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
-       if (((UnloadAll && Module->LoadCount == 0xFFFF) || Module->LoadCount == 0) &&
+       if (((UnloadAll && Module->LoadCount == LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0) &&
            Module->Flags & LDRP_ENTRY_PROCESSED &&
            !(Module->Flags & LDRP_UNLOAD_IN_PROGRESS))
          {
@@ -2563,7 +2676,7 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
              {
                TRACE_LDR("Unload %wZ - Calling entry point at %x\n",
                          &Module->BaseDllName, Module->EntryPoint);
-               LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == 0xFFFF ? 1 : 0));
+               LdrpCallDllEntry(Module, DLL_PROCESS_DETACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
              }
            else
              {
@@ -2585,7 +2698,7 @@ LdrpDetachProcess(BOOLEAN UnloadAll)
            Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
            Entry = Entry->Blink;
            if (Module->Flags & LDRP_UNLOAD_IN_PROGRESS &&
-               ((UnloadAll && Module->LoadCount != 0xFFFF) || Module->LoadCount == 0))
+               ((UnloadAll && Module->LoadCount != LDRP_PROCESS_CREATION_TIME) || Module->LoadCount == 0))
              {
                /* remove the module entry from the list */
                RemoveEntryList (&Module->InLoadOrderLinks);
@@ -2648,7 +2761,7 @@ LdrpAttachProcess(VOID)
            Module->Flags |= LDRP_LOAD_IN_PROGRESS;
            TRACE_LDR("%wZ loaded - Calling init routine at %x for process attaching\n",
                      &Module->BaseDllName, Module->EntryPoint);
-           Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == 0xFFFF ? 1 : 0));
+           Result = LdrpCallDllEntry(Module, DLL_PROCESS_ATTACH, (PVOID)(INT_PTR)(Module->LoadCount == LDRP_PROCESS_CREATION_TIME ? 1 : 0));
            if (!Result)
              {
                Status = STATUS_DLL_INIT_FAILED;