test: ldrapi.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# ldrapi.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     ldrapi.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the Ldr APIs that can be linked with
    00012     an application to perform loader services. All of the APIs in
    00013     this component are implemented in a DLL. They are not part of the
    00014     DLL snap procedure.
    00015
    00016 Author:
    00017
    00018     Mike O'Leary (mikeol) 23-Mar-1990
    00019
    00020 Revision History:
    00021
    00022 --*/
    00023
    00024 #include "ldrp.h"
    00025
    00026 #define DLLEXTENSION ((PWSTR)".\0d\0l\0l\0\0")    // .dll
    00027
    00028
    00029 ULONG
    00030 LdrpClearLoadInProgress(
    00031     VOID
    00032     );
    00033
    00034 NTSTATUS
    00035 LdrLoadDll (
    00036     IN PWSTR DllPath OPTIONAL,
    00037     IN PULONG DllCharacteristics OPTIONAL,
    00038     IN PUNICODE_STRING DllName,
    00039     OUT PVOID *DllHandle
    00040     )
    00041
    00042 /*++
    00043
    00044 Routine Description:
    00045
    00046     This function loads a DLL into the calling process address space.
    00047
    00048 Arguments:
    00049
    00050     DllPath - Supplies the search path to be used to locate the DLL.
    00051
    00052     DllCharacteristics - Supplies an optional DLL characteristics flag,
    00053         that if specified is used to match against the dll being loaded.
    00054
    00055     DllName - Supplies the name of the DLL to load.
    00056
    00057     DllHandle - Returns a handle to the loaded DLL.
    00058
    00059 Return Value:
    00060
    00061     TBD
    00062
    00063 --*/
    00064 {
    00065     return LdrpLoadDll(DllPath,DllCharacteristics,DllName,DllHandle,TRUE);
    00066 }
    00067
    00068 NTSTATUS
    00069 NTAPI
    00070 LdrpLoadDll(
    00071     IN PWSTR DllPath OPTIONAL,
    00072     IN PULONG DllCharacteristics OPTIONAL,
    00073     IN PUNICODE_STRING DllName,
    00074     OUT PVOID *DllHandle,
    00075     IN BOOLEAN RunInitRoutines
    00076     )
    00077
    00078 {
    00079     PPEB Peb;
    00080     PTEB Teb;
    00081     NTSTATUS st;
    00082     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    00083     PWSTR ActualDllName;
    00084     PWCH p, pp;
    00085     UNICODE_STRING ActualDllNameStr;
    00086     BOOLEAN Wx86KnownDll = FALSE;
    00087     WCHAR FreeBuffer[266];
    00088
    00089     Peb = NtCurrentPeb();
    00090     Teb = NtCurrentTeb();
    00091
    00092     st = STATUS_SUCCESS;
    00093
    00094     try {
    00095
    00096         //
    00097         // Grab Peb lock and Snap All Links to specified DLL
    00098         //
    00099
    00100         if ( LdrpInLdrInit == FALSE ) {
    00101             RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00102             }
    00103
    00104
    00105
    00106 #if defined (WX86)
    00107
    00108         if (Teb->Wx86Thread.UseKnownWx86Dll) {
    00109             Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll;
    00110             Teb->Wx86Thread.UseKnownWx86Dll = FALSE;
    00111             }
    00112 #endif
    00113
    00114
    00115
    00116         p = DllName->Buffer;
    00117         pp = NULL;
    00118         while (*p) {
    00119             if (*p++ == (WCHAR)'.') {
    00120                 //
    00121                 // pp will point to first character after last '.'
    00122                 //
    00123                 pp = p;
    00124                 }
    00125             }
    00126
    00127
    00128         ActualDllName = FreeBuffer;
    00129         if ( DllName->Length >= sizeof(FreeBuffer)) {
    00130             return STATUS_NAME_TOO_LONG;
    00131             }
    00132         RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length);
    00133
    00134
    00135         if (!pp || *pp == (WCHAR)'\\') {
    00136             //
    00137             // No extension found (just ..\)
    00138             //
    00139             if ( DllName->Length+10 >= sizeof(FreeBuffer) ) {
    00140                 return STATUS_NAME_TOO_LONG;
    00141                 }
    00142
    00143             RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10);
    00144             }
    00145         else {
    00146             ActualDllName[DllName->Length >> 1] = UNICODE_NULL;
    00147             }
    00148
    00149         if (ShowSnaps) {
    00150             DbgPrint("LDR: LdrLoadDll, loading %ws from %ws\n",
    00151                      ActualDllName,
    00152                      ARGUMENT_PRESENT(DllPath) ? DllPath : L""
    00153                      );
    00154             }
    00155
    00156
    00157         RtlInitUnicodeString(&ActualDllNameStr,ActualDllName);
    00158         ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);
    00159
    00160         if (!LdrpCheckForLoadedDll( DllPath,
    00161                                     &ActualDllNameStr,
    00162                                     FALSE,
    00163                                     Wx86KnownDll,
    00164                                     &LdrDataTableEntry
    00165                                   )
    00166            ) {
    00167             st = LdrpMapDll(DllPath,
    00168                             ActualDllName,
    00169                             DllCharacteristics,
    00170                             FALSE,
    00171                             Wx86KnownDll,
    00172                             &LdrDataTableEntry
    00173                             );
    00174
    00175             if (!NT_SUCCESS(st)) {
    00176                 return st;
    00177                 }
    00178
    00179             if (ARGUMENT_PRESENT( DllCharacteristics ) &&
    00180                 *DllCharacteristics & IMAGE_FILE_EXECUTABLE_IMAGE
    00181                ) {
    00182                 LdrDataTableEntry->EntryPoint = 0;
    00183                 LdrDataTableEntry->Flags &= ~LDRP_IMAGE_DLL;
    00184                 }
    00185
    00186             //
    00187             // and walk the import descriptor.
    00188             //
    00189
    00190             if (LdrDataTableEntry->Flags & LDRP_IMAGE_DLL) {
    00191
    00192                 try {
    00193                     st = LdrpWalkImportDescriptor(
    00194                               DllPath,
    00195                               LdrDataTableEntry
    00196                               );
    00197                     }
    00198                 except(EXCEPTION_EXECUTE_HANDLER) {
    00199                     st = GetExceptionCode();
    00200                     }
    00201                 if ( LdrDataTableEntry->LoadCount != 0xffff ) {
    00202                     LdrDataTableEntry->LoadCount++;
    00203                     }
    00204                 LdrpReferenceLoadedDll(LdrDataTableEntry);
    00205                 if (!NT_SUCCESS(st)) {
    00206                     LdrDataTableEntry->EntryPoint = NULL;
    00207                     InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
    00208                            &LdrDataTableEntry->InInitializationOrderLinks);
    00209                     LdrpClearLoadInProgress();
    00210                     LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
    00211                     return st;
    00212                     }
    00213                 }
    00214             else {
    00215                 if ( LdrDataTableEntry->LoadCount != 0xffff ) {
    00216                     LdrDataTableEntry->LoadCount++;
    00217                     }
    00218                 }
    00219
    00220             //
    00221             // Add init routine to list
    00222             //
    00223
    00224             InsertTailList(&NtCurrentPeb()->Ldr->InInitializationOrderModuleList,
    00225                            &LdrDataTableEntry->InInitializationOrderLinks);
    00226
    00227
    00228             //
    00229             // If the loader data base is not fully setup, this load was because
    00230             // of a forwarder in the static load set. Can't run init routines
    00231             // yet because the load counts are NOT set
    00232             //
    00233
    00234             if ( RunInitRoutines && LdrpLdrDatabaseIsSetup ) {
    00235
    00236                 try {
    00237                     st = LdrpRunInitializeRoutines(NULL);
    00238                     if ( !NT_SUCCESS(st) ) {
    00239                         LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
    00240                         }
    00241                     }
    00242                 except( EXCEPTION_EXECUTE_HANDLER ) {
    00243                     LdrUnloadDll((PVOID)LdrDataTableEntry->DllBase);
    00244                     return GetExceptionCode();
    00245                     }
    00246                 }
    00247             else {
    00248                 st = STATUS_SUCCESS;
    00249                 }
    00250
    00251             }
    00252         else {
    00253
    00254             //
    00255             // Count it. And everything that it imports.
    00256             //
    00257
    00258             if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL &&
    00259                  LdrDataTableEntry->LoadCount != 0xffff  ) {
    00260
    00261                 LdrDataTableEntry->LoadCount++;
    00262
    00263                 LdrpReferenceLoadedDll(LdrDataTableEntry);
    00264
    00265                 //
    00266                 // Now clear the Load in progress bits
    00267                 //
    00268
    00269                 LdrpClearLoadInProgress();
    00270
    00271                 }
    00272             else {
    00273                 if ( LdrDataTableEntry->LoadCount != 0xffff ) {
    00274                     LdrDataTableEntry->LoadCount++;
    00275                     }
    00276                 }
    00277             }
    00278         }
    00279     finally {
    00280         if ( LdrpInLdrInit == FALSE ) {
    00281             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00282             }
    00283
    00284         }
    00285     if ( NT_SUCCESS(st) ) {
    00286         *DllHandle = (PVOID)LdrDataTableEntry->DllBase;
    00287         }
    00288     else {
    00289         *DllHandle = NULL;
    00290         }
    00291     return st;
    00292 }
    00293
    00294 NTSTATUS
    00295 LdrGetDllHandle (
    00296     IN PWSTR DllPath OPTIONAL,
    00297     IN PULONG DllCharacteristics OPTIONAL,
    00298     IN PUNICODE_STRING DllName,
    00299     OUT PVOID *DllHandle
    00300     )
    00301
    00302 /*++
    00303
    00304 Routine Description:
    00305
    00306     This function locates the specified DLL and returns its handle.
    00307
    00308 Arguments:
    00309
    00310     DllPath - Supplies the search path to be used to locate the DLL.
    00311
    00312     DllCharacteristics - Supplies an optional DLL characteristics flag,
    00313         that if specified is used to match against the dll being loaded.
    00314
    00315     DllName - Supplies the name of the DLL to load.
    00316
    00317     DllHandle - Returns a handle to the loaded DLL.
    00318
    00319 Return Value:
    00320
    00321     TBD
    00322
    00323 --*/
    00324
    00325 {
    00326     NTSTATUS st;
    00327     PPEB Peb;
    00328     PTEB Teb;
    00329     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    00330     PWSTR ActualDllName;
    00331     PWCH p, pp;
    00332     UNICODE_STRING ActualDllNameStr;
    00333     BOOLEAN Wx86KnownDll = FALSE;
    00334     WCHAR FreeBuffer[266];
    00335
    00336
    00337     DllCharacteristics;
    00338
    00339     Peb = NtCurrentPeb();
    00340     Teb = NtCurrentTeb();
    00341
    00342     st = STATUS_DLL_NOT_FOUND;
    00343
    00344     try {
    00345
    00346           //
    00347           // Grab Peb lock
    00348           //
    00349
    00350           if ( LdrpInLdrInit == FALSE ) {
    00351             RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00352             }
    00353
    00354 #if defined (WX86)
    00355
    00356
    00357           if (Teb->Wx86Thread.UseKnownWx86Dll) {
    00358               Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll;
    00359               Teb->Wx86Thread.UseKnownWx86Dll = FALSE;
    00360               }
    00361
    00362            //
    00363            //  No module handle cache lookup for Wx86,
    00364            //  (relies on unique basename)
    00365            //
    00366            if (Wx86ProcessInit) {
    00367                LdrpGetModuleHandleCache = NULL;
    00368                }
    00369
    00370 #endif
    00371
    00372
    00373           if ( LdrpGetModuleHandleCache ) {
    00374               if (RtlEqualUnicodeString(DllName,
    00375                           &LdrpGetModuleHandleCache->BaseDllName,
    00376                           TRUE
    00377                           )) {
    00378                   *DllHandle = (PVOID)LdrpGetModuleHandleCache->DllBase;
    00379                   st = STATUS_SUCCESS;
    00380                   leave;
    00381                   }
    00382               }
    00383
    00384
    00385
    00386           p = DllName->Buffer;
    00387           pp = NULL;
    00388           while (*p) {
    00389              if (*p++ == (WCHAR)'.') {
    00390                  //
    00391                  // pp will point to first character after last '.'
    00392                  //
    00393                  pp = p;
    00394              }
    00395           }
    00396
    00397           ActualDllName = FreeBuffer;
    00398           if ( DllName->Length >= sizeof(FreeBuffer)) {
    00399               return STATUS_NAME_TOO_LONG;
    00400               }
    00401           RtlMoveMemory(ActualDllName, DllName->Buffer, DllName->Length);
    00402
    00403           if (!pp || *pp == (WCHAR)'\\') {
    00404               //
    00405               // No extension found (just ..\)
    00406               //
    00407               if ( DllName->Length+10 >= sizeof(FreeBuffer) ) {
    00408                   return STATUS_NAME_TOO_LONG;
    00409                   }
    00410
    00411               RtlMoveMemory((PCHAR)ActualDllName+DllName->Length, DLLEXTENSION, 10);
    00412               }
    00413
    00414           else {
    00415
    00416               //
    00417               // see if the name ends in . If it does, trim out the trailing
    00418               // .
    00419               //
    00420
    00421               if ( ActualDllName[ (DllName->Length-2) >> 1] == L'.' ) {
    00422                  DllName->Length -= 2;
    00423                  }
    00424
    00425               ActualDllName[DllName->Length >> 1] = UNICODE_NULL;
    00426               }
    00427
    00428
    00429
    00430           //
    00431           // Check the LdrTable to see if Dll has already been loaded
    00432           // into this image.
    00433           //
    00434
    00435           RtlInitUnicodeString(&ActualDllNameStr,ActualDllName);
    00436           ActualDllNameStr.MaximumLength = sizeof(FreeBuffer);
    00437
    00438           if (ShowSnaps) {
    00439               DbgPrint("LDR: LdrGetDllHandle, searching for %ws from %ws\n",
    00440                        ActualDllName,
    00441                        ARGUMENT_PRESENT(DllPath) ? (DllPath == (PWSTR)1 ? L"" : DllPath) : L""
    00442                        );
    00443           }
    00444
    00445
    00446           //
    00447           // sort of a hack, but done to speed up GetModuleHandle. kernel32
    00448           // now does a two pass call here to avoid computing
    00449           // process dll path
    00450           //
    00451
    00452
    00453           if (LdrpCheckForLoadedDll( DllPath,
    00454                                      &ActualDllNameStr,
    00455                                      (BOOLEAN)(DllPath == (PWSTR)1 ? TRUE : FALSE),
    00456                                      Wx86KnownDll,
    00457                                      &LdrDataTableEntry
    00458                                    )
    00459              ) {
    00460               *DllHandle = (PVOID)LdrDataTableEntry->DllBase;
    00461               LdrpGetModuleHandleCache = LdrDataTableEntry;
    00462               st = STATUS_SUCCESS;
    00463
    00464           }
    00465         } finally {
    00466                     if ( LdrpInLdrInit == FALSE ) {
    00467                         RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00468                         }
    00469                   }
    00470     return st;
    00471 }
    00472
    00473 NTSTATUS
    00474 LdrDisableThreadCalloutsForDll (
    00475     IN PVOID DllHandle
    00476     )
    00477
    00478 /*++
    00479
    00480 Routine Description:
    00481
    00482     This function disables thread attach and detach notification
    00483     for the specified DLL.
    00484
    00485 Arguments:
    00486
    00487     DllHandle - Supplies a handle to the DLL to disable.
    00488
    00489 Return Value:
    00490
    00491     TBD
    00492
    00493 --*/
    00494
    00495 {
    00496     NTSTATUS st;
    00497     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    00498
    00499     st = STATUS_SUCCESS;
    00500
    00501     try {
    00502
    00503         if ( LdrpInLdrInit == FALSE ) {
    00504             RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00505             }
    00506         if ( LdrpShutdownInProgress ) {
    00507             return STATUS_SUCCESS;
    00508             }
    00509
    00510         if (LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
    00511             if ( LdrDataTableEntry->TlsIndex ) {
    00512                 st = STATUS_DLL_NOT_FOUND;
    00513                 }
    00514             else {
    00515                 LdrDataTableEntry->Flags |= LDRP_DONT_CALL_FOR_THREADS;
    00516                 }
    00517             }
    00518         }
    00519     finally {
    00520         if ( LdrpInLdrInit == FALSE ) {
    00521             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00522             }
    00523         }
    00524     return st;
    00525 }
    00526
    00527 NTSTATUS
    00528 LdrUnloadDll (
    00529     IN PVOID DllHandle
    00530     )
    00531
    00532 /*++
    00533
    00534 Routine Description:
    00535
    00536     This function unloads the DLL from the specified process
    00537
    00538 Arguments:
    00539
    00540     DllHandle - Supplies a handle to the DLL to unload.
    00541
    00542 Return Value:
    00543
    00544     TBD
    00545
    00546 --*/
    00547
    00548 {
    00549     NTSTATUS st;
    00550     PPEB Peb;
    00551     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    00552     PLDR_DATA_TABLE_ENTRY Entry;
    00553     PDLL_INIT_ROUTINE InitRoutine;
    00554     LIST_ENTRY LocalUnloadHead;
    00555     PLIST_ENTRY Next;
    00556 #if defined (WX86)
    00557     PVOID Wx86Plugin = NULL;
    00558 #endif
    00559
    00560     Peb = NtCurrentPeb();
    00561     st = STATUS_SUCCESS;
    00562
    00563     try {
    00564
    00565         //
    00566         // Grab Peb lock and decrement reference count of all affected DLLs
    00567         //
    00568
    00569
    00570         if ( LdrpInLdrInit == FALSE ) {
    00571             RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00572             }
    00573
    00574         LdrpActiveUnloadCount++;
    00575
    00576         if ( LdrpShutdownInProgress ) {
    00577             goto leave_finally;
    00578             }
    00579
    00580         if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
    00581             st = STATUS_DLL_NOT_FOUND;
    00582             goto leave_finally;
    00583         }
    00584
    00585         //
    00586         // Now that we have the data table entry, unload it
    00587         //
    00588
    00589         if ( LdrDataTableEntry->LoadCount != 0xffff ) {
    00590             LdrDataTableEntry->LoadCount--;
    00591             if ( LdrDataTableEntry->Flags & LDRP_IMAGE_DLL ) {
    00592                 LdrpDereferenceLoadedDll(LdrDataTableEntry);
    00593                 }
    00594         } else {
    00595
    00596             //
    00597             // if the load count is 0xffff, then we do not need to recurse
    00598             // through this DLL's import table.
    00599             //
    00600             // Additionally, we don't have to scan more LoadCount == 0
    00601             // modules since nothing could have happened as a result of a free on this
    00602             // DLL.
    00603
    00604             goto leave_finally;
    00605         }
    00606
    00607         //
    00608         // Now process init routines and then in a second pass, unload
    00609         // DLLs
    00610         //
    00611
    00612         if (ShowSnaps) {
    00613             DbgPrint("LDR: UNINIT LIST\n");
    00614         }
    00615
    00616         if (LdrpActiveUnloadCount == 1 ) {
    00617             InitializeListHead(&LdrpUnloadHead);
    00618             }
    00619
    00620         //
    00621         // Go in reverse order initialization order and build
    00622         // the unload list
    00623         //
    00624
    00625         Next = Peb->Ldr->InInitializationOrderModuleList.Blink;
    00626         while ( Next != &Peb->Ldr->InInitializationOrderModuleList) {
    00627             LdrDataTableEntry
    00628                 = (PLDR_DATA_TABLE_ENTRY)
    00629                   (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,InInitializationOrderLinks));
    00630
    00631             Next = Next->Blink;
    00632             LdrDataTableEntry->Flags &= ~LDRP_UNLOAD_IN_PROGRESS;
    00633
    00634             if (LdrDataTableEntry->LoadCount == 0) {
    00635
    00636                 if (ShowSnaps) {
    00637                       DbgPrint("          (%d) [%ws] %ws (%lx) deinit %lx\n",
    00638                               LdrpActiveUnloadCount,
    00639                               LdrDataTableEntry->BaseDllName.Buffer,
    00640                               LdrDataTableEntry->FullDllName.Buffer,
    00641                               (ULONG)LdrDataTableEntry->LoadCount,
    00642                               LdrDataTableEntry->EntryPoint
    00643                               );
    00644                 }
    00645
    00646                 Entry = LdrDataTableEntry;
    00647
    00648                 RemoveEntryList(&Entry->InInitializationOrderLinks);
    00649                 RemoveEntryList(&Entry->InMemoryOrderLinks);
    00650                 RemoveEntryList(&Entry->HashLinks);
    00651
    00652                 if ( LdrpActiveUnloadCount > 1 ) {
    00653                     LdrpLoadedDllHandleCache = NULL;
    00654                     Entry->InMemoryOrderLinks.Flink = NULL;
    00655                     }
    00656                 InsertTailList(&LdrpUnloadHead,&Entry->HashLinks);
    00657             }
    00658         }
    00659         //
    00660         // End of new code
    00661         //
    00662
    00663         //
    00664         // We only do init routine call's and module free's at the top level,
    00665         // so if the active count is > 1, just return
    00666         //
    00667
    00668         if (LdrpActiveUnloadCount > 1 ) {
    00669             goto leave_finally;
    00670             }
    00671
    00672         //
    00673         // Now that the unload list is built, walk through the unload
    00674         // list in order and call the init routine. The dll must remain
    00675         // on the InLoadOrderLinks so that the pctoheader stuff will
    00676         // still work
    00677         //
    00678
    00679         InitializeListHead(&LocalUnloadHead);
    00680         Entry = NULL;
    00681         Next = LdrpUnloadHead.Flink;
    00682         while ( Next != &LdrpUnloadHead ) {
    00683 top:
    00684             if ( Entry ) {
    00685                 RemoveEntryList(&(Entry->InLoadOrderLinks));
    00686                 Entry = NULL;
    00687                 Next = LdrpUnloadHead.Flink;
    00688                 if (Next == &LdrpUnloadHead ) {
    00689                     goto bottom;
    00690                     }
    00691             }
    00692             LdrDataTableEntry
    00693                 = (PLDR_DATA_TABLE_ENTRY)
    00694                   (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
    00695
    00696             //
    00697             // Remove dll from the global unload list and place
    00698             // on the local unload list. This is because the global list
    00699             // can change during the callout to the init routine
    00700             //
    00701
    00702             Entry = LdrDataTableEntry;
    00703             LdrpLoadedDllHandleCache = NULL;
    00704             Entry->InMemoryOrderLinks.Flink = NULL;
    00705
    00706             RemoveEntryList(&Entry->HashLinks);
    00707             InsertTailList(&LocalUnloadHead,&Entry->HashLinks);
    00708
    00709             //
    00710             // If the function has an init routine, call it.
    00711             //
    00712
    00713             InitRoutine = (PDLL_INIT_ROUTINE)LdrDataTableEntry->EntryPoint;
    00714
    00715 #if defined (WX86)
    00716             if (Wx86ProcessInit) {
    00717                 try {
    00718                    LdrpWx86DllProcessDetach(LdrDataTableEntry);
    00719                    RemoveEntryList(&Entry->InLoadOrderLinks);
    00720                    Entry = NULL;
    00721                    Next = LdrpUnloadHead.Flink;
    00722                    }
    00723                 except(EXCEPTION_EXECUTE_HANDLER){
    00724                     goto top;
    00725                     }
    00726                 }
    00727             else
    00728 #endif
    00729             if (InitRoutine && (LdrDataTableEntry->Flags & LDRP_PROCESS_ATTACH_CALLED) ) {
    00730                 try {
    00731                     if (ShowSnaps) {
    00732                         DbgPrint("LDR: Calling deinit %lx\n",InitRoutine);
    00733                         }
    00734
    00735                     LdrpCallInitRoutine(InitRoutine,
    00736                                         LdrDataTableEntry->DllBase,
    00737                                         DLL_PROCESS_DETACH,
    00738                                         NULL);
    00739
    00740                     RemoveEntryList(&Entry->InLoadOrderLinks);
    00741                     Entry = NULL;
    00742                     Next = LdrpUnloadHead.Flink;
    00743                     }
    00744                 except(EXCEPTION_EXECUTE_HANDLER){
    00745                     goto top;
    00746                     }
    00747             } else {
    00748                 RemoveEntryList(&(Entry->InLoadOrderLinks));
    00749                 Entry = NULL;
    00750                 Next = LdrpUnloadHead.Flink;
    00751             }
    00752         }
    00753 bottom:
    00754
    00755 #if defined (WX86)
    00756         if (Wx86ProcessInit) {
    00757
    00758             //
    00759             // Notify Wx86 that the modules are about to be unmapped.  This
    00760             // must be done in a separate pass from the unmap loop, as wx86.dll
    00761             // might be in the list of modules to unmap.
    00762             //
    00763             Next = LocalUnloadHead.Flink;
    00764             while ( Next != &LocalUnloadHead ) {
    00765                 LdrDataTableEntry
    00766                     = (PLDR_DATA_TABLE_ENTRY)
    00767                       (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
    00768
    00769                 Next = Next->Flink;
    00770
    00771                 LdrpWx86DllMapNotify(LdrDataTableEntry->DllBase, FALSE);
    00772
    00773                 // Remember if we are unloading a plugin dll
    00774
    00775                 if ((LdrDataTableEntry->DllBase == DllHandle) &&
    00776                     (LdrDataTableEntry->Flags & LDRP_WX86_PLUGIN)) {
    00777                         Wx86Plugin = DllHandle;
    00778                 }
    00779             }
    00780         }
    00781 #endif
    00782
    00783         //
    00784         // Now, go through the modules and unmap them
    00785         //
    00786
    00787         Next = LocalUnloadHead.Flink;
    00788         while ( Next != &LocalUnloadHead ) {
    00789             LdrDataTableEntry
    00790                 = (PLDR_DATA_TABLE_ENTRY)
    00791                   (CONTAINING_RECORD(Next,LDR_DATA_TABLE_ENTRY,HashLinks));
    00792
    00793             Next = Next->Flink;
    00794             Entry = LdrDataTableEntry;
    00795
    00796             if (ShowSnaps) {
    00797                   DbgPrint("LDR: Unmapping [%ws]\n",
    00798                           LdrDataTableEntry->BaseDllName.Buffer
    00799                           );
    00800                 }
    00801             st = NtUnmapViewOfSection(NtCurrentProcess(),Entry->DllBase);
    00802             ASSERT(NT_SUCCESS(st));
    00803
    00804             LdrUnloadAlternateResourceModule(Entry->DllBase);
    00805
    00806             if (Entry->FullDllName.Buffer) {
    00807                 RtlFreeUnicodeString(&Entry->FullDllName);
    00808                 }
    00809             if (Entry->BaseDllName.Buffer) {
    00810                 RtlFreeUnicodeString(&Entry->BaseDllName);
    00811                 }
    00812
    00813             if ( Entry == LdrpGetModuleHandleCache ) {
    00814                 LdrpGetModuleHandleCache = NULL;
    00815                 }
    00816
    00817             RtlFreeHeap(Peb->ProcessHeap, 0,Entry);
    00818             }
    00819
    00820 leave_finally:;
    00821         }
    00822     finally {
    00823         LdrpActiveUnloadCount--;
    00824         if ( LdrpInLdrInit == FALSE ) {
    00825
    00826 #if defined (WX86)
    00827             if (Wx86ProcessInit && Wx86Plugin) {
    00828                 Wx86UnloadProviders( Wx86Plugin );
    00829             }
    00830 #endif
    00831             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00832             }
    00833         }
    00834     return st;
    00835 }
    00836
    00837 NTSTATUS
    00838 LdrGetProcedureAddress (
    00839     IN PVOID DllHandle,
    00840     IN PANSI_STRING ProcedureName OPTIONAL,
    00841     IN ULONG ProcedureNumber OPTIONAL,
    00842     OUT PVOID *ProcedureAddress
    00843     )
    00844 {
    00845
    00846     return LdrpGetProcedureAddress(DllHandle,ProcedureName,ProcedureNumber,ProcedureAddress,TRUE);
    00847
    00848 }
    00849
    00850 NTSTATUS
    00851 LdrpGetProcedureAddress (
    00852     IN PVOID DllHandle,
    00853     IN PANSI_STRING ProcedureName OPTIONAL,
    00854     IN ULONG ProcedureNumber OPTIONAL,
    00855     OUT PVOID *ProcedureAddress,
    00856     IN BOOLEAN RunInitRoutines
    00857     )
    00858
    00859 /*++
    00860
    00861 Routine Description:
    00862
    00863     This function locates the address of the specified procedure in the
    00864     specified DLL and returns its address.
    00865
    00866 Arguments:
    00867
    00868     DllHandle - Supplies a handle to the DLL that the address is being
    00869         looked up in.
    00870
    00871     ProcedureName - Supplies that address of a string that contains the
    00872         name of the procedure to lookup in the DLL.  If this argument is
    00873         not specified, then the ProcedureNumber is used.
    00874
    00875     ProcedureNumber - Supplies the procedure number to lookup.  If
    00876         ProcedureName is specified, then this argument is ignored.
    00877         Otherwise, it specifies the procedure ordinal number to locate
    00878         in the DLL.
    00879
    00880     ProcedureAddress - Returns the address of the procedure found in
    00881         the DLL.
    00882
    00883 Return Value:
    00884
    00885     TBD
    00886
    00887 --*/
    00888
    00889 {
    00890     NTSTATUS st;
    00891     UCHAR FunctionNameBuffer[64];
    00892     PUCHAR src, dst;
    00893     ULONG cb, ExportSize;
    00894     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    00895     IMAGE_THUNK_DATA Thunk;
    00896     PVOID ImageBase;
    00897     PIMAGE_IMPORT_BY_NAME FunctionName;
    00898     PIMAGE_EXPORT_DIRECTORY ExportDirectory;
    00899     PLIST_ENTRY Next;
    00900 #if defined (WX86)
    00901     PTEB Teb;
    00902     BOOLEAN Wx86KnownDll = FALSE;
    00903 #endif
    00904
    00905     if (ShowSnaps) {
    00906         DbgPrint("LDR: LdrGetProcedureAddress by ");
    00907     }
    00908
    00909 #if defined (WX86)
    00910     Teb = NtCurrentTeb();
    00911     if (Teb->Wx86Thread.UseKnownWx86Dll) {
    00912         Wx86KnownDll = Teb->Wx86Thread.UseKnownWx86Dll;
    00913         Teb->Wx86Thread.UseKnownWx86Dll = FALSE;
    00914         }
    00915 #endif
    00916
    00917     FunctionName = NULL;
    00918     if ( ARGUMENT_PRESENT(ProcedureName) ) {
    00919
    00920         if (ShowSnaps) {
    00921             DbgPrint("NAME - %s\n", ProcedureName->Buffer);
    00922         }
    00923
    00924         //
    00925         // BUGBUG need STRING to PSZ
    00926         //
    00927
    00928
    00929         if (ProcedureName->Length >= sizeof( FunctionNameBuffer )-1 ) {
    00930             FunctionName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TEMP_TAG ),ProcedureName->Length+1+sizeof(USHORT));
    00931             if ( !FunctionName ) {
    00932                 return STATUS_INVALID_PARAMETER;
    00933                 }
    00934         } else {
    00935             FunctionName = (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer;
    00936         }
    00937
    00938         FunctionName->Hint = 0;
    00939
    00940         cb = ProcedureName->Length;
    00941         src = ProcedureName->Buffer;
    00942         dst = FunctionName->Name;
    00943
    00944         while (cb--) {
    00945             *dst++ = *src++;
    00946         }
    00947         *dst = '\0';
    00948
    00949         //
    00950         // Make sure we don't pass in address with high bit set so we
    00951         // can still use it as ordinal flag
    00952         //
    00953
    00954         ImageBase = FunctionName;
    00955         Thunk.u1.AddressOfData = 0;
    00956
    00957     } else {
    00958             ImageBase = NULL;
    00959              if (ShowSnaps) {
    00960                  DbgPrint("ORDINAL - %lx\n", ProcedureNumber);
    00961              }
    00962
    00963              if (ProcedureNumber) {
    00964                  Thunk.u1.Ordinal = ProcedureNumber | IMAGE_ORDINAL_FLAG;
    00965              } else {
    00966                       return STATUS_INVALID_PARAMETER;
    00967                     }
    00968           }
    00969
    00970     if ( LdrpInLdrInit == FALSE ) {
    00971         RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    00972         }
    00973     try {
    00974
    00975         if (!LdrpCheckForLoadedDllHandle(DllHandle, &LdrDataTableEntry)) {
    00976             st = STATUS_DLL_NOT_FOUND;
    00977             return st;
    00978         }
    00979
    00980         ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
    00981                            LdrDataTableEntry->DllBase,
    00982                            TRUE,
    00983                            IMAGE_DIRECTORY_ENTRY_EXPORT,
    00984                            &ExportSize
    00985                            );
    00986
    00987         if (!ExportDirectory) {
    00988             return STATUS_PROCEDURE_NOT_FOUND;
    00989         }
    00990
    00991         st = LdrpSnapThunk(LdrDataTableEntry->DllBase,
    00992                            ImageBase,
    00993                            &Thunk,
    00994                            &Thunk,
    00995                            ExportDirectory,
    00996                            ExportSize,
    00997                            FALSE,
    00998                            NULL
    00999                           );
    01000
    01001         if ( RunInitRoutines ) {
    01002             PLDR_DATA_TABLE_ENTRY LdrInitEntry;
    01003
    01004             //
    01005             // Look at last entry in init order list. If entry processed
    01006             // flag is not set, then a forwarded dll was loaded during the
    01007             // getprocaddr call and we need to run init routines
    01008             //
    01009
    01010             Next = NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Blink;
    01011             LdrInitEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
    01012             if ( !(LdrInitEntry->Flags & LDRP_ENTRY_PROCESSED) ) {
    01013                 try {
    01014                     st = LdrpRunInitializeRoutines(NULL);
    01015                     }
    01016                 except( EXCEPTION_EXECUTE_HANDLER ) {
    01017                     st = GetExceptionCode();
    01018                     }
    01019
    01020                 }
    01021             }
    01022
    01023         if ( NT_SUCCESS(st) ) {
    01024             *ProcedureAddress = (PVOID)Thunk.u1.Function;
    01025 #if defined (WX86)
    01026             // For dlls loaded as a Wx86 plugin ...
    01027
    01028             if (Wx86ProcessInit && (LdrDataTableEntry->Flags & LDRP_WX86_PLUGIN)) {
    01029                 PVOID ExportThunk = NULL;
    01030                 USHORT MachineType = RtlImageNtHeader(LdrDataTableEntry->DllBase)->FileHeader.Machine;
    01031
    01032                 // and the GetProcAddress call is cross-architecture ...
    01033
    01034                 if ((!Wx86KnownDll && (MachineType == IMAGE_FILE_MACHINE_I386))
    01035                   || (Wx86KnownDll && (MachineType != IMAGE_FILE_MACHINE_I386))) {
    01036
    01037                     // Thunk the export
    01038
    01039                     st = Wx86ThunkPluginExport(LdrDataTableEntry->DllBase,
    01040                                                FunctionName? FunctionName->Name : NULL,
    01041                                                ProcedureNumber,
    01042                                                (PVOID)(Thunk.u1.Function),
    01043                                                &ExportThunk
    01044                                                );
    01045                     if (NT_SUCCESS(st) && ExportThunk) {
    01046                         *ProcedureAddress = ExportThunk;
    01047                     } else {
    01048                         // Don't let unthunked cross-architecture addresses get out
    01049                         *ProcedureAddress = NULL;
    01050                         st = STATUS_INVALID_IMAGE_FORMAT;
    01051                         }
    01052                     }
    01053                 }
    01054 #endif
    01055             }
    01056     } finally {
    01057         if ( FunctionName && (FunctionName != (PIMAGE_IMPORT_BY_NAME) FunctionNameBuffer) ) {
    01058             RtlFreeHeap(RtlProcessHeap(),0,FunctionName);
    01059             }
    01060         if ( LdrpInLdrInit == FALSE ) {
    01061             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    01062             }
    01063     }
    01064     return st;
    01065 }
    01066
    01067 NTSTATUS
    01068 NTAPI
    01069 LdrVerifyImageMatchesChecksum (
    01070     IN HANDLE ImageFileHandle,
    01071     IN PLDR_IMPORT_MODULE_CALLBACK ImportCallbackRoutine OPTIONAL,
    01072     IN PVOID ImportCallbackParameter,
    01073     OUT PUSHORT ImageCharacteristics OPTIONAL
    01074     )
    01075 {
    01076
    01077     NTSTATUS Status;
    01078     HANDLE Section;
    01079     PVOID ViewBase;
    01080     SIZE_T ViewSize;
    01081     IO_STATUS_BLOCK IoStatusBlock;
    01082     FILE_STANDARD_INFORMATION StandardInfo;
    01083     PIMAGE_SECTION_HEADER LastRvaSection;
    01084     BOOLEAN b;
    01085     BOOLEAN JustDoSideEffects;
    01086
    01087     //
    01088     // stevewo added all sorts of side effects to this API. We want to stop
    01089     // doing checksums for known dll's, but really want the sideeffects
    01090     // (ImageCharacteristics write, and Import descriptor walk).
    01091     //
    01092
    01093     if ( (UINT_PTR) ImageFileHandle & 1 ) {
    01094         JustDoSideEffects = TRUE;
    01095         }
    01096     else {
    01097         JustDoSideEffects = FALSE;
    01098         }
    01099
    01100     Status = NtCreateSection(
    01101                 &Section,
    01102                 SECTION_MAP_EXECUTE,
    01103                 NULL,
    01104                 NULL,
    01105                 PAGE_EXECUTE,
    01106                 SEC_COMMIT,
    01107                 ImageFileHandle
    01108                 );
    01109     if ( !NT_SUCCESS(Status) ) {
    01110         return Status;
    01111         }
    01112
    01113     ViewBase = NULL;
    01114     ViewSize = 0;
    01115
    01116     Status = NtMapViewOfSection(
    01117                 Section,
    01118                 NtCurrentProcess(),
    01119                 (PVOID *)&ViewBase,
    01120                 0L,
    01121                 0L,
    01122                 NULL,
    01123                 &ViewSize,
    01124                 ViewShare,
    01125                 0L,
    01126                 PAGE_EXECUTE
    01127                 );
    01128
    01129     if ( !NT_SUCCESS(Status) ) {
    01130         NtClose(Section);
    01131         return Status;
    01132         }
    01133
    01134     //
    01135     // now the image is mapped as a data file... Calculate it's size and then
    01136     // check it's checksum
    01137     //
    01138
    01139     Status = NtQueryInformationFile(
    01140                 ImageFileHandle,
    01141                 &IoStatusBlock,
    01142                 &StandardInfo,
    01143                 sizeof(StandardInfo),
    01144                 FileStandardInformation
    01145                 );
    01146
    01147     if ( !NT_SUCCESS(Status) ) {
    01148         NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
    01149         NtClose(Section);
    01150         return Status;
    01151         }
    01152
    01153     try {
    01154         if ( JustDoSideEffects ) {
    01155             b = TRUE;
    01156             }
    01157         else {
    01158             b = LdrVerifyMappedImageMatchesChecksum(ViewBase,StandardInfo.EndOfFile.LowPart);
    01159             }
    01160         if (b && ARGUMENT_PRESENT( ImportCallbackRoutine )) {
    01161             PIMAGE_NT_HEADERS NtHeaders;
    01162             PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
    01163             ULONG ImportSize;
    01164             PCHAR ImportName;
    01165
    01166             //
    01167             // Caller wants to enumerate the import descriptors while we have
    01168             // the image mapped.  Call back to their routine for each module
    01169             // name in the import descriptor table.
    01170             //
    01171             LastRvaSection = NULL;
    01172             NtHeaders = RtlImageNtHeader( ViewBase );
    01173             if (ARGUMENT_PRESENT( ImageCharacteristics )) {
    01174                 *ImageCharacteristics = NtHeaders->FileHeader.Characteristics;
    01175                 }
    01176
    01177             ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)
    01178                 RtlImageDirectoryEntryToData( ViewBase,
    01179                                               FALSE,
    01180                                               IMAGE_DIRECTORY_ENTRY_IMPORT,
    01181                                               &ImportSize
    01182                                             );
    01183             if (ImportDescriptor != NULL) {
    01184                 while (ImportDescriptor->Name) {
    01185                     ImportName = (PSZ)RtlImageRvaToVa( NtHeaders,
    01186                                                        ViewBase,
    01187                                                        ImportDescriptor->Name,
    01188                                                        &LastRvaSection
    01189                                                      );
    01190                     (*ImportCallbackRoutine)( ImportCallbackParameter, ImportName );
    01191                     ImportDescriptor += 1;
    01192                     }
    01193                 }
    01194             }
    01195         }
    01196     except (EXCEPTION_EXECUTE_HANDLER) {
    01197         NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
    01198         NtClose(Section);
    01199         return STATUS_IMAGE_CHECKSUM_MISMATCH;
    01200         }
    01201     NtUnmapViewOfSection(NtCurrentProcess(),ViewBase);
    01202     NtClose(Section);
    01203     if ( !b ) {
    01204         Status = STATUS_IMAGE_CHECKSUM_MISMATCH;
    01205         }
    01206     return Status;
    01207 }
    01208
    01209 NTSTATUS
    01210 LdrQueryProcessModuleInformation(
    01211     OUT PRTL_PROCESS_MODULES ModuleInformation,
    01212     IN ULONG ModuleInformationLength,
    01213     OUT PULONG ReturnLength OPTIONAL
    01214     )
    01215 {
    01216     NTSTATUS Status;
    01217     PPEB Peb;
    01218     PLIST_ENTRY LoadOrderListHead;
    01219     PLIST_ENTRY InitOrderListHead;
    01220     ULONG RequiredLength;
    01221     PLIST_ENTRY Next;
    01222     PLIST_ENTRY Next1;
    01223     PRTL_PROCESS_MODULE_INFORMATION ModuleInfo;
    01224     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    01225     PLDR_DATA_TABLE_ENTRY LdrDataTableEntry1;
    01226     ANSI_STRING AnsiString;
    01227     PUCHAR s;
    01228
    01229     Peb = NtCurrentPeb();
    01230
    01231     //
    01232     // Grab Peb lock and capture information about of DLLs loaded in current process.
    01233     //
    01234
    01235     if ( LdrpInLdrInit == FALSE ) {
    01236         RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    01237         }
    01238
    01239     try {
    01240         RequiredLength = FIELD_OFFSET( RTL_PROCESS_MODULES, Modules );
    01241         if (ModuleInformationLength < RequiredLength) {
    01242             Status = STATUS_INFO_LENGTH_MISMATCH;
    01243             ModuleInfo = NULL;
    01244             }
    01245         else {
    01246             ModuleInformation->NumberOfModules = 0;
    01247             ModuleInfo = &ModuleInformation->Modules[ 0 ];
    01248             Status = STATUS_SUCCESS;
    01249             }
    01250
    01251         LoadOrderListHead = &Peb->Ldr->InLoadOrderModuleList;
    01252         InitOrderListHead = &Peb->Ldr->InInitializationOrderModuleList;
    01253         Next = LoadOrderListHead->Flink;
    01254         while ( Next != LoadOrderListHead ) {
    01255             LdrDataTableEntry = CONTAINING_RECORD( Next,
    01256                                                    LDR_DATA_TABLE_ENTRY,
    01257                                                    InLoadOrderLinks
    01258                                                  );
    01259
    01260             RequiredLength += sizeof( RTL_PROCESS_MODULE_INFORMATION );
    01261             if (ModuleInformationLength < RequiredLength) {
    01262                 Status = STATUS_INFO_LENGTH_MISMATCH;
    01263                 }
    01264             else {
    01265                 ModuleInfo->MappedBase = NULL;
    01266                 ModuleInfo->ImageBase = LdrDataTableEntry->DllBase;
    01267                 ModuleInfo->ImageSize = LdrDataTableEntry->SizeOfImage;
    01268                 ModuleInfo->Flags = LdrDataTableEntry->Flags;
    01269                 ModuleInfo->LoadCount = LdrDataTableEntry->LoadCount;
    01270
    01271                 ModuleInfo->LoadOrderIndex = (USHORT)(ModuleInformation->NumberOfModules);
    01272
    01273                 ModuleInfo->InitOrderIndex = 0;
    01274                 Next1 = InitOrderListHead->Flink;
    01275                 while ( Next1 != InitOrderListHead ) {
    01276                     LdrDataTableEntry1 = CONTAINING_RECORD( Next1,
    01277                                                             LDR_DATA_TABLE_ENTRY,
    01278                                                             InInitializationOrderLinks
    01279                                                           );
    01280
    01281                     ModuleInfo->InitOrderIndex++;
    01282                     if (LdrDataTableEntry1 == LdrDataTableEntry) {
    01283                         break;
    01284                         }
    01285
    01286                     Next1 = Next1->Flink;
    01287                     }
    01288
    01289                 AnsiString.Buffer = ModuleInfo->FullPathName;
    01290                 AnsiString.Length = 0;
    01291                 AnsiString.MaximumLength = sizeof( ModuleInfo->FullPathName );
    01292                 RtlUnicodeStringToAnsiString( &AnsiString,
    01293                                               &LdrDataTableEntry->FullDllName,
    01294                                               FALSE
    01295                                             );
    01296                 s = AnsiString.Buffer + AnsiString.Length;
    01297                 while (s > AnsiString.Buffer && *--s) {
    01298                     if (*s == (UCHAR)OBJ_NAME_PATH_SEPARATOR) {
    01299                         s++;
    01300                         break;
    01301                         }
    01302                     }
    01303                 ModuleInfo->OffsetToFileName = (USHORT)(s - AnsiString.Buffer);
    01304
    01305                 ModuleInfo++;
    01306                 }
    01307
    01308             if (ModuleInformation != NULL) {
    01309                 ModuleInformation->NumberOfModules++;
    01310                 }
    01311
    01312             Next = Next->Flink;
    01313             }
    01314
    01315         if (ARGUMENT_PRESENT( ReturnLength )) {
    01316             *ReturnLength = RequiredLength;
    01317             }
    01318         }
    01319     finally {
    01320         if ( LdrpInLdrInit == FALSE ) {
    01321             RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock);
    01322             }
    01323         }
    01324
    01325     return( Status );
    01326 }
    01327
    01328 #if defined(MIPS)
    01329 VOID
    01330 LdrProcessStarterHelper(
    01331     IN PPROCESS_STARTER_ROUTINE ProcessStarter,
    01332     IN PVOID RealStartAddress
    01333     )
    01334
    01335 /*++
    01336
    01337 Routine Description:
    01338
    01339     This function is used to call the code that calls the initial entry point
    01340     of a win32 process. On all other platforms, this wrapper is not used since
    01341     they can cope with a process entrypoint being in kernel32 prior to it being
    01342     mapped.
    01343
    01344 Arguments:
    01345
    01346     ProcessStarter - Supplies the address of the function in Kernel32 that ends up
    01347         calling the real process entrypoint
    01348
    01349     RealStartAddress - Supplies the real start address of the process
    01350     .
    01351
    01352 Return Value:
    01353
    01354     None.
    01355
    01356 --*/
    01357
    01358 {
    01359     (ProcessStarter)(RealStartAddress);
    01360     NtTerminateProcess(NtCurrentProcess(),0);
    01361 }
    01362
    01363 #endif