mirror of https://github.com/lianthony/NT4.0
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.
2689 lines
76 KiB
2689 lines
76 KiB
/****************************************************************************/
|
|
/* */
|
|
/* EXTRACT.C - */
|
|
/* */
|
|
/* Icon Extraction Routines */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
#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))
|
|
// #define NEMAGIC ((WORD)'N'+((WORD)'E'<<8)) // defined in newexe.h
|
|
|
|
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')
|
|
|
|
|
|
#define WIN32VER30 0x00030000 // for CreateIconFromResource()
|
|
|
|
#define GET_COUNT 424242
|
|
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
#ifndef WINNT
|
|
UINT ExtractIconFromICO (LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT nIcons, UINT flags);
|
|
UINT ExtractIconFromBMP (LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT nIcons, UINT flags);
|
|
UINT ExtractIconFromEXE (HANDLE hFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags);
|
|
|
|
LPVOID GetResourceTablePE(LPVOID pBase);
|
|
LPVOID FindResourcePE(LPVOID pBase, LPVOID prt, int iResIndex, int ResType, DWORD *pcb);
|
|
|
|
LPVOID GetResourceTableNE(LPVOID pBase);
|
|
LPVOID FindResourceNE(LPVOID pBase, LPVOID prt, int iResIndex, int ResType, DWORD *pcb);
|
|
|
|
DWORD HasExtension(LPCTSTR lpszPath);
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* ExtractIcon PUBLIC WIN30
|
|
*
|
|
* 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)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;
|
|
}
|
|
|
|
#ifndef WINNT
|
|
/****************************************************************************
|
|
* InternalExtractIcon PRIVATE WIN30
|
|
*
|
|
* returns a list of icons.
|
|
*
|
|
* in:
|
|
* hInst Instance handle.
|
|
* lpszExeFileName File to read from.
|
|
* nIconIndex Index to first icon.
|
|
* nIcons The number of icons to read.
|
|
*
|
|
* returns:
|
|
* handle to arrary of hicons
|
|
*
|
|
* note(s) noone calls this, so we just fail it.
|
|
*
|
|
****************************************************************************/
|
|
|
|
HGLOBAL WINAPI InternalExtractIcon(HINSTANCE hInst, LPCTSTR lpszExeFileName, UINT nIconIndex, UINT nIcons)
|
|
{
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
*
|
|
* ExtractAssociatedIcon PRIVATE WIN30
|
|
*
|
|
* 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;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("ExtractAssociatedIcon(\"%s\")"), lpIconPath);
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* ExtractIconEx - 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)
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef WINNT
|
|
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 );
|
|
|
|
}
|
|
#else
|
|
|
|
UINT WINAPI ExtractIconEx(LPCTSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
|
|
{
|
|
UINT result;
|
|
|
|
if (nIconIndex == -1 || (phiconLarge == NULL && phiconSmall == NULL))
|
|
return ExtractIcons(szFileName, 0, 0, 0, NULL, NULL, 0, 0);
|
|
|
|
if (phiconLarge && phiconSmall && nIcons == 1)
|
|
{
|
|
HICON ahicon[2];
|
|
ahicon[0]=NULL;
|
|
ahicon[1]=NULL;
|
|
|
|
result = ExtractIcons(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 = ExtractIcons(szFileName, nIconIndex, GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON), phiconLarge, NULL, nIcons, 0);
|
|
if (phiconSmall)
|
|
result = ExtractIcons(szFileName, nIconIndex, GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), phiconSmall, NULL, nIcons, 0);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
*
|
|
* ExtractIcons - 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 stupid 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.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#ifdef WINNT
|
|
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
|
|
|
|
}
|
|
#else
|
|
|
|
UINT WINAPI ExtractIcons(LPCTSTR szFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags)
|
|
{
|
|
HANDLE hFile=INVALID_HANDLE_VALUE;
|
|
UINT result=0;
|
|
WORD magic[6];
|
|
TCHAR achFileName[MAX_PATH];
|
|
FILETIME ftAccess;
|
|
TCHAR szExpFileName[MAX_PATH];
|
|
|
|
TIMEVAR(x);
|
|
TIMEIN(x);
|
|
TIMESTART(x);
|
|
|
|
//
|
|
// set failure defaults.
|
|
//
|
|
if (phicon)
|
|
*phicon = NULL;
|
|
|
|
//
|
|
// check for special extensions, and fail quick
|
|
//
|
|
switch (HasExtension(szFileName))
|
|
{
|
|
case COM_FILE:
|
|
case BAT_FILE:
|
|
#ifdef WINNT
|
|
case CMD_FILE:
|
|
#endif
|
|
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 ] = (TCHAR)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))
|
|
{
|
|
lstrcpyn(achFileName, szExpFileName, ARRAYSIZE(achFileName)); // BUGBUG sizeof
|
|
if (!SHValidateUNC(NULL, achFileName, VALIDATEUNC_NOUI))
|
|
goto error_file;
|
|
// We don't need to search the path if we know this is a UNC name
|
|
}
|
|
else
|
|
{
|
|
if (SearchPath(NULL, szExpFileName, NULL, ARRAYSIZE(achFileName),
|
|
achFileName, NULL) == 0)
|
|
{
|
|
// There was an error...
|
|
DWORD dwError = GetLastError();
|
|
DebugMsg(DM_TRACE, TEXT("ExtractIcon:SearchPath Fail(\"%s\") ==> %d"),
|
|
szExpFileName, result);
|
|
goto error_file;
|
|
}
|
|
}
|
|
|
|
// BUGBUGBC Is FILE_WRITE_ATTRIBUTES really valid for CreateFile?
|
|
|
|
hFile = CreateFile(achFileName, GENERIC_READ|FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFile = CreateFile(achFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 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);
|
|
}
|
|
|
|
|
|
if (_lread((HFILE)hFile, &magic, SIZEOF(magic)) != 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, nIcons, flags);
|
|
break;
|
|
|
|
case BMP_MAGIC: // possible bitmap
|
|
result = ExtractIconFromBMP(achFileName, nIconIndex, cxIcon, cyIcon, phicon, nIcons, 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) &&
|
|
magic[2] >= 1 && magic[2] <= 10)
|
|
result = ExtractIconFromICO(achFileName, nIconIndex, cxIcon, cyIcon, phicon, nIcons, flags);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
|
|
#ifdef YOUR_PRIVATE_DEBUG_FLAG
|
|
TIMESTOP(x);
|
|
DebugMsg(DM_TRACE, TEXT("ExtractIcon(\"%s\", %d) ==> %d (%ld.%03ld sec)"), szExpFileName, nIconIndex, result,TIMEFMT(xT));
|
|
#endif
|
|
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:
|
|
|
|
if (phicon)
|
|
result = (UINT)-1;
|
|
else
|
|
result = 0;
|
|
goto exit;
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
***************************************************************************/
|
|
UINT ExtractIconFromICO(LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT nIcons, UINT flags)
|
|
{
|
|
HICON hicon;
|
|
|
|
if (nIconIndex >= 1)
|
|
return 0;
|
|
|
|
flags |= LR_LOADFROMFILE;
|
|
|
|
again:
|
|
hicon = LoadImage(HINST_THISDLL, szFile, IMAGE_ICON,
|
|
LOWORD(cxIcon), LOWORD(cyIcon), flags);
|
|
|
|
if (hicon == NULL)
|
|
return 0;
|
|
|
|
// do we just want a count?
|
|
if (phicon == NULL)
|
|
DestroyIcon(hicon);
|
|
else
|
|
*phicon = hicon;
|
|
|
|
//
|
|
// check for large/small icon extract
|
|
//
|
|
if (HIWORD(cxIcon))
|
|
{
|
|
cxIcon = HIWORD(cxIcon);
|
|
cyIcon = HIWORD(cyIcon);
|
|
phicon++;
|
|
goto again;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/****************************************************************************
|
|
***************************************************************************/
|
|
UINT ExtractIconFromBMP(LPTSTR szFile, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT nIcons, UINT flags)
|
|
{
|
|
HICON hicon;
|
|
HBITMAP hbm;
|
|
HBITMAP hbmMask;
|
|
HDC hdc;
|
|
HDC hdcMask;
|
|
ICONINFO ii;
|
|
|
|
if (nIconIndex >= 1)
|
|
return 0;
|
|
|
|
// BOGUS: dont use LR_CREATEDIBSECTION; USER can't make an icon out of a DS
|
|
flags |= LR_LOADFROMFILE;
|
|
|
|
again:
|
|
hbm = (HBITMAP)LoadImage(HINST_THISDLL, 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));
|
|
#define ROP_DSna 0x00220326
|
|
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;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
***************************************************************************/
|
|
// BUGBUG Why is this not inline?
|
|
// BECAUSE THE COMPILER WOULD OPTIMIZE IT OUT AND GENERATE A WARNING
|
|
BOOL
|
|
ReadAByte(LPCVOID pmem)
|
|
{
|
|
return (*(BYTE *)pmem == 0);
|
|
}
|
|
|
|
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 *pne;
|
|
LPVOID pBase;
|
|
LPVOID pres=NULL;
|
|
UINT result=0;
|
|
LONG FileLength;
|
|
DWORD cbSize;
|
|
int cxIcon,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*)((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 = (UINT)FindResourceX(pBase, pres, GET_COUNT, (int)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, (int)RT_GROUP_ICON, &cbSize);
|
|
|
|
if (lpIconDir == NULL)
|
|
goto exit;
|
|
|
|
if ( (((LPNEWHEADER)lpIconDir)->Reserved != 0)
|
|
|| (((LPNEWHEADER)lpIconDir)->ResType != FT_ICON) )
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("sh ER - ExtractIconFromEXE found bad icondir"));
|
|
Assert(0);
|
|
goto exit;
|
|
}
|
|
again:
|
|
idIcon = LookupIconIdFromDirectoryEx((LPBYTE)lpIconDir,TRUE,
|
|
LOWORD(cxIcon),LOWORD(cyIcon),flags);
|
|
lpIcon = FindResourceX(pBase, pres, -idIcon, (int)RT_ICON, &cbSize);
|
|
|
|
if (lpIcon == NULL)
|
|
goto exit;
|
|
|
|
if ( (((LPBITMAPINFOHEADER)lpIcon)->biSize != SIZEOF(BITMAPINFOHEADER)) &&
|
|
(((LPBITMAPINFOHEADER)lpIcon)->biSize != SIZEOF(BITMAPCOREHEADER)) )
|
|
{
|
|
DebugMsg(DM_ERROR, TEXT("sh ER - ExtractIconFromEXE found bad BITMAPINFO"));
|
|
Assert(0);
|
|
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 (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
result = 0;
|
|
}
|
|
|
|
exit:
|
|
if (lpFile)
|
|
UnmapViewOfFile(lpFile);
|
|
if (hFileMap!=INVALID_HANDLE_VALUE)
|
|
CloseHandle(hFileMap);
|
|
|
|
return result;
|
|
}
|
|
#endif // not defined WINNT
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
DWORD HasExtension(LPCTSTR pszPath)
|
|
{
|
|
LPCTSTR p = PathFindExtension(pszPath);
|
|
|
|
//
|
|
// BUGBUG - BobDay - Shouldn't this limit the length to 4 characters?
|
|
// "Fister.Bather" would return .BAT
|
|
//
|
|
// BUGBUG - 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;
|
|
#ifdef WINNT
|
|
if ( lstrcmpi(szExt,TEXT(".cmd")) == 0 ) return CMD_FILE;
|
|
#endif
|
|
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;
|
|
|
|
}
|
|
|
|
#ifndef WINNT
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
/* 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;
|
|
LPRESTYPEINFO lpResTypeInfo;
|
|
LPRESNAMEINFO lpResNameInfo;
|
|
int i;
|
|
|
|
lpResTable = (LPRESTABLE)prt;
|
|
////lpResTypeInfo = (LPRESTYPEINFO)(LPWBYTE)&lpResTable->rs_typeinfo;
|
|
lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)lpResTable + 2);
|
|
|
|
while (lpResTypeInfo->rt_id)
|
|
{
|
|
if (lpResTypeInfo->rt_id == (iResType | RSORDID))
|
|
{
|
|
lpResNameInfo = (LPRESNAMEINFO)(lpResTypeInfo+1);
|
|
|
|
if (iResIndex == GET_COUNT)
|
|
return (LPVOID)lpResTypeInfo->rt_nres;
|
|
|
|
if (iResIndex < 0)
|
|
{
|
|
for (i=0; i < (int)lpResTypeInfo->rt_nres; i++)
|
|
{
|
|
if (lpResNameInfo[i].rn_id == ((-iResIndex) | RSORDID))
|
|
break;
|
|
}
|
|
|
|
iResIndex = i;
|
|
}
|
|
|
|
if (iResIndex >= (int)lpResTypeInfo->rt_nres)
|
|
return NULL;
|
|
|
|
*pcb = ((DWORD)lpResNameInfo[iResIndex].rn_length) << lpResTable->rs_align;
|
|
return (LPBYTE)lpBase + ((long)lpResNameInfo[iResIndex].rn_offset << lpResTable->rs_align);
|
|
}
|
|
|
|
lpResTypeInfo = (LPRESTYPEINFO)((LPRESNAMEINFO)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres);
|
|
}
|
|
|
|
*pcb = 0;
|
|
return NULL;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
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
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
LPVOID RVAtoP(LPVOID pBase, DWORD rva)
|
|
{
|
|
LPEXEHDR pmz;
|
|
IMAGE_NT_HEADERS *ppe;
|
|
IMAGE_SECTION_HEADER *pSection; // section table
|
|
int i;
|
|
|
|
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++)
|
|
{
|
|
DWORD size;
|
|
|
|
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;
|
|
}
|
|
|
|
/****************************************************************************
|
|
****************************************************************************/
|
|
|
|
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->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER)
|
|
return 0;
|
|
|
|
return RVAtoP(pBase, RESOURCE_VA(ppe));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* 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,cnt;
|
|
IMAGE_RESOURCE_DIRECTORY *pdir;
|
|
IMAGE_RESOURCE_DIRECTORY_ENTRY *pres;
|
|
IMAGE_RESOURCE_DATA_ENTRY *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)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!
|
|
// !!!for now just punt and return the first one.
|
|
// !!!BUGBUG we dont handle multi-language icons
|
|
//
|
|
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);
|
|
}
|
|
#endif // not defined WINNT
|
|
|
|
/****************************************************************************
|
|
* GetExeType - 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
|
|
*
|
|
* BUGBUG 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,dwUNC;
|
|
|
|
//
|
|
// check for special extensions, and fail quick
|
|
//
|
|
switch (HasExtension(szFile))
|
|
{
|
|
case COM_FILE:
|
|
// handle the case like \\server.microsoft.com
|
|
dwUNC = PathIsUNCServerShare(szFile);
|
|
if ((dwUNC == UNC_SERVER_ONLY) || (dwUNC == UNC_SERVER_SHARE))
|
|
return 0;
|
|
#ifndef WINNT
|
|
case BAT_FILE:
|
|
case CMD_FILE:
|
|
#endif
|
|
return MAKELONG(MZMAGIC, 0); // DOS exe
|
|
#ifdef WINNT
|
|
case BAT_FILE:
|
|
case CMD_FILE:
|
|
return MAKELONG(PEMAGIC, 0); // NT exe (pretend)
|
|
#endif
|
|
|
|
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)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 _ExtractIconInfo
|
|
{
|
|
HANDLE hAppInst;
|
|
HANDLE hFileName;
|
|
HANDLE hIconList;
|
|
INT nIcons;
|
|
} EXTRACTICONINFO;
|
|
|
|
EXTRACTICONINFO ExtractIconInfo = {NULL, NULL, NULL, 0};
|
|
|
|
INT nIcons;
|
|
|
|
typedef struct _MyIconInfo {
|
|
HICON hIcon;
|
|
INT iIconId;
|
|
} MYICONINFO, *LPMYICONINFO;
|
|
|
|
HANDLE APIENTRY InternalExtractIconW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex, UINT nIcons);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* DuplicateIcon() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
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;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* FindResWithIndex() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* 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)
|
|
{
|
|
LPRESTYPEINFO lpResTypeInfo;
|
|
|
|
try {
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* GetResIndex() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* 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)
|
|
{
|
|
register WORD w;
|
|
LPRESTYPEINFO lpResTypeInfo;
|
|
LPRESNAMEINFO lpResNameInfo;
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* SimpleLoadResource() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
HANDLE
|
|
SimpleLoadResource(
|
|
HFILE fh,
|
|
LPBYTE lpResTable,
|
|
INT iResIndex,
|
|
LPBYTE lpResType)
|
|
{
|
|
register INT iShiftCount;
|
|
register 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);
|
|
}
|
|
|
|
#if !defined(UNICODE) && defined(PARTIAL_UNICODE)
|
|
BOOL
|
|
EnumIconFunc(
|
|
HANDLE hModule,
|
|
LPWSTR lpType,
|
|
LPWSTR lpName,
|
|
LONG lParam)
|
|
{
|
|
HICON hIcon = NULL;
|
|
HANDLE hIconList = *(LPHANDLE)lParam;
|
|
LPMYICONINFO lpIconList;
|
|
HANDLE h;
|
|
PBYTE p;
|
|
INT id;
|
|
INT cb;
|
|
|
|
if (!lpName)
|
|
return TRUE;
|
|
|
|
if (!hIconList)
|
|
return FALSE;
|
|
|
|
/*
|
|
* Look up the icon id from the directory.
|
|
*/
|
|
h = FindResourceW(hModule, lpName, lpType);
|
|
if (!h)
|
|
return TRUE;
|
|
h = LoadResource(hModule, h);
|
|
p = LockResource(h);
|
|
id = LookupIconIdFromDirectory(p, TRUE);
|
|
UnlockResource(h);
|
|
FreeResource(h);
|
|
|
|
/*
|
|
* Load the icon.
|
|
*/
|
|
h = FindResourceW(hModule, (LPWSTR)MAKEINTRESOURCE(id), (LPWSTR)MAKEINTRESOURCE(RT_ICON));
|
|
if (h) {
|
|
cb = SizeofResource(hModule, h);
|
|
h = LoadResource(hModule, h);
|
|
p = LockResource(h);
|
|
hIcon = CreateIconFromResource(p, cb, TRUE, 0x00030000);
|
|
UnlockResource(h);
|
|
FreeResource(h);
|
|
}
|
|
if (hIcon) {
|
|
if (hIconList = GlobalReAlloc(hIconList, (nIcons+1) * SIZEOF(MYICONINFO), GMEM_MOVEABLE)) {
|
|
if (lpIconList = (LPMYICONINFO)GlobalLock(hIconList)) {
|
|
(lpIconList + nIcons)->hIcon = hIcon;
|
|
(lpIconList + nIcons)->iIconId = id;
|
|
nIcons++;
|
|
GlobalUnlock(hIconList);
|
|
}
|
|
*(LPHANDLE)lParam = hIconList;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
INT _CRTAPI1
|
|
CompareIconId(
|
|
LPMYICONINFO lpIconInfo1,
|
|
LPMYICONINFO lpIconInfo2)
|
|
{
|
|
return(lpIconInfo1->iIconId - lpIconInfo2->iIconId);
|
|
}
|
|
|
|
VOID
|
|
FreeIconList(HANDLE hIconList, int iKeepIcon)
|
|
{
|
|
LPMYICONINFO lpIconList;
|
|
INT i;
|
|
|
|
if (ExtractIconInfo.hIconList == hIconList) {
|
|
ExtractIconInfo.hIconList = NULL;
|
|
}
|
|
if (NULL != (lpIconList = (LPMYICONINFO)GlobalLock(hIconList))) {
|
|
for (i = 0; i < ExtractIconInfo.nIcons; i++) {
|
|
if (i != iKeepIcon) {
|
|
DestroyIcon((lpIconList + i)->hIcon);
|
|
}
|
|
}
|
|
GlobalUnlock(hIconList);
|
|
GlobalFree(hIconList);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
FreeExtractIconInfo(INT iKeepIcon)
|
|
{
|
|
LPMYICONINFO lpIconList;
|
|
INT i;
|
|
|
|
if (ExtractIconInfo.hIconList) {
|
|
if (NULL != (lpIconList = (LPMYICONINFO)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;
|
|
}
|
|
}
|
|
#ifndef WIN32
|
|
#define FreeExtractIconInfo()
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ExtractIcon() - */
|
|
/* */
|
|
/* 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. */
|
|
/* -2, if the user requested to have the buffer freed
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
#if !defined(UNICODE) && defined(PARTIAL_UNICODE) // BUGBUG - BobDay - This function should be removed
|
|
HICON APIENTRY
|
|
ExtractIconW(
|
|
HINSTANCE hInst,
|
|
LPCWSTR lpszExeFileName,
|
|
UINT nIconIndex)
|
|
{
|
|
HANDLE hIconList;
|
|
LPMYICONINFO lpIconList;
|
|
HICON hIcon = NULL;
|
|
HANDLE hModule;
|
|
LPWSTR lpszT = NULL;
|
|
DWORD OldErrorMode;
|
|
|
|
if (nIconIndex == -2) {
|
|
FreeExtractIconInfo(-1);
|
|
return ((HICON)nIconIndex);
|
|
}
|
|
|
|
//
|
|
// This is the caching code. If the user called in with the
|
|
// same parameters as the last time he called, and our buffer
|
|
// still exists, then we can grab from the cache and return.
|
|
//
|
|
|
|
|
|
if ((ExtractIconInfo.hAppInst == hInst) &&
|
|
ExtractIconInfo.hFileName &&
|
|
(lpszT = (LPWSTR)GlobalLock(ExtractIconInfo.hFileName)) &&
|
|
(!lstrcmpW(lpszT, lpszExeFileName)) &&
|
|
(lpIconList = (LPMYICONINFO)GlobalLock(ExtractIconInfo.hIconList)) ) {
|
|
/*
|
|
* The file is a WIN32 exe.
|
|
*/
|
|
|
|
if ((WORD)nIconIndex == (WORD)-1) /* just want the number of icons */
|
|
hIcon = (HICON)ExtractIconInfo.nIcons;
|
|
else if (nIconIndex < (UINT)ExtractIconInfo.nIcons)
|
|
hIcon = DuplicateIcon(hInst, (lpIconList+nIconIndex)->hIcon);
|
|
GlobalUnlock(ExtractIconInfo.hIconList);
|
|
|
|
GlobalUnlock(ExtractIconInfo.hFileName);
|
|
return (hIcon);
|
|
}
|
|
|
|
if (lpszT) {
|
|
GlobalUnlock(ExtractIconInfo.hFileName);
|
|
}
|
|
|
|
/* reset ExtractIconInfo */
|
|
FreeExtractIconInfo(-1);
|
|
|
|
OldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
if (hModule = LoadLibraryExW(lpszExeFileName,
|
|
NULL,
|
|
DONT_RESOLVE_DLL_REFERENCES)) {
|
|
SetErrorMode(OldErrorMode);
|
|
/*
|
|
* this exe is a WIN32 exe
|
|
*/
|
|
|
|
ExtractIconInfo.hAppInst = hInst;
|
|
if (ExtractIconInfo.hFileName = GlobalAlloc(GMEM_MOVEABLE, ((lstrlenW(lpszExeFileName)+1) * SIZEOF(WCHAR)))) {
|
|
if (lpszT = (LPWSTR)GlobalLock(ExtractIconInfo.hFileName)) {
|
|
lstrcpyW(lpszT, lpszExeFileName);
|
|
GlobalUnlock(ExtractIconInfo.hFileName);
|
|
}
|
|
}
|
|
|
|
if (hIconList = GlobalAlloc(GMEM_MOVEABLE, SIZEOF(MYICONINFO))) {
|
|
nIcons = 0;
|
|
EnumResourceNamesW(hModule, (LPWSTR)RT_GROUP_ICON,
|
|
(ENUMRESNAMEPROC)EnumIconFunc,
|
|
(LONG)&hIconList);
|
|
if (!nIcons || !hIconList)
|
|
goto Win32Exit;
|
|
ExtractIconInfo.nIcons = nIcons;
|
|
ExtractIconInfo.hIconList = hIconList;
|
|
|
|
if (lpIconList = (LPMYICONINFO)GlobalLock(hIconList)) {
|
|
/*
|
|
* Sort the icons by their IDs.
|
|
*/
|
|
qsort(lpIconList, nIcons, SIZEOF(MYICONINFO), (PVOID)CompareIconId);
|
|
/*
|
|
* Return the desired icon.
|
|
*/
|
|
if ((WORD)nIconIndex == (WORD)-1) /* just want the number of icons */
|
|
hIcon = (HICON)nIcons;
|
|
else if (nIconIndex < (UINT)nIcons)
|
|
hIcon = DuplicateIcon(hInst, (lpIconList+nIconIndex)->hIcon);
|
|
GlobalUnlock(hIconList);
|
|
}
|
|
}
|
|
Win32Exit:
|
|
FreeLibrary(hModule);
|
|
return(hIcon);
|
|
} else {
|
|
SetErrorMode(OldErrorMode);
|
|
}
|
|
/*
|
|
* this exe is a 16bit EXE
|
|
*/
|
|
|
|
/*
|
|
* Get the list of icons.
|
|
*/
|
|
hIconList = InternalExtractIconW(hInst, lpszExeFileName, nIconIndex, 1);
|
|
if (!hIconList) {
|
|
return NULL;
|
|
}
|
|
/*
|
|
* Get the one icon in the list.
|
|
*/
|
|
lpIconList = (LPMYICONINFO)GlobalLock(hIconList);
|
|
hIcon = lpIconList[0].hIcon;
|
|
|
|
/* Delete the list. */
|
|
GlobalUnlock(hIconList);
|
|
GlobalFree(hIconList);
|
|
|
|
return hIcon;
|
|
}
|
|
#endif
|
|
#if !defined(UNICODE) && !defined(PARTIAL_UNICODE)
|
|
HICON APIENTRY
|
|
ExtractIconW(
|
|
HINSTANCE hInst,
|
|
LPCWSTR lpszExeFileName,
|
|
UINT nIconIndex)
|
|
{
|
|
return 0; // BUGBUG- BobDay - We should move this into SHUNIMP.C
|
|
}
|
|
#endif
|
|
|
|
#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);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* InternalExtractIconList() - */
|
|
/* */
|
|
/* 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;
|
|
LPMYICONINFO lpIconInfo = NULL;
|
|
|
|
|
|
//
|
|
// Determine the number of icons
|
|
//
|
|
|
|
cIcons = (UINT) 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)
|
|
{
|
|
|
|
// BUGBUG: This should be moved to shlunimp.c
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
HANDLE APIENTRY
|
|
InternalExtractIconListA(
|
|
HANDLE hInst,
|
|
LPSTR lpszExeFileName,
|
|
LPINT lpnIcons)
|
|
{
|
|
//
|
|
// Nobody ever should have used this, once progman on NT became unicode,
|
|
// this entrypoint became useless.
|
|
//
|
|
return (HANDLE)NULL;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
HANDLE APIENTRY
|
|
InternalExtractIconA(
|
|
HINSTANCE hInst,
|
|
LPCSTR lpszExeFileName,
|
|
UINT wIconIndex,
|
|
UINT nIcons)
|
|
{
|
|
//
|
|
// Nobody ever should have used this, once progman on NT became unicode,
|
|
// this entrypoint became useless. Plus progman really only used the
|
|
// InternalExtractIconListA entrypoint anyway...
|
|
//
|
|
return (HANDLE)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 = (HFILE)CreateFileW(lpwstrFilename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (fh == (HFILE)INVALID_HANDLE_VALUE) {
|
|
fh = (HFILE)CreateFileW(lpwstrFilename,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
|
|
if (fh == (HFILE)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 = GlobalSize(hRes);
|
|
|
|
if (lphData) {
|
|
|
|
*lphData = hRes;
|
|
} else {
|
|
|
|
GlobalFree(hRes);
|
|
}
|
|
}
|
|
|
|
EIErrExit:
|
|
GlobalUnlock(hResTable);
|
|
GlobalFree(hResTable);
|
|
break;
|
|
|
|
}
|
|
EIExit:
|
|
_lclose(fh);
|
|
|
|
return dwSize;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ExtractIconResInfo() - */
|
|
/* */
|
|
/* 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 = (HFILE)CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fh == (HFILE)INVALID_HANDLE_VALUE) {
|
|
fh = (HFILE)CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
|
|
if (fh == (HFILE)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).
|
|
*/
|
|
#ifdef ORGCODE
|
|
// GetIconId() returns the icon id of the icon is most
|
|
// most appropriate for the current display.
|
|
|
|
wIconIndex = (WORD)(GetIconId(hIconDir, (LPBYTE)RT_ICON) - 1);
|
|
#else
|
|
lpIconDir = GlobalLock(hIconDir);
|
|
if (!lpIconDir) {
|
|
GlobalFree(hIconDir);
|
|
goto EIErrExit;
|
|
}
|
|
wIconIndex = (WORD)(LookupIconIdFromDirectory(lpIconDir, TRUE) - 1);
|
|
GlobalUnlock(hIconDir);
|
|
#endif
|
|
lpResDir = (LPRESDIR)(lpHeader+1) + wIconIndex;
|
|
|
|
/* Allocate memory for the Resource to be loaded. */
|
|
#ifdef ORGCODE
|
|
if ((hIcon = (HICON)DirectResAlloc(hInst, NSMOVE, (WORD)lpResDir->BytesInRes)) == NULL)
|
|
#else
|
|
if ((hIcon = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, (DWORD)lpResDir->BytesInRes)) == NULL)
|
|
#endif
|
|
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;
|
|
#ifdef ORGCODE
|
|
/* Get the index of the Icon which best matches the current display. */
|
|
nIconId = GetIconId(hIconDir, (LPBYTE)RT_ICON);
|
|
|
|
/* GetIconId() returns the id of the icon; But we need the index
|
|
* of the icon to call SimpleLoadResource(); IconId is the unique
|
|
* number given to each form of Icon and Cursor; Icon index is the index of the
|
|
* icon among all icons in the application;
|
|
*/
|
|
wIconIndex = (WORD)(GetResIndex(lpResTable, (int)nIconId, (LPBYTE)RT_ICON) - 1);
|
|
#else
|
|
lpIconDir = GlobalLock(hIconDir);
|
|
if (!lpIconDir) {
|
|
GlobalFree(hIconDir);
|
|
goto EIErrExit;
|
|
}
|
|
nIconId = LookupIconIdFromDirectory(lpIconDir, TRUE);
|
|
wIconIndex = (WORD)(GetResIndex(lpResTable, nIconId, (LPBYTE)RT_ICON) - 1);
|
|
GlobalUnlock(hIconDir);
|
|
#endif
|
|
/* 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--);
|
|
|
|
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(WINNT)
|
|
#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;
|
|
|
|
DebugMsg(DM_TRACE, TEXT("ExtractAssociatedIconExW(\"%s\")"), lpIconPath);
|
|
|
|
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 = 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;
|
|
LPMYICONINFO 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))) {
|
|
|
|
// BUGBUG handle failures here
|
|
|
|
h = LoadResource(hInst, h);
|
|
p = LockResource(h);
|
|
*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))) {
|
|
|
|
// BUGBUG handle failures here
|
|
|
|
h = LoadResource(hInst, h);
|
|
p = LockResource(h);
|
|
*lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
|
|
UnlockResource(h);
|
|
FreeResource(h);
|
|
}
|
|
*lpiIconIndex = DOSAPPICONINDEX;
|
|
return LoadIcon(hInst, MAKEINTRESOURCE(DOSAPPICON));
|
|
}
|
|
else {
|
|
goto GotIcon;
|
|
}
|
|
}
|
|
|
|
else {
|
|
#ifdef WIN32
|
|
|
|
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 = (LPMYICONINFO)GlobalLock(hIconList))) {
|
|
hIcon = (lpIconList + *lpiIconIndex)->hIcon;
|
|
*lpiIconId = (lpIconList + *lpiIconIndex)->iIconId;
|
|
GlobalUnlock(hIconList);
|
|
}
|
|
FreeIconList(hIconList, *lpiIconIndex);
|
|
return(hIcon);
|
|
}
|
|
#endif
|
|
}
|
|
return hIcon;
|
|
}
|
|
#endif
|
|
#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
|
|
//
|
|
//
|
|
|
|
#ifndef UNICODE // BUGBUG - BobDay - This function should be removed
|
|
HICON APIENTRY
|
|
ExtractAssociatedIconW(
|
|
HINSTANCE hInst,
|
|
LPWSTR lpIconPath,
|
|
LPWORD lpiIconId)
|
|
{
|
|
WORD wIconIndex;
|
|
|
|
wIconIndex = *lpiIconId;
|
|
|
|
return ExtractAssociatedIconExW(hInst, lpIconPath, &wIconIndex, lpiIconId);
|
|
}
|
|
#endif
|
|
|
|
|
|
#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
|