/****************************************************************************/ /* */ /* 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= 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= 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) 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