/* * PE (Portable Execute) File Resources * * Copyright 1995 Thomas Sandford * Copyright 1996 Martin von Loewis * * Based on the Win16 resource handling code in loader/resource.c * Copyright 1993 Robert J. Amstadt * Copyright 1995 Alexandre Julliard * Copyright 1997 Marcus Meissner */ #include #include #include "wine/winestring.h" #include "wine/unicode.h" #include "windef.h" #include "winnls.h" #include "module.h" #include "heap.h" #include "task.h" #include "process.h" #include "stackframe.h" #include "neexe.h" #include "debugtools.h" /********************************************************************** * get_resdir * * Get the resource directory of a PE module */ static IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod ) { IMAGE_DATA_DIRECTORY *dir; IMAGE_RESOURCE_DIRECTORY *ret = NULL; if (!hmod) hmod = GetModuleHandleA( NULL ); dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]; if (dir->Size && dir->VirtualAddress) ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress); return ret; } /********************************************************************** * GetResDirEntryW * * Helper function - goes down one level of PE resource tree * */ PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr, LPCWSTR name,DWORD root, BOOL allowdefault) { int entrynum; PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable; int namelen; if (HIWORD(name)) { if (name[0]=='#') { char buf[10]; if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL )) return NULL; return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault); } entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdirptr + 1); namelen = strlenW(name); for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++) { PIMAGE_RESOURCE_DIR_STRING_U str = (PIMAGE_RESOURCE_DIR_STRING_U) (root + entryTable[entrynum].u1.s.NameOffset); if(namelen != str->Length) continue; if(strncmpiW(name,str->NameString,str->Length)==0) return (PIMAGE_RESOURCE_DIRECTORY) ( root + entryTable[entrynum].u2.s.OffsetToDirectory); } return NULL; } else { entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) ( (BYTE *) resdirptr + sizeof(IMAGE_RESOURCE_DIRECTORY) + resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY)); for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++) if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name) return (PIMAGE_RESOURCE_DIRECTORY) ( root + entryTable[entrynum].u2.s.OffsetToDirectory); /* just use first entry if no default can be found */ if (allowdefault && !name && resdirptr->NumberOfIdEntries) return (PIMAGE_RESOURCE_DIRECTORY) ( root + entryTable[0].u2.s.OffsetToDirectory); return NULL; } } /********************************************************************** * GetResDirEntryA */ PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr, LPCSTR name, DWORD root, BOOL allowdefault ) { PIMAGE_RESOURCE_DIRECTORY retv; LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name ) : (LPWSTR)name; retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault ); if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW ); return retv; } /********************************************************************** * PE_FindResourceExW */ HANDLE PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang ) { PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod); DWORD root; HANDLE result; if (!resdirptr) return 0; root = (DWORD) resdirptr; if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL) return 0; if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL) return 0; result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE); /* Try with only the primary language set */ if (!result) { lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_DEFAULT); result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE); } /* Try LANG_NEUTRAL, too */ if(!result) return (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)0, root, TRUE); return result; } /********************************************************************** * PE_LoadResource */ HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc ) { if (!hRsrc) return 0; return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData); } /********************************************************************** * PE_SizeofResource */ DWORD PE_SizeofResource( HANDLE hRsrc ) { if (!hRsrc) return 0; return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size; } /********************************************************************** * EnumResourceTypesA (KERNEL32.90) */ BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam) { int i; PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; HANDLE heap = GetProcessHeap(); if (!resdir) return FALSE; et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { LPSTR name; if (et[i].u1.s.NameIsString) name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)resdir + et[i].u1.s.NameOffset)); else name = (LPSTR)(int)et[i].u1.Id; ret = lpfun(hmod,name,lparam); if (HIWORD(name)) HeapFree(heap,0,name); if (!ret) break; } return ret; } /********************************************************************** * EnumResourceTypesW (KERNEL32.91) */ BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam) { int i; PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; if (!resdir) return FALSE; et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { LPWSTR type; if (et[i].u1.s.NameIsString) type = (LPWSTR)((LPBYTE)resdir + et[i].u1.s.NameOffset); else type = (LPWSTR)(int)et[i].u1.Id; ret = lpfun(hmod,type,lparam); if (!ret) break; } return ret; } /********************************************************************** * EnumResourceNamesA (KERNEL32.88) */ BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam ) { int i; PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY resdir; PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; HANDLE heap = GetProcessHeap(); LPWSTR typeW; if (!basedir) return FALSE; if (HIWORD(type)) typeW = HEAP_strdupAtoW(heap,0,type); else typeW = (LPWSTR)type; resdir = GetResDirEntryW(basedir,typeW,(DWORD)basedir,FALSE); if (HIWORD(typeW)) HeapFree(heap,0,typeW); if (!resdir) return FALSE; et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { LPSTR name; if (et[i].u1.s.NameIsString) name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)basedir + et[i].u1.s.NameOffset)); else name = (LPSTR)(int)et[i].u1.Id; ret = lpfun(hmod,type,name,lparam); if (HIWORD(name)) HeapFree(heap,0,name); if (!ret) break; } return ret; } /********************************************************************** * EnumResourceNamesW (KERNEL32.89) */ BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam ) { int i; PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY resdir; PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; if (!basedir) return FALSE; resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE); if (!resdir) return FALSE; et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { LPWSTR name; if (et[i].u1.s.NameIsString) name = (LPWSTR)((LPBYTE)basedir + et[i].u1.s.NameOffset); else name = (LPWSTR)(int)et[i].u1.Id; ret = lpfun(hmod,type,name,lparam); if (!ret) break; } return ret; } /********************************************************************** * EnumResourceLanguagesA (KERNEL32.86) */ BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name, ENUMRESLANGPROCA lpfun, LONG lparam ) { int i; PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY resdir; PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; HANDLE heap = GetProcessHeap(); if (!basedir) return FALSE; if (HIWORD(type)) { LPWSTR typeW = HEAP_strdupAtoW(heap,0,type); resdir = GetResDirEntryW(basedir,typeW,(DWORD)basedir,FALSE); HeapFree(heap,0,typeW); } else resdir = GetResDirEntryW(basedir,(LPWSTR)type,(DWORD)basedir,FALSE); if (!resdir) return FALSE; if (HIWORD(name)) { LPWSTR nameW = HEAP_strdupAtoW(heap,0,name); resdir = GetResDirEntryW(resdir,nameW,(DWORD)basedir,FALSE); HeapFree(heap,0,nameW); } else resdir = GetResDirEntryW(resdir,(LPWSTR)name,(DWORD)basedir,FALSE); if (!resdir) return FALSE; et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { /* languages are just ids... I hope */ ret = lpfun(hmod,type,name,et[i].u1.Id,lparam); if (!ret) break; } return ret; } /********************************************************************** * EnumResourceLanguagesW (KERNEL32.87) */ BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name, ENUMRESLANGPROCW lpfun, LONG lparam ) { int i; PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod); PIMAGE_RESOURCE_DIRECTORY resdir; PIMAGE_RESOURCE_DIRECTORY_ENTRY et; BOOL ret; if (!basedir) return FALSE; resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE); if (!resdir) return FALSE; resdir = GetResDirEntryW(resdir,name,(DWORD)basedir,FALSE); if (!resdir) return FALSE; et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1); ret = FALSE; for (i=0;iNumberOfNamedEntries+resdir->NumberOfIdEntries;i++) { ret = lpfun(hmod,type,name,et[i].u1.Id,lparam); if (!ret) break; } return ret; }