Fixed typos
[reactos.git] / reactos / lib / ntdll / ldr / utils.c
1 /* $Id: utils.c,v 1.40 2001/02/10 22:23:30 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/ldr/startup.c
6 * PURPOSE: Process startup for PE executables
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /*
12 * TODO:
13 * - Fix calling of entry points
14 * - Handle loading flags correctly
15 * - any more ??
16 */
17
18 /* INCLUDES *****************************************************************/
19
20 #include <reactos/config.h>
21 #include <ddk/ntddk.h>
22 #include <windows.h>
23 #include <string.h>
24 #include <wchar.h>
25 #include <ntdll/ldr.h>
26 #include <ntos/minmax.h>
27 #include <napi/shared_data.h>
28
29
30 #ifdef DBG_NTDLL_LDR_UTILS
31 #define NDEBUG
32 #endif
33 #include <ntdll/ntdll.h>
34
35 /* PROTOTYPES ****************************************************************/
36
37
38 /* Type for a DLL's entry point */
39 typedef
40 WINBOOL
41 STDCALL
42 (* PDLLMAIN_FUNC) (
43 HANDLE hInst,
44 ULONG ul_reason_for_call,
45 LPVOID lpReserved
46 );
47
48 static NTSTATUS LdrFindDll(PLDR_MODULE *Dll,PUNICODE_STRING Name);
49 static PVOID LdrFixupForward(PCHAR ForwardName);
50 static PVOID LdrGetExportByName(PVOID BaseAddress, PUCHAR SymbolName, USHORT Hint);
51
52
53 /* FUNCTIONS *****************************************************************/
54
55 /***************************************************************************
56 * NAME LOCAL
57 * LdrAdjustDllName
58 *
59 * DESCRIPTION
60 * Adjusts the name of a dll to a fully qualified name.
61 *
62 * ARGUMENTS
63 * FullDllName: Pointer to caller supplied storage for the fully
64 * qualified dll name.
65 * DllName: Pointer to the dll name.
66 * BaseName: TRUE: Only the file name is passed to FullDllName
67 * FALSE: The full path is preserved in FullDllName
68 *
69 * RETURN VALUE
70 * None
71 *
72 * REVISIONS
73 *
74 * NOTE
75 * A given path is not affected by the adjustment, but the file
76 * name only:
77 * ntdll --> ntdll.dll
78 * ntdll. --> ntdll
79 * ntdll.xyz --> ntdll.xyz
80 */
81
82 static VOID
83 LdrAdjustDllName (PUNICODE_STRING FullDllName,
84 PUNICODE_STRING DllName,
85 BOOLEAN BaseName)
86 {
87 WCHAR Buffer[MAX_PATH];
88 ULONG Length;
89 PWCHAR Extension;
90 PWCHAR Pointer;
91
92 Length = DllName->Length / sizeof(WCHAR);
93
94 if (BaseName == TRUE)
95 {
96 /* get the base dll name */
97 Pointer = DllName->Buffer + Length;
98 Extension = Pointer;
99
100 do
101 {
102 --Pointer;
103 }
104 while (Pointer >= DllName->Buffer && *Pointer != L'\\' && *Pointer != L'/');
105
106 Pointer++;
107 Length = Extension - Pointer;
108 memmove (Buffer, Pointer, Length * sizeof(WCHAR));
109 }
110 else
111 {
112 /* get the full dll name */
113 memmove (Buffer, DllName->Buffer, DllName->Length);
114 }
115
116 /* Build the DLL's absolute name */
117 Extension = wcsrchr (Buffer, L'.');
118 if ((Extension != NULL) && (*Extension == L'.'))
119 {
120 /* with extension - remove dot if it's the last character */
121 if (Buffer[Length - 1] == L'.')
122 Length--;
123 Buffer[Length] = 0;
124 }
125 else
126 {
127 /* name without extension - assume that it is .dll */
128 memmove (Buffer + Length, L".dll", 10);
129 }
130
131 RtlCreateUnicodeString (FullDllName,
132 Buffer);
133 }
134
135
136 /***************************************************************************
137 * NAME EXPORTED
138 * LdrLoadDll
139 *
140 * DESCRIPTION
141 *
142 * ARGUMENTS
143 *
144 * RETURN VALUE
145 *
146 * REVISIONS
147 *
148 * NOTE
149 *
150 */
151
152 NTSTATUS STDCALL
153 LdrLoadDll (IN PWSTR SearchPath OPTIONAL,
154 IN ULONG LoadFlags,
155 IN PUNICODE_STRING Name,
156 OUT PVOID *BaseAddress OPTIONAL)
157 {
158 WCHAR SearchPathBuffer[MAX_PATH];
159 WCHAR FullDosName[MAX_PATH];
160 UNICODE_STRING AdjustedName;
161 UNICODE_STRING FullNtFileName;
162 OBJECT_ATTRIBUTES FileObjectAttributes;
163 char BlockBuffer [1024];
164 PIMAGE_DOS_HEADER DosHeader;
165 NTSTATUS Status;
166 PIMAGE_NT_HEADERS NTHeaders;
167 ULONG ImageSize;
168 ULONG InitialViewSize;
169 PVOID ImageBase;
170 HANDLE FileHandle;
171 HANDLE SectionHandle;
172 PDLLMAIN_FUNC Entrypoint = NULL;
173 PLDR_MODULE Module;
174
175 if ( Name == NULL )
176 {
177 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
178 return STATUS_SUCCESS;
179 }
180
181 *BaseAddress = NULL;
182
183 DPRINT("LdrLoadDll(Name \"%wZ\" BaseAddress %x)\n",
184 Name, BaseAddress);
185
186 /* adjust the full dll name */
187 LdrAdjustDllName (&AdjustedName,
188 Name,
189 FALSE);
190 DPRINT("AdjustedName: %wZ\n", &AdjustedName);
191
192 /*
193 * Test if dll is already loaded.
194 */
195 if (LdrFindDll(&Module, &AdjustedName) == STATUS_SUCCESS)
196 {
197 DPRINT("DLL %wZ already loaded.\n", &AdjustedName);
198 if (Module->LoadCount != -1)
199 Module->LoadCount++;
200 *BaseAddress = Module->BaseAddress;
201 return STATUS_SUCCESS;
202 }
203 DPRINT("Loading \"%wZ\"\n", Name);
204
205 if (SearchPath == NULL)
206 {
207 PKUSER_SHARED_DATA SharedUserData =
208 (PKUSER_SHARED_DATA)USER_SHARED_DATA_BASE;
209
210 SearchPath = SearchPathBuffer;
211 wcscpy (SearchPathBuffer, SharedUserData->NtSystemRoot);
212 wcscat (SearchPathBuffer, L"\\system32;");
213 wcscat (SearchPathBuffer, SharedUserData->NtSystemRoot);
214 }
215
216 DPRINT("SearchPath %S\n", SearchPath);
217
218 if (RtlDosSearchPath_U (SearchPath,
219 AdjustedName.Buffer,
220 NULL,
221 MAX_PATH,
222 FullDosName,
223 NULL) == 0)
224 return STATUS_DLL_NOT_FOUND;
225
226 DPRINT("FullDosName %S\n", FullDosName);
227
228 RtlFreeUnicodeString (&AdjustedName);
229
230 if (!RtlDosPathNameToNtPathName_U (FullDosName,
231 &FullNtFileName,
232 NULL,
233 NULL))
234 return STATUS_DLL_NOT_FOUND;
235
236 DPRINT("FullNtFileName %wZ\n", &FullNtFileName);
237
238 InitializeObjectAttributes(
239 & FileObjectAttributes,
240 & FullNtFileName,
241 0,
242 NULL,
243 NULL
244 );
245
246 DPRINT("Opening dll \"%wZ\"\n", &FullNtFileName);
247
248 Status = ZwOpenFile(
249 & FileHandle,
250 FILE_ALL_ACCESS,
251 & FileObjectAttributes,
252 NULL,
253 0,
254 0
255 );
256 if (!NT_SUCCESS(Status))
257 {
258 DbgPrint("Dll open of %wZ failed: Status = 0x%08x\n",
259 &FullNtFileName, Status);
260 RtlFreeUnicodeString (&FullNtFileName);
261 return Status;
262 }
263 RtlFreeUnicodeString (&FullNtFileName);
264
265 Status = ZwReadFile(
266 FileHandle,
267 0,
268 0,
269 0,
270 0,
271 BlockBuffer,
272 sizeof BlockBuffer,
273 0,
274 0
275 );
276 if (!NT_SUCCESS(Status))
277 {
278 DPRINT("Dll header read failed: Status = 0x%08x\n", Status);
279 ZwClose(FileHandle);
280 return Status;
281 }
282 /*
283 * Overlay DOS and NT headers structures to the
284 * buffer with DLL's header raw data.
285 */
286 DosHeader = (PIMAGE_DOS_HEADER) BlockBuffer;
287 NTHeaders = (PIMAGE_NT_HEADERS) (BlockBuffer + DosHeader->e_lfanew);
288 /*
289 * Check it is a PE image file.
290 */
291 if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
292 || (DosHeader->e_lfanew == 0L)
293 || (*(PULONG)(NTHeaders) != IMAGE_PE_MAGIC))
294 {
295 DPRINT("NTDLL format invalid\n");
296 ZwClose(FileHandle);
297
298 return STATUS_UNSUCCESSFUL;
299 }
300
301 ImageBase = (PVOID) NTHeaders->OptionalHeader.ImageBase;
302 ImageSize = NTHeaders->OptionalHeader.SizeOfImage;
303
304 DPRINT("ImageBase 0x%08x\n", ImageBase);
305
306 /*
307 * Create a section for dll.
308 */
309 Status = ZwCreateSection(
310 & SectionHandle,
311 SECTION_ALL_ACCESS,
312 NULL,
313 NULL,
314 PAGE_READWRITE,
315 MEM_COMMIT,
316 FileHandle
317 );
318 if (!NT_SUCCESS(Status))
319 {
320 DPRINT("NTDLL create section failed: Status = 0x%08x\n", Status);
321 ZwClose(FileHandle);
322 return Status;
323 }
324
325 /*
326 * Map the dll into the process.
327 */
328 InitialViewSize =
329 DosHeader->e_lfanew
330 + sizeof (IMAGE_NT_HEADERS)
331 + sizeof (IMAGE_SECTION_HEADER) * NTHeaders->FileHeader.NumberOfSections;
332 Status = ZwMapViewOfSection(
333 SectionHandle,
334 NtCurrentProcess(),
335 (PVOID*)&ImageBase,
336 0,
337 InitialViewSize,
338 NULL,
339 &InitialViewSize,
340 0,
341 MEM_COMMIT,
342 PAGE_READWRITE
343 );
344 if (!NT_SUCCESS(Status))
345 {
346 DbgPrint("NTDLL.LDR: map view of section failed (Status %x)\n",
347 Status);
348 ZwClose(FileHandle);
349 return(Status);
350 }
351 ZwClose(FileHandle);
352
353 /* relocate dll and fixup import table */
354 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
355 IMAGE_FILE_DLL)
356 {
357 Entrypoint =
358 (PDLLMAIN_FUNC) LdrPEStartup(
359 ImageBase,
360 SectionHandle
361 );
362 }
363
364 /* build module entry */
365 Module = RtlAllocateHeap(
366 RtlGetProcessHeap(),
367 0,
368 sizeof (LDR_MODULE)
369 );
370 Module->BaseAddress = (PVOID)ImageBase;
371 Module->EntryPoint = NTHeaders->OptionalHeader.AddressOfEntryPoint;
372 if (Module->EntryPoint != 0)
373 Module->EntryPoint += (ULONG)Module->BaseAddress;
374 Module->SizeOfImage = ImageSize;
375 if (NtCurrentPeb()->Ldr->Initialized == TRUE)
376 {
377 /* loading while app is running */
378 Module->LoadCount = 1;
379 }
380 else
381 {
382 /*
383 * loading while app is initializing
384 * dll must not be unloaded
385 */
386 Module->LoadCount = -1;
387 }
388
389 Module->TlsIndex = 0;
390 Module->CheckSum = NTHeaders->OptionalHeader.CheckSum;
391 Module->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
392
393 RtlCreateUnicodeString (&Module->FullDllName,
394 FullDosName);
395 RtlCreateUnicodeString (&Module->BaseDllName,
396 wcsrchr(FullDosName, L'\\') + 1);
397 DPRINT ("BaseDllName %wZ\n", &Module->BaseDllName);
398
399 /* FIXME: aquire loader lock */
400 InsertTailList(&NtCurrentPeb()->Ldr->InLoadOrderModuleList,
401 &Module->InLoadOrderModuleList);
402 InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
403 &Module->InInitializationOrderModuleList);
404 /* FIXME: release loader lock */
405
406 /* initialize dll */
407 if ((NTHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) ==
408 IMAGE_FILE_DLL)
409 {
410 if (Module->EntryPoint != 0)
411 {
412 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
413
414 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
415 if (FALSE == Entrypoint(
416 Module->BaseAddress,
417 DLL_PROCESS_ATTACH,
418 NULL
419 ))
420 {
421 DPRINT("NTDLL.LDR: DLL \"%wZ\" failed to initialize\n",
422 &Module->BaseDllName);
423 /* FIXME: should clean up and fail */
424 }
425 else
426 {
427 DPRINT("NTDLL.LDR: DLL \"%wZ\" initialized successfully\n",
428 &Module->BaseDllName);
429 }
430 }
431 else
432 {
433 DPRINT("NTDLL.LDR: Entrypoint is NULL for \"%wZ\"\n",
434 &Module->BaseDllName);
435 }
436 }
437
438 *BaseAddress = Module->BaseAddress;
439 return STATUS_SUCCESS;
440 }
441
442
443 /***************************************************************************
444 * NAME LOCAL
445 * LdrFindDll
446 *
447 * DESCRIPTION
448 *
449 * ARGUMENTS
450 *
451 * RETURN VALUE
452 *
453 * REVISIONS
454 *
455 * NOTE
456 *
457 */
458 static NTSTATUS LdrFindDll(PLDR_MODULE *Dll, PUNICODE_STRING Name)
459 {
460 PLIST_ENTRY ModuleListHead;
461 PLIST_ENTRY Entry;
462 PLDR_MODULE Module;
463
464 DPRINT("NTDLL.LdrFindDll(Name %wZ)\n", Name);
465
466 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
467 Entry = ModuleListHead->Flink;
468
469 // NULL is the current process
470 if ( Name == NULL )
471 {
472 *Dll = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
473 return STATUS_SUCCESS;
474 }
475
476 while (Entry != ModuleListHead)
477 {
478 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
479
480 DPRINT("Scanning %wZ %wZ\n", &Module->BaseDllName, Name);
481
482 if (RtlCompareUnicodeString(&Module->BaseDllName, Name, TRUE) == 0)
483 {
484 *Dll = Module;
485 return STATUS_SUCCESS;
486 }
487
488 Entry = Entry->Flink;
489 }
490
491 DPRINT("Failed to find dll %wZ\n", Name);
492
493 return STATUS_UNSUCCESSFUL;
494 }
495
496
497 /**********************************************************************
498 * NAME
499 * LdrMapSections
500 *
501 * DESCRIPTION
502 *
503 * ARGUMENTS
504 *
505 * RETURN VALUE
506 *
507 * REVISIONS
508 *
509 * NOTE
510 *
511 */
512 NTSTATUS LdrMapSections(HANDLE ProcessHandle,
513 PVOID ImageBase,
514 HANDLE SectionHandle,
515 PIMAGE_NT_HEADERS NTHeaders)
516 {
517 ULONG i;
518 NTSTATUS Status;
519
520 for (i = 0; (i < NTHeaders->FileHeader.NumberOfSections); i++)
521 {
522 PIMAGE_SECTION_HEADER Sections;
523 LARGE_INTEGER Offset;
524 ULONG Base;
525 ULONG Size;
526
527 Sections = (PIMAGE_SECTION_HEADER) SECHDROFFSET(ImageBase);
528 Base = (ULONG) (Sections[i].VirtualAddress + ImageBase);
529 Offset.u.LowPart = Sections[i].PointerToRawData;
530 Offset.u.HighPart = 0;
531
532 Size = max(Sections[i].Misc.VirtualSize, Sections[i].SizeOfRawData);
533
534 DPRINT("Mapping section %d offset %x base %x size %x\n",
535 i, Offset.u.LowPart, Base, Sections[i].Misc.VirtualSize);
536 DPRINT("Size %x\n", Sections[i].SizeOfRawData);
537 if( Offset.u.LowPart )
538 { // only map section if it is initialized
539 Status = ZwMapViewOfSection(SectionHandle,
540 ProcessHandle,
541 (PVOID*)&Base,
542 0,
543 Size,
544 &Offset,
545 (PULONG)&Size,
546 0,
547 MEM_COMMIT,
548 PAGE_READWRITE);
549 if (!NT_SUCCESS(Status))
550 {
551 DPRINT1("Failed to map section");
552 return(Status);
553 }
554 }
555 else {
556 // allocate pure memory for uninitialized section
557 Status = NtAllocateVirtualMemory( NtCurrentProcess(),
558 (PVOID *)&Base,
559 0,
560 &Size,
561 MEM_COMMIT,
562 PAGE_READWRITE );
563 if( !NT_SUCCESS( Status ) )
564 {
565 DPRINT1( "Failed to allocate memory for uninitialized section\n" );
566 return Status;
567 }
568 }
569 }
570 return STATUS_SUCCESS;
571 }
572
573
574 /**********************************************************************
575 * NAME LOCAL
576 * LdrFixupForward
577 *
578 * DESCRIPTION
579 *
580 * ARGUMENTS
581 *
582 * RETURN VALUE
583 *
584 * REVISIONS
585 *
586 * NOTE
587 *
588 */
589 static PVOID
590 LdrFixupForward(PCHAR ForwardName)
591 {
592 CHAR NameBuffer[128];
593 UNICODE_STRING DllName;
594 UNICODE_STRING FunctionName;
595 NTSTATUS Status;
596 PCHAR p;
597 PVOID BaseAddress;
598
599 strcpy(NameBuffer, ForwardName);
600 p = strchr(NameBuffer, '.');
601 if (p != NULL)
602 {
603 *p = 0;
604
605 DPRINT("Dll: %s Function: %s\n", NameBuffer, p+1);
606 RtlCreateUnicodeStringFromAsciiz (&DllName,
607 NameBuffer);
608
609 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
610 if (!NT_SUCCESS(Status))
611 {
612 Status = LdrLoadDll(NULL,
613 0,
614 &DllName,
615 &BaseAddress);
616 RtlFreeUnicodeString (&DllName);
617 if (!NT_SUCCESS(Status))
618 {
619 DbgPrint("LdrFixupForward: failed to load %wZ\n", &DllName);
620 return NULL;
621 }
622 }
623
624 RtlFreeUnicodeString (&DllName);
625 DPRINT("BaseAddress: %p\n", BaseAddress);
626
627 return LdrGetExportByName(BaseAddress, p+1, -1);
628 }
629
630 return NULL;
631 }
632
633
634 /**********************************************************************
635 * NAME LOCAL
636 * LdrGetExportByOrdinal
637 *
638 * DESCRIPTION
639 *
640 * ARGUMENTS
641 *
642 * RETURN VALUE
643 *
644 * REVISIONS
645 *
646 * NOTE
647 *
648 */
649 static PVOID
650 LdrGetExportByOrdinal (
651 PVOID BaseAddress,
652 ULONG Ordinal
653 )
654 {
655 PIMAGE_EXPORT_DIRECTORY ExportDir;
656 PDWORD * ExFunctions;
657 USHORT * ExOrdinals;
658
659 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
660 RtlImageDirectoryEntryToData (BaseAddress,
661 TRUE,
662 IMAGE_DIRECTORY_ENTRY_EXPORT,
663 NULL);
664
665
666 ExOrdinals = (USHORT *)
667 RVA(
668 BaseAddress,
669 ExportDir->AddressOfNameOrdinals
670 );
671 ExFunctions = (PDWORD *)
672 RVA(
673 BaseAddress,
674 ExportDir->AddressOfFunctions
675 );
676 DbgPrint(
677 "LdrGetExportByOrdinal(Ordinal %d) = %x\n",
678 Ordinal,
679 ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]
680 );
681 return(ExFunctions[ExOrdinals[Ordinal - ExportDir->Base]]);
682 }
683
684
685 /**********************************************************************
686 * NAME LOCAL
687 * LdrGetExportByName
688 *
689 * DESCRIPTION
690 *
691 * ARGUMENTS
692 *
693 * RETURN VALUE
694 *
695 * REVISIONS
696 *
697 * NOTE
698 *
699 */
700 static PVOID
701 LdrGetExportByName(PVOID BaseAddress,
702 PUCHAR SymbolName,
703 WORD Hint)
704 {
705 PIMAGE_EXPORT_DIRECTORY ExportDir;
706 PDWORD * ExFunctions;
707 PDWORD * ExNames;
708 USHORT * ExOrdinals;
709 ULONG i;
710 PVOID ExName;
711 ULONG Ordinal;
712 PVOID Function;
713 ULONG minn, maxn;
714 ULONG ExportDirSize;
715
716 DPRINT("LdrGetExportByName %x %s %hu\n", BaseAddress, SymbolName, Hint);
717
718 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
719 RtlImageDirectoryEntryToData(BaseAddress,
720 TRUE,
721 IMAGE_DIRECTORY_ENTRY_EXPORT,
722 &ExportDirSize);
723
724 /*
725 * Get header pointers
726 */
727 ExNames = (PDWORD *)RVA(BaseAddress,
728 ExportDir->AddressOfNames);
729 ExOrdinals = (USHORT *)RVA(BaseAddress,
730 ExportDir->AddressOfNameOrdinals);
731 ExFunctions = (PDWORD *)RVA(BaseAddress,
732 ExportDir->AddressOfFunctions);
733
734 /*
735 * Check the hint first
736 */
737 if (Hint < ExportDir->NumberOfFunctions)
738 {
739 ExName = RVA(BaseAddress, ExNames[Hint]);
740 if (strcmp(ExName, SymbolName) == 0)
741 {
742 Ordinal = ExOrdinals[Hint];
743 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
744 if (((ULONG)Function >= (ULONG)ExportDir) &&
745 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
746 {
747 DPRINT("Forward: %s\n", (PCHAR)Function);
748 Function = LdrFixupForward((PCHAR)Function);
749 }
750 if (Function != NULL)
751 return Function;
752 }
753 }
754
755 /*
756 * Try a binary search first
757 */
758 minn = 0, maxn = ExportDir->NumberOfFunctions;
759 while (minn <= maxn)
760 {
761 ULONG mid;
762 LONG res;
763
764 mid = (minn + maxn) / 2;
765
766 ExName = RVA(BaseAddress, ExNames[mid]);
767 res = strcmp(ExName, SymbolName);
768 if (res == 0)
769 {
770 Ordinal = ExOrdinals[mid];
771 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
772 if (((ULONG)Function >= (ULONG)ExportDir) &&
773 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
774 {
775 DPRINT("Forward: %s\n", (PCHAR)Function);
776 Function = LdrFixupForward((PCHAR)Function);
777 }
778 if (Function != NULL)
779 return Function;
780 }
781 else if (res > 0)
782 {
783 maxn = mid - 1;
784 }
785 else
786 {
787 minn = mid + 1;
788 }
789 }
790 /*
791 * Fall back on a linear search
792 */
793
794 DbgPrint("LDR: Falling back on a linear search of export table\n");
795 for (i = 0; i < ExportDir->NumberOfFunctions; i++)
796 {
797 ExName = RVA(BaseAddress, ExNames[i]);
798 if (strcmp(ExName,SymbolName) == 0)
799 {
800 Ordinal = ExOrdinals[i];
801 Function = RVA(BaseAddress, ExFunctions[Ordinal]);
802 DPRINT("%x %x %x\n", Function, ExportDir, ExportDir + ExportDirSize);
803 if (((ULONG)Function >= (ULONG)ExportDir) &&
804 ((ULONG)Function < (ULONG)ExportDir + (ULONG)ExportDirSize))
805 {
806 DPRINT("Forward: %s\n", (PCHAR)Function);
807 Function = LdrFixupForward((PCHAR)Function);
808 }
809 return Function;
810 }
811 }
812 DbgPrint("LdrGetExportByName() = failed to find %s\n",SymbolName);
813 return NULL;
814 }
815
816
817 /**********************************************************************
818 * NAME LOCAL
819 * LdrPerformRelocations
820 *
821 * DESCRIPTION
822 * Relocate a DLL's memory image.
823 *
824 * ARGUMENTS
825 *
826 * RETURN VALUE
827 *
828 * REVISIONS
829 *
830 * NOTE
831 *
832 */
833 static NTSTATUS LdrPerformRelocations (PIMAGE_NT_HEADERS NTHeaders,
834 PVOID ImageBase)
835 {
836 USHORT NumberOfEntries;
837 PUSHORT pValue16;
838 ULONG RelocationRVA;
839 ULONG Delta32;
840 ULONG Offset;
841 PULONG pValue32;
842 PRELOCATION_DIRECTORY RelocationDir;
843 PRELOCATION_ENTRY RelocationBlock;
844 int i;
845
846
847 RelocationRVA = NTHeaders->OptionalHeader
848 .DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]
849 .VirtualAddress;
850
851 if (RelocationRVA)
852 {
853 RelocationDir = (PRELOCATION_DIRECTORY)
854 ((PCHAR)ImageBase + RelocationRVA);
855
856 while (RelocationDir->SizeOfBlock)
857 {
858 Delta32 = (ULONG)(ImageBase -
859 NTHeaders->OptionalHeader.ImageBase);
860 RelocationBlock = (PRELOCATION_ENTRY) (
861 RelocationRVA
862 + ImageBase
863 + sizeof (RELOCATION_DIRECTORY)
864 );
865 NumberOfEntries = (
866 RelocationDir->SizeOfBlock
867 - sizeof (RELOCATION_DIRECTORY)
868 )
869 / sizeof (RELOCATION_ENTRY);
870
871 for ( i = 0;
872 (i < NumberOfEntries);
873 i++
874 )
875 {
876 Offset = (
877 RelocationBlock[i].TypeOffset
878 & 0xfff
879 )
880 + RelocationDir->VirtualAddress;
881 /*
882 * What kind of relocations should we perform
883 * for the current entry?
884 */
885 switch (RelocationBlock[i].TypeOffset >> 12)
886 {
887 case TYPE_RELOC_ABSOLUTE:
888 break;
889
890 case TYPE_RELOC_HIGH:
891 pValue16 = (PUSHORT) (ImageBase + Offset);
892 *pValue16 += Delta32 >> 16;
893 break;
894
895 case TYPE_RELOC_LOW:
896 pValue16 = (PUSHORT)(ImageBase + Offset);
897 *pValue16 += Delta32 & 0xffff;
898 break;
899
900 case TYPE_RELOC_HIGHLOW:
901 pValue32 = (PULONG) (ImageBase + Offset);
902 *pValue32 += Delta32;
903 break;
904
905 case TYPE_RELOC_HIGHADJ:
906 /* FIXME: do the highadjust fixup */
907 DPRINT(
908 "TYPE_RELOC_HIGHADJ fixup not implemented"
909 ", sorry\n"
910 );
911 return(STATUS_UNSUCCESSFUL);
912
913 default:
914 DPRINT("unexpected fixup type\n");
915 return STATUS_UNSUCCESSFUL;
916 }
917 }
918 RelocationRVA += RelocationDir->SizeOfBlock;
919 RelocationDir = (PRELOCATION_DIRECTORY) (
920 ImageBase
921 + RelocationRVA
922 );
923 }
924 }
925 return STATUS_SUCCESS;
926 }
927
928
929 /**********************************************************************
930 * NAME LOCAL
931 * LdrFixupImports
932 *
933 * DESCRIPTION
934 * Compute the entry point for every symbol the DLL imports
935 * from other modules.
936 *
937 * ARGUMENTS
938 *
939 * RETURN VALUE
940 *
941 * REVISIONS
942 *
943 * NOTE
944 *
945 */
946 static NTSTATUS LdrFixupImports(PIMAGE_NT_HEADERS NTHeaders,
947 PVOID ImageBase)
948 {
949 PIMAGE_IMPORT_MODULE_DIRECTORY ImportModuleDirectory;
950 ULONG Ordinal;
951 PVOID BaseAddress;
952 NTSTATUS Status;
953
954 DPRINT("LdrFixupImports(NTHeaders %x, ImageBase %x)\n", NTHeaders,
955 ImageBase);
956
957 /*
958 * Process each import module.
959 */
960 ImportModuleDirectory = (PIMAGE_IMPORT_MODULE_DIRECTORY)(
961 ImageBase + NTHeaders->OptionalHeader
962 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
963 .VirtualAddress);
964 DPRINT("ImportModuleDirectory %x\n", ImportModuleDirectory);
965
966 while (ImportModuleDirectory->dwRVAModuleName)
967 {
968 PVOID * ImportAddressList;
969 PULONG FunctionNameList;
970 UNICODE_STRING DllName;
971 DWORD pName;
972 WORD pHint;
973
974 DPRINT("ImportModule->Directory->dwRVAModuleName %s\n",
975 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
976
977 RtlCreateUnicodeStringFromAsciiz (&DllName,
978 (PCHAR)(ImageBase + ImportModuleDirectory->dwRVAModuleName));
979
980 Status = LdrGetDllHandle (0, 0, &DllName, &BaseAddress);
981 if (!NT_SUCCESS(Status))
982 {
983 Status = LdrLoadDll(NULL,
984 0,
985 &DllName,
986 &BaseAddress);
987 RtlFreeUnicodeString (&DllName);
988 if (!NT_SUCCESS(Status))
989 {
990 DbgPrint("LdrFixupImports:failed to load %s\n"
991 ,(PCHAR)(ImageBase
992 + ImportModuleDirectory->dwRVAModuleName));
993
994 return Status;
995 }
996 }
997
998 /*
999 * Get the import address list.
1000 */
1001 ImportAddressList = (PVOID *)(NTHeaders->OptionalHeader.ImageBase
1002 + ImportModuleDirectory->dwRVAFunctionAddressList);
1003
1004 /*
1005 * Get the list of functions to import.
1006 */
1007 if (ImportModuleDirectory->dwRVAFunctionNameList != 0)
1008 {
1009 FunctionNameList = (PULONG) (
1010 ImageBase
1011 + ImportModuleDirectory->dwRVAFunctionNameList
1012 );
1013 }
1014 else
1015 {
1016 FunctionNameList =
1017 (PULONG)(ImageBase
1018 + ImportModuleDirectory->dwRVAFunctionAddressList);
1019 }
1020 /*
1021 * Walk through function list and fixup addresses.
1022 */
1023 while (*FunctionNameList != 0L)
1024 {
1025 if ((*FunctionNameList) & 0x80000000)
1026 {
1027 Ordinal = (*FunctionNameList) & 0x7fffffff;
1028 *ImportAddressList =
1029 LdrGetExportByOrdinal(BaseAddress,
1030 Ordinal);
1031 }
1032 else
1033 {
1034 pName = (DWORD) (ImageBase + *FunctionNameList + 2);
1035 pHint = *(PWORD)(ImageBase + *FunctionNameList);
1036
1037 *ImportAddressList =
1038 LdrGetExportByName(BaseAddress, (PUCHAR)pName, pHint);
1039 if ((*ImportAddressList) == NULL)
1040 {
1041 DbgPrint("Failed to import %s\n", pName);
1042 return STATUS_UNSUCCESSFUL;
1043 }
1044 }
1045 ImportAddressList++;
1046 FunctionNameList++;
1047 }
1048 ImportModuleDirectory++;
1049 }
1050 return STATUS_SUCCESS;
1051 }
1052
1053
1054 /**********************************************************************
1055 * NAME
1056 * LdrPEStartup
1057 *
1058 * DESCRIPTION
1059 * 1. Map the DLL's sections into memory.
1060 * 2. Relocate, if needed the DLL.
1061 * 3. Fixup any imported symbol.
1062 * 4. Compute the DLL's entry point.
1063 *
1064 * ARGUMENTS
1065 * ImageBase
1066 * Address at which the DLL's image
1067 * is loaded.
1068 *
1069 * SectionHandle
1070 * Handle of the section that contains
1071 * the DLL's image.
1072 *
1073 * RETURN VALUE
1074 * NULL on error; otherwise the entry point
1075 * to call for initializing the DLL.
1076 *
1077 * REVISIONS
1078 *
1079 * NOTE
1080 *
1081 */
1082 PEPFUNC LdrPEStartup (PVOID ImageBase,
1083 HANDLE SectionHandle)
1084 {
1085 NTSTATUS Status;
1086 PEPFUNC EntryPoint = NULL;
1087 PIMAGE_DOS_HEADER DosHeader;
1088 PIMAGE_NT_HEADERS NTHeaders;
1089
1090 DPRINT("LdrPEStartup(ImageBase %x SectionHandle %x)\n",
1091 ImageBase, (ULONG)SectionHandle);
1092
1093 /*
1094 * Overlay DOS and WNT headers structures
1095 * to the DLL's image.
1096 */
1097 DosHeader = (PIMAGE_DOS_HEADER) ImageBase;
1098 NTHeaders = (PIMAGE_NT_HEADERS) (ImageBase + DosHeader->e_lfanew);
1099
1100 /*
1101 * Initialize image sections.
1102 */
1103 if (SectionHandle != NULL)
1104 {
1105 LdrMapSections(NtCurrentProcess(),
1106 ImageBase,
1107 SectionHandle,
1108 NTHeaders);
1109 }
1110
1111 /*
1112 * If the base address is different from the
1113 * one the DLL is actually loaded, perform any
1114 * relocation.
1115 */
1116 if (ImageBase != (PVOID) NTHeaders->OptionalHeader.ImageBase)
1117 {
1118 DbgPrint("LDR: Performing relocations\n");
1119 Status = LdrPerformRelocations(NTHeaders, ImageBase);
1120 if (!NT_SUCCESS(Status))
1121 {
1122 DbgPrint("LdrPerformRelocations() failed\n");
1123 return NULL;
1124 }
1125 }
1126
1127 /*
1128 * If the DLL's imports symbols from other
1129 * modules, fixup the imported calls entry points.
1130 */
1131 if (NTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
1132 .VirtualAddress != 0)
1133 {
1134 DPRINT("About to fixup imports\n");
1135 Status = LdrFixupImports(NTHeaders, ImageBase);
1136 if (!NT_SUCCESS(Status))
1137 {
1138 DbgPrint("LdrFixupImports() failed\n");
1139 return NULL;
1140 }
1141 DPRINT("Fixup done\n");
1142 }
1143
1144 /*
1145 * Compute the DLL's entry point's address.
1146 */
1147 DPRINT("ImageBase = %x\n",(ULONG)ImageBase);
1148 DPRINT("AddressOfEntryPoint = %x\n",(ULONG)NTHeaders->OptionalHeader.AddressOfEntryPoint);
1149 if (NTHeaders->OptionalHeader.AddressOfEntryPoint != 0)
1150 {
1151 EntryPoint = (PEPFUNC) (ImageBase
1152 + NTHeaders->OptionalHeader.AddressOfEntryPoint);
1153 }
1154 DPRINT("LdrPEStartup() = %x\n",EntryPoint);
1155 return EntryPoint;
1156 }
1157
1158
1159 NTSTATUS STDCALL
1160 LdrUnloadDll (IN PVOID BaseAddress)
1161 {
1162 PIMAGE_NT_HEADERS NtHeaders;
1163 PDLLMAIN_FUNC Entrypoint;
1164 PLIST_ENTRY ModuleListHead;
1165 PLIST_ENTRY Entry;
1166 PLDR_MODULE Module;
1167 NTSTATUS Status;
1168
1169 if (BaseAddress == NULL)
1170 return STATUS_SUCCESS;
1171
1172 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1173 Entry = ModuleListHead->Flink;
1174
1175 while (Entry != ModuleListHead);
1176 {
1177 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1178 if (Module->BaseAddress == BaseAddress)
1179 {
1180 if (Module->LoadCount == -1)
1181 {
1182 /* never unload this dll */
1183 return STATUS_SUCCESS;
1184 }
1185 else if (Module->LoadCount > 1)
1186 {
1187 Module->LoadCount--;
1188 return STATUS_SUCCESS;
1189 }
1190
1191 NtHeaders = RtlImageNtHeader (Module->BaseAddress);
1192 if ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
1193 {
1194 if (Module->EntryPoint != 0)
1195 {
1196 Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1197 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1198 Entrypoint(Module->BaseAddress,
1199 DLL_PROCESS_DETACH,
1200 NULL);
1201 }
1202 else
1203 {
1204 DPRINT("NTDLL.LDR: Entrypoint is NULL for \n");
1205 }
1206 }
1207 Status = ZwUnmapViewOfSection (NtCurrentProcess (),
1208 Module->BaseAddress);
1209 ZwClose (Module->SectionHandle);
1210
1211 /* remove the module entry from the list */
1212 RtlFreeUnicodeString (&Module->FullDllName);
1213 RtlFreeUnicodeString (&Module->BaseDllName);
1214 RemoveEntryList (Entry);
1215 RtlFreeHeap (RtlGetProcessHeap (), 0, Module);
1216
1217 return Status;
1218 }
1219
1220 Entry = Entry->Flink;
1221 }
1222
1223 DPRINT("NTDLL.LDR: Dll not found\n")
1224
1225 return STATUS_UNSUCCESSFUL;
1226 }
1227
1228
1229 NTSTATUS STDCALL
1230 LdrFindResource_U(PVOID BaseAddress,
1231 PLDR_RESOURCE_INFO ResourceInfo,
1232 ULONG Level,
1233 PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry)
1234 {
1235 PIMAGE_RESOURCE_DIRECTORY ResDir;
1236 PIMAGE_RESOURCE_DIRECTORY ResBase;
1237 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1238 NTSTATUS Status = STATUS_SUCCESS;
1239 ULONG EntryCount;
1240 PWCHAR ws;
1241 ULONG i;
1242 ULONG Id;
1243
1244 DPRINT ("LdrFindResource_U()\n");
1245
1246 /* Get the pointer to the resource directory */
1247 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1248 RtlImageDirectoryEntryToData (BaseAddress,
1249 TRUE,
1250 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1251 &i);
1252 if (ResDir == NULL)
1253 {
1254 return STATUS_RESOURCE_DATA_NOT_FOUND;
1255 }
1256
1257 DPRINT("ResourceDirectory: %x\n", (ULONG)ResDir);
1258
1259 ResBase = ResDir;
1260
1261 /* Let's go into resource tree */
1262 for (i = 0; i < Level; i++)
1263 {
1264 DPRINT("ResDir: %x\n", (ULONG)ResDir);
1265 Id = ((PULONG)ResourceInfo)[i];
1266 EntryCount = ResDir->NumberOfNamedEntries;
1267 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1268 DPRINT("ResEntry %x\n", (ULONG)ResEntry);
1269 if (Id & 0xFFFF0000)
1270 {
1271 /* Resource name is a unicode string */
1272 for (; EntryCount--; ResEntry++)
1273 {
1274 /* Scan entries for equal name */
1275 if (ResEntry->Name & 0x80000000)
1276 {
1277 ws = (PWCHAR)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1278 if (!wcsncmp((PWCHAR)Id, ws + 1, *ws ) &&
1279 wcslen((PWCHAR)Id) == (int)*ws )
1280 {
1281 goto found;
1282 }
1283 }
1284 }
1285 }
1286 else
1287 {
1288 /* We use ID number instead of string */
1289 ResEntry += EntryCount;
1290 EntryCount = ResDir->NumberOfIdEntries;
1291 for (; EntryCount--; ResEntry++)
1292 {
1293 /* Scan entries for equal name */
1294 if (ResEntry->Name == Id)
1295 {
1296 DPRINT("ID entry found %x\n", Id);
1297 goto found;
1298 }
1299 }
1300 }
1301 DPRINT("Error %lu\n", i);
1302
1303 switch (i)
1304 {
1305 case 0:
1306 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1307
1308 case 1:
1309 return STATUS_RESOURCE_NAME_NOT_FOUND;
1310
1311 case 2:
1312 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1313 {
1314 /* Use the first available language */
1315 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1316 break;
1317 }
1318 return STATUS_RESOURCE_LANG_NOT_FOUND;
1319
1320 case 3:
1321 return STATUS_RESOURCE_DATA_NOT_FOUND;
1322
1323 default:
1324 return STATUS_INVALID_PARAMETER;
1325 }
1326 found:;
1327 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResBase +
1328 (ResEntry->OffsetToData & 0x7FFFFFFF));
1329 }
1330 DPRINT("ResourceDataEntry: %x\n", (ULONG)ResDir);
1331
1332 if (ResourceDataEntry)
1333 {
1334 *ResourceDataEntry = (PVOID)ResDir;
1335 }
1336
1337 return Status;
1338 }
1339
1340
1341 NTSTATUS STDCALL
1342 LdrAccessResource(IN PVOID BaseAddress,
1343 IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry,
1344 OUT PVOID *Resource OPTIONAL,
1345 OUT PULONG Size OPTIONAL)
1346 {
1347 PIMAGE_SECTION_HEADER Section;
1348 PIMAGE_NT_HEADERS NtHeader;
1349 ULONG SectionRva;
1350 ULONG SectionVa;
1351 ULONG DataSize;
1352 ULONG Offset = 0;
1353 ULONG Data;
1354
1355 Data = (ULONG)RtlImageDirectoryEntryToData (BaseAddress,
1356 TRUE,
1357 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1358 &DataSize);
1359 if (Data == 0)
1360 return STATUS_RESOURCE_DATA_NOT_FOUND;
1361
1362 if ((ULONG)BaseAddress & 1)
1363 {
1364 /* loaded as ordinary file */
1365 NtHeader = RtlImageNtHeader((PVOID)((ULONG)BaseAddress & ~1UL));
1366 Offset = (ULONG)BaseAddress - Data + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
1367 Section = RtlImageRvaToSection (NtHeader, BaseAddress, NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
1368 if (Section == NULL)
1369 {
1370 return STATUS_RESOURCE_DATA_NOT_FOUND;
1371 }
1372
1373 if (Section->Misc.VirtualSize < ResourceDataEntry->OffsetToData)
1374 {
1375 SectionRva = RtlImageRvaToSection (NtHeader, BaseAddress, ResourceDataEntry->OffsetToData)->VirtualAddress;
1376 SectionVa = RtlImageRvaToVa(NtHeader, BaseAddress, SectionRva, NULL);
1377 Offset = SectionRva - SectionVa + Data - Section->VirtualAddress;
1378 }
1379 }
1380
1381 if (Resource)
1382 {
1383 *Resource = (PVOID)(ResourceDataEntry->OffsetToData - Offset + (ULONG)BaseAddress);
1384 }
1385
1386 if (Size)
1387 {
1388 *Size = ResourceDataEntry->Size;
1389 }
1390
1391 return STATUS_SUCCESS;
1392 }
1393
1394
1395 NTSTATUS STDCALL
1396 LdrDisableThreadCalloutsForDll (IN PVOID BaseAddress)
1397 {
1398 PLIST_ENTRY ModuleListHead;
1399 PLIST_ENTRY Entry;
1400 PLDR_MODULE Module;
1401 NTSTATUS Status;
1402
1403 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %x)\n",
1404 BaseAddress);
1405
1406 Status = STATUS_DLL_NOT_FOUND;
1407
1408 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1409 Entry = ModuleListHead->Flink;
1410
1411 while (Entry != ModuleListHead)
1412 {
1413 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1414
1415 DPRINT("BaseDllName %wZ BaseAddress %x\n",
1416 &Module->BaseDllName,
1417 Module->BaseAddress);
1418
1419 if (Module->BaseAddress == BaseAddress)
1420 {
1421 if (Module->TlsIndex == 0)
1422 {
1423 Module->Flags |= 0x00040000;
1424 Status = STATUS_SUCCESS;
1425 }
1426 return Status;
1427 }
1428
1429 Entry = Entry->Flink;
1430 }
1431
1432 return Status;
1433 }
1434
1435
1436 NTSTATUS STDCALL
1437 LdrFindResourceDirectory_U (IN PVOID BaseAddress,
1438 WCHAR **name,
1439 DWORD level,
1440 OUT PVOID *addr)
1441 {
1442 PIMAGE_RESOURCE_DIRECTORY ResDir;
1443 PIMAGE_RESOURCE_DIRECTORY_ENTRY ResEntry;
1444 ULONG EntryCount;
1445 ULONG i;
1446 NTSTATUS Status = STATUS_SUCCESS;
1447 WCHAR *ws;
1448
1449 /* Get the pointer to the resource directory */
1450 ResDir = (PIMAGE_RESOURCE_DIRECTORY)
1451 RtlImageDirectoryEntryToData (BaseAddress,
1452 TRUE,
1453 IMAGE_DIRECTORY_ENTRY_RESOURCE,
1454 &i);
1455 if (ResDir == NULL)
1456 {
1457 return STATUS_RESOURCE_DATA_NOT_FOUND;
1458 }
1459
1460 /* Let's go into resource tree */
1461 for (i = 0; i < level; i++, name++)
1462 {
1463 EntryCount = ResDir->NumberOfNamedEntries;
1464 ResEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResDir + 1);
1465 if ((ULONG)(*name) & 0xFFFF0000)
1466 {
1467 /* Resource name is a unicode string */
1468 for (; EntryCount--; ResEntry++)
1469 {
1470 /* Scan entries for equal name */
1471 if (ResEntry->Name & 0x80000000)
1472 {
1473 ws = (WCHAR*)((ULONG)ResDir + (ResEntry->Name & 0x7FFFFFFF));
1474 if (!wcsncmp( *name, ws + 1, *ws ) && wcslen( *name ) == (int)*ws )
1475 {
1476 goto found;
1477 }
1478 }
1479 }
1480 }
1481 else
1482 {
1483 /* We use ID number instead of string */
1484 ResEntry += EntryCount;
1485 EntryCount = ResDir->NumberOfIdEntries;
1486 for (; EntryCount--; ResEntry++)
1487 {
1488 /* Scan entries for equal name */
1489 if (ResEntry->Name == (ULONG)(*name))
1490 goto found;
1491 }
1492 }
1493
1494 switch (i)
1495 {
1496 case 0:
1497 return STATUS_RESOURCE_TYPE_NOT_FOUND;
1498
1499 case 1:
1500 return STATUS_RESOURCE_NAME_NOT_FOUND;
1501
1502 case 2:
1503 Status = STATUS_RESOURCE_LANG_NOT_FOUND;
1504 /* Just use first language entry */
1505 if (ResDir->NumberOfNamedEntries || ResDir->NumberOfIdEntries)
1506 {
1507 ResEntry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(ResDir + 1);
1508 break;
1509 }
1510 return Status;
1511
1512 case 3:
1513 return STATUS_RESOURCE_DATA_NOT_FOUND;
1514
1515 default:
1516 return STATUS_INVALID_PARAMETER;
1517 }
1518 found:;
1519 ResDir = (PIMAGE_RESOURCE_DIRECTORY)((ULONG)ResDir + ResEntry->OffsetToData);
1520 }
1521
1522 if (addr)
1523 {
1524 *addr = (PVOID)ResDir;
1525 }
1526
1527 return Status;
1528 }
1529
1530
1531 NTSTATUS STDCALL
1532 LdrGetDllHandle (IN ULONG Unknown1,
1533 IN ULONG Unknown2,
1534 IN PUNICODE_STRING DllName,
1535 OUT PVOID *BaseAddress)
1536 {
1537 UNICODE_STRING FullDllName;
1538 PLIST_ENTRY ModuleListHead;
1539 PLIST_ENTRY Entry;
1540 PLDR_MODULE Module;
1541
1542 DPRINT("LdrGetDllHandle (Unknown1 %x Unknown2 %x DllName %wZ BaseAddress %p)\n",
1543 Unknown1, Unknown2, DllName, BaseAddress);
1544
1545 /* NULL is the current executable */
1546 if ( DllName == NULL )
1547 {
1548 *BaseAddress = NtCurrentPeb()->ImageBaseAddress;
1549 DPRINT("BaseAddress %x\n", *BaseAddress);
1550 return STATUS_SUCCESS;
1551 }
1552
1553 LdrAdjustDllName (&FullDllName,
1554 DllName,
1555 TRUE);
1556
1557 DPRINT("FullDllName %wZ\n",
1558 &FullDllName);
1559
1560 ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
1561 Entry = ModuleListHead->Flink;
1562
1563 while (Entry != ModuleListHead)
1564 {
1565 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InLoadOrderModuleList);
1566
1567 DPRINT("EntryPoint %x\n", Module->EntryPoint);
1568 DPRINT("Comparing %wZ and %wZ\n",
1569 &Module->BaseDllName,
1570 &FullDllName);
1571
1572 if (!RtlCompareUnicodeString(&Module->BaseDllName, &FullDllName, TRUE))
1573 {
1574 RtlFreeUnicodeString (&FullDllName);
1575 *BaseAddress = Module->BaseAddress;
1576 DPRINT("BaseAddress %x\n", *BaseAddress);
1577 return STATUS_SUCCESS;
1578 }
1579
1580 Entry = Entry->Flink;
1581 }
1582
1583 DPRINT("Failed to find dll %wZ\n", &FullDllName);
1584 RtlFreeUnicodeString (&FullDllName);
1585 *BaseAddress = NULL;
1586 return STATUS_DLL_NOT_FOUND;
1587 }
1588
1589
1590 NTSTATUS STDCALL
1591 LdrGetProcedureAddress (IN PVOID BaseAddress,
1592 IN PANSI_STRING Name,
1593 IN ULONG Ordinal,
1594 OUT PVOID *ProcedureAddress)
1595 {
1596 PIMAGE_EXPORT_DIRECTORY ExportDir;
1597 PUSHORT OrdinalPtr;
1598 PULONG NamePtr;
1599 PULONG AddressPtr;
1600 ULONG i = 0;
1601
1602 DPRINT("LdrGetProcedureAddress (BaseAddress %x Name %Z Ordinal %lu ProcedureAddress %x)\n",
1603 BaseAddress, Name, Ordinal, ProcedureAddress);
1604
1605 /* Get the pointer to the export directory */
1606 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
1607 RtlImageDirectoryEntryToData (BaseAddress,
1608 TRUE,
1609 IMAGE_DIRECTORY_ENTRY_EXPORT,
1610 &i);
1611
1612 DPRINT("ExportDir %x i %lu\n", ExportDir, i);
1613
1614 if (!ExportDir || !i || !ProcedureAddress)
1615 {
1616 return STATUS_INVALID_PARAMETER;
1617 }
1618
1619 AddressPtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfFunctions);
1620 if (Name && Name->Length)
1621 {
1622 /* by name */
1623 OrdinalPtr = (PUSHORT)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNameOrdinals);
1624 NamePtr = (PULONG)((ULONG)BaseAddress + (ULONG)ExportDir->AddressOfNames);
1625 for( i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
1626 {
1627 if (!_strnicmp(Name->Buffer, (char*)(BaseAddress + *NamePtr), Name->Length))
1628 {
1629 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[*OrdinalPtr]);
1630 return STATUS_SUCCESS;
1631 }
1632 }
1633 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
1634 }
1635 else
1636 {
1637 /* by ordinal */
1638 Ordinal &= 0x0000FFFF;
1639 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
1640 {
1641 *ProcedureAddress = (PVOID)((ULONG)BaseAddress + (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
1642 return STATUS_SUCCESS;
1643 }
1644 DbgPrint("LdrGetProcedureAddress: Can't resolve symbol @%d\n", Ordinal);
1645 }
1646
1647 return STATUS_PROCEDURE_NOT_FOUND;
1648 }
1649
1650
1651 NTSTATUS STDCALL
1652 LdrShutdownProcess (VOID)
1653 {
1654 PLIST_ENTRY ModuleListHead;
1655 PLIST_ENTRY Entry;
1656 PLDR_MODULE Module;
1657
1658 DPRINT("LdrShutdownProcess() called\n");
1659
1660 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1661
1662 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1663 Entry = ModuleListHead->Blink;
1664
1665 while (Entry != ModuleListHead)
1666 {
1667 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1668
1669 DPRINT(" Unloading %wZ\n",
1670 &Module->BaseDllName);
1671
1672 if (Module->EntryPoint != 0)
1673 {
1674 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1675
1676 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1677 Entrypoint (Module->BaseAddress,
1678 DLL_PROCESS_DETACH,
1679 NULL);
1680 }
1681
1682 Entry = Entry->Blink;
1683 }
1684
1685 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1686
1687 DPRINT("LdrShutdownProcess() done\n");
1688
1689 return STATUS_SUCCESS;
1690 }
1691
1692
1693 NTSTATUS STDCALL
1694 LdrShutdownThread (VOID)
1695 {
1696 PLIST_ENTRY ModuleListHead;
1697 PLIST_ENTRY Entry;
1698 PLDR_MODULE Module;
1699
1700 DPRINT("LdrShutdownThread() called\n");
1701
1702 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
1703
1704 ModuleListHead = &NtCurrentPeb()->Ldr->InInitializationOrderModuleList;
1705 Entry = ModuleListHead->Blink;
1706
1707 while (Entry != ModuleListHead)
1708 {
1709 Module = CONTAINING_RECORD(Entry, LDR_MODULE, InInitializationOrderModuleList);
1710
1711 DPRINT(" Unloading %wZ\n",
1712 &Module->BaseDllName);
1713
1714 if (Module->EntryPoint != 0)
1715 {
1716 PDLLMAIN_FUNC Entrypoint = (PDLLMAIN_FUNC)Module->EntryPoint;
1717
1718 DPRINT("Calling entry point at 0x%08x\n", Entrypoint);
1719 Entrypoint (Module->BaseAddress,
1720 DLL_THREAD_DETACH,
1721 NULL);
1722 }
1723
1724 Entry = Entry->Blink;
1725 }
1726
1727 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
1728
1729 DPRINT("LdrShutdownThread() done\n");
1730
1731 return STATUS_SUCCESS;
1732 }
1733
1734 /* EOF */