ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ldrapi.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS NT User Mode Library
00004  * FILE:            dll/ntdll/ldr/ldrapi.c
00005  * PURPOSE:         PE Loader Public APIs
00006  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
00007  *                  Aleksey Bragin (aleksey@reactos.org)
00008  */
00009 
00010 /* INCLUDES *****************************************************************/
00011 
00012 #include <ntdll.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 /* GLOBALS *******************************************************************/
00017 
00018 LIST_ENTRY LdrpUnloadHead;
00019 LONG LdrpLoaderLockAcquisitonCount;
00020 BOOLEAN LdrpShowRecursiveLoads, LdrpBreakOnRecursiveDllLoads;
00021 UNICODE_STRING LdrApiDefaultExtension = RTL_CONSTANT_STRING(L".DLL");
00022 ULONG AlternateResourceModuleCount;
00023 
00024 /* FUNCTIONS *****************************************************************/
00025 
00026 BOOLEAN
00027 NTAPI
00028 LdrAlternateResourcesEnabled(VOID)
00029 {
00030     /* ReactOS does not support this */
00031     return FALSE;
00032 }
00033 
00034 ULONG_PTR
00035 FORCEINLINE
00036 LdrpMakeCookie(VOID)
00037 {
00038     /* Generate a cookie */
00039     return (((ULONG_PTR)NtCurrentTeb()->RealClientId.UniqueThread & 0xFFF) << 16) |
00040                         _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount);
00041 }
00042 
00043 /*
00044  * @implemented
00045  */
00046 NTSTATUS
00047 NTAPI
00048 LdrUnlockLoaderLock(IN ULONG Flags,
00049                     IN ULONG Cookie OPTIONAL)
00050 {
00051     NTSTATUS Status = STATUS_SUCCESS;
00052 
00053     DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags, Cookie);
00054 
00055     /* Check for valid flags */
00056     if (Flags & ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00057     {
00058         /* Flags are invalid, check how to fail */
00059         if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00060         {
00061             /* The caller wants us to raise status */
00062             RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
00063         }
00064 
00065         /* A normal failure */
00066         return STATUS_INVALID_PARAMETER_1;
00067     }
00068 
00069     /* If we don't have a cookie, just return */
00070     if (!Cookie) return STATUS_SUCCESS;
00071 
00072     /* Validate the cookie */
00073     if ((Cookie & 0xF0000000) ||
00074         ((Cookie >> 16) ^ ((ULONG)(NtCurrentTeb()->RealClientId.UniqueThread) & 0xFFF)))
00075     {
00076         DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
00077 
00078         /* Invalid cookie, check how to fail */
00079         if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00080         {
00081             /* The caller wants us to raise status */
00082             RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
00083         }
00084 
00085         /* A normal failure */
00086         return STATUS_INVALID_PARAMETER_2;
00087     }
00088 
00089     /* Ready to release the lock */
00090     if (Flags & LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00091     {
00092         /* Do a direct leave */
00093         RtlLeaveCriticalSection(&LdrpLoaderLock);
00094     }
00095     else
00096     {
00097         /* Wrap this in SEH, since we're not supposed to raise */
00098         _SEH2_TRY
00099         {
00100             /* Leave the lock */
00101             RtlLeaveCriticalSection(&LdrpLoaderLock);
00102         }
00103         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00104         {
00105             /* We should use the LDR Filter instead */
00106             Status = _SEH2_GetExceptionCode();
00107         }
00108         _SEH2_END;
00109     }
00110 
00111     /* All done */
00112     return Status;
00113 }
00114 
00115 /*
00116  * @implemented
00117  */
00118 NTSTATUS
00119 NTAPI
00120 LdrLockLoaderLock(IN ULONG Flags,
00121                   OUT PULONG Disposition OPTIONAL,
00122                   OUT PULONG_PTR Cookie OPTIONAL)
00123 {
00124     NTSTATUS Status = STATUS_SUCCESS;
00125     BOOLEAN InInit = LdrpInLdrInit;
00126 
00127     DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags, Disposition, Cookie);
00128 
00129     /* Zero out the outputs */
00130     if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID;
00131     if (Cookie) *Cookie = 0;
00132 
00133     /* Validate the flags */
00134     if (Flags & ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS |
00135                   LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY))
00136     {
00137         /* Flags are invalid, check how to fail */
00138         if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00139         {
00140             /* The caller wants us to raise status */
00141             RtlRaiseStatus(STATUS_INVALID_PARAMETER_1);
00142         }
00143 
00144         /* A normal failure */
00145         return STATUS_INVALID_PARAMETER_1;
00146     }
00147 
00148     /* Make sure we got a cookie */
00149     if (!Cookie)
00150     {
00151         /* No cookie check how to fail */
00152         if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00153         {
00154             /* The caller wants us to raise status */
00155             RtlRaiseStatus(STATUS_INVALID_PARAMETER_3);
00156         }
00157 
00158         /* A normal failure */
00159         return STATUS_INVALID_PARAMETER_3;
00160     }
00161 
00162     /* Do or Do Not. There is no Try */
00163     ASSERT((Disposition != NULL) || !(Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY));
00164 
00165     /* If the flag is set, make sure we have a valid pointer to use */
00166     if ((Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY) && !(Disposition))
00167     {
00168         /* No pointer to return the data to */
00169         if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00170         {
00171             /* The caller wants us to raise status */
00172             RtlRaiseStatus(STATUS_INVALID_PARAMETER_2);
00173         }
00174 
00175         /* Fail */
00176         return STATUS_INVALID_PARAMETER_2;
00177     }
00178 
00179     /* Return now if we are in the init phase */
00180     if (InInit) return STATUS_SUCCESS;
00181 
00182     /* Check what locking semantic to use */
00183     if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS)
00184     {
00185         /* Check if we should enter or simply try */
00186         if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
00187         {
00188             /* Do a try */
00189             if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
00190             {
00191                 /* It's locked */
00192                 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
00193             }
00194             else
00195             {
00196                 /* It worked */
00197                 *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
00198                 *Cookie = LdrpMakeCookie();
00199             }
00200         }
00201         else
00202         {
00203             /* Do a enter */
00204             RtlEnterCriticalSection(&LdrpLoaderLock);
00205 
00206             /* See if result was requested */
00207             if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
00208             *Cookie = LdrpMakeCookie();
00209         }
00210     }
00211     else
00212     {
00213         /* Wrap this in SEH, since we're not supposed to raise */
00214         _SEH2_TRY
00215         {
00216             /* Check if we should enter or simply try */
00217             if (Flags & LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY)
00218             {
00219                 /* Do a try */
00220                 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock))
00221                 {
00222                     /* It's locked */
00223                     *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED;
00224                 }
00225                 else
00226                 {
00227                     /* It worked */
00228                     *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
00229                     *Cookie = LdrpMakeCookie();
00230                 }
00231             }
00232             else
00233             {
00234                 /* Do an enter */
00235                 RtlEnterCriticalSection(&LdrpLoaderLock);
00236 
00237                 /* See if result was requested */
00238                 if (Disposition) *Disposition = LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED;
00239                 *Cookie = LdrpMakeCookie();
00240             }
00241         }
00242         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00243         {
00244             /* We should use the LDR Filter instead */
00245             Status = _SEH2_GetExceptionCode();
00246         }
00247         _SEH2_END;
00248     }
00249 
00250     /* Return status */
00251     return Status;
00252 }
00253 
00254 /*
00255  * @implemented
00256  */
00257 NTSTATUS
00258 NTAPI
00259 LdrLoadDll(IN PWSTR SearchPath OPTIONAL,
00260            IN PULONG DllCharacteristics OPTIONAL,
00261            IN PUNICODE_STRING DllName,
00262            OUT PVOID *BaseAddress)
00263 {
00264     WCHAR StringBuffer[MAX_PATH];
00265     UNICODE_STRING DllString1, DllString2;
00266     BOOLEAN RedirectedDll = FALSE;
00267     NTSTATUS Status;
00268     ULONG Cookie;
00269     PUNICODE_STRING OldTldDll;
00270     PTEB Teb = NtCurrentTeb();
00271 
00272     /* Initialize the strings */
00273     RtlInitEmptyUnicodeString(&DllString2, NULL, 0);
00274     DllString1.Buffer = StringBuffer;
00275     DllString1.Length = 0;
00276     DllString1.MaximumLength = sizeof(StringBuffer);
00277 
00278     /* Check if the SxS Assemblies specify another file */
00279     Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
00280                                                       DllName,
00281                                                       &LdrApiDefaultExtension,
00282                                                       &DllString1,
00283                                                       &DllString2,
00284                                                       &DllName,
00285                                                       NULL,
00286                                                       NULL,
00287                                                       NULL);
00288 
00289     /* Check success */
00290     if (NT_SUCCESS(Status))
00291     {
00292         /* Let Ldrp know */
00293         RedirectedDll = TRUE;
00294     }
00295     else if (Status != STATUS_SXS_KEY_NOT_FOUND)
00296     {
00297         /* Unrecoverable SxS failure; did we get a string? */
00298         if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
00299         return Status;
00300     }
00301 
00302     /* Lock the loader lock */
00303     LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, NULL, &Cookie);
00304 
00305     /* Check if there's a TLD DLL being loaded */
00306     OldTldDll = LdrpTopLevelDllBeingLoaded;
00307     if (OldTldDll)
00308     {
00309         /* This is a recursive load, do something about it? */
00310         if ((ShowSnaps) || (LdrpShowRecursiveLoads) || (LdrpBreakOnRecursiveDllLoads))
00311         {
00312             /* Print out debug messages */
00313             DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
00314                     Teb->RealClientId.UniqueProcess,
00315                     Teb->RealClientId.UniqueThread);
00316             DPRINT1("[%lx, %lx]      Previous DLL being loaded \"%wZ\"\n",
00317                     Teb->RealClientId.UniqueProcess,
00318                     Teb->RealClientId.UniqueThread,
00319                     OldTldDll);
00320             DPRINT1("[%lx, %lx]      DLL being requested \"%wZ\"\n",
00321                     Teb->RealClientId.UniqueProcess,
00322                     Teb->RealClientId.UniqueThread,
00323                     DllName);
00324 
00325             /* Was it initializing too? */
00326             if (!LdrpCurrentDllInitializer)
00327             {
00328                 DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
00329                         Teb->RealClientId.UniqueProcess,
00330                         Teb->RealClientId.UniqueThread);
00331             }
00332             else
00333             {
00334                 DPRINT1("[%lx, %lx]      DLL whose initializer was currently running \"%wZ\"\n",
00335                         Teb->ClientId.UniqueProcess,
00336                         Teb->ClientId.UniqueThread,
00337                         &LdrpCurrentDllInitializer->BaseDllName);
00338             }
00339         }
00340     }
00341 
00342     /* Set this one as the TLD DLL being loaded*/
00343     LdrpTopLevelDllBeingLoaded = DllName;
00344 
00345     /* Load the DLL */
00346     Status = LdrpLoadDll(RedirectedDll,
00347                          SearchPath,
00348                          DllCharacteristics,
00349                          DllName,
00350                          BaseAddress,
00351                          TRUE);
00352     if (NT_SUCCESS(Status))
00353     {
00354         Status = STATUS_SUCCESS;
00355     }
00356     else if ((Status != STATUS_NO_SUCH_FILE) &&
00357              (Status != STATUS_DLL_NOT_FOUND) &&
00358              (Status != STATUS_OBJECT_NAME_NOT_FOUND) &&
00359              (Status != STATUS_DLL_INIT_FAILED))
00360     {
00361         // 85 == DPFLTR_LDR_ID;
00362         DbgPrintEx(85,
00363                    DPFLTR_WARNING_LEVEL,
00364                    "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
00365                    __FUNCTION__,
00366                    DllName,
00367                    Status);
00368     }
00369 
00370     /* Restore the old TLD DLL */
00371     LdrpTopLevelDllBeingLoaded = OldTldDll;
00372 
00373     /* Release the lock */
00374     LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
00375 
00376     /* Do we have a redirect string? */
00377     if (DllString2.Buffer) RtlFreeUnicodeString(&DllString2);
00378 
00379     /* Return */
00380     return Status;
00381 }
00382 
00383 /*
00384  * @implemented
00385  */
00386 NTSTATUS
00387 NTAPI
00388 LdrFindEntryForAddress(PVOID Address,
00389                        PLDR_DATA_TABLE_ENTRY *Module)
00390 {
00391     PLIST_ENTRY ListHead, NextEntry;
00392     PLDR_DATA_TABLE_ENTRY LdrEntry;
00393     PIMAGE_NT_HEADERS NtHeader;
00394     PPEB_LDR_DATA Ldr = NtCurrentPeb()->Ldr;
00395     ULONG_PTR DllBase, DllEnd;
00396 
00397     DPRINT("LdrFindEntryForAddress(Address %p)\n", Address);
00398 
00399     /* Nothing to do */
00400     if (!Ldr) return STATUS_NO_MORE_ENTRIES;
00401 
00402     /* Get the current entry */
00403     LdrEntry = Ldr->EntryInProgress;
00404     if (LdrEntry)
00405     {
00406         /* Get the NT Headers */
00407         NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
00408         if (NtHeader)
00409         {
00410             /* Get the Image Base */
00411             DllBase = (ULONG_PTR)LdrEntry->DllBase;
00412             DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
00413 
00414             /* Check if they match */
00415             if (((ULONG_PTR)Address >= DllBase) &&
00416                 ((ULONG_PTR)Address < DllEnd))
00417             {
00418                 /* Return it */
00419                 *Module = LdrEntry;
00420                 return STATUS_SUCCESS;
00421             }
00422         }
00423     }
00424 
00425     /* Loop the module list */
00426     ListHead = &Ldr->InMemoryOrderModuleList;
00427     NextEntry = ListHead->Flink;
00428     while (NextEntry != ListHead)
00429     {
00430         /* Get the entry and NT Headers */
00431         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);
00432         NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
00433         if (NtHeader)
00434         {
00435             /* Get the Image Base */
00436             DllBase = (ULONG_PTR)LdrEntry->DllBase;
00437             DllEnd = DllBase + NtHeader->OptionalHeader.SizeOfImage;
00438 
00439             /* Check if they match */
00440             if (((ULONG_PTR)Address >= DllBase) &&
00441                 ((ULONG_PTR)Address < DllEnd))
00442             {
00443                 /* Return it */
00444                 *Module = LdrEntry;
00445                 return STATUS_SUCCESS;
00446             }
00447 
00448             /* Next Entry */
00449             NextEntry = NextEntry->Flink;
00450         }
00451     }
00452 
00453     /* Nothing found */
00454     // 85 == DPFLTR_LDR_ID;
00455     DbgPrintEx(85, DPFLTR_WARNING_LEVEL, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__, STATUS_NO_MORE_ENTRIES);
00456     return STATUS_NO_MORE_ENTRIES;
00457 }
00458 
00459 /*
00460  * @implemented
00461  */
00462 NTSTATUS
00463 NTAPI
00464 LdrGetDllHandleEx(IN ULONG Flags,
00465                   IN PWSTR DllPath OPTIONAL,
00466                   IN PULONG DllCharacteristics OPTIONAL,
00467                   IN PUNICODE_STRING DllName,
00468                   OUT PVOID *DllHandle OPTIONAL)
00469 {
00470     NTSTATUS Status;
00471     PLDR_DATA_TABLE_ENTRY LdrEntry;
00472     UNICODE_STRING RedirectName, DllString1, RawDllName;
00473     PUNICODE_STRING pRedirectName, CompareName;
00474     PWCHAR p1, p2, p3;
00475     BOOLEAN Locked, RedirectedDll;
00476     ULONG_PTR Cookie;
00477     ULONG LoadFlag, Length;
00478 
00479     /* Initialize the strings */
00480     RtlInitEmptyUnicodeString(&DllString1, NULL, 0);
00481     RtlInitEmptyUnicodeString(&RawDllName, NULL, 0);
00482     RedirectName = *DllName;
00483     pRedirectName = &RedirectName;
00484 
00485     /* Initialize state */
00486     RedirectedDll = Locked = FALSE;
00487     LdrEntry = NULL;
00488     Cookie = 0;
00489 
00490     /* Clear the handle */
00491     if (DllHandle) *DllHandle = NULL;
00492 
00493     /* Check for a valid flag combination */
00494     if ((Flags & ~(LDR_GET_DLL_HANDLE_EX_PIN | LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT)) ||
00495         (!DllHandle && !(Flags & LDR_GET_DLL_HANDLE_EX_PIN)))
00496     {
00497         DPRINT1("Flags are invalid or no DllHandle given\n");
00498         Status = STATUS_INVALID_PARAMETER;
00499         goto Quickie;
00500     }
00501 
00502     /* If not initializing */
00503     if (!LdrpInLdrInit)
00504     {
00505         /* Acquire the lock */
00506         Status = LdrLockLoaderLock(0, NULL, &Cookie);
00507         if (!NT_SUCCESS(Status)) goto Quickie;
00508 
00509         /* Remember we own it */
00510         Locked = TRUE;
00511     }
00512 
00513     /* Check if the SxS Assemblies specify another file */
00514     Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
00515                                                       pRedirectName,
00516                                                       &LdrApiDefaultExtension,
00517                                                       NULL,
00518                                                       &DllString1,
00519                                                       &pRedirectName,
00520                                                       NULL,
00521                                                       NULL,
00522                                                       NULL);
00523 
00524     /* Check success */
00525     if (NT_SUCCESS(Status))
00526     {
00527         /* Let Ldrp know */
00528         RedirectedDll = TRUE;
00529     }
00530     else if (Status != STATUS_SXS_KEY_NOT_FOUND)
00531     {
00532         /* Unrecoverable SxS failure; */
00533         goto Quickie;
00534     }
00535     else
00536     {
00537         ASSERT(pRedirectName == &RedirectName);
00538     }
00539 
00540     /* Set default failure code */
00541     Status = STATUS_DLL_NOT_FOUND;
00542 
00543     /* Use the cache if we can */
00544     if (LdrpGetModuleHandleCache)
00545     {
00546         /* Check if we were redirected */
00547         if (RedirectedDll)
00548         {
00549             /* Check the flag */
00550             if (!(LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED))
00551             {
00552                 goto DontCompare;
00553             }
00554 
00555             /* Use the right name */
00556             CompareName = &LdrpGetModuleHandleCache->FullDllName;
00557         }
00558         else
00559         {
00560             /* Check the flag */
00561             if (LdrpGetModuleHandleCache->Flags & LDRP_REDIRECTED)
00562             {
00563                 goto DontCompare;
00564             }
00565 
00566             /* Use the right name */
00567             CompareName = &LdrpGetModuleHandleCache->BaseDllName;
00568         }
00569 
00570         /* Check if the name matches */
00571         if (RtlEqualUnicodeString(pRedirectName,
00572                                   CompareName,
00573                                   TRUE))
00574         {
00575             /* Skip the rest */
00576             LdrEntry = LdrpGetModuleHandleCache;
00577 
00578             /* Return success */
00579             Status = STATUS_SUCCESS;
00580             goto Quickie;
00581         }
00582     }
00583 
00584 DontCompare:
00585     /* Find the name without the extension */
00586     p1 = pRedirectName->Buffer;
00587     p2 = NULL;
00588     p3 = &p1[pRedirectName->Length / sizeof(WCHAR)];
00589     while (p1 != p3)
00590     {
00591         if (*p1++ == L'.')
00592         {
00593             p2 = p1;
00594         }
00595         else if (*p1 == L'\\')
00596         {
00597             p2 = NULL;
00598         }
00599     }
00600 
00601     /* Check if no extension was found or if we got a slash */
00602     if (!(p2) || (*p2 == L'\\') || (*p2 == L'/'))
00603     {
00604         /* Check that we have space to add one */
00605         Length = pRedirectName->Length +
00606                  LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL);
00607         if (Length >= UNICODE_STRING_MAX_BYTES)
00608         {
00609             /* No space to add the extension */
00610             Status = STATUS_NAME_TOO_LONG;
00611             goto Quickie;
00612         }
00613 
00614         /* Setup the string */
00615         RawDllName.MaximumLength = Length;
00616         ASSERT(Length >= sizeof(UNICODE_NULL));
00617         RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
00618                                             0,
00619                                             RawDllName.MaximumLength);
00620         if (!RawDllName.Buffer)
00621         {
00622             Status = STATUS_NO_MEMORY;
00623             goto Quickie;
00624         }
00625 
00626         /* Copy the string and add extension */
00627         RtlCopyUnicodeString(&RawDllName, pRedirectName);
00628         RtlAppendUnicodeStringToString(&RawDllName, &LdrApiDefaultExtension);
00629     }
00630     else
00631     {
00632         /* Check if there's something in the name */
00633         Length = pRedirectName->Length;
00634         if (Length)
00635         {
00636             /* Check and remove trailing period */
00637             if (pRedirectName->Buffer[Length / sizeof(WCHAR) - sizeof(ANSI_NULL)] == '.')
00638             {
00639                 /* Decrease the size */
00640                 pRedirectName->Length -= sizeof(WCHAR);
00641             }
00642         }
00643 
00644         /* Setup the string */
00645         RawDllName.MaximumLength = pRedirectName->Length + sizeof(WCHAR);
00646         RawDllName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
00647                                             0,
00648                                             RawDllName.MaximumLength);
00649         if (!RawDllName.Buffer)
00650         {
00651             Status = STATUS_NO_MEMORY;
00652             goto Quickie;
00653         }
00654 
00655         /* Copy the string */
00656         RtlCopyUnicodeString(&RawDllName, pRedirectName);
00657     }
00658 
00659     /* Display debug string */
00660     if (ShowSnaps)
00661     {
00662         DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
00663                 &RawDllName,
00664                 DllPath ? ((ULONG_PTR)DllPath == 1 ? L"" : DllPath) : L"");
00665     }
00666 
00667     /* Do the lookup */
00668     if (LdrpCheckForLoadedDll(DllPath,
00669                               &RawDllName,
00670                               ((ULONG_PTR)DllPath == 1) ? TRUE : FALSE,
00671                               RedirectedDll,
00672                               &LdrEntry))
00673     {
00674         /* Update cached entry */
00675         LdrpGetModuleHandleCache = LdrEntry;
00676 
00677         /* Return success */
00678         Status = STATUS_SUCCESS;
00679     }
00680     else
00681     {
00682         /* Make sure to NULL this */
00683         LdrEntry = NULL;
00684     }
00685 Quickie:
00686     /* The success path must have a valid loader entry */
00687     ASSERT((LdrEntry != NULL) == NT_SUCCESS(Status));
00688 
00689     /* Check if we got an entry and success */
00690     DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry ? &LdrEntry->BaseDllName : NULL);
00691     if ((LdrEntry) && (NT_SUCCESS(Status)))
00692     {
00693         /* Check if the DLL is locked */
00694         if ((LdrEntry->LoadCount != 0xFFFF) &&
00695             !(Flags & LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT))
00696         {
00697             /* Check what to do with the load count */
00698             if (Flags & LDR_GET_DLL_HANDLE_EX_PIN)
00699             {
00700                 /* Pin it */
00701                 LdrEntry->LoadCount = 0xFFFF;
00702                 LoadFlag = LDRP_UPDATE_PIN;
00703             }
00704             else
00705             {
00706                 /* Increase the load count */
00707                 LdrEntry->LoadCount++;
00708                 LoadFlag = LDRP_UPDATE_REFCOUNT;
00709             }
00710 
00711             /* Update the load count now */
00712             LdrpUpdateLoadCount2(LdrEntry, LoadFlag);
00713             LdrpClearLoadInProgress();
00714         }
00715 
00716         /* Check if the caller is requesting the handle */
00717         if (DllHandle) *DllHandle = LdrEntry->DllBase;
00718     }
00719 
00720     /* Free string if needed */
00721     if (DllString1.Buffer) RtlFreeUnicodeString(&DllString1);
00722 
00723     /* Free the raw DLL Name if needed */
00724     if (RawDllName.Buffer)
00725     {
00726         /* Free the heap-allocated buffer */
00727         RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName.Buffer);
00728         RawDllName.Buffer = NULL;
00729     }
00730 
00731     /* Release lock */
00732     if (Locked)
00733     {
00734         LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS,
00735                             Cookie);
00736     }
00737 
00738     /* Return */
00739     return Status;
00740 }
00741 
00742 /*
00743  * @implemented
00744  */
00745 NTSTATUS
00746 NTAPI
00747 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL,
00748                 IN PULONG DllCharacteristics OPTIONAL,
00749                 IN PUNICODE_STRING DllName,
00750                 OUT PVOID *DllHandle)
00751 {
00752     /* Call the newer API */
00753     return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT,
00754                              DllPath,
00755                              DllCharacteristics,
00756                              DllName,
00757                              DllHandle);
00758 }
00759 
00760 /*
00761  * @implemented
00762  */
00763 NTSTATUS
00764 NTAPI
00765 LdrGetProcedureAddress(IN PVOID BaseAddress,
00766                        IN PANSI_STRING Name,
00767                        IN ULONG Ordinal,
00768                        OUT PVOID *ProcedureAddress)
00769 {
00770     /* Call the internal routine and tell it to execute DllInit */
00771     return LdrpGetProcedureAddress(BaseAddress, Name, Ordinal, ProcedureAddress, TRUE);
00772 }
00773 
00774 /*
00775  * @implemented
00776  */
00777 NTSTATUS
00778 NTAPI
00779 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle,
00780                               IN PLDR_CALLBACK Callback,
00781                               IN PVOID CallbackContext,
00782                               OUT PUSHORT ImageCharacteristics)
00783 {
00784     FILE_STANDARD_INFORMATION FileStandardInfo;
00785     PIMAGE_IMPORT_DESCRIPTOR ImportData;
00786     PIMAGE_SECTION_HEADER LastSection = NULL;
00787     IO_STATUS_BLOCK IoStatusBlock;
00788     PIMAGE_NT_HEADERS NtHeader;
00789     HANDLE SectionHandle;
00790     SIZE_T ViewSize;
00791     PVOID ViewBase;
00792     BOOLEAN Result, NoActualCheck;
00793     NTSTATUS Status;
00794     PVOID ImportName;
00795     ULONG Size;
00796     DPRINT("LdrVerifyImageMatchesChecksum() called\n");
00797 
00798     /* If the handle has the magic KnownDll flag, skip actual checksums */
00799     NoActualCheck = ((ULONG_PTR)FileHandle & 1);
00800 
00801     /* Create the section */
00802     Status = NtCreateSection(&SectionHandle,
00803                              SECTION_MAP_EXECUTE,
00804                              NULL,
00805                              NULL,
00806                              PAGE_EXECUTE,
00807                              SEC_COMMIT,
00808                              FileHandle);
00809     if (!NT_SUCCESS(Status))
00810     {
00811         DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status);
00812         return Status;
00813     }
00814 
00815     /* Map the section */
00816     ViewSize = 0;
00817     ViewBase = NULL;
00818     Status = NtMapViewOfSection(SectionHandle,
00819                                 NtCurrentProcess(),
00820                                 &ViewBase,
00821                                 0,
00822                                 0,
00823                                 NULL,
00824                                 &ViewSize,
00825                                 ViewShare,
00826                                 0,
00827                                 PAGE_EXECUTE);
00828     if (!NT_SUCCESS(Status))
00829     {
00830         DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
00831         NtClose(SectionHandle);
00832         return Status;
00833     }
00834 
00835     /* Get the file information */
00836     Status = NtQueryInformationFile(FileHandle,
00837                                     &IoStatusBlock,
00838                                     &FileStandardInfo,
00839                                     sizeof(FILE_STANDARD_INFORMATION),
00840                                     FileStandardInformation);
00841     if (!NT_SUCCESS(Status))
00842     {
00843         DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status);
00844         NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
00845         NtClose(SectionHandle);
00846         return Status;
00847     }
00848 
00849     /* Protect with SEH */
00850     _SEH2_TRY
00851     {
00852         /* Check if this is the KnownDll hack */
00853         if (NoActualCheck)
00854         {
00855             /* Don't actually do it */
00856             Result = TRUE;
00857         }
00858         else
00859         {
00860             /* Verify the checksum */
00861             Result = LdrVerifyMappedImageMatchesChecksum(ViewBase,
00862                                                          FileStandardInfo.EndOfFile.LowPart,
00863                                                          FileStandardInfo.EndOfFile.LowPart);
00864         }
00865 
00866         /* Check if a callback was supplied */
00867         if ((Result) && (Callback))
00868         {
00869             /* Get the NT Header */
00870             NtHeader = RtlImageNtHeader(ViewBase);
00871 
00872             /* Check if caller requested this back */
00873             if (ImageCharacteristics)
00874             {
00875                 /* Return to caller */
00876                 *ImageCharacteristics = NtHeader->FileHeader.Characteristics;
00877             }
00878 
00879             /* Get the Import Directory Data */
00880             ImportData = RtlImageDirectoryEntryToData(ViewBase,
00881                                                       FALSE,
00882                                                       IMAGE_DIRECTORY_ENTRY_IMPORT,
00883                                                       &Size);
00884 
00885             /* Make sure there is one */
00886             if (ImportData)
00887             {
00888                 /* Loop the imports */
00889                 while (ImportData->Name)
00890                 {
00891                     /* Get the name */
00892                     ImportName = RtlImageRvaToVa(NtHeader,
00893                                                  ViewBase,
00894                                                  ImportData->Name,
00895                                                  &LastSection);
00896 
00897                     /* Notify the callback */
00898                     Callback(CallbackContext, ImportName);
00899                     ImportData++;
00900                 }
00901             }
00902         }
00903     }
00904     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00905     {
00906         /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
00907         Result = FALSE;
00908     }
00909     _SEH2_END;
00910 
00911     /* Unmap file and close handle */
00912     NtUnmapViewOfSection(NtCurrentProcess(), ViewBase);
00913     NtClose(SectionHandle);
00914 
00915     /* Return status */
00916     return Result ? Status : STATUS_IMAGE_CHECKSUM_MISMATCH;
00917 }
00918 
00919 NTSTATUS
00920 NTAPI
00921 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId,
00922                                    IN ULONG Reserved,
00923                                    OUT PRTL_PROCESS_MODULES ModuleInformation,
00924                                    IN ULONG Size,
00925                                    OUT PULONG ReturnedSize OPTIONAL)
00926 {
00927     PLIST_ENTRY ModuleListHead, InitListHead;
00928     PLIST_ENTRY Entry, InitEntry;
00929     PLDR_DATA_TABLE_ENTRY Module, InitModule;
00930     PRTL_PROCESS_MODULE_INFORMATION ModulePtr = NULL;
00931     NTSTATUS Status = STATUS_SUCCESS;
00932     ULONG UsedSize = sizeof(ULONG);
00933     ANSI_STRING AnsiString;
00934     PCHAR p;
00935 
00936     DPRINT("LdrQueryProcessModuleInformation() called\n");
00937 
00938     /* Acquire loader lock */
00939     RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock);
00940 
00941     _SEH2_TRY
00942     {
00943         /* Check if we were given enough space */
00944         if (Size < UsedSize)
00945         {
00946             Status = STATUS_INFO_LENGTH_MISMATCH;
00947         }
00948         else
00949         {
00950             ModuleInformation->NumberOfModules = 0;
00951             ModulePtr = &ModuleInformation->Modules[0];
00952             Status = STATUS_SUCCESS;
00953         }
00954 
00955         /* Traverse the list of modules */
00956         ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
00957         Entry = ModuleListHead->Flink;
00958 
00959         while (Entry != ModuleListHead)
00960         {
00961             Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
00962 
00963             DPRINT("  Module %wZ\n", &Module->FullDllName);
00964 
00965             /* Increase the used size */
00966             UsedSize += sizeof(RTL_PROCESS_MODULE_INFORMATION);
00967 
00968             if (UsedSize > Size)
00969             {
00970                 Status = STATUS_INFO_LENGTH_MISMATCH;
00971             }
00972             else
00973             {
00974                 ModulePtr->ImageBase = Module->DllBase;
00975                 ModulePtr->ImageSize = Module->SizeOfImage;
00976                 ModulePtr->Flags = Module->Flags;
00977                 ModulePtr->LoadCount = Module->LoadCount;
00978                 ModulePtr->MappedBase = NULL;
00979                 ModulePtr->InitOrderIndex = 0;
00980                 ModulePtr->LoadOrderIndex = ModuleInformation->NumberOfModules;
00981 
00982                 /* Now get init order index by traversing init list */
00983                 InitListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
00984                 InitEntry = InitListHead->Flink;
00985 
00986                 while (InitEntry != InitListHead)
00987                 {
00988                     InitModule = CONTAINING_RECORD(InitEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);
00989 
00990                     /* Increase the index */
00991                     ModulePtr->InitOrderIndex++;
00992 
00993                     /* Quit the loop if our module is found */
00994                     if (InitModule == Module) break;
00995 
00996                     /* Advance to the next entry */
00997                     InitEntry = InitEntry->Flink;
00998                 }
00999 
01000                 /* Prepare ANSI string with the module's name */
01001                 AnsiString.Length = 0;
01002                 AnsiString.MaximumLength = sizeof(ModulePtr->FullPathName);
01003                 AnsiString.Buffer = ModulePtr->FullPathName;
01004                 RtlUnicodeStringToAnsiString(&AnsiString,
01005                                              &Module->FullDllName,
01006                                              FALSE);
01007 
01008                 /* Calculate OffsetToFileName field */
01009                 p = strrchr(ModulePtr->FullPathName, '\\');
01010                 if (p != NULL)
01011                     ModulePtr->OffsetToFileName = p - ModulePtr->FullPathName + 1;
01012                 else
01013                     ModulePtr->OffsetToFileName = 0;
01014 
01015                 /* Advance to the next module in the output list */
01016                 ModulePtr++;
01017 
01018                 /* Increase number of modules */
01019                 if (ModuleInformation)
01020                     ModuleInformation->NumberOfModules++;
01021             }
01022 
01023             /* Go to the next entry in the modules list */
01024             Entry = Entry->Flink;
01025         }
01026 
01027         /* Set returned size if it was provided */
01028         if (ReturnedSize)
01029             *ReturnedSize = UsedSize;
01030     }
01031     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01032     {
01033         /* Ignoring the exception */
01034     } _SEH2_END;
01035 
01036     /* Release the lock */
01037     RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock);
01038 
01039     DPRINT("LdrQueryProcessModuleInformation() done\n");
01040 
01041     return Status;
01042 }
01043 
01044 /*
01045  * @implemented
01046  */
01047 NTSTATUS
01048 NTAPI
01049 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation,
01050                                  IN ULONG Size,
01051                                  OUT PULONG ReturnedSize OPTIONAL)
01052 {
01053     /* Call Ex version of the API */
01054     return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation, Size, ReturnedSize);
01055 }
01056 
01057 /*
01058  * @implemented
01059  */
01060 NTSTATUS
01061 NTAPI
01062 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag,
01063                           IN PLDR_ENUM_CALLBACK EnumProc,
01064                           IN PVOID Context)
01065 {
01066     PLIST_ENTRY ListHead, ListEntry;
01067     PLDR_DATA_TABLE_ENTRY LdrEntry;
01068     NTSTATUS Status;
01069     ULONG Cookie;
01070     BOOLEAN Stop = FALSE;
01071 
01072     /* Check parameters */
01073     if ((ReservedFlag) || !(EnumProc)) return STATUS_INVALID_PARAMETER;
01074 
01075     /* Acquire the loader lock */
01076     Status = LdrLockLoaderLock(0, NULL, &Cookie);
01077     if (!NT_SUCCESS(Status)) return Status;
01078 
01079     /* Loop all the modules and call enum proc */
01080     ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
01081     ListEntry = ListHead->Flink;
01082     while (ListHead != ListEntry)
01083     {
01084         /* Get the entry */
01085         LdrEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
01086 
01087         /* Call the enumeration proc inside SEH */
01088         _SEH2_TRY
01089         {
01090             EnumProc(LdrEntry, Context, &Stop);
01091         }
01092         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01093         {
01094             /* Ignoring the exception */
01095         } _SEH2_END;
01096 
01097         /* Break if we were asked to stop enumeration */
01098         if (Stop)
01099         {
01100             /* Release loader lock */
01101             Status = LdrUnlockLoaderLock(0, Cookie);
01102 
01103             /* Reset any successful status to STATUS_SUCCESS, but leave
01104                failure to the caller */
01105             if (NT_SUCCESS(Status))
01106                 Status = STATUS_SUCCESS;
01107 
01108             /* Return any possible failure status */
01109             return Status;
01110         }
01111 
01112         /* Advance to the next module */
01113         ListEntry = ListEntry->Flink;
01114     }
01115 
01116     /* Release loader lock, it must succeed this time */
01117     Status = LdrUnlockLoaderLock(0, Cookie);
01118     ASSERT(NT_SUCCESS(Status));
01119 
01120     /* Return success */
01121     return STATUS_SUCCESS;
01122 }
01123 
01124 /*
01125  * @implemented
01126  */
01127 NTSTATUS
01128 NTAPI
01129 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress)
01130 {
01131     PLDR_DATA_TABLE_ENTRY LdrEntry;
01132     NTSTATUS Status;
01133     BOOLEAN LockHeld;
01134     ULONG_PTR Cookie;
01135     DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress);
01136 
01137     /* Don't do it during shutdown */
01138     if (LdrpShutdownInProgress) return STATUS_SUCCESS;
01139 
01140     /* Check if we should grab the lock */
01141     LockHeld = FALSE;
01142     if (!LdrpInLdrInit)
01143     {
01144         /* Grab the lock */
01145         Status = LdrLockLoaderLock(0, NULL, &Cookie);
01146         if (!NT_SUCCESS(Status)) return Status;
01147         LockHeld = TRUE;
01148     }
01149 
01150     /* Make sure the DLL is valid and get its entry */
01151     Status = STATUS_DLL_NOT_FOUND;
01152     if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
01153     {
01154         /* Get if it has a TLS slot */
01155         if (!LdrEntry->TlsIndex)
01156         {
01157             /* It doesn't, so you're allowed to call this */
01158             LdrEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
01159             Status = STATUS_SUCCESS;
01160         }
01161     }
01162 
01163     /* Check if the lock was held */
01164     if (LockHeld)
01165     {
01166         /* Release it */
01167         LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
01168     }
01169 
01170     /* Return the status */
01171     return Status;
01172 }
01173 
01174 /*
01175  * @implemented
01176  */
01177 NTSTATUS
01178 NTAPI
01179 LdrAddRefDll(IN ULONG Flags,
01180              IN PVOID BaseAddress)
01181 {
01182     PLDR_DATA_TABLE_ENTRY LdrEntry;
01183     NTSTATUS Status = STATUS_SUCCESS;
01184     ULONG Cookie;
01185     BOOLEAN Locked = FALSE;
01186 
01187     /* Check for invalid flags */
01188     if (Flags & ~(LDR_ADDREF_DLL_PIN))
01189     {
01190         /* Fail with invalid parameter status if so */
01191         Status = STATUS_INVALID_PARAMETER;
01192         goto quickie;
01193     }
01194 
01195     /* Acquire the loader lock if not in init phase */
01196     if (!LdrpInLdrInit)
01197     {
01198         /* Acquire the lock */
01199         Status = LdrLockLoaderLock(0, NULL, &Cookie);
01200         if (!NT_SUCCESS(Status)) goto quickie;
01201         Locked = TRUE;
01202     }
01203 
01204     /* Get this module's data table entry */
01205     if (LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
01206     {
01207         if (!LdrEntry)
01208         {
01209             /* Shouldn't happen */
01210             Status = STATUS_INTERNAL_ERROR;
01211             goto quickie;
01212         }
01213 
01214         /* If this is not a pinned module */
01215         if (LdrEntry->LoadCount != 0xFFFF)
01216         {
01217             /* Update its load count */
01218             if (Flags & LDR_ADDREF_DLL_PIN)
01219             {
01220                 /* Pin it by setting load count to -1 */
01221                 LdrEntry->LoadCount = 0xFFFF;
01222                 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_PIN);
01223             }
01224             else
01225             {
01226                 /* Increase its load count by one */
01227                 LdrEntry->LoadCount++;
01228                 LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_REFCOUNT);
01229             }
01230 
01231             /* Clear load in progress */
01232             LdrpClearLoadInProgress();
01233         }
01234     }
01235     else
01236     {
01237         /* There was an error getting this module's handle, return invalid param status */
01238         Status = STATUS_INVALID_PARAMETER;
01239     }
01240 
01241 quickie:
01242     /* Check for error case */
01243     if (!NT_SUCCESS(Status))
01244     {
01245         /* Print debug information */
01246         if ((ShowSnaps) || ((Status != STATUS_NO_SUCH_FILE) &&
01247                             (Status != STATUS_DLL_NOT_FOUND) &&
01248                             (Status != STATUS_OBJECT_NAME_NOT_FOUND)))
01249         {
01250             DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress);
01251         }
01252     }
01253 
01254     /* Release the lock if needed */
01255     if (Locked) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS, Cookie);
01256     return Status;
01257 }
01258 
01259 /*
01260  * @implemented
01261  */
01262 NTSTATUS
01263 NTAPI
01264 LdrUnloadDll(IN PVOID BaseAddress)
01265 {
01266     NTSTATUS Status = STATUS_SUCCESS;
01267     PPEB Peb = NtCurrentPeb();
01268     PLDR_DATA_TABLE_ENTRY LdrEntry, CurrentEntry;
01269     PVOID EntryPoint;
01270     PLIST_ENTRY NextEntry;
01271     LIST_ENTRY UnloadList;
01272     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
01273     PVOID CorImageData;
01274     ULONG ComSectionSize;
01275 
01276     /* Get the LDR Lock */
01277     if (!LdrpInLdrInit) RtlEnterCriticalSection(Peb->LoaderLock);
01278 
01279     /* Increase the unload count */
01280     LdrpActiveUnloadCount++;
01281 
01282     /* Skip unload */
01283     if (LdrpShutdownInProgress) goto Quickie;
01284 
01285     /* Make sure the DLL is valid and get its entry */
01286     if (!LdrpCheckForLoadedDllHandle(BaseAddress, &LdrEntry))
01287     {
01288         Status = STATUS_DLL_NOT_FOUND;
01289         goto Quickie;
01290     }
01291 
01292     /* Check the current Load Count */
01293     if (LdrEntry->LoadCount != 0xFFFF)
01294     {
01295         /* Decrease it */
01296         LdrEntry->LoadCount--;
01297 
01298         /* If it's a dll */
01299         if (LdrEntry->Flags & LDRP_IMAGE_DLL)
01300         {
01301             /* Set up the Act Ctx */
01302             ActCtx.Size = sizeof(ActCtx);
01303             ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
01304             RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
01305 
01306             /* Activate the ActCtx */
01307             RtlActivateActivationContextUnsafeFast(&ActCtx,
01308                                                    LdrEntry->EntryPointActivationContext);
01309 
01310             /* Update the load count */
01311             LdrpUpdateLoadCount2(LdrEntry, LDRP_UPDATE_DEREFCOUNT);
01312 
01313             /* Release the context */
01314             RtlDeactivateActivationContextUnsafeFast(&ActCtx);
01315         }
01316     }
01317     else
01318     {
01319         /* The DLL is locked */
01320         goto Quickie;
01321     }
01322 
01323     /* Show debug message */
01324     if (ShowSnaps) DPRINT1("LDR: UNINIT LIST\n");
01325 
01326     /* Check if this is our only unload and initialize the list if so */
01327     if (LdrpActiveUnloadCount == 1) InitializeListHead(&LdrpUnloadHead);
01328 
01329     /* Loop the modules to build the list */
01330     NextEntry = Peb->Ldr->InInitializationOrderModuleList.Blink;
01331     while (NextEntry != &Peb->Ldr->InInitializationOrderModuleList)
01332     {
01333         /* Get the entry */
01334         LdrEntry = CONTAINING_RECORD(NextEntry,
01335                                      LDR_DATA_TABLE_ENTRY,
01336                                      InInitializationOrderModuleList);
01337         NextEntry = NextEntry->Blink;
01338 
01339         /* Remove flag */
01340         LdrEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
01341 
01342         /* If the load count is now 0 */
01343         if (!LdrEntry->LoadCount)
01344         {
01345             /* Show message */
01346             if (ShowSnaps)
01347             {
01348                 DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n",
01349                         LdrpActiveUnloadCount,
01350                         LdrEntry->BaseDllName.Buffer,
01351                         LdrEntry->FullDllName.Buffer,
01352                         (ULONG)LdrEntry->LoadCount,
01353                         LdrEntry->EntryPoint);
01354             }
01355 
01356             /* FIXME: Call Shim Engine and notify */
01357 
01358             /* Unlink it */
01359             CurrentEntry = LdrEntry;
01360             RemoveEntryList(&CurrentEntry->InInitializationOrderModuleList);
01361             RemoveEntryList(&CurrentEntry->InMemoryOrderModuleList);
01362             RemoveEntryList(&CurrentEntry->HashLinks);
01363 
01364             /* If there's more then one active unload */
01365             if (LdrpActiveUnloadCount > 1)
01366             {
01367                 /* Flush the cached DLL handle and clear the list */
01368                 LdrpLoadedDllHandleCache = NULL;
01369                 CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
01370             }
01371 
01372             /* Add the entry on the unload list */
01373             InsertTailList(&LdrpUnloadHead, &CurrentEntry->HashLinks);
01374         }
01375     }
01376 
01377     /* Only call the entrypoints once */
01378     if (LdrpActiveUnloadCount > 1) goto Quickie;
01379 
01380     /* Now loop the unload list and create our own */
01381     InitializeListHead(&UnloadList);
01382     CurrentEntry = NULL;
01383     NextEntry = LdrpUnloadHead.Flink;
01384     while (NextEntry != &LdrpUnloadHead)
01385     {
01386         /* Get the current entry */
01387         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
01388 
01389         /* FIXME: Log the Unload Event */
01390         //LdrpRecordUnloadEvent(LdrEntry);
01391 
01392         /* Set the entry and clear it from the list */
01393         CurrentEntry = LdrEntry;
01394         LdrpLoadedDllHandleCache = NULL;
01395         CurrentEntry->InMemoryOrderModuleList.Flink = NULL;
01396 
01397         /* Move it from the global to the local list */
01398         RemoveEntryList(&CurrentEntry->HashLinks);
01399         InsertTailList(&UnloadList, &CurrentEntry->HashLinks);
01400 
01401         /* Get the entrypoint */
01402         EntryPoint = LdrEntry->EntryPoint;
01403 
01404         /* Check if we should call it */
01405         if ((EntryPoint) && (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED))
01406         {
01407             /* Show message */
01408             if (ShowSnaps)
01409             {
01410                 DPRINT1("LDR: Calling deinit %lx\n", EntryPoint);
01411             }
01412 
01413             /* Set up the Act Ctx */
01414             ActCtx.Size = sizeof(ActCtx);
01415             ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
01416             RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
01417 
01418             /* Activate the ActCtx */
01419             RtlActivateActivationContextUnsafeFast(&ActCtx,
01420                                                    LdrEntry->EntryPointActivationContext);
01421 
01422             /* Call the entrypoint */
01423             LdrpCallInitRoutine(LdrEntry->EntryPoint,
01424                                 LdrEntry->DllBase,
01425                                 DLL_PROCESS_DETACH,
01426                                 NULL);
01427 
01428             /* Release the context */
01429             RtlDeactivateActivationContextUnsafeFast(&ActCtx);
01430         }
01431 
01432         /* Remove it from the list */
01433         RemoveEntryList(&CurrentEntry->InLoadOrderLinks);
01434         CurrentEntry = NULL;
01435         NextEntry = LdrpUnloadHead.Flink;
01436     }
01437 
01438     /* Now loop our local list */
01439     NextEntry = UnloadList.Flink;
01440     while (NextEntry != &UnloadList)
01441     {
01442         /* Get the entry */
01443         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, HashLinks);
01444         NextEntry = NextEntry->Flink;
01445         CurrentEntry = LdrEntry;
01446 
01447         /* Notify Application Verifier */
01448         if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
01449         {
01450             DPRINT1("We don't support Application Verifier yet\n");
01451         }
01452 
01453         /* Show message */
01454         if (ShowSnaps)
01455         {
01456             DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry->BaseDllName.Buffer);
01457         }
01458 
01459         /* Check if this is a .NET executable */
01460         CorImageData = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
01461                                                     TRUE,
01462                                                     IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
01463                                                     &ComSectionSize);
01464         if (CorImageData)
01465         {
01466             /* FIXME */
01467             DPRINT1(".NET Images are not supported yet\n");
01468         }
01469 
01470         /* Check if we should unmap*/
01471         if (!(CurrentEntry->Flags & LDR_COR_OWNS_UNMAP))
01472         {
01473             /* Unmap the DLL */
01474             Status = NtUnmapViewOfSection(NtCurrentProcess(),
01475                                           CurrentEntry->DllBase);
01476             ASSERT(NT_SUCCESS(Status));
01477         }
01478 
01479         /* Unload the alternate resource module, if any */
01480         LdrUnloadAlternateResourceModule(CurrentEntry->DllBase);
01481 
01482         /* FIXME: Send shutdown notification */
01483         //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
01484 
01485         /* Check if a Hotpatch is active */
01486         if (LdrEntry->PatchInformation)
01487         {
01488             /* FIXME */
01489             DPRINT1("We don't support Hotpatching yet\n");
01490         }
01491 
01492         /* Deallocate the Entry */
01493         LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry);
01494 
01495         /* If this is the cached entry, invalidate it */
01496         if (LdrpGetModuleHandleCache == CurrentEntry)
01497         {
01498             LdrpGetModuleHandleCache = NULL;
01499         }
01500     }
01501 
01502 Quickie:
01503     /* Decrease unload count */
01504     LdrpActiveUnloadCount--;
01505     if (!LdrpInLdrInit) RtlLeaveCriticalSection(Peb->LoaderLock);
01506 
01507     /* Return to caller */
01508     return Status;
01509 }
01510 
01511 /*
01512  * @implemented
01513  */
01514 BOOLEAN
01515 NTAPI
01516 RtlDllShutdownInProgress(VOID)
01517 {
01518     /* Return the internal global */
01519     return LdrpShutdownInProgress;
01520 }
01521 
01522 /*
01523  * @implemented
01524  */
01525 PIMAGE_BASE_RELOCATION
01526 NTAPI
01527 LdrProcessRelocationBlock(IN ULONG_PTR Address,
01528                           IN ULONG Count,
01529                           IN PUSHORT TypeOffset,
01530                           IN LONG_PTR Delta)
01531 {
01532     return LdrProcessRelocationBlockLongLong(Address, Count, TypeOffset, Delta);
01533 }
01534 
01535 /*
01536  * @implemented
01537  */
01538 BOOLEAN
01539 NTAPI
01540 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress)
01541 {
01542     ULONG_PTR Cookie;
01543     
01544     /* Acquire the loader lock */
01545     LdrLockLoaderLock(TRUE, NULL, &Cookie);
01546     
01547     /* Check if there's any alternate resources loaded */
01548     if (AlternateResourceModuleCount)
01549     {
01550         UNIMPLEMENTED;
01551     }
01552     
01553     /* Release the loader lock */
01554     LdrUnlockLoaderLock(1, Cookie);
01555     
01556     /* All done */
01557     return TRUE;
01558 }
01559 
01560 /* FIXME: Add to ntstatus.mc */
01561 #define STATUS_MUI_FILE_NOT_FOUND        ((NTSTATUS)0xC00B0001L)
01562 
01563 /*
01564  * @implemented
01565  */
01566 NTSTATUS
01567 NTAPI
01568 LdrLoadAlternateResourceModule(IN PVOID Module,
01569                                IN PWSTR Buffer)
01570 {
01571     /* Is MUI Support enabled? */
01572     if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS;
01573     
01574     UNIMPLEMENTED;
01575     return STATUS_MUI_FILE_NOT_FOUND;
01576 }
01577     
01578 /* EOF */

Generated on Sat May 26 2012 04:21:03 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.