/*++ Copyright (c) 1991 Microsoft Corporation Module Name: ldrrsrc.c Abstract: Loader API calls for accessing resource sections. Author: Steve Wood (stevewo) 16-Sep-1991 Revision History: --*/ #include "ntrtlp.h" #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) #pragma alloc_text(PAGE,LdrAccessResource) #pragma alloc_text(PAGE,LdrpAccessResourceData) #pragma alloc_text(PAGE,LdrFindEntryForAddress) #pragma alloc_text(PAGE,LdrFindResource_U) #pragma alloc_text(PAGE,LdrFindResourceDirectory_U) #pragma alloc_text(PAGE,LdrpCompareResourceNames_U) #pragma alloc_text(PAGE,LdrpSearchResourceSection_U) #pragma alloc_text(PAGE,LdrEnumResources) #endif NTSTATUS LdrAccessResource( IN PVOID DllHandle, IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, OUT PVOID *Address OPTIONAL, OUT PULONG Size OPTIONAL ) /*++ Routine Description: This function locates the address of the specified resource in the specified DLL and returns its address. Arguments: DllHandle - Supplies a handle to the image file that the resource is contained in. ResourceDataEntry - Supplies a pointer to the resource data entry in the resource data section of the image file specified by the DllHandle parameter. This pointer should have been one returned by the LdrFindResource function. Address - Optional pointer to a variable that will receive the address of the resource specified by the first two parameters. Size - Optional pointer to a variable that will receive the size of the resource specified by the first two parameters. Return Value: TBD --*/ { RTL_PAGED_CODE(); return LdrpAccessResourceData( DllHandle, ResourceDataEntry, Address, Size ); } NTSTATUS LdrpAccessResourceData( IN PVOID DllHandle, IN PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry, OUT PVOID *Address OPTIONAL, OUT PULONG Size OPTIONAL ) /*++ Routine Description: This function returns the data necessary to actually examine the contents of a particular resource. Arguments: DllHandle - Supplies a handle to the image file that the resource is contained in. ResourceDataEntry - Supplies a pointer to the resource data entry in the resource data directory of the image file specified by the DllHandle parameter. This pointer should have been one returned by the LdrFindResource function. Address - Optional pointer to a variable that will receive the address of the resource specified by the first two parameters. Size - Optional pointer to a variable that will receive the size of the resource specified by the first two parameters. Return Value: TBD --*/ { PIMAGE_RESOURCE_DIRECTORY ResourceDirectory; ULONG ResourceSize; PIMAGE_NT_HEADERS NtHeaders; ULONG VirtualAddressOffset; PIMAGE_SECTION_HEADER NtSection; RTL_PAGED_CODE(); ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) RtlImageDirectoryEntryToData(DllHandle, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &ResourceSize ); if (!ResourceDirectory) { return( STATUS_RESOURCE_DATA_NOT_FOUND ); } if ((ULONG)DllHandle & 0x00000001) { DllHandle = (PVOID)((ULONG)DllHandle & ~0x00000001); NtHeaders = RtlImageNtHeader( DllHandle ); VirtualAddressOffset = (ULONG)DllHandle + NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress - (ULONG)ResourceDirectory; // // Now, we must check to see if the resource is not in the // same section as the resource table. If it's in .rsrc1, // we've got to adjust the RVA in the ResourceDataEntry // to point to the correct place in the non-VA data file. // NtSection= RtlSectionTableFromVirtualAddress( NtHeaders, DllHandle, (PVOID)NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_RESOURCE ].VirtualAddress ); if (!NtSection) { return( STATUS_RESOURCE_DATA_NOT_FOUND ); } if ( ResourceDataEntry->OffsetToData > NtSection->Misc.VirtualSize ) { ULONG rva; rva = NtSection->VirtualAddress; NtSection= RtlSectionTableFromVirtualAddress ( NtHeaders, DllHandle, (PVOID)ResourceDataEntry->OffsetToData ); VirtualAddressOffset += ((ULONG)NtSection->VirtualAddress - rva) - ((ULONG)RtlAddressInSectionTable ( NtHeaders, DllHandle, (PVOID)NtSection->VirtualAddress ) - (ULONG)ResourceDirectory); } } else { VirtualAddressOffset = 0; } try { if (ARGUMENT_PRESENT( Address )) { *Address = (PVOID)( (ULONG)DllHandle + (ResourceDataEntry->OffsetToData - VirtualAddressOffset) ); } if (ARGUMENT_PRESENT( Size )) { *Size = ResourceDataEntry->Size; } } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } return( STATUS_SUCCESS ); } NTSTATUS LdrFindEntryForAddress( IN PVOID Address, OUT PLDR_DATA_TABLE_ENTRY *TableEntry ) /*++ Routine Description: This function returns the load data table entry that describes the virtual address range that contains the passed virtual address. Arguments: Address - Supplies a 32-bit virtual address. TableEntry - Supplies a pointer to the variable that will receive the address of the loader data table entry. Return Value: Status --*/ { PPEB_LDR_DATA Ldr; PLIST_ENTRY Head, Next; PLDR_DATA_TABLE_ENTRY Entry; PIMAGE_NT_HEADERS NtHeaders; PVOID ImageBase; PVOID EndOfImage; Ldr = NtCurrentPeb()->Ldr; if (Ldr == NULL) { return( STATUS_NO_MORE_ENTRIES ); } Head = &Ldr->InMemoryOrderModuleList; Next = Head->Flink; while ( Next != Head ) { Entry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks ); NtHeaders = RtlImageNtHeader( Entry->DllBase ); if (NtHeaders != NULL) { ImageBase = (PVOID)Entry->DllBase; EndOfImage = (PVOID) ((ULONG)ImageBase + NtHeaders->OptionalHeader.SizeOfImage); if ((ULONG)Address >= (ULONG)ImageBase && (ULONG)Address < (ULONG)EndOfImage) { *TableEntry = Entry; return( STATUS_SUCCESS ); } } Next = Next->Flink; } return( STATUS_NO_MORE_ENTRIES ); } NTSTATUS LdrFindResource_U( IN PVOID DllHandle, IN PULONG ResourceIdPath, IN ULONG ResourceIdPathLength, OUT PIMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry ) /*++ Routine Description: This function locates the address of the specified resource in the specified DLL and returns its address. Arguments: DllHandle - Supplies a handle to the image file that the resource is contained in. ResourceIdPath - Supplies a pointer to an array of 32-bit resource identifiers. Each identifier is either an integer or a pointer to a STRING structure that specifies a resource name. The array is used to traverse the directory structure contained in the resource section in the image file specified by the DllHandle parameter. ResourceIdPathLength - Supplies the number of elements in the ResourceIdPath array. ResourceDataEntry - Supplies a pointer to a variable that will receive the address of the resource data entry in the resource data section of the image file specified by the DllHandle parameter. Return Value: TBD --*/ { RTL_PAGED_CODE(); return LdrpSearchResourceSection_U( DllHandle, ResourceIdPath, ResourceIdPathLength, FALSE, // Look for a leaf node (PVOID *)ResourceDataEntry ); } NTSTATUS LdrFindResourceDirectory_U( IN PVOID DllHandle, IN PULONG ResourceIdPath, IN ULONG ResourceIdPathLength, OUT PIMAGE_RESOURCE_DIRECTORY *ResourceDirectory ) /*++ Routine Description: This function locates the address of the specified resource directory in specified DLL and returns its address. Arguments: DllHandle - Supplies a handle to the image file that the resource directory is contained in. ResourceIdPath - Supplies a pointer to an array of 32-bit resource identifiers. Each identifier is either an integer or a pointer to a STRING structure that specifies a resource name. The array is used to traverse the directory structure contained in the resource section in the image file specified by the DllHandle parameter. ResourceIdPathLength - Supplies the number of elements in the ResourceIdPath array. ResourceDirectory - Supplies a pointer to a variable that will receive the address of the resource directory specified by ResourceIdPath in the resource data section of the image file the DllHandle parameter. Return Value: TBD --*/ { RTL_PAGED_CODE(); return LdrpSearchResourceSection_U( DllHandle, ResourceIdPath, ResourceIdPathLength, TRUE, // Look for a directory node (PVOID *)ResourceDirectory ); } LONG LdrpCompareResourceNames_U( IN ULONG ResourceName, IN PIMAGE_RESOURCE_DIRECTORY ResourceDirectory, IN PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirectoryEntry ) { LONG li; PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString; if (ResourceName & LDR_RESOURCE_ID_NAME_MASK) { if (!ResourceDirectoryEntry->NameIsString) { return( -1 ); } ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) ((PCHAR)ResourceDirectory + ResourceDirectoryEntry->NameOffset); li = wcsncmp( (LPWSTR)ResourceName, ResourceNameString->NameString, ResourceNameString->Length ); if (!li && wcslen((PWSTR)ResourceName) != ResourceNameString->Length) { return( 1 ); } return(li); } else { if (ResourceDirectoryEntry->NameIsString) { return( 1 ); } return( ResourceName - ResourceDirectoryEntry->Name ); } } #define USE_FIRSTAVAILABLE_LANGID (0xFFFFFFFF & ~LDR_RESOURCE_ID_NAME_MASK) NTSTATUS LdrpSearchResourceSection_U( IN PVOID DllHandle, IN PULONG ResourceIdPath, IN ULONG ResourceIdPathLength, IN BOOLEAN FindDirectoryEntry, OUT PVOID *ResourceDirectoryOrData ) /*++ Routine Description: This function locates the address of the specified resource in the specified DLL and returns its address. Arguments: DllHandle - Supplies a handle to the image file that the resource is contained in. ResourceIdPath - Supplies a pointer to an array of 32-bit resource identifiers. Each identifier is either an integer or a pointer to a null terminated string (PSZ) that specifies a resource name. The array is used to traverse the directory structure contained in the resource section in the image file specified by the DllHandle parameter. ResourceIdPathLength - Supplies the number of elements in the ResourceIdPath array. FindDirectoryEntry - Supplies a boolean that is TRUE if caller is searching for a resource directory, otherwise the caller is searching for a resource data entry. ResourceDirectoryOrData - Supplies a pointer to a variable that will receive the address of the resource directory or data entry in the resource data section of the image file specified by the DllHandle parameter. Return Value: TBD --*/ { NTSTATUS Status; PIMAGE_RESOURCE_DIRECTORY LanguageResourceDirectory, ResourceDirectory, TopResourceDirectory; PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntLow; PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntMiddle; PIMAGE_RESOURCE_DIRECTORY_ENTRY ResourceDirEntHigh; PIMAGE_RESOURCE_DATA_ENTRY ResourceEntry; USHORT n, half; LONG dir; ULONG size; ULONG ResourceIdRetry, RetryCount; LCID DefaultThreadLocale, DefaultSystemLocale; LANGID NewLangId; PULONG IdPath = ResourceIdPath; ULONG IdPathLength = ResourceIdPathLength; BOOLEAN fIsNeutral = FALSE; LANGID GivenLanguage; RTL_PAGED_CODE(); TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) RtlImageDirectoryEntryToData(DllHandle, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size ); if (!TopResourceDirectory) { return( STATUS_RESOURCE_DATA_NOT_FOUND ); } try { ResourceDirectory = TopResourceDirectory; ResourceIdRetry = USE_FIRSTAVAILABLE_LANGID; RetryCount = 0; ResourceEntry = NULL; LanguageResourceDirectory = NULL; while (ResourceDirectory != NULL && ResourceIdPathLength--) { // // If search path includes a language id, then attempt to // match the following language ids in this order: // // (0) use given language id // (1) use primary language of given language id // (2) use id 0 (neutral resource) // // If the PRIMARY language id is ZERO, then ALSO attempt to // match the following language ids in this order: // // (3) use lang id from locale in TEB // (4) use lang id from user's locale id // (5) use primary language of user's locale id // (6) use lang id from system default locale id // (7) use primary language of system default locale id // (8) use US English lang id // (9) use any lang id that matches requested info // if (ResourceIdPathLength == 0 && IdPathLength == 3) { LanguageResourceDirectory = ResourceDirectory; } if (LanguageResourceDirectory != NULL) { GivenLanguage = (LANGID)IdPath[ 2 ]; fIsNeutral = (PRIMARYLANGID( GivenLanguage ) == LANG_NEUTRAL); TryNextLangId: switch( RetryCount++ ) { case 0: // Use given language id NewLangId = GivenLanguage; break; case 1: // Use primary language of given language id NewLangId = PRIMARYLANGID( GivenLanguage ); break; case 2: // Use id 0 (neutral resource) NewLangId = LANG_USER_DEFAULT; NewLangId = LANG_SYSTEM_DEFAULT; NewLangId = 0; break; case 3: // Use lang id from locale in TEB if ( !fIsNeutral ) { // Stop looking - Not in the neutral case goto ReturnFailure; break; } if (SUBLANGID( GivenLanguage ) == SUBLANG_SYS_DEFAULT) { // Skip over all USER locale options DefaultThreadLocale = 0; RetryCount += 2; break; } if (NtCurrentTeb() != NULL) { NewLangId = LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale); } break; case 4: // Use User's default locale Status = NtQueryDefaultLocale( TRUE, &DefaultThreadLocale ); if (NT_SUCCESS( Status )) { NewLangId = LANGIDFROMLCID(DefaultThreadLocale); break; } RetryCount++; break; case 5: // Use primary language of User's default locale NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry ); break; case 6: // Use System default locale Status = NtQueryDefaultLocale( FALSE, &DefaultSystemLocale ); if (!NT_SUCCESS( Status )) { RetryCount++; break; } if (DefaultSystemLocale != DefaultThreadLocale) { NewLangId = LANGIDFROMLCID(DefaultSystemLocale); break; } RetryCount += 2; // fall through case 8: // Use US English language NewLangId = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ); break; case 7: // Use primary language of System default locale NewLangId = PRIMARYLANGID( (LANGID)ResourceIdRetry ); break; case 9: // Take any lang id that matches NewLangId = USE_FIRSTAVAILABLE_LANGID; break; default: // No lang ids to match goto ReturnFailure; break; } // // If looking for a specific language id and same as the // one we just looked up, then skip it. // if (NewLangId != USE_FIRSTAVAILABLE_LANGID && NewLangId == ResourceIdRetry ) { goto TryNextLangId; } // // Try this new language Id // ResourceIdRetry = (ULONG)NewLangId; ResourceIdPath = &ResourceIdRetry; ResourceDirectory = LanguageResourceDirectory; } n = ResourceDirectory->NumberOfNamedEntries; ResourceDirEntLow = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(ResourceDirectory+1); if (!(*ResourceIdPath & LDR_RESOURCE_ID_NAME_MASK)) { ResourceDirEntLow += n; n = ResourceDirectory->NumberOfIdEntries; } if (!n) { ResourceDirectory = NULL; goto NotFound; } if (LanguageResourceDirectory != NULL && *ResourceIdPath == USE_FIRSTAVAILABLE_LANGID ) { ResourceDirectory = NULL; ResourceIdRetry = ResourceDirEntLow->Name; ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) ((PCHAR)TopResourceDirectory + ResourceDirEntLow->OffsetToData ); break; } ResourceDirectory = NULL; ResourceDirEntHigh = ResourceDirEntLow + n - 1; while (ResourceDirEntLow <= ResourceDirEntHigh) { if ((half = (n >> 1)) != 0) { ResourceDirEntMiddle = ResourceDirEntLow; if (*(PUCHAR)&n & 1) { ResourceDirEntMiddle += half; } else { ResourceDirEntMiddle += half - 1; } dir = LdrpCompareResourceNames_U( *ResourceIdPath, TopResourceDirectory, ResourceDirEntMiddle ); if (!dir) { if (ResourceDirEntMiddle->DataIsDirectory) { ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) ((PCHAR)TopResourceDirectory + ResourceDirEntMiddle->OffsetToDirectory ); } else { ResourceDirectory = NULL; ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) ((PCHAR)TopResourceDirectory + ResourceDirEntMiddle->OffsetToData ); } break; } else { if (dir < 0) { ResourceDirEntHigh = ResourceDirEntMiddle - 1; if (*(PUCHAR)&n & 1) { n = half; } else { n = half - 1; } } else { ResourceDirEntLow = ResourceDirEntMiddle + 1; n = half; } } } else { if (n != 0) { dir = LdrpCompareResourceNames_U( *ResourceIdPath, TopResourceDirectory, ResourceDirEntLow ); if (!dir) { if (ResourceDirEntLow->DataIsDirectory) { ResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) ((PCHAR)TopResourceDirectory + ResourceDirEntLow->OffsetToDirectory ); } else { ResourceEntry = (PIMAGE_RESOURCE_DATA_ENTRY) ((PCHAR)TopResourceDirectory + ResourceDirEntLow->OffsetToData ); } } } break; } } ResourceIdPath++; } if (ResourceEntry != NULL && !FindDirectoryEntry) { *ResourceDirectoryOrData = (PVOID)ResourceEntry; Status = STATUS_SUCCESS; } else if (ResourceDirectory != NULL && FindDirectoryEntry) { *ResourceDirectoryOrData = (PVOID)ResourceDirectory; Status = STATUS_SUCCESS; } else { NotFound: switch( IdPathLength - ResourceIdPathLength) { case 3: Status = STATUS_RESOURCE_LANG_NOT_FOUND; break; case 2: Status = STATUS_RESOURCE_NAME_NOT_FOUND; break; case 1: Status = STATUS_RESOURCE_TYPE_NOT_FOUND; break; default: Status = STATUS_INVALID_PARAMETER; break; } } if (Status == STATUS_RESOURCE_LANG_NOT_FOUND && LanguageResourceDirectory != NULL ) { ResourceEntry = NULL; goto TryNextLangId; ReturnFailure: ; } } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); } return Status; } NTSTATUS LdrEnumResources( IN PVOID DllHandle, IN PULONG ResourceIdPath, IN ULONG ResourceIdPathLength, IN OUT PULONG NumberOfResources, OUT PLDR_ENUM_RESOURCE_ENTRY Resources OPTIONAL ) { NTSTATUS Status; PIMAGE_RESOURCE_DIRECTORY TopResourceDirectory; PIMAGE_RESOURCE_DIRECTORY TypeResourceDirectory; PIMAGE_RESOURCE_DIRECTORY NameResourceDirectory; PIMAGE_RESOURCE_DIRECTORY LangResourceDirectory; PIMAGE_RESOURCE_DIRECTORY_ENTRY TypeResourceDirectoryEntry; PIMAGE_RESOURCE_DIRECTORY_ENTRY NameResourceDirectoryEntry; PIMAGE_RESOURCE_DIRECTORY_ENTRY LangResourceDirectoryEntry; ULONG TypeDirectoryIndex, NumberOfTypeDirectoryEntries; ULONG NameDirectoryIndex, NumberOfNameDirectoryEntries; ULONG LangDirectoryIndex, NumberOfLangDirectoryEntries; BOOLEAN ScanTypeDirectory; BOOLEAN ScanNameDirectory; BOOLEAN ReturnThisResource; PIMAGE_RESOURCE_DIR_STRING_U ResourceNameString; ULONG TypeResourceNameOrId; ULONG NameResourceNameOrId; ULONG LangResourceNameOrId; PLDR_ENUM_RESOURCE_ENTRY ResourceInfo; PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry; ULONG ResourceIndex, MaxResourceIndex; ULONG Size; ResourceIndex = 0; if (!ARGUMENT_PRESENT( Resources )) { MaxResourceIndex = 0; } else { MaxResourceIndex = *NumberOfResources; } *NumberOfResources = 0; TopResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) RtlImageDirectoryEntryToData( DllHandle, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &Size ); if (!TopResourceDirectory) { return STATUS_RESOURCE_DATA_NOT_FOUND; } TypeResourceDirectory = TopResourceDirectory; TypeResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(TypeResourceDirectory+1); NumberOfTypeDirectoryEntries = TypeResourceDirectory->NumberOfNamedEntries + TypeResourceDirectory->NumberOfIdEntries; TypeDirectoryIndex = 0; Status = STATUS_SUCCESS; for (TypeDirectoryIndex=0; TypeDirectoryIndex 0) { ScanTypeDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 0 ], TopResourceDirectory, TypeResourceDirectoryEntry ) == 0; } else { ScanTypeDirectory = TRUE; } if (ScanTypeDirectory) { if (!TypeResourceDirectoryEntry->DataIsDirectory) { return STATUS_INVALID_IMAGE_FORMAT; } if (TypeResourceDirectoryEntry->NameIsString) { ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->NameOffset); TypeResourceNameOrId = (ULONG)ResourceNameString; } else { TypeResourceNameOrId = (ULONG)TypeResourceDirectoryEntry->Id; } NameResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) ((PCHAR)TopResourceDirectory + TypeResourceDirectoryEntry->OffsetToDirectory); NameResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(NameResourceDirectory+1); NumberOfNameDirectoryEntries = NameResourceDirectory->NumberOfNamedEntries + NameResourceDirectory->NumberOfIdEntries; NameDirectoryIndex = 0; for (NameDirectoryIndex=0; NameDirectoryIndex 1) { ScanNameDirectory = LdrpCompareResourceNames_U( ResourceIdPath[ 1 ], TopResourceDirectory, NameResourceDirectoryEntry ) == 0; } else { ScanNameDirectory = TRUE; } if (ScanNameDirectory) { if (!NameResourceDirectoryEntry->DataIsDirectory) { return STATUS_INVALID_IMAGE_FORMAT; } if (NameResourceDirectoryEntry->NameIsString) { ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->NameOffset); NameResourceNameOrId = (ULONG)ResourceNameString; } else { NameResourceNameOrId = (ULONG)NameResourceDirectoryEntry->Id; } LangResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY) ((PCHAR)TopResourceDirectory + NameResourceDirectoryEntry->OffsetToDirectory); LangResourceDirectoryEntry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(LangResourceDirectory+1); NumberOfLangDirectoryEntries = LangResourceDirectory->NumberOfNamedEntries + LangResourceDirectory->NumberOfIdEntries; LangDirectoryIndex = 0; for (LangDirectoryIndex=0; LangDirectoryIndex 2) { ReturnThisResource = LdrpCompareResourceNames_U( ResourceIdPath[ 2 ], TopResourceDirectory, LangResourceDirectoryEntry ) == 0; } else { ReturnThisResource = TRUE; } if (ReturnThisResource) { if (LangResourceDirectoryEntry->DataIsDirectory) { return STATUS_INVALID_IMAGE_FORMAT; } if (LangResourceDirectoryEntry->NameIsString) { ResourceNameString = (PIMAGE_RESOURCE_DIR_STRING_U) ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->NameOffset); LangResourceNameOrId = (ULONG)ResourceNameString; } else { LangResourceNameOrId = (ULONG)LangResourceDirectoryEntry->Id; } ResourceDataEntry = (PIMAGE_RESOURCE_DATA_ENTRY) ((PCHAR)TopResourceDirectory + LangResourceDirectoryEntry->OffsetToData); ResourceInfo = &Resources[ ResourceIndex++ ]; if (ResourceIndex <= MaxResourceIndex) { ResourceInfo->Path[ 0 ].NameOrId = TypeResourceNameOrId; ResourceInfo->Path[ 1 ].NameOrId = NameResourceNameOrId; ResourceInfo->Path[ 2 ].NameOrId = LangResourceNameOrId; ResourceInfo->Data = (PVOID)((ULONG)DllHandle + ResourceDataEntry->OffsetToData); ResourceInfo->Size = ResourceDataEntry->Size; ResourceInfo->Reserved = 0; } else { Status = STATUS_INFO_LENGTH_MISMATCH; } } } } } } } *NumberOfResources = ResourceIndex; return Status; }