Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1147 lines
33 KiB

/****************************** 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;
}