windows-nt/Source/XPSP1/NT/shell/shell32/extract.c
2020-09-26 16:20:57 +08:00

1546 lines
46 KiB
C

#include "shellprv.h"
#pragma hdrstop
#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 new_rsrc RESTABLE, *LPRESTABLE;
#define RESOURCE_VA(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
#define RESOURCE_SIZE(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size)
#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')
/****************************************************************************
* extract a single icon from a exe file, or get the count.
*
* If nIconIndex != -1
* Returns:
* The handle of the icon, if successful.
* 0, if the file does not exist or an icon with the "nIconIndex"
* does not exist.
* 1, if the given file is not an EXE or ICO file.
*
* If nIconIndex == -1
* Returns:
* The number of icons in the file if successful.
* 0, if the file has no icons or isn't an icon file.
*
****************************************************************************/
HICON WINAPI ExtractIcon(HINSTANCE hInst, LPCTSTR szFileName, UINT nIconIndex)
{
HICON hIcon;
if (nIconIndex == (UINT) -1)
hIcon = (HICON)IntToPtr( ExtractIcons(szFileName, 0, 0, 0, NULL, NULL, 0, 0) );
else
ExtractIcons(szFileName, nIconIndex, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &hIcon, NULL, 1, 0);
return hIcon;
}
/****************************************************************************
*
* in:
* lpIconPath path of thing to extract icon for (may be an exe
* or something that is associated)
* lpiIcon icon index to use
*
* lpIconPath filled in with the real path where the icon came from
* lpiIcon filled in with the real icon index
*
* returns:
*
* note: if the caller is the shell it returns special icons
* from within the shell.dll
*
****************************************************************************/
HICON WINAPI ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, WORD *lpiIcon)
{
HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
if (hIcon == NULL)
hIcon = SHGetFileIcon(NULL, lpIconPath, 0, SHGFI_LARGEICON);
if (hIcon == NULL)
{
*lpiIcon = IDI_DOCUMENT;
GetModuleFileName(HINST_THISDLL, lpIconPath, 128);
hIcon = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(*lpiIcon));
}
return hIcon;
}
/****************************************************************************
*
* 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)
*
****************************************************************************/
UINT WINAPI ExtractIconExW(LPCWSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
{
return PrivateExtractIconExW( szFileName, nIconIndex, phiconLarge, phiconSmall, nIcons );
}
UINT WINAPI ExtractIconExA(LPCSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
{
return PrivateExtractIconExA( szFileName, nIconIndex, phiconLarge, phiconSmall, nIcons );
}
/****************************************************************************
*
* 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.
* yea 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.
*
****************************************************************************/
UINT WINAPI SHExtractIconsW(LPCWSTR wszFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags)
{
#ifdef UNICODE
return ExtractIcons(wszFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags);
#else // UNICODE
TCHAR sz[MAX_PATH];
SHUnicodeToTChar(wszFileName, sz, ARRAYSIZE(sz));
return ExtractIcons(sz, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags);
#endif // UNICODE
}
UINT WINAPI ExtractIcons(LPCTSTR szFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags)
{
#ifdef UNICODE
return PrivateExtractIconsW( szFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags );
#else
return PrivateExtractIconsA( szFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags );
#endif
}
DWORD HasExtension(LPCTSTR pszPath)
{
LPCTSTR p = PathFindExtension(pszPath);
//
//
// PERF: BobDay - We could make this EXTKEY based like the extension
// matching stuff elsewhere. EXTKEY is a QWORD value so UNICODE would fit.
//
if (*p == TEXT('.'))
{
#ifdef UNICODE
WCHAR szExt[5];
lstrcpyn(szExt,p,5);
if ( lstrcmpi(szExt,TEXT(".com")) == 0 ) return COM_FILE;
if ( lstrcmpi(szExt,TEXT(".bat")) == 0 ) return BAT_FILE;
if ( lstrcmpi(szExt,TEXT(".cmd")) == 0 ) return CMD_FILE;
if ( lstrcmpi(szExt,TEXT(".pif")) == 0 ) return PIF_FILE;
if ( lstrcmpi(szExt,TEXT(".lnk")) == 0 ) return LNK_FILE;
if ( lstrcmpi(szExt,TEXT(".ico")) == 0 ) return ICO_FILE;
if ( lstrcmpi(szExt,TEXT(".exe")) == 0 ) return EXE_FILE;
return 0;
#else
return *((UNALIGNED DWORD *)p) | 0x20202000; // make lower case
#endif
}
else
return 0;
}
/****************************************************************************
* get the EXE type of the passed file (DOS, Win16, Win32)
*
* returns:
* 0 = not a exe of any type.
*
* if a windows app
* LOWORD = NE or PE
* HIWORD = windows version 3.0, 3.5, 4.0
*
* if a DOS app (or a .com or batch file on non-NT)
* LOWORD = MZ
* HIWORD = 0
*
* if a Win32 console app (or a batch file on NT)
* LOWORD = PE
* HIWORD = 0
*
* this is so similar to the Win32 API GetBinaryType() too bad Win95
* kernel does not support it.
*
****************************************************************************/
DWORD WINAPI GetExeType(LPCTSTR szFile)
{
HANDLE fh;
DWORD dw;
struct exe_hdr exehdr;
struct new_exe newexe;
FILETIME ftAccess;
DWORD dwRead;
//
// check for special extensions, and fail quick
//
switch (HasExtension(szFile))
{
case COM_FILE:
// handle the case like \\server.microsoft.com
// PERF - Bobday - This does the same operation twice, we should really
// make PathIsUNCServerShare return a code based on what it found...
if (PathIsUNCServer(szFile) || PathIsUNCServerShare(szFile))
return 0;
return MAKELONG(MZMAGIC, 0); // DOS exe
case BAT_FILE:
case CMD_FILE:
return MAKELONG(PEMAGIC, 0); // NT exe (pretend)
case EXE_FILE: // we need to open it.
break;
default:
return 0; // not a exe, or if it is we dont care
}
newexe.ne_expver = 0;
fh = CreateFile(szFile, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0);
if (fh == INVALID_HANDLE_VALUE)
{
//
// We may be trying to get properties for a file on a volume where
// we don't have write access, so try opening the file for read
// only access. This will mean we can't preserve the access
// time (those calls will fail), but this is better than not returning
// the exe type at all...
//
fh = CreateFile(szFile, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0, OPEN_EXISTING, 0, 0);
//
// at this point if we get an INVALID_HANDLE_VALUE, we really
// can't do much else, so now return a failure...
//
if (fh == INVALID_HANDLE_VALUE)
{
return 0;
}
}
// preserve the access time
if (GetFileTime(fh, NULL, &ftAccess, NULL))
SetFileTime(fh, NULL, &ftAccess, NULL);
if (!ReadFile(fh, &exehdr, sizeof(exehdr), &dwRead, NULL) ||
(dwRead != sizeof(exehdr)))
goto error;
if (exehdr.e_magic != EMAGIC)
goto error;
SetFilePointer(fh, exehdr.e_lfanew, NULL, FILE_BEGIN);
ReadFile(fh,&newexe, sizeof(newexe), &dwRead, NULL);
if (newexe.ne_magic == PEMAGIC)
{
// read the SubsystemVersion
SetFilePointer(fh, exehdr.e_lfanew+18*4, NULL, FILE_BEGIN);
ReadFile(fh,&dw,4, &dwRead, NULL);
newexe.ne_expver = LOBYTE(LOWORD(dw)) << 8 | LOBYTE(HIWORD(dw));
// read the Subsystem
SetFilePointer(fh, exehdr.e_lfanew+23*4, NULL, FILE_BEGIN);
ReadFile(fh,&dw,4, &dwRead, NULL);
// if it is not a Win32 GUI app return a version of 0
if (LOWORD(dw) != 2) // IMAGE_SUBSYSTEM_WINDOWS_GUI
newexe.ne_expver = 0;
goto exit;
}
else if (newexe.ne_magic == LEMAGIC)
{
newexe.ne_magic = MZMAGIC; // just a DOS exe
newexe.ne_expver = 0;
}
else if (newexe.ne_magic == NEMAGIC)
{
//
// we found a 'NE' it still might not be a windows
// app, it could be.....
//
// a OS/2 app ne_exetyp==NE_OS2
// a DOS4 app ne_exetyp==NE_DOS4
// a VxD ne_exetyp==DEV386
//
// only treat it as a Windows app if the exetype
// is NE_WINDOWS or NE_UNKNOWN
//
if (newexe.ne_exetyp != NE_WINDOWS && newexe.ne_exetyp != NE_UNKNOWN)
{
newexe.ne_magic = MZMAGIC; // just a DOS exe
newexe.ne_expver = 0;
}
//
// if could also have a bogus expected windows version
// (treat 0 as invalid)
//
if (newexe.ne_expver == 0)
{
newexe.ne_magic = MZMAGIC; // just a DOS exe
newexe.ne_expver = 0;
}
}
else // if (newexe.ne_magic != NEMAGIC)
{
newexe.ne_magic = MZMAGIC; // just a DOS exe
newexe.ne_expver = 0;
}
exit:
CloseHandle(fh);
return MAKELONG(newexe.ne_magic, newexe.ne_expver);
error:
CloseHandle(fh);
return 0;
}
#define M_llseek(fh, lOff, iOrg) SetFilePointer((HANDLE)IntToPtr( fh ), lOff, NULL, (DWORD)iOrg)
#define M_lread(fh, lpBuf, cb) _lread((HFILE)fh, lpBuf, cb)
#define MAGIC_ICON30 0
#define MAGIC_MARKZIBO ((WORD)'M'+((WORD)'Z'<<8))
typedef struct new_exe NEWEXEHDR;
typedef NEWEXEHDR *PNEWEXEHDR;
#define SEEK_FROMZERO 0
#define SEEK_FROMCURRENT 1
#define SEEK_FROMEND 2
#define NSMOVE 0x0010
#define VER 0x0300
#define CCHICONPATHMAXLEN 128
typedef struct
{
HANDLE hAppInst;
HANDLE hFileName;
HANDLE hIconList;
INT nIcons;
} EXTRACTICONINFO;
EXTRACTICONINFO ExtractIconInfo = {NULL, NULL, NULL, 0};
INT nIcons;
typedef struct
{
HICON hIcon;
INT iIconId;
} MYICONINFO;
HANDLE APIENTRY InternalExtractIconW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex, UINT nIcons);
HICON APIENTRY DuplicateIcon(HINSTANCE hInst, HICON hIcon)
{
ICONINFO IconInfo;
if (!GetIconInfo(hIcon, &IconInfo))
return NULL;
hIcon = CreateIconIndirect(&IconInfo);
DeleteObject(IconInfo.hbmMask);
DeleteObject(IconInfo.hbmColor);
UNREFERENCED_PARAMETER(hInst);
return hIcon;
}
// 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.
LPBYTE FindResWithIndex(LPBYTE lpResTable, INT iResIndex, LPBYTE lpResType)
{
try
{
LPRESTYPEINFO lpResTypeInfo = (LPRESTYPEINFO)(lpResTable + sizeof(WORD));
while (lpResTypeInfo->rt_id)
{
if ((lpResTypeInfo->rt_id & RSORDID) &&
(MAKEINTRESOURCE(lpResTypeInfo->rt_id & ~RSORDID) == (LPTSTR)lpResType))
{
if (lpResTypeInfo->rt_nres > (WORD)iResIndex)
return((LPBYTE)(lpResTypeInfo+1) + iResIndex * sizeof(RESNAMEINFO));
else
return NULL;
}
lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres * sizeof(RESNAMEINFO));
}
return NULL;
}
except (EXCEPTION_EXECUTE_HANDLER)
{
return NULL;
}
}
/* This returns the index (1-relative) of the given resource-id
* in the resource table, if it is found, otherwise it returns NULL.
*/
INT GetResIndex(LPBYTE lpResTable, INT iResId, LPBYTE lpResType)
{
WORD w;
LPRESNAMEINFO lpResNameInfo;
LPRESTYPEINFO lpResTypeInfo = (LPRESTYPEINFO)(lpResTable + sizeof(WORD));
while (lpResTypeInfo->rt_id)
{
if ((lpResTypeInfo->rt_id & RSORDID) && (MAKEINTRESOURCE(lpResTypeInfo->rt_id & ~RSORDID) == (LPTSTR)lpResType))
{
lpResNameInfo = (LPRESNAMEINFO)(lpResTypeInfo+1);
for (w=0; w < lpResTypeInfo->rt_nres; w++, lpResNameInfo++)
{
if ((lpResNameInfo->rn_id & RSORDID) && ((lpResNameInfo->rn_id & ~RSORDID) == iResId))
return(w+1);
}
return 0;
}
lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres * sizeof(RESNAMEINFO));
}
return 0;
}
HANDLE SimpleLoadResource(HFILE fh, LPBYTE lpResTable, INT iResIndex, LPBYTE lpResType)
{
INT iShiftCount;
HICON hIcon;
LPBYTE lpIcon;
DWORD dwSize;
DWORD dwOffset;
LPRESNAMEINFO lpResPtr;
/* The first 2 bytes in ResTable indicate the amount other values should be
* shifted left.
*/
iShiftCount = *((WORD *)lpResTable);
lpResPtr = (LPRESNAMEINFO)FindResWithIndex(lpResTable, iResIndex, lpResType);
if (!lpResPtr)
return NULL;
/* Left shift the offset to form a LONG. */
dwOffset = MAKELONG(lpResPtr->rn_offset << iShiftCount, (lpResPtr->rn_offset) >> (16 - iShiftCount));
dwSize = lpResPtr->rn_length << iShiftCount;
if (M_llseek(fh, dwOffset, SEEK_FROMZERO) == -1L)
return NULL;
if (!(hIcon = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, dwSize)))
return NULL;
if (!(lpIcon = GlobalLock(hIcon)))
goto SLRErr1;
if (_lread(fh, (LPVOID)lpIcon, dwSize) < dwSize)
goto SLRErr2;
GlobalUnlock(hIcon);
return hIcon;
SLRErr2:
GlobalUnlock(hIcon);
SLRErr1:
GlobalFree(hIcon);
return NULL;
}
INT __cdecl CompareIconId(MYICONINFO *lpIconInfo1, MYICONINFO *lpIconInfo2)
{
return lpIconInfo1->iIconId - lpIconInfo2->iIconId;
}
VOID FreeIconList(HANDLE hIconList, int iKeepIcon)
{
MYICONINFO *lpIconList;
INT i;
if (ExtractIconInfo.hIconList == hIconList) {
ExtractIconInfo.hIconList = NULL;
}
if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(hIconList))) {
for (i = 0; i < ExtractIconInfo.nIcons; i++) {
if (i != iKeepIcon) {
DestroyIcon((lpIconList + i)->hIcon);
}
}
GlobalUnlock(hIconList);
GlobalFree(hIconList);
}
}
VOID FreeExtractIconInfo(INT iKeepIcon)
{
MYICONINFO *lpIconList;
INT i;
if (ExtractIconInfo.hIconList) {
if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(ExtractIconInfo.hIconList))) {
for (i = 0; i < ExtractIconInfo.nIcons; i++) {
if (i != iKeepIcon) {
DestroyIcon((lpIconList + i)->hIcon);
}
}
GlobalUnlock(ExtractIconInfo.hIconList);
}
GlobalFree(ExtractIconInfo.hIconList);
ExtractIconInfo.hIconList = NULL;
}
ExtractIconInfo.hAppInst = NULL;
ExtractIconInfo.nIcons = 0;
if (ExtractIconInfo.hFileName) {
GlobalFree(ExtractIconInfo.hFileName);
ExtractIconInfo.hFileName = NULL;
}
}
#ifdef UNICODE
HICON APIENTRY ExtractIconA(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex)
{
if (lpszExeFileName) {
LPWSTR lpszExeFileNameW;
WORD wLen = lstrlenA(lpszExeFileName) + 1;
if (!(lpszExeFileNameW = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (wLen * sizeof(WCHAR))))) {
return NULL;
} else {
HICON hIcon;
MultiByteToWideChar(CP_ACP, 0, lpszExeFileName, -1, lpszExeFileNameW, wLen-1);
hIcon = ExtractIconW(hInst, lpszExeFileNameW, nIconIndex);
LocalFree(lpszExeFileNameW);
return hIcon;
}
} else {
return NULL;
}
}
#else
HICON APIENTRY ExtractIconW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex)
{
return NULL;
}
#endif
// Returns a handle to a list of icons
#ifdef UNICODE
HANDLE APIENTRY InternalExtractIconListW(HANDLE hInst, LPWSTR lpszExeFileName, LPINT lpnIcons)
{
UINT cIcons, uiResult, i;
UINT * lpIDs = NULL;
HICON * lpIcons = NULL;
HGLOBAL hIconInfo = NULL;
MYICONINFO *lpIconInfo = NULL;
//
// Determine the number of icons
//
cIcons = PtrToUlong( ExtractIconW(hInst, lpszExeFileName, (UINT)-1));
if (cIcons <= 0)
return NULL;
//
// Allocate space for an array of UINT's and HICON's
//
lpIDs = GlobalAlloc(GPTR, cIcons * sizeof(UINT));
if (!lpIDs) {
goto IconList_Exit;
}
lpIcons = GlobalAlloc(GPTR, cIcons * sizeof(HICON));
if (!lpIcons) {
goto IconList_Exit;
}
//
// Allocate space for the array of icons
//
hIconInfo = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, cIcons * sizeof(MYICONINFO));
if (!hIconInfo) {
goto IconList_Exit;
}
//
// This has to be GlobalLock'ed since the handle is going to
// be passed back to the application.
//
lpIconInfo = GlobalLock(hIconInfo);
if (!lpIconInfo) {
goto IconList_Exit;
}
//
// Call ExtractIcons to do the real work.
//
uiResult = ExtractIcons(lpszExeFileName,
0,
GetSystemMetrics(SM_CXICON),
GetSystemMetrics(SM_CYICON),
lpIcons,
lpIDs,
cIcons,
0);
if (uiResult <= 0) {
goto IconList_Exit;
}
//
// Loop through the icons and fill in the array.
//
for (i=0; i < cIcons; i++) {
lpIconInfo[i].hIcon = lpIcons[i];
lpIconInfo[i].iIconId = lpIDs[i];
}
//
// Unlock the array handle.
//
GlobalUnlock(hIconInfo);
//
// Clean up allocations
//
GlobalFree(lpIDs);
GlobalFree(lpIcons);
//
// Success.
//
return hIconInfo;
IconList_Exit:
//
// Error case. Clean up and return NULL
//
if (lpIconInfo)
GlobalUnlock(hIconInfo);
if (hIconInfo)
GlobalFree(hIconInfo);
if (lpIcons)
GlobalFree(lpIcons);
if (lpIDs)
GlobalFree(lpIDs);
return NULL;
}
#else // Unicode
HANDLE APIENTRY InternalExtractIconListW(HANDLE hInst, LPWSTR lpszExeFileName, LPINT lpnIcons)
{
return NULL;
}
#endif
HANDLE APIENTRY InternalExtractIconListA(HANDLE hInst, LPSTR lpszExeFileName, LPINT lpnIcons)
{
return NULL;
}
#ifdef UNICODE
HANDLE APIENTRY InternalExtractIconA(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT wIconIndex, UINT nIcons)
{
return NULL;
}
#endif
/* ExtractVersionResource16W
* Retrieves a resource from win16 images. Most of this code
* is stolen from ExtractIconResInfoW in ..\library\extract.c
*
* LPWSTR lpwstrFilename - file to extract
* LPHANDLE lpData - return buffer for handle, NULL if not needed
*
* Returns: size of buffer needed
*/
DWORD ExtractVersionResource16W(LPCWSTR lpwstrFilename, LPHANDLE lphData)
{
HFILE fh;
WORD wMagic;
INT iTableSize;
LPBYTE lpResTable;
DWORD lOffset;
HANDLE hResTable;
NEWEXEHDR NEHeader;
HANDLE hRes;
DWORD dwSize =0;
//
// Try to open the specified file.
//
fh = HandleToLong(CreateFileW(lpwstrFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL));
if (fh == HandleToLong(INVALID_HANDLE_VALUE)) {
fh = HandleToLong(CreateFileW(lpwstrFilename,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
}
if (fh == HandleToLong(INVALID_HANDLE_VALUE))
return 0;
//
// Read the first two bytes in the file.
//
if (_lread(fh, (LPVOID)&wMagic, 2) != 2)
goto EIExit;
switch (wMagic) {
case MAGIC_MARKZIBO:
//
// Make sure that the file is in the NEW EXE format.
//
if (M_llseek(fh, (LONG)0x3C, SEEK_FROMZERO) == -1L)
goto EIExit;
if (_lread(fh, (LPVOID)&lOffset, sizeof(LONG)) != sizeof(LONG))
goto EIExit;
if (lOffset == 0L)
goto EIExit;
//
// Read in the EXE header.
//
if (M_llseek(fh, lOffset, SEEK_FROMZERO) == -1L)
goto EIExit;
if (_lread(fh, (LPVOID)&NEHeader, sizeof(NEWEXEHDR)) != sizeof(NEWEXEHDR))
goto EIExit;
//
// Is it a NEW EXE?
//
if (NE_MAGIC(NEHeader) != NEMAGIC)
goto EIExit;
if ((NE_EXETYP(NEHeader) != NE_WINDOWS) &&
(NE_EXETYP(NEHeader) != NE_DEV386) &&
(NE_EXETYP(NEHeader) != NE_UNKNOWN)) /* Some Win2.X apps have NE_UNKNOWN in this field */
goto EIExit;
//
// Are there any resources?
//
if (NE_RSRCTAB(NEHeader) == NE_RESTAB(NEHeader))
goto EIExit;
//
// Allocate space for the resource table.
//
iTableSize = NE_RESTAB(NEHeader) - NE_RSRCTAB(NEHeader);
hResTable = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, (DWORD)iTableSize);
if (!hResTable)
goto EIExit;
//
// Lock down the resource table.
lpResTable = GlobalLock(hResTable);
if (!lpResTable) {
GlobalFree(hResTable);
goto EIExit;
}
//
// Copy the resource table into memory.
//
if (M_llseek(fh,
(LONG)(lOffset + NE_RSRCTAB(NEHeader)),
SEEK_FROMZERO) == -1) {
goto EIErrExit;
}
if (_lread(fh, (LPBYTE)lpResTable, iTableSize) != (DWORD)iTableSize)
goto EIErrExit;
//
// Simply load the specified icon.
//
hRes = SimpleLoadResource(fh, lpResTable, 0, (LPBYTE)RT_VERSION);
if (hRes) {
dwSize = (DWORD) GlobalSize(hRes);
if (lphData) {
*lphData = hRes;
} else {
GlobalFree(hRes);
}
}
EIErrExit:
GlobalUnlock(hResTable);
GlobalFree(hResTable);
break;
}
EIExit:
_lclose(fh);
return dwSize;
}
/* Returns the file's format: 2 for WIndows 2.X, 3 for WIndows 3.X, */
/* 0 if error. */
/* Returns the handle to the Icon resource corresponding to wIconIndex */
/* in lphIconRes, and the size of the resource in lpwSize. */
/* This is used only by Progman which needs to save the icon resource */
/* itself in the .GRP files (the actual icon handle is not wanted). */
/* */
/* 08-04-91 JohanneC Created. */
WORD APIENTRY ExtractIconResInfoW(HANDLE hInst, LPWSTR lpszFileName, WORD wIconIndex, LPWORD lpwSize, LPHANDLE lphIconRes)
{
HFILE fh;
WORD wMagic;
BOOL bNewResFormat;
HANDLE hIconDir; /* Icon directory */
LPBYTE lpIconDir;
HICON hIcon = NULL;
BOOL bFormatOK = FALSE;
INT nIconId;
WCHAR szFullPath[MAX_PATH];
int cbPath;
/* Try to open the specified file. */
/* Try to open the specified file. */
cbPath = SearchPathW(NULL, lpszFileName, NULL, MAX_PATH, szFullPath, NULL);
if (cbPath == 0 || cbPath >= MAX_PATH)
return 0;
fh = HandleToLong(CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
if (fh == HandleToLong(INVALID_HANDLE_VALUE)) {
fh = HandleToLong(CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
}
if (fh == HandleToLong(INVALID_HANDLE_VALUE))
return 0;
/* Read the first two bytes in the file. */
if (_lread(fh, (LPVOID)&wMagic, 2) != 2)
goto EIExit;
switch (wMagic) {
case MAGIC_ICON30:
{
INT i;
LPVOID lpIcon;
NEWHEADER NewHeader;
LPNEWHEADER lpHeader;
LPRESDIR lpResDir;
RESDIRDISK ResDirDisk;
#define MAXICONS 10
DWORD Offsets[MAXICONS];
/* Only one icon per .ICO file. */
if (wIconIndex) {
break;
}
/* Read the header and check if it is a valid ICO file. */
if (_lread(fh, ((LPBYTE)&NewHeader)+2, sizeof(NEWHEADER)-2) != sizeof(NEWHEADER)-2)
goto EICleanup1;
NewHeader.Reserved = MAGIC_ICON30;
/* Check if the file is in correct format */
if (NewHeader.ResType != 1)
goto EICleanup1;
/* Allocate enough space to create a Global Directory Resource. */
hIconDir = GlobalAlloc(GHND, (LONG)(sizeof(NEWHEADER)+NewHeader.ResCount*sizeof(RESDIR)));
if (hIconDir == NULL)
goto EICleanup1;
if ((lpHeader = (LPNEWHEADER)GlobalLock(hIconDir)) == NULL)
goto EICleanup2;
NewHeader.ResCount = (WORD)min((int)NewHeader.ResCount, MAXICONS);
// fill in this structure for user
*lpHeader = NewHeader;
// read in the stuff from disk, transfer it to a memory structure
// that user can deal with
lpResDir = (LPRESDIR)(lpHeader + 1);
for (i = 0; (WORD)i < NewHeader.ResCount; i++) {
if (_lread(fh, (LPVOID)&ResDirDisk, sizeof(RESDIRDISK)) < sizeof(RESDIR))
goto EICleanup3;
Offsets[i] = ResDirDisk.Offset;
*lpResDir = *((LPRESDIR)&ResDirDisk);
lpResDir->idIcon = (WORD)(i+1); // fill in the id
lpResDir++;
}
/* Now that we have the Complete resource directory, let us find out the
* suitable form of icon (that matches the current display driver).
*/
lpIconDir = GlobalLock(hIconDir);
if (!lpIconDir) {
GlobalFree(hIconDir);
goto EIErrExit;
}
wIconIndex = (WORD)(LookupIconIdFromDirectory(lpIconDir, TRUE) - 1);
GlobalUnlock(hIconDir);
lpResDir = (LPRESDIR)(lpHeader+1) + wIconIndex;
/* Allocate memory for the Resource to be loaded. */
if ((hIcon = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, (DWORD)lpResDir->BytesInRes)) == NULL)
goto EICleanup3;
if ((lpIcon = GlobalLock(hIcon)) == NULL)
goto EICleanup4;
/* Seek to the correct place and read in the resource */
if (M_llseek(fh, Offsets[wIconIndex], SEEK_FROMZERO) == -1L)
goto EICleanup5;
if (_lread(fh, (LPVOID)lpIcon, (DWORD)lpResDir->BytesInRes) < lpResDir->BytesInRes)
goto EICleanup5;
GlobalUnlock(hIcon);
*lphIconRes = hIcon;
*lpwSize = (WORD)lpResDir->BytesInRes;
bFormatOK = TRUE;
bNewResFormat = TRUE;
goto EICleanup3;
EICleanup5:
GlobalUnlock(hIcon);
EICleanup4:
GlobalFree(hIcon);
hIcon = (HICON)1;
EICleanup3:
GlobalUnlock(hIconDir);
EICleanup2:
GlobalFree(hIconDir);
EICleanup1:
break;
}
case MAGIC_MARKZIBO:
{
INT iTableSize;
LPBYTE lpResTable;
DWORD lOffset;
HANDLE hResTable;
NEWEXEHDR NEHeader;
/* Make sure that the file is in the NEW EXE format. */
if (M_llseek(fh, (LONG)0x3C, SEEK_FROMZERO) == -1L)
goto EIExit;
if (_lread(fh, (LPVOID)&lOffset, sizeof(LONG)) != sizeof(LONG))
goto EIExit;
if (lOffset == 0L)
goto EIExit;
/* Read in the EXE header. */
if (M_llseek(fh, lOffset, SEEK_FROMZERO) == -1L)
goto EIExit;
if (_lread(fh, (LPVOID)&NEHeader, sizeof(NEWEXEHDR)) != sizeof(NEWEXEHDR))
goto EIExit;
/* Is it a NEW EXE? */
if (NE_MAGIC(NEHeader) != NEMAGIC)
goto EIExit;
if ((NE_EXETYP(NEHeader) != NE_WINDOWS) &&
(NE_EXETYP(NEHeader) != NE_DEV386) &&
(NE_EXETYP(NEHeader) != NE_UNKNOWN)) /* Some Win2.X apps have NE_UNKNOWN in this field */
goto EIExit;
hIcon = NULL;
/* Are there any resources? */
if (NE_RSRCTAB(NEHeader) == NE_RESTAB(NEHeader))
goto EIExit;
/* Remember whether or not this is a Win3.0 EXE. */
bNewResFormat = (NEHeader.ne_expver >= VER);
/* Allocate space for the resource table. */
iTableSize = NE_RESTAB(NEHeader) - NE_RSRCTAB(NEHeader);
hResTable = GlobalAlloc(GMEM_ZEROINIT, (DWORD)iTableSize);
if (!hResTable)
goto EIExit;
/* Lock down the resource table. */
lpResTable = GlobalLock(hResTable);
if (!lpResTable) {
GlobalFree(hResTable);
goto EIExit;
}
/* Copy the resource table into memory. */
if (M_llseek(fh, (LONG)(lOffset + NE_RSRCTAB(NEHeader)), SEEK_FROMZERO) == -1)
goto EIErrExit;
if (_lread(fh, (LPBYTE)lpResTable, iTableSize) != (DWORD)iTableSize)
goto EIErrExit;
/* Is this a Win3.0 EXE? */
if (bNewResFormat) {
/* First, load the Icon directory. */
hIconDir = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_GROUP_ICON);
if (!hIconDir)
goto EIErrExit;
lpIconDir = GlobalLock(hIconDir);
if (!lpIconDir) {
GlobalFree(hIconDir);
goto EIErrExit;
}
nIconId = LookupIconIdFromDirectory(lpIconDir, TRUE);
wIconIndex = (WORD)(GetResIndex(lpResTable, nIconId, (LPBYTE)RT_ICON) - 1);
GlobalUnlock(hIconDir);
/* We're finished with the icon directory. */
GlobalFree(hIconDir);
/* Now load the selected icon. */
*lphIconRes = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_ICON);
}
else {
/* Simply load the specified icon. */
*lphIconRes = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_ICON);
}
if (*lphIconRes) {
*lpwSize = (WORD)GlobalSize(*lphIconRes);
}
bFormatOK = TRUE;
EIErrExit:
GlobalUnlock(hResTable);
GlobalFree(hResTable);
break;
}
}
EIExit:
_lclose(fh);
hInst;
if (bFormatOK)
return (WORD)(bNewResFormat ? 3 : 2);
else
return 0;
}
WORD APIENTRY ExtractIconResInfoA(HANDLE hInst, LPSTR lpszFileName, WORD wIconIndex, LPWORD lpwSize, LPHANDLE lphIconRes)
{
if (lpszFileName)
{
LPWSTR lpszFileNameW;
WORD wLen = lstrlenA(lpszFileName) + 1;
if (!(lpszFileNameW = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (wLen * sizeof(WCHAR)))))
{
return 0;
}
else
{
WORD wRet;
MultiByteToWideChar(CP_ACP, 0, lpszFileName, -1, lpszFileNameW, wLen - 1);
wRet = ExtractIconResInfoW(hInst, lpszFileNameW, wIconIndex, lpwSize, lphIconRes);
LocalFree(lpszFileNameW);
return wRet;
}
}
else
{
return 0;
}
}
LPCWSTR HasAnyExtension(LPCWSTR lpszPath)
{
LPCWSTR p;
for (p = lpszPath + lstrlenW(lpszPath); p > lpszPath && *p != L'.' && *p != L'\\'; p--)
{
// do nothing
}
if (*p == L'.')
return p+1;
else
return NULL;
}
//
// in:
// lpIconPath path of thing to extract icon for (may be an exe
// or something that is associated)
// lpiIconIndex icon index to use
//
// out:
// lpIconPath filled in with the real path where the icon came from
// lpiIconIndex filled in with the real icon index
// lpiIconId filled in with the icon id
//
// returns:
// icon handle
//
// note: if the caller is progman it returns special icons from within progman
//
//
#if defined(UNICODE)
HICON APIENTRY ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
{
WCHAR wszExePath[MAX_PATH];
HICON hIcon;
UINT idIcon = (UINT)-1; // Don't know value
BOOL fAssociated = FALSE;
if ((INT)*lpiIconIndex == -1)
return (HICON)NULL;
Retry:
ExtractIcons(lpIconPath, *lpiIconIndex, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
&hIcon, &idIcon, 1, 0);
if (hIcon == NULL)
{
wszExePath[0] = TEXT('\0');
FindExecutable(lpIconPath,NULL,wszExePath);
//
// If FindExecutable fails, or fAssociated
// is true, or FindExecutable returns the
// extact same filename it was looking for,
// then issue the default icon from progman.
//
if (!*wszExePath || fAssociated ||
(*wszExePath && (lstrcmpi(lpIconPath, wszExePath) == 0)))
{
LPTSTR lpId;
WORD wDefIconId;
HANDLE h;
LPVOID p;
//
// Magic values from NT's old progman
//
#define ITEMICON 7
#define DOSAPPICON 2
#define ITEMICONINDEX 6
#define DOSAPPICONINDEX 1
if ( *wszExePath && (HasExtension(wszExePath) == 0) )
{
//
// Generic Document icon processing
//
lpId = MAKEINTRESOURCE(ITEMICON);
wDefIconId = ITEMICONINDEX;
}
else
{
//
// Generic Program icon processing
//
lpId = MAKEINTRESOURCE(DOSAPPICON);
wDefIconId = DOSAPPICONINDEX;
}
GetModuleFileName(hInst, lpIconPath, CCHICONPATHMAXLEN);
/*
* Look up the icon id from the directory.
*/
if (NULL != (h = FindResource(hInst, lpId, RT_GROUP_ICON))) {
h = LoadResource(hInst, h);
p = LockResource(h);
*lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
UnlockResource(h);
FreeResource(h);
}
*lpiIconIndex = wDefIconId;
return LoadIcon(hInst, lpId);
}
SheRemoveQuotes(wszExePath);
lstrcpy(lpIconPath,wszExePath);
fAssociated = TRUE;
goto Retry;
}
*lpiIconId = (WORD) idIcon; // Fill in with whatever we've found (or -1)
return hIcon;
}
#else // defined(UNICODE)
HICON APIENTRY ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
{
HICON hIcon = NULL;
WCHAR szIconExe[MAX_PATH];
HANDLE hIconList = NULL;
MYICONINFO *lpIconList;
HANDLE h;
PBYTE p;
DWORD dwBinaryType;
BOOL bRet;
int cIcons;
#define ITEMICON 7 // taken from progman!
#define DOSAPPICON 2
#define ITEMICONINDEX 6
#define DOSAPPICONINDEX 1
if (!lpIconPath)
return NULL;
FreeExtractIconInfo(-1);
hIcon = ExtractIconW(hInst, lpIconPath, (UINT)*lpiIconIndex);
if (!hIcon)
{
// lpIconPath is a windows EXE, no icons found
GenericDocument:
FreeExtractIconInfo(-1);
GetModuleFileNameW(hInst, lpIconPath, CCHICONPATHMAXLEN);
// Look up the icon id from the directory.
if (NULL != (h = FindResource(hInst, MAKEINTRESOURCE(ITEMICON), RT_GROUP_ICON)))
{
h = LoadResource(hInst, h);
if (h != NULL)
{
p = LockResource(h);
if (p != NULL)
{
*lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
UnlockResource(h);
}
FreeResource(h);
}
}
*lpiIconIndex = ITEMICONINDEX;
return LoadIcon(hInst, MAKEINTRESOURCE(ITEMICON));
}
if ((int)hIcon == 1)
{
// lpIconPath is not a windows EXE
// this fills in szIconExe with the thing that would be exected
// for lpIconPath (applying associations)
FindExecutableW(lpIconPath, NULL, szIconExe);
if (!*szIconExe)
{
// not associated, assume things with extension are
// programs, things without are documents
if (!HasAnyExtension(lpIconPath))
goto GenericDocument;
else
goto GenericProgram;
}
//
// If FindExecutable returned an icon path with quotes, we must
// remove them because ExtractIcon fails with quoted paths.
//
SheRemoveQuotesW(szIconExe);
lstrcpyW(lpIconPath, szIconExe);
if (!HasAnyExtension(lpIconPath))
lstrcatW(lpIconPath, L".EXE");
hIcon = ExtractIconW(hInst, lpIconPath, (UINT)*lpiIconIndex);
if (!hIcon)
goto GenericDocument;
if ((int)hIcon == 1)
{
// this is a DOS exe
GenericProgram:
FreeExtractIconInfo(-1);
GetModuleFileNameW(hInst, lpIconPath, CCHICONPATHMAXLEN);
// Look up the icon id from the directory.
if (NULL != (h = FindResource(hInst, MAKEINTRESOURCE(DOSAPPICON), RT_GROUP_ICON)))
{
h = LoadResource(hInst, h);
if (h != NULL)
{
p = LockResource(h);
if ( p != NULL)
{
*lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
UnlockResource(h);
}
FreeResource(h);
}
}
*lpiIconIndex = DOSAPPICONINDEX;
return LoadIcon(hInst, MAKEINTRESOURCE(DOSAPPICON));
}
else
{
goto GotIcon;
}
}
else
{
GotIcon:
bRet = GetBinaryTypeW(lpIconPath, &dwBinaryType);
if (bRet)
{
if (dwBinaryType != SCS_32BIT_BINARY)
{
*lpiIconId = *lpiIconIndex;
return hIcon;
}
}
ExtractIconW(hInst, lpIconPath, (UINT)-1);
if (NULL == (hIconList = ExtractIconInfo.hIconList))
return hIcon;
// since the icon exe is a WIN32 app, then we must update *lpiIcon.
if (NULL != (hIconList = InternalExtractIconListW(hInst, lpIconPath, &cIcons)))
{
if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(hIconList)))
{
hIcon = (lpIconList + *lpiIconIndex)->hIcon;
*lpiIconId = (lpIconList + *lpiIconIndex)->iIconId;
GlobalUnlock(hIconList);
}
FreeIconList(hIconList, *lpiIconIndex);
return hIcon;
}
}
return hIcon;
}
#endif
HICON APIENTRY ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
{
HICON hIcon = NULL;
if (lpIconPath)
{
BOOL fDefCharUsed;
WCHAR IconPathW[MAX_PATH] = L"";
MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1 , (LPWSTR)IconPathW, MAX_PATH);
hIcon = ExtractAssociatedIconExW(hInst, (LPWSTR)IconPathW, lpiIconIndex, lpiIconId);
try
{
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)IconPathW, -1, lpIconPath, CCHICONPATHMAXLEN,
NULL, &fDefCharUsed);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
hIcon = NULL;
}
}
return hIcon;
}
//
// in:
// lpIconPath path of thing to extract icon for (may be an exe
// or something that is associated)
// lpiIcon icon index to use
//
// out:
// lpIconPath filled in with the real path where the icon came from
// lpiIcon filled in with the real icon index
//
// returns:
// icon handle
//
// note: if the caller is progman it returns special icons from within progman
//
//
#ifdef UNICODE
HICON APIENTRY ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
{
HICON hIcon = NULL;
if (lpIconPath)
{
BOOL fDefCharUsed;
WCHAR IconPathW[MAX_PATH] = L"";
MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1 , (LPWSTR)IconPathW, MAX_PATH);
hIcon = ExtractAssociatedIconW(hInst, (LPWSTR)IconPathW, lpiIcon);
try
{
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)IconPathW, -1, lpIconPath, CCHICONPATHMAXLEN,
NULL, &fDefCharUsed);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
hIcon = NULL;
}
}
return hIcon;
}
#endif