|
|
/****************************** Module Header ******************************\
* * Module Name: extract.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Icon Extraction Routines * * History: \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "newexe.h"
/****************************************************************************
****************************************************************************/
#define ICON_MAGIC 0
#define ICO_MAGIC1 1
#define CUR_MAGIC1 2
#define BMP_MAGIC ((WORD)'B'+((WORD)'M'<<8))
#define ANI_MAGIC ((WORD)'R'+((WORD)'I'<<8))
#define ANI_MAGIC1 ((WORD)'F'+((WORD)'F'<<8))
#define ANI_MAGIC4 ((WORD)'A'+((WORD)'C'<<8))
#define ANI_MAGIC5 ((WORD)'O'+((WORD)'N'<<8))
#define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
#define PEMAGIC ((WORD)'P'+((WORD)'E'<<8))
#define LEMAGIC ((WORD)'L'+((WORD)'E'<<8))
typedef struct new_exe NEWEXE, *LPNEWEXE; typedef struct exe_hdr EXEHDR, *LPEXEHDR; typedef struct rsrc_nameinfo RESNAMEINFO, *LPRESNAMEINFO; typedef struct rsrc_typeinfo RESTYPEINFO, *LPRESTYPEINFO; typedef struct rsrc_typeinfo UNALIGNED *ULPRESTYPEINFO; typedef struct new_rsrc RESTABLE, *LPRESTABLE;
#define NUMBER_OF_SECTIONS(x) ((x)->FileHeader.NumberOfSections)
#define FCC(c0,c1,c2,c3) ((DWORD)(c0)|((DWORD)(c1)<<8)|((DWORD)(c2)<<16)|((DWORD)(c3)<<24))
#define COM_FILE FCC('.', 'c', 'o', 'm')
#define BAT_FILE FCC('.', 'b', 'a', 't')
#define CMD_FILE FCC('.', 'c', 'm', 'd')
#define PIF_FILE FCC('.', 'p', 'i', 'f')
#define LNK_FILE FCC('.', 'l', 'n', 'k')
#define ICO_FILE FCC('.', 'i', 'c', 'o')
#define EXE_FILE FCC('.', 'e', 'x', 'e')
#define WIN32VER30 0x00030000 // for CreateIconFromResource()
#define GET_COUNT 424242
/***************************************************************************\
* PathIsUNC * * Inline function to check for a double-backslash at the * beginning of a string * \***************************************************************************/
__inline BOOL PathIsUNC( LPWSTR psz) { return (psz[0] == L'\\' && psz[1] == L'\\'); }
/***************************************************************************\
* ReadAByte * * This is used to touch memory to assure that if we page-fault, it is * outside win16lock. Most icons aren't more than two pages. * \***************************************************************************/
BOOL ReadAByte( LPCVOID pMem) { return ((*(PBYTE)pMem) == 0); }
/***************************************************************************\
* RVAtoP * * \***************************************************************************/
LPVOID RVAtoP( LPVOID pBase, DWORD rva) { LPEXEHDR pmz; IMAGE_NT_HEADERS *ppe; IMAGE_SECTION_HEADER *pSection; // section table
int i; DWORD size;
pmz = (LPEXEHDR)pBase; ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew);
/*
* Scan the section table looking for the RVA */ pSection = IMAGE_FIRST_SECTION(ppe);
for (i = 0; i < NUMBER_OF_SECTIONS(ppe); i++) {
size = pSection[i].Misc.VirtualSize ? pSection[i].Misc.VirtualSize : pSection[i].SizeOfRawData;
if (rva >= pSection[i].VirtualAddress && rva < pSection[i].VirtualAddress + size) {
return (LPBYTE)pBase + pSection[i].PointerToRawData + (rva - pSection[i].VirtualAddress); } }
return NULL; }
/***************************************************************************\
* GetResourceTablePE * * \***************************************************************************/
LPVOID GetResourceTablePE( LPVOID pBase) { LPEXEHDR pmz; IMAGE_NT_HEADERS *ppe;
pmz = (LPEXEHDR)pBase; ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew);
if (pmz->e_magic != MZMAGIC) return 0;
if (ppe->Signature != IMAGE_NT_SIGNATURE) return 0;
if (ppe->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { IMAGE_NT_HEADERS64* ppe64 = (IMAGE_NT_HEADERS64*)ppe;
if (ppe64->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL64_HEADER) { return 0; } return RVAtoP(pBase, ppe64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); } else { // assume a 32-bit image
IMAGE_NT_HEADERS32* ppe32 = (IMAGE_NT_HEADERS32*)ppe;
if (ppe32->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL32_HEADER) { return 0; } return RVAtoP(pBase, ppe32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); } }
/****************************************************************************
* FindResourcePE * * given a PE resource directory will find a resource in it. * * if iResIndex < 0 we will search for the specific index * if iResIndex >= 0 we will return the Nth index * if iResIndex == GET_COUNT the count of resources will be returned * \*****************************************************************************/
LPVOID FindResourcePE( LPVOID pBase, LPVOID prt, int iResIndex, int ResType, DWORD *pcb) { int i; int cnt; IMAGE_RESOURCE_DIRECTORY *pdir; IMAGE_RESOURCE_DIRECTORY_ENTRY *pres; IMAGE_RESOURCE_DATA_ENTRY UNALIGNED *pent;
pdir = (IMAGE_RESOURCE_DIRECTORY *)prt;
/*
* First find the type always a ID so ignore strings totaly */ cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries; pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1);
for (i = 0; i < cnt; i++) {
if (pres[i].Name == (DWORD)ResType) break; }
if (i==cnt) // did not find the type
return 0;
/*
* Now go find the actual resource either by id (iResIndex < 0) or * by ordinal (iResIndex >= 0) */ pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt + (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY));
cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries; pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1);
/*
* If we just want size, do it. */ if (iResIndex == GET_COUNT) return (LPVOID)UIntToPtr( cnt );
/*
* if we are to search for a specific id do it. */ if (iResIndex < 0) {
for (i = 0; i < cnt; i++) if (pres[i].Name == (DWORD)(-iResIndex)) break; } else { i = iResIndex; }
/*
* is the index in range? */ if (i >= cnt) return 0;
/*
* if we get this far the resource has a language part, ick! * We don't handle multi-language icons, so just return the first one. * Note, this isn't a problem since this function isn't called from * anywhere that could specify a language. As this is called from an * API (albeit a private one), changing this behavior is dangerous. */ if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) {
pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt + (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY)); pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1); i = 0; // choose first one
}
/*
* Nested way to deep for me! */ if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) return 0;
pent = (IMAGE_RESOURCE_DATA_ENTRY*)((LPBYTE)prt + pres[i].OffsetToData);
/*
* all OffsetToData fields except the final one are relative to * the start of the section. the final one is a virtual address * we need to go back to the header and get the virtual address * of the resource section to do this right. */ *pcb = pent->Size; return RVAtoP(pBase, pent->OffsetToData); }
/***************************************************************************\
* GetResourceTableNE * * \***************************************************************************/
LPVOID GetResourceTableNE( LPVOID pBase) { LPNEWEXE pne; LPEXEHDR pmz;
pmz = (LPEXEHDR)pBase; pne = (LPNEWEXE)((LPBYTE)pBase + pmz->e_lfanew);
if (pmz->e_magic != MZMAGIC) return 0;
if (pne->ne_magic != NEMAGIC) // must be a NEWEXE
return 0;
if (pne->ne_exetyp != NE_WINDOWS && // must be a Win DLL/EXE/386
pne->ne_exetyp != NE_DEV386) return 0;
if (pne->ne_expver < 0x0300) // must be 3.0 or greater
return 0;
if (pne->ne_rsrctab == pne->ne_restab) // no resources
return 0;
return (LPBYTE)pne + pne->ne_rsrctab; // return resource table pointer
}
/***************************************************************************\
* FindResourceNE * * This returns a pointer to the rsrc_nameinfo of the resource with the * given index and type, if it is found, otherwise it returns NULL. * * if iResIndex is < 0, then it is assumed to be a ID and the res table * will be searched for a matching id. * * if iResIndex is >= 0, then it is assumed to be a index and the Nth * resorce of the specifed type will be returned. * * if iResIndex == GET_COUNT the count of resources will be returned * \***************************************************************************/
LPVOID FindResourceNE( LPVOID lpBase, LPVOID prt, int iResIndex, int iResType, DWORD *pcb) { LPRESTABLE lpResTable; ULPRESTYPEINFO ulpResTypeInfo; LPRESNAMEINFO lpResNameInfo; // 16 bit alignment ok - had ushorts only
int i;
lpResTable = (LPRESTABLE)prt; //ulpResTypeInfo = (ULPRESTYPEINFO)(LPWBYTE)&lpResTable->rs_typeinfo;
ulpResTypeInfo = (ULPRESTYPEINFO)((LPBYTE)lpResTable + 2);
while (ulpResTypeInfo->rt_id) {
if (ulpResTypeInfo->rt_id == (iResType | RSORDID)) {
lpResNameInfo = (LPRESNAMEINFO)(ulpResTypeInfo + 1);
if (iResIndex == GET_COUNT) return (LPVOID)ulpResTypeInfo->rt_nres;
if (iResIndex < 0) {
for (i=0; i < (int)ulpResTypeInfo->rt_nres; i++) {
if (lpResNameInfo[i].rn_id == ((-iResIndex) | RSORDID)) break; }
iResIndex = i; }
if (iResIndex >= (int)ulpResTypeInfo->rt_nres) return NULL;
*pcb = ((DWORD)lpResNameInfo[iResIndex].rn_length) << lpResTable->rs_align; return (LPBYTE)lpBase + ((long)lpResNameInfo[iResIndex].rn_offset << lpResTable->rs_align); }
ulpResTypeInfo = (ULPRESTYPEINFO)((LPRESNAMEINFO)(ulpResTypeInfo + 1) + ulpResTypeInfo->rt_nres); }
*pcb = 0; return NULL; }
/***************************************************************************\
* ExtractIconFromICO * * \***************************************************************************/
UINT ExtractIconFromICO( LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT flags) { HICON hicon;
if (nIconIndex >= 1) return 0;
flags |= LR_LOADFROMFILE;
again:
hicon = LoadImage(NULL, szFile, IMAGE_ICON, LOWORD(cxIcon), LOWORD(cyIcon), flags);
if (hicon == NULL) return 0;
/*
* Do we just want a count? */ if (phicon == NULL) DestroyCursor((HCURSOR)hicon); else *phicon = hicon;
/*
* Check for large/small icon extract */ if (HIWORD(cxIcon)) {
cxIcon = HIWORD(cxIcon); cyIcon = HIWORD(cyIcon); phicon++;
goto again; }
return 1; }
/***************************************************************************\
* ExtractIconFromBMP * * \***************************************************************************/
#define ROP_DSna 0x00220326
UINT ExtractIconFromBMP( LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT flags) { HICON hicon; HBITMAP hbm; HBITMAP hbmMask; HDC hdc; HDC hdcMask; ICONINFO ii;
if (nIconIndex >= 1) return 0;
/*
* BUGUS: don't use LR_CREATEDIBSECTION. USER can't make an icon out * of a DibSection. */ flags |= LR_LOADFROMFILE;
again:
hbm = (HBITMAP)LoadImage(NULL, szFile, IMAGE_BITMAP, LOWORD(cxIcon), LOWORD(cyIcon), flags);
if (hbm == NULL) return 0;
/*
* do we just want a count? */ if (phicon == NULL) { DeleteObject(hbm); return 1; }
hbmMask = CreateBitmap(LOWORD(cxIcon), LOWORD(cyIcon), 1, 1, NULL);
hdc = CreateCompatibleDC(NULL); SelectObject(hdc, hbm);
hdcMask = CreateCompatibleDC(NULL); SelectObject(hdcMask, hbmMask);
SetBkColor(hdc, GetPixel(hdc, 0, 0));
BitBlt(hdcMask, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdc, 0, 0, SRCCOPY); BitBlt(hdc, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdcMask, 0, 0, ROP_DSna);
ii.fIcon = TRUE; ii.xHotspot = 0; ii.yHotspot = 0; ii.hbmColor = hbm; ii.hbmMask = hbmMask; hicon = CreateIconIndirect(&ii);
DeleteObject(hdc); DeleteObject(hbm); DeleteObject(hdcMask); DeleteObject(hbmMask);
*phicon = hicon;
/*
* Check for large/small icon extract */ if (HIWORD(cxIcon)) { cxIcon = HIWORD(cxIcon); cyIcon = HIWORD(cyIcon); phicon++;
goto again; }
return 1; }
/***************************************************************************\
* ExtractIconFromEXE * * \***************************************************************************/
UINT ExtractIconFromEXE( HANDLE hFile, int nIconIndex, int cxIconSize, int cyIconSize, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags) { HANDLE hFileMap = INVALID_HANDLE_VALUE; LPVOID lpFile = NULL; EXEHDR *pmz; NEWEXE UNALIGNED *pne; LPVOID pBase; LPVOID pres = NULL; UINT result = 0; LONG FileLength; DWORD cbSize; int cxIcon; int cyIcon;
LPVOID (*FindResourceX)(LPVOID pBase, LPVOID prt, int iResIndex, int iResType, DWORD *pcb);
FileLength = (LONG)GetFileSize(hFile, NULL);
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMap == NULL) goto exit;
lpFile = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if (lpFile == NULL) goto exit;
pBase = (LPVOID)lpFile; pmz = (struct exe_hdr *)pBase;
_try {
if (pmz->e_magic != MZMAGIC) goto exit;
if (pmz->e_lfanew <= 0) // not a new exe
goto exit;
if (pmz->e_lfanew >= FileLength) // not a new exe
goto exit;
pne = (NEWEXE UNALIGNED *)((BYTE*)pmz + pmz->e_lfanew);
switch (pne->ne_magic) { case NEMAGIC: pres = GetResourceTableNE(pBase); FindResourceX = FindResourceNE; break;
case PEMAGIC: pres = GetResourceTablePE(pBase); FindResourceX = FindResourcePE; break; }
/*
* cant find the resource table, fail */ if (pres == NULL) goto exit;
/*
* do we just want a count? */ if (phicon == NULL) { result = PtrToUlong(FindResourceX(pBase, pres, GET_COUNT, (LONG_PTR)RT_GROUP_ICON, &cbSize)); goto exit; }
while (result < nIcons) {
LPVOID lpIconDir; LPVOID lpIcon; int idIcon;
cxIcon = cxIconSize; cyIcon = cyIconSize;
/*
* find the icon dir for this icon. */ lpIconDir = FindResourceX(pBase, pres, nIconIndex, (LONG_PTR)RT_GROUP_ICON, &cbSize);
if (lpIconDir == NULL) goto exit;
if ((((LPNEWHEADER)lpIconDir)->Reserved != 0) || (((LPNEWHEADER)lpIconDir)->ResType != FT_ICON)) {
goto exit; } again: idIcon = LookupIconIdFromDirectoryEx((LPBYTE)lpIconDir, TRUE, LOWORD(cxIcon), LOWORD(cyIcon), flags); lpIcon = FindResourceX(pBase, pres, -idIcon, (LONG_PTR)RT_ICON, &cbSize);
if (lpIcon == NULL) goto exit;
if ((((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPINFOHEADER)) && (((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPCOREHEADER))) {
goto exit; }
#ifndef WINNT
/* touch this memory before calling USER
* so if we page fault we will do it outside of the Win16Lock * most icons aren't more than 2 pages */ ReadAByte(((BYTE *)lpIcon) + cbSize - 1); #endif
if (piconid) piconid[result] = idIcon;
phicon[result++] = CreateIconFromResourceEx((LPBYTE)lpIcon, cbSize, TRUE, WIN32VER30, LOWORD(cxIcon), LOWORD(cyIcon), flags);
/*
* check for large/small icon extract */ if (HIWORD(cxIcon)) {
cxIcon = HIWORD(cxIcon); cyIcon = HIWORD(cyIcon);
goto again; }
nIconIndex++; // next icon index
}
} _except (W32ExceptionHandler(FALSE, RIP_WARNING)) { result = 0; }
exit:
if (lpFile) UnmapViewOfFile(lpFile);
if (hFileMap != INVALID_HANDLE_VALUE) CloseHandle(hFileMap);
return result; }
/***************************************************************************\
* PathFindExtension * * \***************************************************************************/
LPWSTR PathFindExtension( LPWSTR pszPath) { LPWSTR pszDot;
for (pszDot = NULL; *pszPath; pszPath = CharNext(pszPath)) {
switch (*pszPath) { case L'.': pszDot = pszPath; // remember the last dot
break;
case L'\\': case L' ': // extensions can't have spaces
pszDot = NULL; // forget last dot, it was in a directory
break; } }
/*
* if we found the extension, return ptr to the dot, else * ptr to end of the string (NULL extension) (cast->non const) */ return pszDot ? (LPWSTR)pszDot : (LPWSTR)pszPath; }
/***************************************************************************\
* PrivateExtractIconExA * * Ansi version of PrivateExtractIconExW * \***************************************************************************/
WINUSERAPI UINT PrivateExtractIconExA( LPCSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons) { LPWSTR szFileNameW; UINT uRet;
if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE)) return 0;
uRet = PrivateExtractIconExW(szFileNameW, nIconIndex, phiconLarge, phiconSmall, nIcons);
UserLocalFree(szFileNameW);
return uRet; }
/***************************************************************************\
* HasExtension * * \***************************************************************************/
DWORD HasExtension( LPWSTR pszPath) { LPWSTR p = PathFindExtension(pszPath);
/*
* (BobDay, emended by JasonSch): * * NOTE: This routine can produce false positives. E.g., "Fister.Bather" * would return .BAT. This doesn't currently hurt us in the instances where * this routine is used. However, people stealing this code should verify * that this is okay for them. * * NOTE: We could make this EXTKEY based like the extension matching * stuff elsewhere (e.g., shlwapi\urlpars.cpp). EXTKEY is a QWORD * so UNICODE would fit. */ if (*p == L'.') {
WCHAR szExt[5];
lstrcpynW(szExt, p, 5);
if (lstrcmpiW(szExt,TEXT(".com")) == 0) return COM_FILE; if (lstrcmpiW(szExt,TEXT(".bat")) == 0) return BAT_FILE; if (lstrcmpiW(szExt,TEXT(".cmd")) == 0) return CMD_FILE; if (lstrcmpiW(szExt,TEXT(".pif")) == 0) return PIF_FILE; if (lstrcmpiW(szExt,TEXT(".lnk")) == 0) return LNK_FILE; if (lstrcmpiW(szExt,TEXT(".ico")) == 0) return ICO_FILE; if (lstrcmpiW(szExt,TEXT(".exe")) == 0) return EXE_FILE; }
return 0; }
/***************************************************************************\
* PrivateExtractIconsW * * Extracts 1 or more icons from a file. * * input: * szFileName - EXE/DLL/ICO/CUR/ANI file to extract from * nIconIndex - what icon to extract * 0 = first icon, 1=second icon, etc. * -N = icon with id==N * cxIcon - icon size wanted (if HIWORD != 0 two sizes...) * cyIcon - icon size wanted (if HIWORD != 0 two sizes...) * 0,0 means extract at natural size. * phicon - place to return extracted icon(s) * nIcons - number of icons to extract. * flags - LoadImage LR_* flags * * returns: * if picon is NULL, number of icons in the file is returned. * * notes: * handles extraction from PE (Win32), NE (Win16), ICO (Icon), * CUR (Cursor), ANI (Animated Cursor), and BMP (Bitmap) files. * only Win16 3.x files are supported (not 2.x) * * cx/cyIcon are the size of the icon to extract, two sizes * can be extracted by putting size 1 in the loword and size 2 in the * hiword, ie MAKELONG(24, 48) would extract 24 and 48 size icons. * This is a hack it is done so IExtractIcon::Extract can be called by * outside people with custom large/small icon sizes that are not what * the shell uses internaly. * \***************************************************************************/
WINUSERAPI UINT WINAPI PrivateExtractIconsW( LPCWSTR szFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags) { HANDLE hFile = (HANDLE)INVALID_HANDLE_VALUE; UINT result = 0; WORD magic[6]; WCHAR achFileName[MAX_PATH]; FILETIME ftAccess; WCHAR szExpFileName[MAX_PATH]; DWORD dwBytesRead;
/*
* Set failure defaults. */ if (phicon) *phicon = NULL;
/*
* Check for special extensions, and fail quick */ switch (HasExtension((LPWSTR)szFileName)) { case COM_FILE: case BAT_FILE: case CMD_FILE: case PIF_FILE: case LNK_FILE: goto exit;
default: break; }
/*
* Try expanding environment variables in the file name we're passed. */ ExpandEnvironmentStrings(szFileName, szExpFileName, MAX_PATH); szExpFileName[ MAX_PATH-1 ] = (WCHAR)0;
/*
* Open the file - First check to see if it is a UNC path. If it * is make sure that we have access to the path... */ if (PathIsUNC(szExpFileName)) {
lstrcpynW(achFileName, szExpFileName, ARRAYSIZE(achFileName));
} else {
if (SearchPath(NULL, szExpFileName, NULL, ARRAYSIZE(achFileName), achFileName, NULL) == 0) {
goto error_file; } }
hFile = CreateFile(achFileName, GENERIC_READ|FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
if (hFile == INVALID_HANDLE_VALUE) {
hFile = CreateFile(achFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0);
if (hFile == INVALID_HANDLE_VALUE) goto error_file;
} else {
/*
* Restore the Access Date */ if (GetFileTime(hFile, NULL, &ftAccess, NULL)) SetFileTime(hFile, NULL, &ftAccess, NULL); }
ReadFile(hFile, &magic, sizeof(magic), &dwBytesRead, NULL); if (dwBytesRead != sizeof(magic)) goto exit;
if (piconid) *piconid = (UINT)-1; // Fill in "don't know" value
switch (magic[0]) { case MZMAGIC: result = ExtractIconFromEXE(hFile, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags); break;
case ANI_MAGIC: // possible .ani cursor
/*
* Ani cursors are easy they are RIFF files of type 'ACON' */ if (magic[1] == ANI_MAGIC1 && magic[4] == ANI_MAGIC4 && magic[5] == ANI_MAGIC5) {
result = ExtractIconFromICO(achFileName, nIconIndex, cxIcon, cyIcon, phicon, flags); } break;
case BMP_MAGIC: // possible bitmap
result = ExtractIconFromBMP(achFileName, nIconIndex, cxIcon, cyIcon, phicon, flags); break;
case ICON_MAGIC: // possible .ico or .cur
/*
* Icons and cursors look like this * * iReserved - always zero * iResourceType - 1 for icons 2 cor cursor. * cresIcons - number of resolutions in this file * * We only allow 1 <= cresIcons <= 10 */ if (magic[1] == ICO_MAGIC1 || magic[1] == CUR_MAGIC1) {
result = ExtractIconFromICO(achFileName, nIconIndex, cxIcon, cyIcon, phicon, flags); } break; }
exit:
if (hFile!=INVALID_HANDLE_VALUE) CloseHandle(hFile);
return result;
/*
* if we cant open the file, return a code saying we cant open the file * if phicon==NULL return the count of icons in the file 0 */
error_file:
result = (phicon ? (UINT)-1 : 0);
goto exit; }
/***************************************************************************\
* PrivateExtractIconsA * * \***************************************************************************/
WINUSERAPI UINT WINAPI PrivateExtractIconsA( LPCSTR szFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags) { LPWSTR szFileNameW; UINT uRet;
if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE)) return 0;
uRet = PrivateExtractIconsW(szFileNameW, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags);
UserLocalFree(szFileNameW);
return uRet; }
/***************************************************************************\
* PrivateExtractIconExW * * extracts 1 or more icons from a file. * * input: * szFileName - EXE/DLL/ICO file to extract from * nIconIndex - what icon to extract * 0 = first icon, 1=second icon, etc. * -N = icon with id==N * phiconLarge - place to return extracted icon(s) * phiconSmall - place to return extracted icon(s) (small size) * nIcons - number of icons to extract. * * returns: * number of icons extracted, or the count of icons if phiconLarge==NULL * * notes: * handles extraction from PE (Win32), NE (Win16), and ICO (Icon) files. * only Win16 3.x files are supported (not 2.x) * \***************************************************************************/
WINUSERAPI UINT PrivateExtractIconExW( LPCWSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons) { UINT result = 0;
if ((nIconIndex == -1) || ((phiconLarge == NULL) && (phiconSmall == NULL))) return PrivateExtractIconsW(szFileName, 0, 0, 0, NULL, NULL, 0, 0);
if (phiconLarge && phiconSmall && (nIcons == 1)) {
HICON ahicon[2];
ahicon[0] = NULL; ahicon[1] = NULL;
result = PrivateExtractIconsW(szFileName, nIconIndex, MAKELONG(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXSMICON)), MAKELONG(GetSystemMetrics(SM_CYICON), GetSystemMetrics(SM_CYSMICON)), ahicon, NULL, 2, 0);
*phiconLarge = ahicon[0]; *phiconSmall = ahicon[1];
} else {
if (phiconLarge) result = PrivateExtractIconsW(szFileName, nIconIndex, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), phiconLarge, NULL, nIcons, 0);
if (phiconSmall) result = PrivateExtractIconsW(szFileName, nIconIndex, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), phiconSmall, NULL, nIcons, 0); }
return result; }
|