Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenldrapi.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
1.7.6.1
|