14f0272dd3e3d5ff5d785bbbcb9602867017ac0d
[reactos.git] / dll / ntdll / ldr / ldrinit.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode Library
4 * FILE: dll/ntdll/ldr/ldrinit.c
5 * PURPOSE: User-Mode Process/Thread Startup
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntdll.h>
13 #include <compat_undoc.h>
14 #include <compatguid_undoc.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* GLOBALS *******************************************************************/
21
22 HANDLE ImageExecOptionsKey;
23 HANDLE Wow64ExecOptionsKey;
24 UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
25 UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
26 UNICODE_STRING NtDllString = RTL_CONSTANT_STRING(L"ntdll.dll");
27 UNICODE_STRING Kernel32String = RTL_CONSTANT_STRING(L"kernel32.dll");
28
29 BOOLEAN LdrpInLdrInit;
30 LONG LdrpProcessInitialized;
31 BOOLEAN LdrpLoaderLockInit;
32 BOOLEAN LdrpLdrDatabaseIsSetup;
33 BOOLEAN LdrpShutdownInProgress;
34 HANDLE LdrpShutdownThreadId;
35
36 BOOLEAN LdrpDllValidation;
37
38 PLDR_DATA_TABLE_ENTRY LdrpImageEntry;
39 PUNICODE_STRING LdrpTopLevelDllBeingLoaded;
40 WCHAR StringBuffer[156];
41 extern PTEB LdrpTopLevelDllBeingLoadedTeb; // defined in rtlsupp.c!
42 PLDR_DATA_TABLE_ENTRY LdrpCurrentDllInitializer;
43 PLDR_DATA_TABLE_ENTRY LdrpNtDllDataTableEntry;
44
45 static NTSTATUS (WINAPI *Kernel32ProcessInitPostImportFunction)(VOID);
46 static BOOL (WINAPI *Kernel32BaseQueryModuleData)(IN LPSTR ModuleName, IN LPSTR Unk1, IN PVOID Unk2, IN PVOID Unk3, IN PVOID Unk4);
47
48 RTL_BITMAP TlsBitMap;
49 RTL_BITMAP TlsExpansionBitMap;
50 RTL_BITMAP FlsBitMap;
51 BOOLEAN LdrpImageHasTls;
52 LIST_ENTRY LdrpTlsList;
53 ULONG LdrpNumberOfTlsEntries;
54 ULONG LdrpNumberOfProcessors;
55 PVOID NtDllBase;
56 extern LARGE_INTEGER RtlpTimeout;
57 BOOLEAN RtlpTimeoutDisable;
58 LIST_ENTRY LdrpHashTable[LDR_HASH_TABLE_ENTRIES];
59 LIST_ENTRY LdrpDllNotificationList;
60 HANDLE LdrpKnownDllObjectDirectory;
61 UNICODE_STRING LdrpKnownDllPath;
62 WCHAR LdrpKnownDllPathBuffer[128];
63 UNICODE_STRING LdrpDefaultPath;
64
65 PEB_LDR_DATA PebLdr;
66
67 RTL_CRITICAL_SECTION_DEBUG LdrpLoaderLockDebug;
68 RTL_CRITICAL_SECTION LdrpLoaderLock =
69 {
70 &LdrpLoaderLockDebug,
71 -1,
72 0,
73 0,
74 0,
75 0
76 };
77 RTL_CRITICAL_SECTION FastPebLock;
78
79 BOOLEAN ShowSnaps;
80
81 ULONG LdrpFatalHardErrorCount;
82 ULONG LdrpActiveUnloadCount;
83
84 //extern LIST_ENTRY RtlCriticalSectionList;
85
86 VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID);
87 VOID NTAPI RtlpInitDeferedCriticalSection(VOID);
88 VOID NTAPI RtlInitializeHeapManager(VOID);
89
90 ULONG RtlpDisableHeapLookaside; // TODO: Move to heap.c
91 ULONG RtlpShutdownProcessFlags; // TODO: Use it
92
93 NTSTATUS LdrPerformRelocations(PIMAGE_NT_HEADERS NTHeaders, PVOID ImageBase);
94 void actctx_init(void);
95 extern BOOLEAN RtlpUse16ByteSLists;
96
97 #ifdef _WIN64
98 #define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll
99 #else
100 #define DEFAULT_SECURITY_COOKIE 0xBB40E64E
101 #endif
102
103 /* FUNCTIONS *****************************************************************/
104
105 /*
106 * @implemented
107 */
108 NTSTATUS
109 NTAPI
110 LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
111 IN BOOLEAN Wow64,
112 OUT PHANDLE NewKeyHandle)
113 {
114 PHANDLE RootKeyLocation;
115 HANDLE RootKey;
116 UNICODE_STRING SubKeyString;
117 OBJECT_ATTRIBUTES ObjectAttributes;
118 NTSTATUS Status;
119 PWCHAR p1;
120
121 /* Check which root key to open */
122 if (Wow64)
123 RootKeyLocation = &Wow64ExecOptionsKey;
124 else
125 RootKeyLocation = &ImageExecOptionsKey;
126
127 /* Get the current key */
128 RootKey = *RootKeyLocation;
129
130 /* Setup the object attributes */
131 InitializeObjectAttributes(&ObjectAttributes,
132 Wow64 ?
133 &Wow64OptionsString : &ImageExecOptionsString,
134 OBJ_CASE_INSENSITIVE,
135 NULL,
136 NULL);
137
138 /* Open the root key */
139 Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
140 if (NT_SUCCESS(Status))
141 {
142 /* Write the key handle */
143 if (InterlockedCompareExchangePointer(RootKeyLocation, RootKey, NULL) != NULL)
144 {
145 /* Someone already opened it, use it instead */
146 NtClose(RootKey);
147 RootKey = *RootKeyLocation;
148 }
149
150 /* Extract the name */
151 SubKeyString = *SubKey;
152 p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
153 while (SubKeyString.Length)
154 {
155 if (p1[-1] == L'\\') break;
156 p1--;
157 SubKeyString.Length -= sizeof(*p1);
158 }
159 SubKeyString.Buffer = p1;
160 SubKeyString.Length = SubKey->Length - SubKeyString.Length;
161
162 /* Setup the object attributes */
163 InitializeObjectAttributes(&ObjectAttributes,
164 &SubKeyString,
165 OBJ_CASE_INSENSITIVE,
166 RootKey,
167 NULL);
168
169 /* Open the setting key */
170 Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
171 }
172
173 /* Return to caller */
174 return Status;
175 }
176
177 /*
178 * @implemented
179 */
180 NTSTATUS
181 NTAPI
182 LdrQueryImageFileKeyOption(IN HANDLE KeyHandle,
183 IN PCWSTR ValueName,
184 IN ULONG Type,
185 OUT PVOID Buffer,
186 IN ULONG BufferSize,
187 OUT PULONG ReturnedLength OPTIONAL)
188 {
189 ULONG KeyInfo[256];
190 UNICODE_STRING ValueNameString, IntegerString;
191 ULONG KeyInfoSize, ResultSize;
192 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
193 BOOLEAN FreeHeap = FALSE;
194 NTSTATUS Status;
195
196 /* Build a string for the value name */
197 Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
198 if (!NT_SUCCESS(Status)) return Status;
199
200 /* Query the value */
201 Status = ZwQueryValueKey(KeyHandle,
202 &ValueNameString,
203 KeyValuePartialInformation,
204 KeyValueInformation,
205 sizeof(KeyInfo),
206 &ResultSize);
207 if (Status == STATUS_BUFFER_OVERFLOW)
208 {
209 /* Our local buffer wasn't enough, allocate one */
210 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
211 KeyValueInformation->DataLength;
212 KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
213 0,
214 KeyInfoSize);
215 if (KeyValueInformation != NULL)
216 {
217 /* Try again */
218 Status = ZwQueryValueKey(KeyHandle,
219 &ValueNameString,
220 KeyValuePartialInformation,
221 KeyValueInformation,
222 KeyInfoSize,
223 &ResultSize);
224 FreeHeap = TRUE;
225 }
226 else
227 {
228 /* Give up this time */
229 Status = STATUS_NO_MEMORY;
230 }
231 }
232
233 /* Check for success */
234 if (NT_SUCCESS(Status))
235 {
236 /* Handle binary data */
237 if (KeyValueInformation->Type == REG_BINARY)
238 {
239 /* Check validity */
240 if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
241 {
242 /* Copy into buffer */
243 RtlMoveMemory(Buffer,
244 &KeyValueInformation->Data,
245 KeyValueInformation->DataLength);
246 }
247 else
248 {
249 Status = STATUS_BUFFER_OVERFLOW;
250 }
251
252 /* Copy the result length */
253 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
254 }
255 else if (KeyValueInformation->Type == REG_DWORD)
256 {
257 /* Check for valid type */
258 if (KeyValueInformation->Type != Type)
259 {
260 /* Error */
261 Status = STATUS_OBJECT_TYPE_MISMATCH;
262 }
263 else
264 {
265 /* Check validity */
266 if ((Buffer) &&
267 (BufferSize == sizeof(ULONG)) &&
268 (KeyValueInformation->DataLength <= BufferSize))
269 {
270 /* Copy into buffer */
271 RtlMoveMemory(Buffer,
272 &KeyValueInformation->Data,
273 KeyValueInformation->DataLength);
274 }
275 else
276 {
277 Status = STATUS_BUFFER_OVERFLOW;
278 }
279
280 /* Copy the result length */
281 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
282 }
283 }
284 else if (KeyValueInformation->Type != REG_SZ)
285 {
286 /* We got something weird */
287 Status = STATUS_OBJECT_TYPE_MISMATCH;
288 }
289 else
290 {
291 /* String, check what you requested */
292 if (Type == REG_DWORD)
293 {
294 /* Validate */
295 if (BufferSize != sizeof(ULONG))
296 {
297 /* Invalid size */
298 BufferSize = 0;
299 Status = STATUS_INFO_LENGTH_MISMATCH;
300 }
301 else
302 {
303 /* OK, we know what you want... */
304 IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
305 IntegerString.Length = (USHORT)KeyValueInformation->DataLength -
306 sizeof(WCHAR);
307 IntegerString.MaximumLength = (USHORT)KeyValueInformation->DataLength;
308 Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
309 }
310 }
311 else
312 {
313 /* Validate */
314 if (KeyValueInformation->DataLength > BufferSize)
315 {
316 /* Invalid */
317 Status = STATUS_BUFFER_OVERFLOW;
318 }
319 else
320 {
321 /* Set the size */
322 BufferSize = KeyValueInformation->DataLength;
323 }
324
325 /* Copy the string */
326 RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
327 }
328
329 /* Copy the result length */
330 if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
331 }
332 }
333
334 /* Check if buffer was in heap */
335 if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
336
337 /* Return status */
338 return Status;
339 }
340
341 /*
342 * @implemented
343 */
344 NTSTATUS
345 NTAPI
346 LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
347 IN PCWSTR ValueName,
348 IN ULONG Type,
349 OUT PVOID Buffer,
350 IN ULONG BufferSize,
351 OUT PULONG ReturnedLength OPTIONAL,
352 IN BOOLEAN Wow64)
353 {
354 NTSTATUS Status;
355 HANDLE KeyHandle;
356
357 /* Open a handle to the key */
358 Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
359
360 /* Check for success */
361 if (NT_SUCCESS(Status))
362 {
363 /* Query the data */
364 Status = LdrQueryImageFileKeyOption(KeyHandle,
365 ValueName,
366 Type,
367 Buffer,
368 BufferSize,
369 ReturnedLength);
370
371 /* Close the key */
372 NtClose(KeyHandle);
373 }
374
375 /* Return to caller */
376 return Status;
377 }
378
379 /*
380 * @implemented
381 */
382 NTSTATUS
383 NTAPI
384 LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
385 IN PCWSTR ValueName,
386 IN ULONG Type,
387 OUT PVOID Buffer,
388 IN ULONG BufferSize,
389 OUT PULONG ReturnedLength OPTIONAL)
390 {
391 /* Call the newer function */
392 return LdrQueryImageFileExecutionOptionsEx(SubKey,
393 ValueName,
394 Type,
395 Buffer,
396 BufferSize,
397 ReturnedLength,
398 FALSE);
399 }
400
401 VOID
402 NTAPI
403 LdrpEnsureLoaderLockIsHeld(VOID)
404 {
405 // Ignored atm
406 }
407
408 PVOID
409 NTAPI
410 LdrpFetchAddressOfSecurityCookie(PVOID BaseAddress, ULONG SizeOfImage)
411 {
412 PIMAGE_LOAD_CONFIG_DIRECTORY ConfigDir;
413 ULONG DirSize;
414 PVOID Cookie = NULL;
415
416 /* Check NT header first */
417 if (!RtlImageNtHeader(BaseAddress)) return NULL;
418
419 /* Get the pointer to the config directory */
420 ConfigDir = RtlImageDirectoryEntryToData(BaseAddress,
421 TRUE,
422 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
423 &DirSize);
424
425 /* Check for sanity */
426 if (!ConfigDir ||
427 (DirSize != 64 && ConfigDir->Size != DirSize) ||
428 (ConfigDir->Size < 0x48))
429 return NULL;
430
431 /* Now get the cookie */
432 Cookie = (PVOID)ConfigDir->SecurityCookie;
433
434 /* Check this cookie */
435 if ((PCHAR)Cookie <= (PCHAR)BaseAddress ||
436 (PCHAR)Cookie >= (PCHAR)BaseAddress + SizeOfImage)
437 {
438 Cookie = NULL;
439 }
440
441 /* Return validated security cookie */
442 return Cookie;
443 }
444
445 PVOID
446 NTAPI
447 LdrpInitSecurityCookie(PLDR_DATA_TABLE_ENTRY LdrEntry)
448 {
449 PULONG_PTR Cookie;
450 LARGE_INTEGER Counter;
451 ULONG_PTR NewCookie;
452
453 /* Fetch address of the cookie */
454 Cookie = LdrpFetchAddressOfSecurityCookie(LdrEntry->DllBase, LdrEntry->SizeOfImage);
455
456 if (Cookie)
457 {
458 /* Check if it's a default one */
459 if ((*Cookie == DEFAULT_SECURITY_COOKIE) ||
460 (*Cookie == 0xBB40))
461 {
462 /* Make up a cookie from a bunch of values which may uniquely represent
463 current moment of time, environment, etc */
464 NtQueryPerformanceCounter(&Counter, NULL);
465
466 NewCookie = Counter.LowPart ^ Counter.HighPart;
467 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
468 NewCookie ^= (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueThread;
469
470 /* Loop like it's done in KeQueryTickCount(). We don't want to call it directly. */
471 while (SharedUserData->SystemTime.High1Time != SharedUserData->SystemTime.High2Time)
472 {
473 YieldProcessor();
474 };
475
476 /* Calculate the milliseconds value and xor it to the cookie */
477 NewCookie ^= Int64ShrlMod32(UInt32x32To64(SharedUserData->TickCountMultiplier, SharedUserData->TickCount.LowPart), 24) +
478 (SharedUserData->TickCountMultiplier * (SharedUserData->TickCount.High1Time << 8));
479
480 /* Make the cookie 16bit if necessary */
481 if (*Cookie == 0xBB40) NewCookie &= 0xFFFF;
482
483 /* If the result is 0 or the same as we got, just subtract one from the existing value
484 and that's it */
485 if ((NewCookie == 0) || (NewCookie == *Cookie))
486 {
487 NewCookie = *Cookie - 1;
488 }
489
490 /* Set the new cookie value */
491 *Cookie = NewCookie;
492 }
493 }
494
495 return Cookie;
496 }
497
498 VOID
499 NTAPI
500 LdrpInitializeThread(IN PCONTEXT Context)
501 {
502 PPEB Peb = NtCurrentPeb();
503 PLDR_DATA_TABLE_ENTRY LdrEntry;
504 PLIST_ENTRY NextEntry, ListHead;
505 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
506 NTSTATUS Status;
507 PVOID EntryPoint;
508
509 DPRINT("LdrpInitializeThread() called for %wZ (%p/%p)\n",
510 &LdrpImageEntry->BaseDllName,
511 NtCurrentTeb()->RealClientId.UniqueProcess,
512 NtCurrentTeb()->RealClientId.UniqueThread);
513
514 /* Allocate an Activation Context Stack */
515 DPRINT("ActivationContextStack %p\n", NtCurrentTeb()->ActivationContextStackPointer);
516 Status = RtlAllocateActivationContextStack(&NtCurrentTeb()->ActivationContextStackPointer);
517 if (!NT_SUCCESS(Status))
518 {
519 DPRINT1("Warning: Unable to allocate ActivationContextStack\n");
520 }
521
522 /* Make sure we are not shutting down */
523 if (LdrpShutdownInProgress) return;
524
525 /* Allocate TLS */
526 LdrpAllocateTls();
527
528 /* Start at the beginning */
529 ListHead = &Peb->Ldr->InMemoryOrderModuleList;
530 NextEntry = ListHead->Flink;
531 while (NextEntry != ListHead)
532 {
533 /* Get the current entry */
534 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
535
536 /* Make sure it's not ourselves */
537 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
538 {
539 /* Check if we should call */
540 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS))
541 {
542 /* Get the entrypoint */
543 EntryPoint = LdrEntry->EntryPoint;
544
545 /* Check if we are ready to call it */
546 if ((EntryPoint) &&
547 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
548 (LdrEntry->Flags & LDRP_IMAGE_DLL))
549 {
550 /* Set up the Act Ctx */
551 ActCtx.Size = sizeof(ActCtx);
552 ActCtx.Format = 1;
553 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
554
555 /* Activate the ActCtx */
556 RtlActivateActivationContextUnsafeFast(&ActCtx,
557 LdrEntry->EntryPointActivationContext);
558
559 _SEH2_TRY
560 {
561 /* Check if it has TLS */
562 if (LdrEntry->TlsIndex)
563 {
564 /* Make sure we're not shutting down */
565 if (!LdrpShutdownInProgress)
566 {
567 /* Call TLS */
568 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_ATTACH);
569 }
570 }
571
572 /* Make sure we're not shutting down */
573 if (!LdrpShutdownInProgress)
574 {
575 /* Call the Entrypoint */
576 DPRINT("%wZ - Calling entry point at %p for thread attaching, %p/%p\n",
577 &LdrEntry->BaseDllName, LdrEntry->EntryPoint,
578 NtCurrentTeb()->RealClientId.UniqueProcess,
579 NtCurrentTeb()->RealClientId.UniqueThread);
580 LdrpCallInitRoutine(LdrEntry->EntryPoint,
581 LdrEntry->DllBase,
582 DLL_THREAD_ATTACH,
583 NULL);
584 }
585 }
586 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
587 {
588 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_ATTACH) for %wZ\n",
589 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
590 }
591 _SEH2_END;
592
593 /* Deactivate the ActCtx */
594 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
595 }
596 }
597 }
598
599 /* Next entry */
600 NextEntry = NextEntry->Flink;
601 }
602
603 /* Check for TLS */
604 if (LdrpImageHasTls && !LdrpShutdownInProgress)
605 {
606 /* Set up the Act Ctx */
607 ActCtx.Size = sizeof(ActCtx);
608 ActCtx.Format = 1;
609 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
610
611 /* Activate the ActCtx */
612 RtlActivateActivationContextUnsafeFast(&ActCtx,
613 LdrpImageEntry->EntryPointActivationContext);
614
615 _SEH2_TRY
616 {
617 /* Do TLS callbacks */
618 LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_ATTACH);
619 }
620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
621 {
622 /* Do nothing */
623 }
624 _SEH2_END;
625
626 /* Deactivate the ActCtx */
627 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
628 }
629
630 DPRINT("LdrpInitializeThread() done\n");
631 }
632
633 NTSTATUS
634 NTAPI
635 LdrpRunInitializeRoutines(IN PCONTEXT Context OPTIONAL)
636 {
637 PLDR_DATA_TABLE_ENTRY LocalArray[16];
638 PLIST_ENTRY ListHead;
639 PLIST_ENTRY NextEntry;
640 PLDR_DATA_TABLE_ENTRY LdrEntry, *LdrRootEntry, OldInitializer;
641 PVOID EntryPoint;
642 ULONG Count, i;
643 //ULONG BreakOnInit;
644 NTSTATUS Status = STATUS_SUCCESS;
645 PPEB Peb = NtCurrentPeb();
646 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
647 ULONG BreakOnDllLoad;
648 PTEB OldTldTeb;
649 BOOLEAN DllStatus;
650
651 DPRINT("LdrpRunInitializeRoutines() called for %wZ (%p/%p)\n",
652 &LdrpImageEntry->BaseDllName,
653 NtCurrentTeb()->RealClientId.UniqueProcess,
654 NtCurrentTeb()->RealClientId.UniqueThread);
655
656 /* Check the Loader Lock */
657 LdrpEnsureLoaderLockIsHeld();
658
659 /* Get the number of entries to call */
660 if ((Count = LdrpClearLoadInProgress()))
661 {
662 /* Check if we can use our local buffer */
663 if (Count > 16)
664 {
665 /* Allocate space for all the entries */
666 LdrRootEntry = RtlAllocateHeap(RtlGetProcessHeap(),
667 0,
668 Count * sizeof(*LdrRootEntry));
669 if (!LdrRootEntry) return STATUS_NO_MEMORY;
670 }
671 else
672 {
673 /* Use our local array */
674 LdrRootEntry = LocalArray;
675 }
676 }
677 else
678 {
679 /* Don't need one */
680 LdrRootEntry = NULL;
681 }
682
683 /* Show debug message */
684 if (ShowSnaps)
685 {
686 DPRINT1("[%p,%p] LDR: Real INIT LIST for Process %wZ\n",
687 NtCurrentTeb()->RealClientId.UniqueThread,
688 NtCurrentTeb()->RealClientId.UniqueProcess,
689 &Peb->ProcessParameters->ImagePathName);
690 }
691
692 /* Loop in order */
693 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
694 NextEntry = ListHead->Flink;
695 i = 0;
696 while (NextEntry != ListHead)
697 {
698 /* Get the Data Entry */
699 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
700
701 /* Check if we have a Root Entry */
702 if (LdrRootEntry)
703 {
704 /* Check flags */
705 if (!(LdrEntry->Flags & LDRP_ENTRY_PROCESSED))
706 {
707 /* Setup the Cookie for the DLL */
708 LdrpInitSecurityCookie(LdrEntry);
709
710 /* Check for valid entrypoint */
711 if (LdrEntry->EntryPoint)
712 {
713 /* Write in array */
714 ASSERT(i < Count);
715 LdrRootEntry[i] = LdrEntry;
716
717 /* Display debug message */
718 if (ShowSnaps)
719 {
720 DPRINT1("[%p,%p] LDR: %wZ init routine %p\n",
721 NtCurrentTeb()->RealClientId.UniqueThread,
722 NtCurrentTeb()->RealClientId.UniqueProcess,
723 &LdrEntry->FullDllName,
724 LdrEntry->EntryPoint);
725 }
726 i++;
727 }
728 }
729 }
730
731 /* Set the flag */
732 LdrEntry->Flags |= LDRP_ENTRY_PROCESSED;
733 NextEntry = NextEntry->Flink;
734 }
735
736 Status = STATUS_SUCCESS;
737
738 /* If we got a context, then we have to call Kernel32 for TS support */
739 if (Context)
740 {
741 /* Check if we have one */
742 if (Kernel32ProcessInitPostImportFunction)
743 {
744 /* Call it */
745 Status = Kernel32ProcessInitPostImportFunction();
746 if (!NT_SUCCESS(Status))
747 {
748 DPRINT1("LDR: LdrpRunInitializeRoutines - Failed running kernel32 post-import function, Status=0x%08lx\n", Status);
749 }
750 }
751 /* Clear it */
752 Kernel32ProcessInitPostImportFunction = NULL;
753 }
754
755 /* No root entry? return */
756 if (!LdrRootEntry)
757 return Status;
758
759 /* Set the TLD TEB */
760 OldTldTeb = LdrpTopLevelDllBeingLoadedTeb;
761 LdrpTopLevelDllBeingLoadedTeb = NtCurrentTeb();
762
763 /* Loop */
764 i = 0;
765 while (i < Count)
766 {
767 /* Get an entry */
768 LdrEntry = LdrRootEntry[i];
769
770 /* FIXME: Verify NX Compat */
771
772 /* Move to next entry */
773 i++;
774
775 /* Get its entrypoint */
776 EntryPoint = LdrEntry->EntryPoint;
777
778 /* Are we being debugged? */
779 BreakOnDllLoad = 0;
780 if (Peb->BeingDebugged || Peb->ReadImageFileExecOptions)
781 {
782 /* Check if we should break on load */
783 Status = LdrQueryImageFileExecutionOptions(&LdrEntry->BaseDllName,
784 L"BreakOnDllLoad",
785 REG_DWORD,
786 &BreakOnDllLoad,
787 sizeof(ULONG),
788 NULL);
789 if (!NT_SUCCESS(Status)) BreakOnDllLoad = 0;
790
791 /* Reset status back to STATUS_SUCCESS */
792 Status = STATUS_SUCCESS;
793 }
794
795 /* Break if aksed */
796 if (BreakOnDllLoad)
797 {
798 /* Check if we should show a message */
799 if (ShowSnaps)
800 {
801 DPRINT1("LDR: %wZ loaded.", &LdrEntry->BaseDllName);
802 DPRINT1(" - About to call init routine at %p\n", EntryPoint);
803 }
804
805 /* Break in debugger */
806 DbgBreakPoint();
807 }
808
809 /* Make sure we have an entrypoint */
810 if (EntryPoint)
811 {
812 /* Save the old Dll Initializer and write the current one */
813 OldInitializer = LdrpCurrentDllInitializer;
814 LdrpCurrentDllInitializer = LdrEntry;
815
816 /* Set up the Act Ctx */
817 ActCtx.Size = sizeof(ActCtx);
818 ActCtx.Format = 1;
819 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
820
821 /* Activate the ActCtx */
822 RtlActivateActivationContextUnsafeFast(&ActCtx,
823 LdrEntry->EntryPointActivationContext);
824
825 _SEH2_TRY
826 {
827 /* Check if it has TLS */
828 if (LdrEntry->TlsIndex && Context)
829 {
830 /* Call TLS */
831 LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_ATTACH);
832 }
833
834 /* Call the Entrypoint */
835 if (ShowSnaps)
836 {
837 DPRINT1("%wZ - Calling entry point at %p for DLL_PROCESS_ATTACH\n",
838 &LdrEntry->BaseDllName, EntryPoint);
839 }
840 DllStatus = LdrpCallInitRoutine(EntryPoint,
841 LdrEntry->DllBase,
842 DLL_PROCESS_ATTACH,
843 Context);
844 }
845 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
846 {
847 DllStatus = FALSE;
848 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_ATTACH) for %wZ\n",
849 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
850 }
851 _SEH2_END;
852
853 /* Deactivate the ActCtx */
854 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
855
856 /* Save the Current DLL Initializer */
857 LdrpCurrentDllInitializer = OldInitializer;
858
859 /* Mark the entry as processed */
860 LdrEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED;
861
862 /* Fail if DLL init failed */
863 if (!DllStatus)
864 {
865 DPRINT1("LDR: DLL_PROCESS_ATTACH for dll \"%wZ\" (InitRoutine: %p) failed\n",
866 &LdrEntry->BaseDllName, EntryPoint);
867
868 Status = STATUS_DLL_INIT_FAILED;
869 goto Quickie;
870 }
871 }
872 }
873
874 /* Loop in order */
875 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
876 NextEntry = NextEntry->Flink;
877 while (NextEntry != ListHead)
878 {
879 /* Get the Data Entry */
880 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
881
882 /* FIXME: Verify NX Compat */
883 // LdrpCheckNXCompatibility()
884
885 /* Next entry */
886 NextEntry = NextEntry->Flink;
887 }
888
889 /* Check for TLS */
890 if (LdrpImageHasTls && Context)
891 {
892 /* Set up the Act Ctx */
893 ActCtx.Size = sizeof(ActCtx);
894 ActCtx.Format = 1;
895 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
896
897 /* Activate the ActCtx */
898 RtlActivateActivationContextUnsafeFast(&ActCtx,
899 LdrpImageEntry->EntryPointActivationContext);
900
901 _SEH2_TRY
902 {
903 /* Do TLS callbacks */
904 LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_ATTACH);
905 }
906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
907 {
908 /* Do nothing */
909 }
910 _SEH2_END;
911
912 /* Deactivate the ActCtx */
913 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
914 }
915
916 Quickie:
917 /* Restore old TEB */
918 LdrpTopLevelDllBeingLoadedTeb = OldTldTeb;
919
920 /* Check if the array is in the heap */
921 if (LdrRootEntry != LocalArray)
922 {
923 /* Free the array */
924 RtlFreeHeap(RtlGetProcessHeap(), 0, LdrRootEntry);
925 }
926
927 /* Return to caller */
928 DPRINT("LdrpRunInitializeRoutines() done\n");
929 return Status;
930 }
931
932 /*
933 * @implemented
934 */
935 NTSTATUS
936 NTAPI
937 LdrShutdownProcess(VOID)
938 {
939 PPEB Peb = NtCurrentPeb();
940 PLDR_DATA_TABLE_ENTRY LdrEntry;
941 PLIST_ENTRY NextEntry, ListHead;
942 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
943 PVOID EntryPoint;
944
945 DPRINT("LdrShutdownProcess() called for %wZ\n", &LdrpImageEntry->BaseDllName);
946 if (LdrpShutdownInProgress) return STATUS_SUCCESS;
947
948 /* Tell the Shim Engine */
949 if (g_ShimsEnabled)
950 {
951 VOID(NTAPI *SE_ProcessDying)();
952 SE_ProcessDying = RtlDecodeSystemPointer(g_pfnSE_ProcessDying);
953 SE_ProcessDying();
954 }
955
956 /* Tell the world */
957 if (ShowSnaps)
958 {
959 DPRINT1("\n");
960 }
961
962 /* Set the shutdown variables */
963 LdrpShutdownThreadId = NtCurrentTeb()->RealClientId.UniqueThread;
964 LdrpShutdownInProgress = TRUE;
965
966 /* Enter the Loader Lock */
967 RtlEnterCriticalSection(&LdrpLoaderLock);
968
969 /* Cleanup trace logging data (Etw) */
970 if (SharedUserData->TraceLogging)
971 {
972 /* FIXME */
973 DPRINT1("We don't support Etw yet.\n");
974 }
975
976 /* Start at the end */
977 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
978 NextEntry = ListHead->Blink;
979 while (NextEntry != ListHead)
980 {
981 /* Get the current entry */
982 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
983 NextEntry = NextEntry->Blink;
984
985 /* Make sure it's not ourselves */
986 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
987 {
988 /* Get the entrypoint */
989 EntryPoint = LdrEntry->EntryPoint;
990
991 /* Check if we are ready to call it */
992 if (EntryPoint &&
993 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
994 LdrEntry->Flags)
995 {
996 /* Set up the Act Ctx */
997 ActCtx.Size = sizeof(ActCtx);
998 ActCtx.Format = 1;
999 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1000
1001 /* Activate the ActCtx */
1002 RtlActivateActivationContextUnsafeFast(&ActCtx,
1003 LdrEntry->EntryPointActivationContext);
1004
1005 _SEH2_TRY
1006 {
1007 /* Check if it has TLS */
1008 if (LdrEntry->TlsIndex)
1009 {
1010 /* Call TLS */
1011 LdrpCallTlsInitializers(LdrEntry, DLL_PROCESS_DETACH);
1012 }
1013
1014 /* Call the Entrypoint */
1015 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1016 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1017 LdrpCallInitRoutine(EntryPoint,
1018 LdrEntry->DllBase,
1019 DLL_PROCESS_DETACH,
1020 (PVOID)1);
1021 }
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1023 {
1024 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_PROCESS_DETACH) for %wZ\n",
1025 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1026 }
1027 _SEH2_END;
1028
1029 /* Deactivate the ActCtx */
1030 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1031 }
1032 }
1033 }
1034
1035 /* Check for TLS */
1036 if (LdrpImageHasTls)
1037 {
1038 /* Set up the Act Ctx */
1039 ActCtx.Size = sizeof(ActCtx);
1040 ActCtx.Format = 1;
1041 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1042
1043 /* Activate the ActCtx */
1044 RtlActivateActivationContextUnsafeFast(&ActCtx,
1045 LdrpImageEntry->EntryPointActivationContext);
1046
1047 _SEH2_TRY
1048 {
1049 /* Do TLS callbacks */
1050 LdrpCallTlsInitializers(LdrpImageEntry, DLL_PROCESS_DETACH);
1051 }
1052 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1053 {
1054 /* Do nothing */
1055 }
1056 _SEH2_END;
1057
1058 /* Deactivate the ActCtx */
1059 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1060 }
1061
1062 /* FIXME: Do Heap detection and Etw final shutdown */
1063
1064 /* Release the lock */
1065 RtlLeaveCriticalSection(&LdrpLoaderLock);
1066 DPRINT("LdrpShutdownProcess() done\n");
1067
1068 return STATUS_SUCCESS;
1069 }
1070
1071 /*
1072 * @implemented
1073 */
1074 NTSTATUS
1075 NTAPI
1076 LdrShutdownThread(VOID)
1077 {
1078 PPEB Peb = NtCurrentPeb();
1079 PTEB Teb = NtCurrentTeb();
1080 PLDR_DATA_TABLE_ENTRY LdrEntry;
1081 PLIST_ENTRY NextEntry, ListHead;
1082 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
1083 PVOID EntryPoint;
1084
1085 DPRINT("LdrShutdownThread() called for %wZ\n",
1086 &LdrpImageEntry->BaseDllName);
1087
1088 /* Cleanup trace logging data (Etw) */
1089 if (SharedUserData->TraceLogging)
1090 {
1091 /* FIXME */
1092 DPRINT1("We don't support Etw yet.\n");
1093 }
1094
1095 /* Get the Ldr Lock */
1096 RtlEnterCriticalSection(&LdrpLoaderLock);
1097
1098 /* Start at the end */
1099 ListHead = &Peb->Ldr->InInitializationOrderModuleList;
1100 NextEntry = ListHead->Blink;
1101 while (NextEntry != ListHead)
1102 {
1103 /* Get the current entry */
1104 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
1105 NextEntry = NextEntry->Blink;
1106
1107 /* Make sure it's not ourselves */
1108 if (Peb->ImageBaseAddress != LdrEntry->DllBase)
1109 {
1110 /* Check if we should call */
1111 if (!(LdrEntry->Flags & LDRP_DONT_CALL_FOR_THREADS) &&
1112 (LdrEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) &&
1113 (LdrEntry->Flags & LDRP_IMAGE_DLL))
1114 {
1115 /* Get the entrypoint */
1116 EntryPoint = LdrEntry->EntryPoint;
1117
1118 /* Check if we are ready to call it */
1119 if (EntryPoint)
1120 {
1121 /* Set up the Act Ctx */
1122 ActCtx.Size = sizeof(ActCtx);
1123 ActCtx.Format = 1;
1124 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1125
1126 /* Activate the ActCtx */
1127 RtlActivateActivationContextUnsafeFast(&ActCtx,
1128 LdrEntry->EntryPointActivationContext);
1129
1130 _SEH2_TRY
1131 {
1132 /* Check if it has TLS */
1133 if (LdrEntry->TlsIndex)
1134 {
1135 /* Make sure we're not shutting down */
1136 if (!LdrpShutdownInProgress)
1137 {
1138 /* Call TLS */
1139 LdrpCallTlsInitializers(LdrEntry, DLL_THREAD_DETACH);
1140 }
1141 }
1142
1143 /* Make sure we're not shutting down */
1144 if (!LdrpShutdownInProgress)
1145 {
1146 /* Call the Entrypoint */
1147 DPRINT("%wZ - Calling entry point at %p for thread detaching\n",
1148 &LdrEntry->BaseDllName, LdrEntry->EntryPoint);
1149 LdrpCallInitRoutine(EntryPoint,
1150 LdrEntry->DllBase,
1151 DLL_THREAD_DETACH,
1152 NULL);
1153 }
1154 }
1155 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1156 {
1157 DPRINT1("WARNING: Exception 0x%x during LdrpCallInitRoutine(DLL_THREAD_DETACH) for %wZ\n",
1158 _SEH2_GetExceptionCode(), &LdrEntry->BaseDllName);
1159 }
1160 _SEH2_END;
1161
1162 /* Deactivate the ActCtx */
1163 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1164 }
1165 }
1166 }
1167 }
1168
1169 /* Check for TLS */
1170 if (LdrpImageHasTls)
1171 {
1172 /* Set up the Act Ctx */
1173 ActCtx.Size = sizeof(ActCtx);
1174 ActCtx.Format = 1;
1175 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
1176
1177 /* Activate the ActCtx */
1178 RtlActivateActivationContextUnsafeFast(&ActCtx,
1179 LdrpImageEntry->EntryPointActivationContext);
1180
1181 _SEH2_TRY
1182 {
1183 /* Do TLS callbacks */
1184 LdrpCallTlsInitializers(LdrpImageEntry, DLL_THREAD_DETACH);
1185 }
1186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1187 {
1188 /* Do nothing */
1189 }
1190 _SEH2_END;
1191
1192 /* Deactivate the ActCtx */
1193 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
1194 }
1195
1196 /* Free TLS */
1197 LdrpFreeTls();
1198 RtlLeaveCriticalSection(&LdrpLoaderLock);
1199
1200 /* Check for expansion slots */
1201 if (Teb->TlsExpansionSlots)
1202 {
1203 /* Free expansion slots */
1204 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->TlsExpansionSlots);
1205 }
1206
1207 /* Check for FLS Data */
1208 if (Teb->FlsData)
1209 {
1210 /* FIXME */
1211 DPRINT1("We don't support FLS Data yet\n");
1212 }
1213
1214 /* Check for Fiber data */
1215 if (Teb->HasFiberData)
1216 {
1217 /* Free Fiber data*/
1218 RtlFreeHeap(RtlGetProcessHeap(), 0, Teb->NtTib.FiberData);
1219 Teb->NtTib.FiberData = NULL;
1220 }
1221
1222 /* Free the activation context stack */
1223 RtlFreeThreadActivationContextStack();
1224 DPRINT("LdrShutdownThread() done\n");
1225
1226 return STATUS_SUCCESS;
1227 }
1228
1229 NTSTATUS
1230 NTAPI
1231 LdrpInitializeTls(VOID)
1232 {
1233 PLIST_ENTRY NextEntry, ListHead;
1234 PLDR_DATA_TABLE_ENTRY LdrEntry;
1235 PIMAGE_TLS_DIRECTORY TlsDirectory;
1236 PLDRP_TLS_DATA TlsData;
1237 ULONG Size;
1238
1239 /* Initialize the TLS List */
1240 InitializeListHead(&LdrpTlsList);
1241
1242 /* Loop all the modules */
1243 ListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1244 NextEntry = ListHead->Flink;
1245 while (ListHead != NextEntry)
1246 {
1247 /* Get the entry */
1248 LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
1249 NextEntry = NextEntry->Flink;
1250
1251 /* Get the TLS directory */
1252 TlsDirectory = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
1253 TRUE,
1254 IMAGE_DIRECTORY_ENTRY_TLS,
1255 &Size);
1256
1257 /* Check if we have a directory */
1258 if (!TlsDirectory) continue;
1259
1260 /* Check if the image has TLS */
1261 if (!LdrpImageHasTls) LdrpImageHasTls = TRUE;
1262
1263 /* Show debug message */
1264 if (ShowSnaps)
1265 {
1266 DPRINT1("LDR: Tls Found in %wZ at %p\n",
1267 &LdrEntry->BaseDllName,
1268 TlsDirectory);
1269 }
1270
1271 /* Allocate an entry */
1272 TlsData = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(LDRP_TLS_DATA));
1273 if (!TlsData) return STATUS_NO_MEMORY;
1274
1275 /* Lock the DLL and mark it for TLS Usage */
1276 LdrEntry->LoadCount = -1;
1277 LdrEntry->TlsIndex = -1;
1278
1279 /* Save the cached TLS data */
1280 TlsData->TlsDirectory = *TlsDirectory;
1281 InsertTailList(&LdrpTlsList, &TlsData->TlsLinks);
1282
1283 /* Update the index */
1284 *(PLONG)TlsData->TlsDirectory.AddressOfIndex = LdrpNumberOfTlsEntries;
1285 TlsData->TlsDirectory.Characteristics = LdrpNumberOfTlsEntries++;
1286 }
1287
1288 /* Done setting up TLS, allocate entries */
1289 return LdrpAllocateTls();
1290 }
1291
1292 NTSTATUS
1293 NTAPI
1294 LdrpAllocateTls(VOID)
1295 {
1296 PTEB Teb = NtCurrentTeb();
1297 PLIST_ENTRY NextEntry, ListHead;
1298 PLDRP_TLS_DATA TlsData;
1299 SIZE_T TlsDataSize;
1300 PVOID *TlsVector;
1301
1302 /* Check if we have any entries */
1303 if (!LdrpNumberOfTlsEntries)
1304 return STATUS_SUCCESS;
1305
1306 /* Allocate the vector array */
1307 TlsVector = RtlAllocateHeap(RtlGetProcessHeap(),
1308 0,
1309 LdrpNumberOfTlsEntries * sizeof(PVOID));
1310 if (!TlsVector) return STATUS_NO_MEMORY;
1311 Teb->ThreadLocalStoragePointer = TlsVector;
1312
1313 /* Loop the TLS Array */
1314 ListHead = &LdrpTlsList;
1315 NextEntry = ListHead->Flink;
1316 while (NextEntry != ListHead)
1317 {
1318 /* Get the entry */
1319 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1320 NextEntry = NextEntry->Flink;
1321
1322 /* Allocate this vector */
1323 TlsDataSize = TlsData->TlsDirectory.EndAddressOfRawData -
1324 TlsData->TlsDirectory.StartAddressOfRawData;
1325 TlsVector[TlsData->TlsDirectory.Characteristics] = RtlAllocateHeap(RtlGetProcessHeap(),
1326 0,
1327 TlsDataSize);
1328 if (!TlsVector[TlsData->TlsDirectory.Characteristics])
1329 {
1330 /* Out of memory */
1331 return STATUS_NO_MEMORY;
1332 }
1333
1334 /* Show debug message */
1335 if (ShowSnaps)
1336 {
1337 DPRINT1("LDR: TlsVector %p Index %lu = %p copied from %x to %p\n",
1338 TlsVector,
1339 TlsData->TlsDirectory.Characteristics,
1340 &TlsVector[TlsData->TlsDirectory.Characteristics],
1341 TlsData->TlsDirectory.StartAddressOfRawData,
1342 TlsVector[TlsData->TlsDirectory.Characteristics]);
1343 }
1344
1345 /* Copy the data */
1346 RtlCopyMemory(TlsVector[TlsData->TlsDirectory.Characteristics],
1347 (PVOID)TlsData->TlsDirectory.StartAddressOfRawData,
1348 TlsDataSize);
1349 }
1350
1351 /* Done */
1352 return STATUS_SUCCESS;
1353 }
1354
1355 VOID
1356 NTAPI
1357 LdrpFreeTls(VOID)
1358 {
1359 PLIST_ENTRY ListHead, NextEntry;
1360 PLDRP_TLS_DATA TlsData;
1361 PVOID *TlsVector;
1362 PTEB Teb = NtCurrentTeb();
1363
1364 /* Get a pointer to the vector array */
1365 TlsVector = Teb->ThreadLocalStoragePointer;
1366 if (!TlsVector) return;
1367
1368 /* Loop through it */
1369 ListHead = &LdrpTlsList;
1370 NextEntry = ListHead->Flink;
1371 while (NextEntry != ListHead)
1372 {
1373 TlsData = CONTAINING_RECORD(NextEntry, LDRP_TLS_DATA, TlsLinks);
1374 NextEntry = NextEntry->Flink;
1375
1376 /* Free each entry */
1377 if (TlsVector[TlsData->TlsDirectory.Characteristics])
1378 {
1379 RtlFreeHeap(RtlGetProcessHeap(),
1380 0,
1381 TlsVector[TlsData->TlsDirectory.Characteristics]);
1382 }
1383 }
1384
1385 /* Free the array itself */
1386 RtlFreeHeap(RtlGetProcessHeap(),
1387 0,
1388 TlsVector);
1389 }
1390
1391 NTSTATUS
1392 NTAPI
1393 LdrpInitializeExecutionOptions(PUNICODE_STRING ImagePathName, PPEB Peb, PHANDLE OptionsKey)
1394 {
1395 NTSTATUS Status;
1396 HANDLE KeyHandle;
1397 ULONG ExecuteOptions, MinimumStackCommit = 0, GlobalFlag;
1398
1399 /* Return error if we were not provided a pointer where to save the options key handle */
1400 if (!OptionsKey) return STATUS_INVALID_HANDLE;
1401
1402 /* Zero initialize the options key pointer */
1403 *OptionsKey = NULL;
1404
1405 /* Open the options key */
1406 Status = LdrOpenImageFileOptionsKey(ImagePathName, 0, &KeyHandle);
1407
1408 /* Save it if it was opened successfully */
1409 if (NT_SUCCESS(Status))
1410 *OptionsKey = KeyHandle;
1411
1412 if (KeyHandle)
1413 {
1414 /* There are image specific options, read them starting with NXCOMPAT */
1415 Status = LdrQueryImageFileKeyOption(KeyHandle,
1416 L"ExecuteOptions",
1417 4,
1418 &ExecuteOptions,
1419 sizeof(ExecuteOptions),
1420 0);
1421
1422 if (NT_SUCCESS(Status))
1423 {
1424 /* TODO: Set execution options for the process */
1425 /*
1426 if (ExecuteOptions == 0)
1427 ExecuteOptions = 1;
1428 else
1429 ExecuteOptions = 2;
1430 ZwSetInformationProcess(NtCurrentProcess(),
1431 ProcessExecuteFlags,
1432 &ExecuteOptions,
1433 sizeof(ULONG));*/
1434
1435 }
1436
1437 /* Check if this image uses large pages */
1438 if (Peb->ImageUsesLargePages)
1439 {
1440 /* TODO: If it does, open large page key */
1441 UNIMPLEMENTED;
1442 }
1443
1444 /* Get various option values */
1445 LdrQueryImageFileKeyOption(KeyHandle,
1446 L"DisableHeapLookaside",
1447 REG_DWORD,
1448 &RtlpDisableHeapLookaside,
1449 sizeof(RtlpDisableHeapLookaside),
1450 NULL);
1451
1452 LdrQueryImageFileKeyOption(KeyHandle,
1453 L"ShutdownFlags",
1454 REG_DWORD,
1455 &RtlpShutdownProcessFlags,
1456 sizeof(RtlpShutdownProcessFlags),
1457 NULL);
1458
1459 LdrQueryImageFileKeyOption(KeyHandle,
1460 L"MinimumStackCommitInBytes",
1461 REG_DWORD,
1462 &MinimumStackCommit,
1463 sizeof(MinimumStackCommit),
1464 NULL);
1465
1466 /* Update PEB's minimum stack commit if it's lower */
1467 if (Peb->MinimumStackCommit < MinimumStackCommit)
1468 Peb->MinimumStackCommit = MinimumStackCommit;
1469
1470 /* Set the global flag */
1471 Status = LdrQueryImageFileKeyOption(KeyHandle,
1472 L"GlobalFlag",
1473 REG_DWORD,
1474 &GlobalFlag,
1475 sizeof(GlobalFlag),
1476 NULL);
1477
1478 if (NT_SUCCESS(Status))
1479 Peb->NtGlobalFlag = GlobalFlag;
1480 else
1481 GlobalFlag = 0;
1482
1483 /* Call AVRF if necessary */
1484 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1485 {
1486 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1487 if (!NT_SUCCESS(Status))
1488 {
1489 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1490 }
1491 }
1492 }
1493 else
1494 {
1495 /* There are no image-specific options, so perform global initialization */
1496 if (Peb->NtGlobalFlag & (FLG_APPLICATION_VERIFIER | FLG_HEAP_PAGE_ALLOCS))
1497 {
1498 /* Initialize app verifier package */
1499 Status = LdrpInitializeApplicationVerifierPackage(KeyHandle, Peb, TRUE, FALSE);
1500 if (!NT_SUCCESS(Status))
1501 {
1502 DPRINT1("AVRF: LdrpInitializeApplicationVerifierPackage failed with %08X\n", Status);
1503 }
1504 }
1505 }
1506
1507 return STATUS_SUCCESS;
1508 }
1509
1510 VOID
1511 NTAPI
1512 LdrpValidateImageForMp(IN PLDR_DATA_TABLE_ENTRY LdrDataTableEntry)
1513 {
1514 UNIMPLEMENTED;
1515 }
1516
1517 VOID
1518 NTAPI
1519 LdrpInitializeProcessCompat(PVOID* pOldShimData)
1520 {
1521 static const GUID* GuidOrder[] = { &COMPAT_GUID_WIN10, &COMPAT_GUID_WIN81, &COMPAT_GUID_WIN8,
1522 &COMPAT_GUID_WIN7, &COMPAT_GUID_VISTA };
1523 static const DWORD GuidVersions[] = { WINVER_WIN10, WINVER_WIN81, WINVER_WIN8, WINVER_WIN7, WINVER_VISTA };
1524
1525 ULONG Buffer[(sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 10 + sizeof(ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION)) / sizeof(ULONG)];
1526 ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION* ContextCompatInfo;
1527 SIZE_T SizeRequired;
1528 NTSTATUS Status;
1529 DWORD n, cur;
1530 ReactOS_ShimData* pShimData = *pOldShimData;
1531
1532 C_ASSERT(RTL_NUMBER_OF(GuidOrder) == RTL_NUMBER_OF(GuidVersions));
1533
1534 if (pShimData)
1535 {
1536 if (pShimData->dwMagic != REACTOS_SHIMDATA_MAGIC ||
1537 pShimData->dwSize != sizeof(ReactOS_ShimData))
1538 {
1539 DPRINT1("LdrpInitializeProcessCompat: Corrupt pShimData (0x%x, %u)\n", pShimData->dwMagic, pShimData->dwSize);
1540 return;
1541 }
1542 if (pShimData->dwRosProcessCompatVersion)
1543 {
1544 DPRINT1("LdrpInitializeProcessCompat: ProcessCompatVersion already set to 0x%x\n", pShimData->dwRosProcessCompatVersion);
1545 return;
1546 }
1547 }
1548
1549 SizeRequired = sizeof(Buffer);
1550 Status = RtlQueryInformationActivationContext(RTL_QUERY_ACTIVATION_CONTEXT_FLAG_NO_ADDREF,
1551 NULL,
1552 NULL,
1553 CompatibilityInformationInActivationContext,
1554 Buffer,
1555 sizeof(Buffer),
1556 &SizeRequired);
1557
1558 if (!NT_SUCCESS(Status))
1559 {
1560 DPRINT1("LdrpInitializeProcessCompat: Unable to query process actctx with status %x\n", Status);
1561 return;
1562 }
1563
1564 ContextCompatInfo = (ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*)Buffer;
1565 /* No Compatibility elements present, bail out */
1566 if (ContextCompatInfo->ElementCount == 0)
1567 return;
1568
1569 /* Search for known GUID's, starting from newest to oldest. */
1570 for (cur = 0; cur < RTL_NUMBER_OF(GuidOrder); ++cur)
1571 {
1572 for (n = 0; n < ContextCompatInfo->ElementCount; ++n)
1573 {
1574 if (ContextCompatInfo->Elements[n].Type == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS &&
1575 RtlCompareMemory(&ContextCompatInfo->Elements[n].Id, GuidOrder[cur], sizeof(GUID)) == sizeof(GUID))
1576 {
1577 /* If this process did not need shim data before, allocate and store it */
1578 if (pShimData == NULL)
1579 {
1580 PPEB Peb = NtCurrentPeb();
1581
1582 ASSERT(Peb->pShimData == NULL);
1583 pShimData = RtlAllocateHeap(Peb->ProcessHeap, HEAP_ZERO_MEMORY, sizeof(*pShimData));
1584
1585 if (!pShimData)
1586 {
1587 DPRINT1("LdrpInitializeProcessCompat: Unable to allocated %u bytes\n", sizeof(*pShimData));
1588 return;
1589 }
1590
1591 pShimData->dwSize = sizeof(*pShimData);
1592 pShimData->dwMagic = REACTOS_SHIMDATA_MAGIC;
1593
1594 Peb->pShimData = pShimData;
1595 *pOldShimData = pShimData;
1596 }
1597
1598 /* Store the highest found version, and bail out. */
1599 pShimData->dwRosProcessCompatVersion = GuidVersions[cur];
1600 DPRINT1("LdrpInitializeProcessCompat: Found guid for winver 0x%x\n", GuidVersions[cur]);
1601 return;
1602 }
1603 }
1604 }
1605 }
1606
1607
1608 NTSTATUS
1609 NTAPI
1610 LdrpInitializeProcess(IN PCONTEXT Context,
1611 IN PVOID SystemArgument1)
1612 {
1613 RTL_HEAP_PARAMETERS HeapParameters;
1614 ULONG ComSectionSize;
1615 ANSI_STRING BaseProcessInitPostImportName = RTL_CONSTANT_STRING("BaseProcessInitPostImport");
1616 ANSI_STRING BaseQueryModuleDataName = RTL_CONSTANT_STRING("BaseQueryModuleData");
1617 PVOID OldShimData;
1618 OBJECT_ATTRIBUTES ObjectAttributes;
1619 //UNICODE_STRING LocalFileName, FullImageName;
1620 HANDLE SymLinkHandle;
1621 //ULONG DebugHeapOnly;
1622 UNICODE_STRING CommandLine, NtSystemRoot, ImagePathName, FullPath, ImageFileName, KnownDllString;
1623 PPEB Peb = NtCurrentPeb();
1624 BOOLEAN IsDotNetImage = FALSE;
1625 BOOLEAN FreeCurDir = FALSE;
1626 //HANDLE CompatKey;
1627 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
1628 //LPWSTR ImagePathBuffer;
1629 ULONG ConfigSize;
1630 UNICODE_STRING CurrentDirectory;
1631 HANDLE OptionsKey;
1632 ULONG HeapFlags;
1633 PIMAGE_NT_HEADERS NtHeader;
1634 LPWSTR NtDllName = NULL;
1635 NTSTATUS Status, ImportStatus;
1636 NLSTABLEINFO NlsTable;
1637 PIMAGE_LOAD_CONFIG_DIRECTORY LoadConfig;
1638 PTEB Teb = NtCurrentTeb();
1639 PLIST_ENTRY ListHead;
1640 PLIST_ENTRY NextEntry;
1641 ULONG i;
1642 PWSTR ImagePath;
1643 ULONG DebugProcessHeapOnly = 0;
1644 PLDR_DATA_TABLE_ENTRY NtLdrEntry;
1645 PWCHAR Current;
1646 ULONG ExecuteOptions = 0;
1647 PVOID ViewBase;
1648
1649 /* Set a NULL SEH Filter */
1650 RtlSetUnhandledExceptionFilter(NULL);
1651
1652 /* Get the image path */
1653 ImagePath = Peb->ProcessParameters->ImagePathName.Buffer;
1654
1655 /* Check if it's not normalized */
1656 if (!(Peb->ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_NORMALIZED))
1657 {
1658 /* Normalize it*/
1659 ImagePath = (PWSTR)((ULONG_PTR)ImagePath + (ULONG_PTR)Peb->ProcessParameters);
1660 }
1661
1662 /* Create a unicode string for the Image Path */
1663 ImagePathName.Length = Peb->ProcessParameters->ImagePathName.Length;
1664 ImagePathName.MaximumLength = ImagePathName.Length + sizeof(WCHAR);
1665 ImagePathName.Buffer = ImagePath;
1666
1667 /* Get the NT Headers */
1668 NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
1669
1670 /* Get the execution options */
1671 Status = LdrpInitializeExecutionOptions(&ImagePathName, Peb, &OptionsKey);
1672
1673 /* Check if this is a .NET executable */
1674 if (RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1675 TRUE,
1676 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
1677 &ComSectionSize))
1678 {
1679 /* Remember this for later */
1680 IsDotNetImage = TRUE;
1681 }
1682
1683 /* Save the NTDLL Base address */
1684 NtDllBase = SystemArgument1;
1685
1686 /* If this is a Native Image */
1687 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE)
1688 {
1689 /* Then do DLL Validation */
1690 LdrpDllValidation = TRUE;
1691 }
1692
1693 /* Save the old Shim Data */
1694 OldShimData = Peb->pShimData;
1695
1696 /* ReactOS specific: do not clear it. (Windows starts doing the same in later versions) */
1697 //Peb->pShimData = NULL;
1698
1699 /* Save the number of processors and CS Timeout */
1700 LdrpNumberOfProcessors = Peb->NumberOfProcessors;
1701 RtlpTimeout = Peb->CriticalSectionTimeout;
1702
1703 /* Normalize the parameters */
1704 ProcessParameters = RtlNormalizeProcessParams(Peb->ProcessParameters);
1705 if (ProcessParameters)
1706 {
1707 /* Save the Image and Command Line Names */
1708 ImageFileName = ProcessParameters->ImagePathName;
1709 CommandLine = ProcessParameters->CommandLine;
1710 }
1711 else
1712 {
1713 /* It failed, initialize empty strings */
1714 RtlInitUnicodeString(&ImageFileName, NULL);
1715 RtlInitUnicodeString(&CommandLine, NULL);
1716 }
1717
1718 /* Initialize NLS data */
1719 RtlInitNlsTables(Peb->AnsiCodePageData,
1720 Peb->OemCodePageData,
1721 Peb->UnicodeCaseTableData,
1722 &NlsTable);
1723
1724 /* Reset NLS Translations */
1725 RtlResetRtlTranslations(&NlsTable);
1726
1727 /* Get the Image Config Directory */
1728 LoadConfig = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress,
1729 TRUE,
1730 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
1731 &ConfigSize);
1732
1733 /* Setup the Heap Parameters */
1734 RtlZeroMemory(&HeapParameters, sizeof(RTL_HEAP_PARAMETERS));
1735 HeapFlags = HEAP_GROWABLE;
1736 HeapParameters.Length = sizeof(RTL_HEAP_PARAMETERS);
1737
1738 /* Check if we have Configuration Data */
1739 if ((LoadConfig) && (ConfigSize == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)))
1740 {
1741 /* FIXME: Custom heap settings and misc. */
1742 DPRINT1("We don't support LOAD_CONFIG data yet\n");
1743 }
1744
1745 /* Check for custom affinity mask */
1746 if (Peb->ImageProcessAffinityMask)
1747 {
1748 /* Set it */
1749 Status = NtSetInformationProcess(NtCurrentProcess(),
1750 ProcessAffinityMask,
1751 &Peb->ImageProcessAffinityMask,
1752 sizeof(Peb->ImageProcessAffinityMask));
1753 }
1754
1755 /* Check if verbose debugging (ShowSnaps) was requested */
1756 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
1757
1758 /* Start verbose debugging messages right now if they were requested */
1759 if (ShowSnaps)
1760 {
1761 DPRINT1("LDR: PID: 0x%p started - '%wZ'\n",
1762 Teb->ClientId.UniqueProcess,
1763 &CommandLine);
1764 }
1765
1766 /* If the timeout is too long */
1767 if (RtlpTimeout.QuadPart < Int32x32To64(3600, -10000000))
1768 {
1769 /* Then disable CS Timeout */
1770 RtlpTimeoutDisable = TRUE;
1771 }
1772
1773 /* Initialize Critical Section Data */
1774 RtlpInitDeferedCriticalSection();
1775
1776 /* Initialize VEH Call lists */
1777 RtlpInitializeVectoredExceptionHandling();
1778
1779 /* Set TLS/FLS Bitmap data */
1780 Peb->FlsBitmap = &FlsBitMap;
1781 Peb->TlsBitmap = &TlsBitMap;
1782 Peb->TlsExpansionBitmap = &TlsExpansionBitMap;
1783
1784 /* Initialize FLS Bitmap */
1785 RtlInitializeBitMap(&FlsBitMap,
1786 Peb->FlsBitmapBits,
1787 FLS_MAXIMUM_AVAILABLE);
1788 RtlSetBit(&FlsBitMap, 0);
1789
1790 /* Initialize TLS Bitmap */
1791 RtlInitializeBitMap(&TlsBitMap,
1792 Peb->TlsBitmapBits,
1793 TLS_MINIMUM_AVAILABLE);
1794 RtlSetBit(&TlsBitMap, 0);
1795 RtlInitializeBitMap(&TlsExpansionBitMap,
1796 Peb->TlsExpansionBitmapBits,
1797 TLS_EXPANSION_SLOTS);
1798 RtlSetBit(&TlsExpansionBitMap, 0);
1799
1800 /* Initialize the Hash Table */
1801 for (i = 0; i < LDR_HASH_TABLE_ENTRIES; i++)
1802 {
1803 InitializeListHead(&LdrpHashTable[i]);
1804 }
1805
1806 /* Initialize the Loader Lock */
1807 // FIXME: What's the point of initing it manually, if two lines lower
1808 // a call to RtlInitializeCriticalSection() is being made anyway?
1809 //InsertTailList(&RtlCriticalSectionList, &LdrpLoaderLock.DebugInfo->ProcessLocksList);
1810 //LdrpLoaderLock.DebugInfo->CriticalSection = &LdrpLoaderLock;
1811 RtlInitializeCriticalSection(&LdrpLoaderLock);
1812 LdrpLoaderLockInit = TRUE;
1813
1814 /* Check if User Stack Trace Database support was requested */
1815 if (Peb->NtGlobalFlag & FLG_USER_STACK_TRACE_DB)
1816 {
1817 DPRINT1("We don't support user stack trace databases yet\n");
1818 }
1819
1820 /* Setup Fast PEB Lock */
1821 RtlInitializeCriticalSection(&FastPebLock);
1822 Peb->FastPebLock = &FastPebLock;
1823 //Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
1824 //Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
1825
1826 /* Setup Callout Lock and Notification list */
1827 //RtlInitializeCriticalSection(&RtlpCalloutEntryLock);
1828 InitializeListHead(&LdrpDllNotificationList);
1829
1830 /* For old executables, use 16-byte aligned heap */
1831 if ((NtHeader->OptionalHeader.MajorSubsystemVersion <= 3) &&
1832 (NtHeader->OptionalHeader.MinorSubsystemVersion < 51))
1833 {
1834 HeapFlags |= HEAP_CREATE_ALIGN_16;
1835 }
1836
1837 /* Setup the Heap */
1838 RtlInitializeHeapManager();
1839 Peb->ProcessHeap = RtlCreateHeap(HeapFlags,
1840 NULL,
1841 NtHeader->OptionalHeader.SizeOfHeapReserve,
1842 NtHeader->OptionalHeader.SizeOfHeapCommit,
1843 NULL,
1844 &HeapParameters);
1845
1846 if (!Peb->ProcessHeap)
1847 {
1848 DPRINT1("Failed to create process heap\n");
1849 return STATUS_NO_MEMORY;
1850 }
1851
1852 /* Allocate an Activation Context Stack */
1853 Status = RtlAllocateActivationContextStack(&Teb->ActivationContextStackPointer);
1854 if (!NT_SUCCESS(Status)) return Status;
1855
1856 // FIXME: Loader private heap is missing
1857 //DPRINT1("Loader private heap is missing\n");
1858
1859 /* Check for Debug Heap */
1860 if (OptionsKey)
1861 {
1862 /* Query the setting */
1863 Status = LdrQueryImageFileKeyOption(OptionsKey,
1864 L"DebugProcessHeapOnly",
1865 REG_DWORD,
1866 &DebugProcessHeapOnly,
1867 sizeof(ULONG),
1868 NULL);
1869
1870 if (NT_SUCCESS(Status))
1871 {
1872 /* Reset DPH if requested */
1873 if (RtlpPageHeapEnabled && DebugProcessHeapOnly)
1874 {
1875 RtlpDphGlobalFlags &= ~DPH_FLAG_DLL_NOTIFY;
1876 RtlpPageHeapEnabled = FALSE;
1877 }
1878 }
1879 }
1880
1881 /* Build the NTDLL Path */
1882 FullPath.Buffer = StringBuffer;
1883 FullPath.Length = 0;
1884 FullPath.MaximumLength = sizeof(StringBuffer);
1885 RtlInitUnicodeString(&NtSystemRoot, SharedUserData->NtSystemRoot);
1886 RtlAppendUnicodeStringToString(&FullPath, &NtSystemRoot);
1887 RtlAppendUnicodeToString(&FullPath, L"\\System32\\");
1888
1889 /* Open the Known DLLs directory */
1890 RtlInitUnicodeString(&KnownDllString, L"\\KnownDlls");
1891 InitializeObjectAttributes(&ObjectAttributes,
1892 &KnownDllString,
1893 OBJ_CASE_INSENSITIVE,
1894 NULL,
1895 NULL);
1896 Status = ZwOpenDirectoryObject(&LdrpKnownDllObjectDirectory,
1897 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1898 &ObjectAttributes);
1899
1900 /* Check if it exists */
1901 if (NT_SUCCESS(Status))
1902 {
1903 /* Open the Known DLLs Path */
1904 RtlInitUnicodeString(&KnownDllString, L"KnownDllPath");
1905 InitializeObjectAttributes(&ObjectAttributes,
1906 &KnownDllString,
1907 OBJ_CASE_INSENSITIVE,
1908 LdrpKnownDllObjectDirectory,
1909 NULL);
1910 Status = NtOpenSymbolicLinkObject(&SymLinkHandle,
1911 SYMBOLIC_LINK_QUERY,
1912 &ObjectAttributes);
1913 if (NT_SUCCESS(Status))
1914 {
1915 /* Query the path */
1916 LdrpKnownDllPath.Length = 0;
1917 LdrpKnownDllPath.MaximumLength = sizeof(LdrpKnownDllPathBuffer);
1918 LdrpKnownDllPath.Buffer = LdrpKnownDllPathBuffer;
1919 Status = ZwQuerySymbolicLinkObject(SymLinkHandle, &LdrpKnownDllPath, NULL);
1920 NtClose(SymLinkHandle);
1921 if (!NT_SUCCESS(Status))
1922 {
1923 DPRINT1("LDR: %s - failed call to ZwQuerySymbolicLinkObject with status %x\n", "", Status);
1924 return Status;
1925 }
1926 }
1927 }
1928
1929 /* Check if we failed */
1930 if (!NT_SUCCESS(Status))
1931 {
1932 /* Assume System32 */
1933 LdrpKnownDllObjectDirectory = NULL;
1934 RtlInitUnicodeString(&LdrpKnownDllPath, StringBuffer);
1935 LdrpKnownDllPath.Length -= sizeof(WCHAR);
1936 }
1937
1938 /* If we have process parameters, get the default path and current path */
1939 if (ProcessParameters)
1940 {
1941 /* Check if we have a Dll Path */
1942 if (ProcessParameters->DllPath.Length)
1943 {
1944 /* Get the path */
1945 LdrpDefaultPath = *(PUNICODE_STRING)&ProcessParameters->DllPath;
1946 }
1947 else
1948 {
1949 /* We need a valid path */
1950 DPRINT1("No valid DllPath was given!\n");
1951 LdrpInitFailure(STATUS_INVALID_PARAMETER);
1952 }
1953
1954 /* Set the current directory */
1955 CurrentDirectory = ProcessParameters->CurrentDirectory.DosPath;
1956
1957 /* Check if it's empty or invalid */
1958 if ((!CurrentDirectory.Buffer) ||
1959 (CurrentDirectory.Buffer[0] == UNICODE_NULL) ||
1960 (!CurrentDirectory.Length))
1961 {
1962 /* Allocate space for the buffer */
1963 CurrentDirectory.Buffer = RtlAllocateHeap(Peb->ProcessHeap,
1964 0,
1965 3 * sizeof(WCHAR) +
1966 sizeof(UNICODE_NULL));
1967 if (!CurrentDirectory.Buffer)
1968 {
1969 DPRINT1("LDR: LdrpInitializeProcess - unable to allocate current working directory buffer\n");
1970 // FIXME: And what?
1971 }
1972
1973 /* Copy the drive of the system root */
1974 RtlMoveMemory(CurrentDirectory.Buffer,
1975 SharedUserData->NtSystemRoot,
1976 3 * sizeof(WCHAR));
1977 CurrentDirectory.Buffer[3] = UNICODE_NULL;
1978 CurrentDirectory.Length = 3 * sizeof(WCHAR);
1979 CurrentDirectory.MaximumLength = CurrentDirectory.Length + sizeof(WCHAR);
1980
1981 FreeCurDir = TRUE;
1982 DPRINT("Using dynamically allocd curdir\n");
1983 }
1984 else
1985 {
1986 /* Use the local buffer */
1987 DPRINT("Using local system root\n");
1988 }
1989 }
1990
1991 /* Setup Loader Data */
1992 Peb->Ldr = &PebLdr;
1993 InitializeListHead(&PebLdr.InLoadOrderModuleList);
1994 InitializeListHead(&PebLdr.InMemoryOrderModuleList);
1995 InitializeListHead(&PebLdr.InInitializationOrderModuleList);
1996 PebLdr.Length = sizeof(PEB_LDR_DATA);
1997 PebLdr.Initialized = TRUE;
1998
1999 /* Allocate a data entry for the Image */
2000 LdrpImageEntry = LdrpAllocateDataTableEntry(Peb->ImageBaseAddress);
2001
2002 /* Set it up */
2003 LdrpImageEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(LdrpImageEntry->DllBase);
2004 LdrpImageEntry->LoadCount = -1;
2005 LdrpImageEntry->EntryPointActivationContext = 0;
2006 LdrpImageEntry->FullDllName = ImageFileName;
2007
2008 if (IsDotNetImage)
2009 LdrpImageEntry->Flags = LDRP_COR_IMAGE;
2010 else
2011 LdrpImageEntry->Flags = 0;
2012
2013 /* Check if the name is empty */
2014 if (!ImageFileName.Buffer[0])
2015 {
2016 /* Use the same Base name */
2017 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2018 }
2019 else
2020 {
2021 /* Find the last slash */
2022 Current = ImageFileName.Buffer;
2023 while (*Current)
2024 {
2025 if (*Current++ == '\\')
2026 {
2027 /* Set this path */
2028 NtDllName = Current;
2029 }
2030 }
2031
2032 /* Did we find anything? */
2033 if (!NtDllName)
2034 {
2035 /* Use the same Base name */
2036 LdrpImageEntry->BaseDllName = LdrpImageEntry->FullDllName;
2037 }
2038 else
2039 {
2040 /* Setup the name */
2041 LdrpImageEntry->BaseDllName.Length = (USHORT)((ULONG_PTR)ImageFileName.Buffer + ImageFileName.Length - (ULONG_PTR)NtDllName);
2042 LdrpImageEntry->BaseDllName.MaximumLength = LdrpImageEntry->BaseDllName.Length + sizeof(WCHAR);
2043 LdrpImageEntry->BaseDllName.Buffer = (PWSTR)((ULONG_PTR)ImageFileName.Buffer +
2044 (ImageFileName.Length - LdrpImageEntry->BaseDllName.Length));
2045 }
2046 }
2047
2048 /* Processing done, insert it */
2049 LdrpInsertMemoryTableEntry(LdrpImageEntry);
2050 LdrpImageEntry->Flags |= LDRP_ENTRY_PROCESSED;
2051
2052 /* Now add an entry for NTDLL */
2053 NtLdrEntry = LdrpAllocateDataTableEntry(SystemArgument1);
2054 NtLdrEntry->Flags = LDRP_IMAGE_DLL;
2055 NtLdrEntry->EntryPoint = LdrpFetchAddressOfEntryPoint(NtLdrEntry->DllBase);
2056 NtLdrEntry->LoadCount = -1;
2057 NtLdrEntry->EntryPointActivationContext = 0;
2058
2059 NtLdrEntry->FullDllName.Length = FullPath.Length;
2060 NtLdrEntry->FullDllName.MaximumLength = FullPath.MaximumLength;
2061 NtLdrEntry->FullDllName.Buffer = StringBuffer;
2062 RtlAppendUnicodeStringToString(&NtLdrEntry->FullDllName, &NtDllString);
2063
2064 NtLdrEntry->BaseDllName.Length = NtDllString.Length;
2065 NtLdrEntry->BaseDllName.MaximumLength = NtDllString.MaximumLength;
2066 NtLdrEntry->BaseDllName.Buffer = NtDllString.Buffer;
2067
2068 /* Processing done, insert it */
2069 LdrpNtDllDataTableEntry = NtLdrEntry;
2070 LdrpInsertMemoryTableEntry(NtLdrEntry);
2071
2072 /* Let the world know */
2073 if (ShowSnaps)
2074 {
2075 DPRINT1("LDR: NEW PROCESS\n");
2076 DPRINT1(" Image Path: %wZ (%wZ)\n", &LdrpImageEntry->FullDllName, &LdrpImageEntry->BaseDllName);
2077 DPRINT1(" Current Directory: %wZ\n", &CurrentDirectory);
2078 DPRINT1(" Search Path: %wZ\n", &LdrpDefaultPath);
2079 }
2080
2081 /* Link the Init Order List */
2082 InsertHeadList(&Peb->Ldr->InInitializationOrderModuleList,
2083 &LdrpNtDllDataTableEntry->InInitializationOrderLinks);
2084
2085 /* Initialize Wine's active context implementation for the current process */
2086 actctx_init();
2087
2088 /* ReactOS specific */
2089 LdrpInitializeProcessCompat(&OldShimData);
2090
2091 /* Set the current directory */
2092 Status = RtlSetCurrentDirectory_U(&CurrentDirectory);
2093 if (!NT_SUCCESS(Status))
2094 {
2095 /* We failed, check if we should free it */
2096 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2097
2098 /* Set it to the NT Root */
2099 CurrentDirectory = NtSystemRoot;
2100 RtlSetCurrentDirectory_U(&CurrentDirectory);
2101 }
2102 else
2103 {
2104 /* We're done with it, free it */
2105 if (FreeCurDir) RtlFreeUnicodeString(&CurrentDirectory);
2106 }
2107
2108 /* Check if we should look for a .local file */
2109 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_LOCAL_DLL_PATH)
2110 {
2111 /* FIXME */
2112 DPRINT1("We don't support .local overrides yet\n");
2113 }
2114
2115 /* Check if the Application Verifier was enabled */
2116 if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
2117 {
2118 Status = AVrfInitializeVerifier();
2119 if (!NT_SUCCESS(Status))
2120 {
2121 DPRINT1("LDR: AVrfInitializeVerifier failed (ntstatus 0x%x)\n", Status);
2122 return Status;
2123 }
2124
2125 }
2126
2127 if (IsDotNetImage)
2128 {
2129 /* FIXME */
2130 DPRINT1("We don't support .NET applications yet\n");
2131 }
2132
2133 if (NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
2134 NtHeader->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2135 {
2136 PVOID Kernel32BaseAddress;
2137 PVOID FunctionAddress;
2138
2139 Status = LdrLoadDll(NULL, NULL, &Kernel32String, &Kernel32BaseAddress);
2140
2141 if (!NT_SUCCESS(Status))
2142 {
2143 if (ShowSnaps)
2144 DPRINT1("LDR: Unable to load %wZ, Status=0x%08lx\n", &Kernel32String, Status);
2145 return Status;
2146 }
2147
2148 Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2149 &BaseProcessInitPostImportName,
2150 0,
2151 &FunctionAddress);
2152
2153 if (!NT_SUCCESS(Status))
2154 {
2155 if (ShowSnaps)
2156 DPRINT1("LDR: Unable to find post-import process init function, Status=0x%08lx\n", &Kernel32String, Status);
2157 return Status;
2158 }
2159 Kernel32ProcessInitPostImportFunction = FunctionAddress;
2160
2161 Status = LdrGetProcedureAddress(Kernel32BaseAddress,
2162 &BaseQueryModuleDataName,
2163 0,
2164 &FunctionAddress);
2165
2166 if (!NT_SUCCESS(Status))
2167 {
2168 if (ShowSnaps)
2169 DPRINT1("LDR: Unable to find BaseQueryModuleData, Status=0x%08lx\n", &Kernel32String, Status);
2170 return Status;
2171 }
2172 Kernel32BaseQueryModuleData = FunctionAddress;
2173 }
2174
2175 /* Walk the IAT and load all the DLLs */
2176 ImportStatus = LdrpWalkImportDescriptor(LdrpDefaultPath.Buffer, LdrpImageEntry);
2177
2178 /* Check if relocation is needed */
2179 if (Peb->ImageBaseAddress != (PVOID)NtHeader->OptionalHeader.ImageBase)
2180 {
2181 DPRINT1("LDR: Performing EXE relocation\n");
2182
2183 /* Change the protection to prepare for relocation */
2184 ViewBase = Peb->ImageBaseAddress;
2185 Status = LdrpSetProtection(ViewBase, FALSE);
2186 if (!NT_SUCCESS(Status)) return Status;
2187
2188 /* Do the relocation */
2189 Status = LdrRelocateImageWithBias(ViewBase,
2190 0LL,
2191 NULL,
2192 STATUS_SUCCESS,
2193 STATUS_CONFLICTING_ADDRESSES,
2194 STATUS_INVALID_IMAGE_FORMAT);
2195 if (!NT_SUCCESS(Status))
2196 {
2197 DPRINT1("LdrRelocateImageWithBias() failed\n");
2198 return Status;
2199 }
2200
2201 /* Check if a start context was provided */
2202 if (Context)
2203 {
2204 DPRINT1("WARNING: Relocated EXE Context");
2205 UNIMPLEMENTED; // We should support this
2206 return STATUS_INVALID_IMAGE_FORMAT;
2207 }
2208
2209 /* Restore the protection */
2210 Status = LdrpSetProtection(ViewBase, TRUE);
2211 if (!NT_SUCCESS(Status)) return Status;
2212 }
2213
2214 /* Lock the DLLs */
2215 ListHead = &Peb->Ldr->InLoadOrderModuleList;
2216 NextEntry = ListHead->Flink;
2217 while (ListHead != NextEntry)
2218 {
2219 NtLdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
2220 NtLdrEntry->LoadCount = -1;
2221 NextEntry = NextEntry->Flink;
2222 }
2223
2224 /* Phase 0 is done */
2225 LdrpLdrDatabaseIsSetup = TRUE;
2226
2227 /* Check whether all static imports were properly loaded and return here */
2228 if (!NT_SUCCESS(ImportStatus)) return ImportStatus;
2229
2230 /* Initialize TLS */
2231 Status = LdrpInitializeTls();
2232 if (!NT_SUCCESS(Status))
2233 {
2234 DPRINT1("LDR: LdrpProcessInitialization failed to initialize TLS slots; status %x\n",
2235 Status);
2236 return Status;
2237 }
2238
2239 /* FIXME Mark the DLL Ranges for Stack Traces later */
2240
2241 /* Notify the debugger now */
2242 if (Peb->BeingDebugged)
2243 {
2244 /* Break */
2245 DbgBreakPoint();
2246
2247 /* Update show snaps again */
2248 ShowSnaps = Peb->NtGlobalFlag & FLG_SHOW_LDR_SNAPS;
2249 }
2250
2251 /* Validate the Image for MP Usage */
2252 if (LdrpNumberOfProcessors > 1) LdrpValidateImageForMp(LdrpImageEntry);
2253
2254 /* Check NX Options */
2255 if (SharedUserData->NXSupportPolicy == 1)
2256 {
2257 ExecuteOptions = 0xD;
2258 }
2259 else if (!SharedUserData->NXSupportPolicy)
2260 {
2261 ExecuteOptions = 0xA;
2262 }
2263
2264 /* Let Mm know */
2265 ZwSetInformationProcess(NtCurrentProcess(),
2266 ProcessExecuteFlags,
2267 &ExecuteOptions,
2268 sizeof(ULONG));
2269
2270 // FIXME: Should be done by Application Compatibility features,
2271 // by reading the registry, etc...
2272 // For now, this is the old code from ntdll!RtlGetVersion().
2273 RtlInitEmptyUnicodeString(&Peb->CSDVersion, NULL, 0);
2274 if (((Peb->OSCSDVersion >> 8) & 0xFF) != 0)
2275 {
2276 WCHAR szCSDVersion[128];
2277 LONG i;
2278 ULONG Length = ARRAYSIZE(szCSDVersion) - 1;
2279 i = _snwprintf(szCSDVersion, Length,
2280 L"Service Pack %d",
2281 ((Peb->OSCSDVersion >> 8) & 0xFF));
2282 if (i < 0)
2283 {
2284 /* Null-terminate if it was overflowed */
2285 szCSDVersion[Length] = UNICODE_NULL;
2286 }
2287
2288 Length *= sizeof(WCHAR);
2289 Peb->CSDVersion.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
2290 0,
2291 Length + sizeof(UNICODE_NULL));
2292 if (Peb->CSDVersion.Buffer)
2293 {
2294 Peb->CSDVersion.Length = Length;
2295 Peb->CSDVersion.MaximumLength = Length + sizeof(UNICODE_NULL);
2296
2297 RtlCopyMemory(Peb->CSDVersion.Buffer,
2298 szCSDVersion,
2299 Peb->CSDVersion.MaximumLength);
2300 Peb->CSDVersion.Buffer[Peb->CSDVersion.Length / sizeof(WCHAR)] = UNICODE_NULL;
2301 }
2302 }
2303
2304 /* Check if we had Shim Data */
2305 if (OldShimData)
2306 {
2307 /* Load the Shim Engine */
2308 Peb->AppCompatInfo = NULL;
2309 LdrpLoadShimEngine(OldShimData, &ImagePathName, OldShimData);
2310 }
2311 else
2312 {
2313 /* Check for Application Compatibility Goo */
2314 //LdrQueryApplicationCompatibilityGoo(hKey);
2315 DPRINT("Querying app compat hacks is missing!\n");
2316 }
2317
2318 /*
2319 * FIXME: Check for special images, SecuROM, SafeDisc and other NX-
2320 * incompatible images.
2321 */
2322
2323 /* Now call the Init Routines */
2324 Status = LdrpRunInitializeRoutines(Context);
2325 if (!NT_SUCCESS(Status))
2326 {
2327 DPRINT1("LDR: LdrpProcessInitialization failed running initialization routines; status %x\n",
2328 Status);
2329 return Status;
2330 }
2331
2332 /* Notify Shim Engine */
2333 if (g_ShimsEnabled)
2334 {
2335 VOID(NTAPI *SE_InstallAfterInit)(PUNICODE_STRING, PVOID);
2336 SE_InstallAfterInit = RtlDecodeSystemPointer(g_pfnSE_InstallAfterInit);
2337 SE_InstallAfterInit(&ImagePathName, OldShimData);
2338 }
2339
2340 /* Check if we have a user-defined Post Process Routine */
2341 if (NT_SUCCESS(Status) && Peb->PostProcessInitRoutine)
2342 {
2343 /* Call it */
2344 Peb->PostProcessInitRoutine();
2345 }
2346
2347 /* Close the key if we have one opened */
2348 if (OptionsKey) NtClose(OptionsKey);
2349
2350 /* Return status */
2351 return Status;
2352 }
2353
2354 VOID
2355 NTAPI
2356 LdrpInitFailure(NTSTATUS Status)
2357 {
2358 ULONG Response;
2359 PPEB Peb = NtCurrentPeb();
2360
2361 /* Print a debug message */
2362 DPRINT1("LDR: Process initialization failure for %wZ; NTSTATUS = %08lx\n",
2363 &Peb->ProcessParameters->ImagePathName, Status);
2364
2365 /* Raise a hard error */
2366 if (!LdrpFatalHardErrorCount)
2367 {
2368 ZwRaiseHardError(STATUS_APP_INIT_FAILURE, 1, 0, (PULONG_PTR)&Status, OptionOk, &Response);
2369 }
2370 }
2371
2372 VOID
2373 NTAPI
2374 LdrpInit(PCONTEXT Context,
2375 PVOID SystemArgument1,
2376 PVOID SystemArgument2)
2377 {
2378 LARGE_INTEGER Timeout;
2379 PTEB Teb = NtCurrentTeb();
2380 NTSTATUS Status, LoaderStatus = STATUS_SUCCESS;
2381 MEMORY_BASIC_INFORMATION MemoryBasicInfo;
2382 PPEB Peb = NtCurrentPeb();
2383
2384 DPRINT("LdrpInit() %p/%p\n",
2385 NtCurrentTeb()->RealClientId.UniqueProcess,
2386 NtCurrentTeb()->RealClientId.UniqueThread);
2387
2388 #ifdef _WIN64
2389 /* Set the SList header usage */
2390 RtlpUse16ByteSLists = SharedUserData->ProcessorFeatures[PF_COMPARE_EXCHANGE128];
2391 #endif /* _WIN64 */
2392
2393 /* Check if we have a deallocation stack */
2394 if (!Teb->DeallocationStack)
2395 {
2396 /* We don't, set one */
2397 Status = NtQueryVirtualMemory(NtCurrentProcess(),
2398 Teb->NtTib.StackLimit,
2399 MemoryBasicInformation,
2400 &MemoryBasicInfo,
2401 sizeof(MEMORY_BASIC_INFORMATION),
2402 NULL);
2403 if (!NT_SUCCESS(Status))
2404 {
2405 /* Fail */
2406 LdrpInitFailure(Status);
2407 RtlRaiseStatus(Status);
2408 return;
2409 }
2410
2411 /* Set the stack */
2412 Teb->DeallocationStack = MemoryBasicInfo.AllocationBase;
2413 }
2414
2415 /* Now check if the process is already being initialized */
2416 while (_InterlockedCompareExchange(&LdrpProcessInitialized,
2417 1,
2418 0) == 1)
2419 {
2420 /* Set the timeout to 30 milliseconds */
2421 Timeout.QuadPart = Int32x32To64(30, -10000);
2422
2423 /* Make sure the status hasn't changed */
2424 while (LdrpProcessInitialized == 1)
2425 {
2426 /* Do the wait */
2427 ZwDelayExecution(FALSE, &Timeout);
2428 }
2429 }
2430
2431 /* Check if we have already setup LDR data */
2432 if (!Peb->Ldr)
2433 {
2434 /* Setup the Loader Lock */
2435 Peb->LoaderLock = &LdrpLoaderLock;
2436
2437 /* Let other code know we're initializing */
2438 LdrpInLdrInit = TRUE;
2439
2440 /* Protect with SEH */
2441 _SEH2_TRY
2442 {
2443 /* Initialize the Process */
2444 LoaderStatus = LdrpInitializeProcess(Context,
2445 SystemArgument1);
2446
2447 /* Check for success and if MinimumStackCommit was requested */
2448 if (NT_SUCCESS(LoaderStatus) && Peb->MinimumStackCommit)
2449 {
2450 /* Enforce the limit */
2451 //LdrpTouchThreadStack(Peb->MinimumStackCommit);
2452 UNIMPLEMENTED;
2453 }
2454 }
2455 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2456 {
2457 /* Fail with the SEH error */
2458 LoaderStatus = _SEH2_GetExceptionCode();
2459 }
2460 _SEH2_END;
2461
2462 /* We're not initializing anymore */
2463 LdrpInLdrInit = FALSE;
2464
2465 /* Check if init worked */
2466 if (NT_SUCCESS(LoaderStatus))
2467 {
2468 /* Set the process as Initialized */
2469 _InterlockedIncrement(&LdrpProcessInitialized);
2470 }
2471 }
2472 else
2473 {
2474 /* Loader data is there... is this a fork() ? */
2475 if(Peb->InheritedAddressSpace)
2476 {
2477 /* Handle the fork() */
2478 //LoaderStatus = LdrpForkProcess();
2479 LoaderStatus = STATUS_NOT_IMPLEMENTED;
2480 UNIMPLEMENTED;
2481 }
2482 else
2483 {
2484 /* This is a new thread initializing */
2485 LdrpInitializeThread(Context);
2486 }
2487 }
2488
2489 /* All done, test alert the thread */
2490 NtTestAlert();
2491
2492 /* Return */
2493 if (!NT_SUCCESS(LoaderStatus))
2494 {
2495 /* Fail */
2496 LdrpInitFailure(LoaderStatus);
2497 RtlRaiseStatus(LoaderStatus);
2498 }
2499 }
2500
2501 /* EOF */