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