/*++ Copyright (c) 1997 Microsoft Corporation Module Name: icontool.c Abstract: Extracts icons in a variety of ways to test the icon extraction code. Author: Jim Schmidt (jimschm) 22-Apr-1998 Revision History: --*/ #include "pch.h" INT g_ErrorLevel; VOID pLaunchCompareDlg ( IN PCTSTR FileName1, IN PCTSTR FileName2 ); UINT pRemoveIcons ( IN PICON_EXTRACT_CONTEXT Context, IN UINT Start, IN UINT End ); UINT pCopyIconRange ( IN PICON_EXTRACT_CONTEXT Context, IN PCTSTR IconFile, IN UINT Start, IN UINT End ); // // This routine is in migutil\icons.c // BOOL pOpenIconImageA ( IN OUT PICON_EXTRACT_CONTEXTA Context, IN PCSTR FileToOpen, OUT PBOOL IsIco, OPTIONAL OUT PBOOL Is16Bit OPTIONAL ); BOOL pOpenIconImageW ( IN OUT PICON_EXTRACT_CONTEXTW Context, IN PCWSTR FileToOpen, OUT PBOOL IsIco, OPTIONAL OUT PBOOL Is16Bit OPTIONAL ); #ifdef UNICODE #define pOpenIconImage pOpenIconImageW #else #define pOpenIconImage pOpenIconImageA #endif typedef enum { NONE, CREATE_ICO, EXTRACT, EXTRACT_ALL, IMPLANT, EXTRACT_ONE, LIST, COMPARE, MAKE_UNIQUE, KILL } MODE; VOID HelpAndExit ( VOID ) { printf ("Command line syntax:\n\n" "icontool -a [-r] \n" "icontool -c \n" "icontool -d [i:] \n" "icontool -e[:range] \n" "icontool [-i:] \n" "icontool -k \n" "icontool -l[i] [-q] [-n] [-p:] [] [...]\n" "icontool -u \n" "icontool -x \n" "\n" " Specifies the file to extract an icon from (.ICO, NE or PE)\n" " Specifies the file to save the icon to (.ICO only)\n" " Specifies the file to save the icon(s) to (PE only)\n" " Specifies the path to migicons.dat (note: same as what\n" " is generated by WINNT32)\n" "-a Scans all files for icons\n" "-c Compare pe-file-1 to pe-file-2 visually\n" "-d Extracts icon from a file into dat file\n" "-e Extracts all icons from , or a range of icons. The\n" " range must be simple (as in these three examples: 152 or 1-4\n" " or 10-)\n" "-i Specifies the index or string ID of the icon to extract, default\n" " is 0\n" "-k Kill icon where is in the form of 1,4-5,10\n" "-l Lists icon resource names\n" "-li Produces output for [Compatible Icon Indexes]\n" "-n No header (used with -li only)\n" "-p Specifies a path to compare the same-named , used to\n" " produce [Compatible Icon Index] that have binaries with icons\n" " in common.\n" "-q Quiet (no error output)\n" "-r Enables recursion\n" "-u Makes all icons unique, removes duplicates\n" "-x Extracts icons from a dat file into a pe file\n" ); exit(0); } BOOL pRemoveDuplicateIcons ( IN PCTSTR SourcePeFile, IN PCTSTR DestPeFile ); BOOL pGetMinAndMax ( IN PICON_EXTRACT_CONTEXT Context, OUT PUINT Min, OUT PUINT Max ); HANDLE g_hHeap; HINSTANCE g_hInst; BOOL pIsErrorOk ( DWORD Error ) { if (Error != ERROR_SUCCESS && Error != ERROR_FILE_INVALID && Error != ERROR_ACCESS_DENIED && Error != ERROR_BAD_FORMAT && Error != ERROR_RESOURCE_TYPE_NOT_FOUND && Error != ERROR_SHARING_VIOLATION && Error != ERROR_NO_MORE_FILES && Error != ERROR_RESOURCE_DATA_NOT_FOUND && Error != ERROR_NOACCESS && Error != ERROR_INVALID_EXE_SIGNATURE && Error != ERROR_CANT_ACCESS_FILE ) { return TRUE; } return FALSE; } BOOL WINAPI MigUtil_Entry ( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ); VOID Init ( VOID ) { MigUtil_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL); } VOID Terminate ( VOID ) { MigUtil_Entry (g_hInst, DLL_PROCESS_DETACH, NULL); } INT __cdecl _tmain ( INT argc, TCHAR *argv[] ) { PCTSTR IconFile = NULL; PCTSTR DestFile = NULL; PCTSTR IconId = NULL; INT IconIndex = 0; INT i; GROWBUFFER Buf = GROWBUF_INIT; GROWBUFFER Buf2 = GROWBUF_INIT; MODE Mode = NONE; BOOL RecurseMode = FALSE; INT Id = 1; ICON_EXTRACT_CONTEXT Context; WORD Icon; DWORD Error; UINT Count; BOOL UseIconIndex = TRUE; TCHAR IconIndexStr[128]; MULTISZ_ENUM MultiSz; PCTSTR IconList; PCTSTR IconList2; BOOL InfOutput = FALSE; INT ResourceId; UINT Column; UINT Indent; TCHAR Buffer[2048]; MULTISZ_ENUM LookAhead; INT Range; PCTSTR LastValidString; BOOL NeedsHeader = TRUE; GROWBUFFER FileList = GROWBUF_INIT; MULTISZ_ENUM FileListEnum; FILE_ENUM FileEnum; UINT Files = 0; TCHAR RootPath[MAX_TCHAR_PATH]; PCTSTR comparePath = NULL; PCTSTR FileName; PCTSTR RootPathPtr; BOOL Quiet = FALSE; PCTSTR NextNum; UINT Start = 0; UINT End = 0xFFFF; UINT Min; UINT Max; TCHAR workPath[MAX_TCHAR_PATH]; PCTSTR fileSpec; MULTISZ_ENUM compareEnum; BOOL match; BOOL noHeader = FALSE; g_hHeap = GetProcessHeap(); g_hInst = GetModuleHandle (NULL); Init(); for (i = 1 ; i < argc ; i++) { if (argv[i][0] == TEXT('-') || argv[i][0] == TEXT('/')) { switch (_totlower (argv[i][1])) { case TEXT('x'): if (Mode != NONE) { HelpAndExit(); } Mode = IMPLANT; break; case TEXT('d'): if (Mode != NONE) { HelpAndExit(); } Mode = EXTRACT_ONE; break; case TEXT('l'): if (Mode != NONE) { HelpAndExit(); } if (_totlower (argv[i][2]) == TEXT('i')) { InfOutput = TRUE; } else if (argv[i][2]) { HelpAndExit(); } Mode = LIST; break; case TEXT('n'): if (noHeader) { HelpAndExit(); } noHeader = TRUE; break; case TEXT('c'): if (Mode != NONE) { HelpAndExit(); } Mode = COMPARE; break; case TEXT('u'): if (Mode != NONE) { HelpAndExit(); } Mode = MAKE_UNIQUE; break; case TEXT('p'): if (comparePath) { HelpAndExit(); } if (argv[i][2] == ':') { comparePath = &argv[i][3]; } else if (i + 1 < argc) { i++; comparePath = argv[i]; } else { HelpAndExit(); } break; case TEXT('i'): if (argv[i][2] == ':') { IconId = &argv[i][3]; } else if (i + 1 < argc) { i++; IconId= argv[i]; } else { HelpAndExit(); } IconIndex = _ttoi (IconId); while (_istspace ((TCHAR)_tcsnextc (IconId))) { IconId = _tcsinc (IconId); } if (*IconId) { if (!IconIndex && iscsymf(_tcsnextc (IconId))) { UseIconIndex = FALSE; } } break; case TEXT('k'): if (Mode != NONE) { HelpAndExit(); } Mode = KILL; break; case TEXT('a'): if (Mode != NONE) { HelpAndExit(); } Mode = EXTRACT_ALL; break; case TEXT('q'): if (Quiet) { HelpAndExit(); } Quiet = TRUE; break; case TEXT('e'): if (Mode != NONE) { HelpAndExit(); } if (argv[i][2] == ':') { NextNum = &argv[i][3]; if (_tcsnextc (NextNum) != TEXT('-')) { Start = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10); } if (_tcsnextc (NextNum) == TEXT('-')) { NextNum = _tcsinc (NextNum); if (*NextNum) { End = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10); } } else { End = Start; } if (*NextNum) { HelpAndExit(); } } Mode = EXTRACT; break; case TEXT('r'): if (RecurseMode) { HelpAndExit(); } RecurseMode = TRUE; break; default: HelpAndExit(); } } else { Files++; MultiSzAppend (&FileList, argv[i]); if (IconFile) { DestFile = argv[i]; } else { IconFile = argv[i]; } } } MultiSzAppend (&FileList, S_EMPTY); // // Enforce syntax // if (Quiet && Mode != LIST) { HelpAndExit(); } if (Mode == EXTRACT_ALL && DestFile) { HelpAndExit(); } if (Mode == EXTRACT_ALL || Mode == LIST) { DestFile = IconFile; } if (Mode == MAKE_UNIQUE) { if (!DestFile) { DestFile = IconFile; } } if (!DestFile) { HelpAndExit(); } if (RecurseMode && Mode != EXTRACT_ALL) { HelpAndExit(); } if (Files > 2 && Mode != LIST) { HelpAndExit(); } if ((comparePath || noHeader) && Mode != LIST) { HelpAndExit(); } if (UseIconIndex) { IconId = (PCTSTR) (WORD) IconIndex; wsprintf (IconIndexStr, TEXT("%i"), IconIndex); } else { StringCopy (IconIndexStr, IconId); } if (Mode == KILL) { fprintf (stderr, "Beginning icon processing\n"); if (!BeginIconExtraction (&Context, IconFile)) { fprintf (stderr, "Can't begin icon extraction\n"); return 0; } // // Get the min and max IDs // if (!pGetMinAndMax (&Context, &Min, &Max)) { fprintf (stderr, "Can't kill icons without min/max info\n"); return 0; } // // Evaluate the range and remove the icons // NextNum = DestFile; Count = 0; fprintf (stderr, "Removing icons\n"); for (;;) { NextNum = SkipSpace (NextNum); if (!(*NextNum)) { break; } if (_tcsnextc (NextNum) == TEXT('-')) { Start = Min; } else { Start = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10); NextNum = SkipSpace (NextNum); } if (_tcsnextc (NextNum) == TEXT('-')) { NextNum = SkipSpace (_tcsinc (NextNum)); if (_tcsnextc (NextNum) == TEXT(',') || !(*NextNum)) { End = Max; } else { End = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10); NextNum = SkipSpace (NextNum); } } else { End = Start; } Count += pRemoveIcons (&Context, Start, End); if (_tcsnextc (NextNum) == TEXT(',')) { NextNum = _tcsinc (NextNum); } else { break; } } fprintf (stderr, "Saving\n"); if (EndIconExtraction (&Context)) { printf ("Icons removed: %u\n", Count); } return 0; } else if (Mode == IMPLANT) { // // Use IconFile as a source to generate a PE file of icons // if (!BeginIconExtraction (&Context, DestFile)) { fprintf (stderr, "Can't begin icon extraction\n"); return 0; } if (!OpenIconImageFile (&Context, IconFile, FALSE)) { _ftprintf (stderr, TEXT("Can't open %s\n"), IconFile); EndIconExtraction (&Context); return 0; } Count = 0; while (CopyIcon (&Context, NULL, NULL, 0)) { Count++; } if (EndIconExtraction (&Context)) { printf ("Icons extracted: %u\n", Count); } } else if (Mode == EXTRACT || Mode == EXTRACT_ONE) { // // Use IconFile as a source to generate a PE file of icons // if (!BeginIconExtraction (&Context, NULL)) { fprintf (stderr, "Can't begin icon extraction\n"); return 0; } if (!OpenIconImageFile (&Context, DestFile, TRUE)) { _ftprintf (stderr, TEXT("Can't create %s\n"), DestFile); EndIconExtraction (&Context); return 0; } if (Mode == EXTRACT) { // // If no range is specified, use the CopyAllIcons api // if (Start == 0 && End == 0xFFFF) { if (!CopyAllIcons (&Context, IconFile)) { _ftprintf (stderr, TEXT("Can't copy all icons from %s, error %u\n"), IconFile, GetLastError()); } else { _tprintf (TEXT("Extracted all icons from %s\n"), IconFile); } } // // If a range is specified, get the names and copy them // if they are in the range. // else { Count = pCopyIconRange (&Context, IconFile, Start, End); _tprintf (TEXT("Icons extracted: %u\n"), Count); } } else { if (!CopyIcon (&Context, IconFile, NULL, IconIndex)) { _ftprintf (stderr, TEXT("Can't copy %s [%i], error %u\n"), IconFile, IconIndex, GetLastError()); } else { _tprintf (TEXT("Extracted %s [%i]\n"), IconFile, IconIndex); } } EndIconExtraction (&Context); } else if (Mode == MAKE_UNIQUE) { pRemoveDuplicateIcons (IconFile, DestFile); } else if (Mode == LIST) { EnumFirstMultiSz (&FileListEnum, (PCTSTR) FileList.Buf); do { // // Separate the path and file pattern // FileName = GetFileNameFromPath (FileListEnum.CurrentString); if (FileName == FileListEnum.CurrentString) { RootPathPtr = TEXT("."); } else { _tcssafecpyab ( RootPath, FileListEnum.CurrentString, FileName, sizeof (RootPath) / sizeof (RootPath[0]) ); RootPathPtr = RootPath; if (CharCount (RootPath) > 3) { RemoveWackAtEnd (RootPath); } } // // Process all files specified // if (EnumFirstFile (&FileEnum, RootPathPtr, FileName)) { do { if (FileEnum.Directory) { continue; } // // Process IconFile // IconFile = FileEnum.FullPath; IconList = ExtractIconNamesFromFile (IconFile, &Buf); Count = 0; if (comparePath) { // // Prepare a list of resources in a binary located // in an alternate path // fileSpec = GetFileNameFromPath (IconFile); StringCopy (workPath, comparePath); StringCopy (AppendWack (workPath), fileSpec); IconList2 = ExtractIconNamesFromFile (workPath, &Buf2); } else { IconList2 = IconList; } if (IconList && IconList2) { if (!InfOutput) { // // Simple output // if (EnumFirstMultiSz (&MultiSz, IconList)) { do { if (IconList != IconList2) { match = FALSE; if (EnumFirstMultiSz (&compareEnum, IconList2)) { do { if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) { match = TRUE; break; } } while (EnumNextMultiSz (&compareEnum)); } if (!match) { continue; } } if (!Count) { if (IconList != IconList2) { _tprintf (TEXT("Icon resources in both %s and %s:\n\n"), IconFile, workPath); } else { _tprintf (TEXT("Icon resources in %s:\n\n"), IconFile); } } _tprintf (TEXT(" %s\n"), MultiSz.CurrentString); Count++; } while (EnumNextMultiSz (&MultiSz)); if (Count) { _tprintf (TEXT("\n")); } } if (IconList != IconList2) { if (EnumFirstMultiSz (&MultiSz, IconList)) { Count = 0; do { match = FALSE; if (EnumFirstMultiSz (&compareEnum, IconList2)) { do { if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) { match = TRUE; break; } } while (EnumNextMultiSz (&compareEnum)); } if (match) { continue; } if (!Count) { _tprintf (TEXT("Icon resources in only in %s:\n\n"), IconFile); } _tprintf (TEXT(" %s\n"), MultiSz.CurrentString); Count++; } while (EnumNextMultiSz (&MultiSz)); if (Count) { _tprintf (TEXT("\n")); } } if (EnumFirstMultiSz (&MultiSz, IconList2)) { Count = 0; do { match = FALSE; if (EnumFirstMultiSz (&compareEnum, IconList)) { do { if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) { match = TRUE; break; } } while (EnumNextMultiSz (&compareEnum)); } if (match) { continue; } if (!Count) { _tprintf (TEXT("Icon resources in only in %s:\n\n"), workPath); } _tprintf (TEXT(" %s\n"), MultiSz.CurrentString); Count++; } while (EnumNextMultiSz (&MultiSz)); if (Count) { _tprintf (TEXT("\n")); } } Count = 1; } } else { // // INF output // // // Count the numeric resources // if (EnumFirstMultiSz (&MultiSz, IconList)) { do { if (IconList != IconList2) { match = FALSE; if (EnumFirstMultiSz (&compareEnum, IconList2)) { do { if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) { match = TRUE; break; } } while (EnumNextMultiSz (&compareEnum)); } if (!match) { continue; } } if (_tcsnextc (MultiSz.CurrentString) == TEXT('#')) { Count++; } } while (EnumNextMultiSz (&MultiSz)); } // // If at least one numeric resource, print it // if (Count) { if (NeedsHeader) { if (!noHeader) { _tprintf (TEXT("[%s]\n"), S_KNOWN_GOOD_ICON_MODULES); } NeedsHeader = FALSE; } wsprintf (Buffer, TEXT("%s="), GetFileNameFromPath (IconFile)); Indent = TcharCount (Buffer); wsprintf (GetEndOfString (Buffer), TEXT("%u"), Count); Column = TcharCount (Buffer); _tprintf (TEXT("%s"), Buffer); if (EnumFirstMultiSz (&MultiSz, IconList)) { do { if (IconList != IconList2) { match = FALSE; if (EnumFirstMultiSz (&compareEnum, IconList2)) { do { if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) { match = TRUE; break; } } while (EnumNextMultiSz (&compareEnum)); } if (!match) { continue; } } if (_tcsnextc (MultiSz.CurrentString) == TEXT('#')) { ResourceId = _ttoi (_tcsinc (MultiSz.CurrentString)); // // Determine if this is a range // Range = ResourceId; EnumFirstMultiSz (&LookAhead, MultiSz.CurrentString); LastValidString = MultiSz.CurrentString; while (EnumNextMultiSz (&LookAhead)) { if (_tcsnextc (LookAhead.CurrentString) != TEXT('#')) { continue; } i = _ttoi (_tcsinc (LookAhead.CurrentString)); if (Range + 1 == i) { Range = i; LastValidString = LookAhead.CurrentString; } else { break; } } // // Add separator // _tprintf (TEXT(",")); Column++; if (Range > ResourceId + 1) { wsprintf (Buffer, TEXT("%u-%u"), ResourceId, Range); MultiSz.CurrentString = LastValidString; } else { wsprintf (Buffer, TEXT("%u"), ResourceId); } if (TcharCount (Buffer) + Column > 78) { _tprintf (TEXT("\\\n")); for (Column = 0 ; Column < Indent ; Column++) { _tprintf (TEXT(" ")); } } Column += TcharCount (Buffer); _tprintf (TEXT("%s"), Buffer); } } while (EnumNextMultiSz (&MultiSz)); } _tprintf (TEXT("\n")); } } } if (!Count && !Quiet) { _ftprintf (stderr, TEXT("No icons in %s\n"), IconFile); } if (Count) { g_ErrorLevel = 1; } } while (EnumNextFile (&FileEnum)); } } while (EnumNextMultiSz (&FileListEnum)); } else if (Mode == EXTRACT_ONE) { // // Extract one icon // if (ExtractIconImageFromFile (IconFile, IconId, &Buf)) { if (WriteIconImageArrayToIcoFile (DestFile, &Buf)) { _ftprintf (stderr, TEXT("Icon %s from %s written successfully to %s.\n"), IconIndexStr, IconFile, DestFile); } else { _ftprintf (stderr, TEXT("Can't write icon to %s (error %u)\n"), DestFile, GetLastError()); } } else { _ftprintf (stderr, TEXT("Can't extract icon %s from %s (error %u)\n"), IconIndexStr, IconFile, GetLastError()); } } else if (Mode == EXTRACT_ALL) { // // Extract default icon of every file // if (!BeginIconExtraction (&Context, DestFile)) { fprintf (stderr, "Can't begin icon extraction\n"); return 0; } if (RecurseMode) { TREE_ENUM e; if (EnumFirstFileInTree (&e, TEXT("."), NULL, FALSE)) { do { if (StringIMatch (e.FullPath, DestFile)) { continue; } Icon = Context.IconId; if (!CopyAllIcons (&Context, e.FullPath)) { Error = GetLastError(); if (pIsErrorOk (Error)) { _ftprintf (stderr, TEXT("Can't copy icons from %s, error %u\n"), e.FullPath, Error); break; } } else { _tprintf (TEXT("%u: %s\n"), Icon, e.FullPath); } } while (EnumNextFileInTree (&e)); } } else { WIN32_FIND_DATA fd; HANDLE FindHandle; TCHAR FullPath[MAX_TCHAR_PATH]; PTSTR p; GetCurrentDirectory (MAX_TCHAR_PATH, FullPath); p = AppendWack (FullPath); StringCopy (p, TEXT("*.*")); FindHandle = FindFirstFile (FullPath, &fd); if (FindHandle != INVALID_HANDLE_VALUE) { do { if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { continue; } StringCopy (p, fd.cFileName); if (StringIMatch (FullPath, DestFile)) { continue; } Icon = Context.IconId; if (!CopyAllIcons (&Context, fd.cFileName)) { Error = GetLastError(); if (pIsErrorOk (Error)) { _ftprintf (stderr, TEXT("Can't copy icons from %s, error %u\n"), fd.cFileName, Error); break; } } else { _tprintf (TEXT("%u: %s\n"), Icon, fd.cFileName); } } while (FindNextFile (FindHandle, &fd)); FindClose (FindHandle); } } if (EndIconExtraction (&Context)) { printf ("Icons extracted.\n"); } } else if (Mode == COMPARE) { pLaunchCompareDlg (IconFile, DestFile); } FreeGrowBuffer (&Buf); FreeGrowBuffer (&Buf2); FreeGrowBuffer (&FileList); Terminate(); return g_ErrorLevel; } BOOL pSetIconInWindow ( IN HWND IconWnd1, IN HWND IconWnd2, IN PCTSTR FileName1, IN PCTSTR FileName2, IN INT ResourceId ) { HANDLE Instance1; HANDLE Instance2; BOOL b = FALSE; HICON Icon1 = NULL; HICON Icon2 = NULL; Instance1 = LoadLibraryEx (FileName1, NULL, LOAD_LIBRARY_AS_DATAFILE); if (Instance1) { // // Get the icon // Icon1 = LoadIcon (Instance1, MAKEINTRESOURCE (ResourceId)); } Instance2 = LoadLibraryEx (FileName2, NULL, LOAD_LIBRARY_AS_DATAFILE); if (Instance2) { // // Get the icon // Icon2 = LoadIcon (Instance2, MAKEINTRESOURCE (ResourceId)); } if (Icon1 && Icon2) { SendMessage (IconWnd1, STM_SETICON, (WPARAM) Icon1, 0); SendMessage (IconWnd2, STM_SETICON, (WPARAM) Icon2, 0); b = TRUE; } if (Instance1) { FreeLibrary (Instance1); } if (Instance2) { FreeLibrary (Instance2); } return b; } typedef struct { GROWBUFFER IdArray; UINT CurrentId; UINT IdCount; PCTSTR FileName1; PCTSTR FileName2; } DLGARGS, *PDLGARGS; #define WMX_UPDATE_ICONS (WM_APP+1) BOOL CALLBACK IconCompareDlgProc ( HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { static PDLGARGS Args; TCHAR Number[32]; INT ResourceId; switch (uMsg) { case WM_INITDIALOG: Args = (PDLGARGS) lParam; SetDlgItemText (hdlg, IDC_FILE_NAME1, Args->FileName1); SetDlgItemText (hdlg, IDC_FILE_NAME2, Args->FileName2); SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0); switch (g_ErrorLevel) { case 0: ResourceId = IDC_NO_MATCH; break; case 1: ResourceId = IDC_PARTIAL; break; case 2: ResourceId = IDC_MATCH; break; } CheckDlgButton (hdlg, ResourceId, BST_CHECKED); break; case WMX_UPDATE_ICONS: ResourceId = (INT) (*((PDWORD) Args->IdArray.Buf + Args->CurrentId)); pSetIconInWindow ( GetDlgItem (hdlg, IDC_ICON1), GetDlgItem (hdlg, IDC_ICON2), Args->FileName1, Args->FileName2, ResourceId ); wsprintf (Number, TEXT("%i"), ResourceId); SetDlgItemText (hdlg, IDC_RESOURCE_ID, Number); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: if (IsDlgButtonChecked (hdlg, IDC_NO_MATCH) == BST_CHECKED) { g_ErrorLevel = 0; } else if (IsDlgButtonChecked (hdlg, IDC_PARTIAL) == BST_CHECKED) { g_ErrorLevel = 1; } else if (IsDlgButtonChecked (hdlg, IDC_MATCH) == BST_CHECKED) { g_ErrorLevel = 2; } EndDialog (hdlg, 0); break; case IDC_NEXT: if (Args->CurrentId < (Args->IdCount - 1)) { Args->CurrentId++; SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0); } break; case IDC_PREV: if (Args->CurrentId > 0) { Args->CurrentId--; SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0); } break; } break; } return FALSE; } VOID pLaunchCompareDlg ( IN PCTSTR FileName1, IN PCTSTR FileName2 ) { DLGARGS Args; PCTSTR IconList1; PCTSTR IconList2; GROWBUFFER Buf1 = GROWBUF_INIT; GROWBUFFER Buf2 = GROWBUF_INIT; MULTISZ_ENUM Enum1, Enum2; BOOL Match; // // Obtain the resource ID list from both FileName1 and FileName2. // Put the union in a grow buffer. // ZeroMemory (&Args, sizeof (Args)); Args.FileName1 = FileName1; Args.FileName2 = FileName2; IconList1 = ExtractIconNamesFromFile (FileName1, &Buf1); IconList2 = ExtractIconNamesFromFile (FileName2, &Buf2); if (IconList1 && IconList2) { // // Enumerate list one, then scan list two for a match // if (EnumFirstMultiSz (&Enum1, IconList1)) { do { if (_tcsnextc (Enum1.CurrentString) != TEXT('#')) { continue; } Match = FALSE; if (EnumFirstMultiSz (&Enum2, IconList2)) { do { if (StringMatch (Enum1.CurrentString, Enum2.CurrentString)) { Match = TRUE; break; } } while (EnumNextMultiSz (&Enum2)); } if (Match) { GrowBufAppendDword ( &Args.IdArray, (DWORD) _ttoi (_tcsinc (Enum1.CurrentString)) ); Args.IdCount++; } else { _ftprintf ( stderr, TEXT("Resource ID %s is not in %s\n"), Enum1.CurrentString, FileName2 ); } } while (EnumNextMultiSz (&Enum1)); } // // Enumerate list two, then scan list one for a match // if (EnumFirstMultiSz (&Enum2, IconList2)) { do { if (_tcsnextc (Enum2.CurrentString) != TEXT('#')) { continue; } Match = FALSE; if (EnumFirstMultiSz (&Enum1, IconList1)) { do { if (StringMatch (Enum1.CurrentString, Enum2.CurrentString)) { Match = TRUE; break; } } while (EnumNextMultiSz (&Enum1)); } if (!Match) { _ftprintf ( stderr, TEXT("Resource ID %s is not in %s\n"), Enum2.CurrentString, FileName1 ); } } while (EnumNextMultiSz (&Enum2)); } // // Now present the dialog // if (Args.IdCount) { DialogBoxParam ( g_hInst, MAKEINTRESOURCE(IDD_COMPARE), NULL, IconCompareDlgProc, (LPARAM) &Args ); } else { _ftprintf (stderr, TEXT("No common icon resources found.\n")); } } else { if (!IconList1) { _ftprintf (stderr, TEXT("Can't get icon list from %s\n"), FileName1); } if (!IconList2) { _ftprintf (stderr, TEXT("Can't get icon list from %s\n"), FileName2); } } FreeGrowBuffer (&Buf1); FreeGrowBuffer (&Buf2); } BOOL pCompareIconImages ( IN PCTSTR SourceFile, IN PCTSTR Name1, IN PCTSTR Name2 ) { GROWBUFFER SrcBuf = GROWBUF_INIT; GROWBUFFER DestBuf = GROWBUF_INIT; BOOL b; b = ExtractIconImageFromFile (SourceFile, Name1, &SrcBuf); if (b) { b = ExtractIconImageFromFile (SourceFile, Name2, &DestBuf); } if (b) { if (SrcBuf.End != DestBuf.End) { b = FALSE; } else { b = (memcmp (SrcBuf.Buf, DestBuf.Buf, SrcBuf.End) == 0); } } FreeGrowBuffer (&SrcBuf); FreeGrowBuffer (&DestBuf); return b; } BOOL pMakeNameIndex ( IN PCTSTR SourceFile, OUT PGROWBUFFER IndexBuf, OUT PGROWBUFFER IndexArray ) { PCTSTR IconList; MULTISZ_ENUM e; IndexBuf->End = 0; IndexArray->End = 0; IconList = ExtractIconNamesFromFile (SourceFile, IndexBuf); if (IconList) { // // Build an index array // if (EnumFirstMultiSz (&e, IconList)) { do { if (_tcsnextc (e.CurrentString) != TEXT('#')) { // // This is a named string // GrowBufAppendDword (IndexArray, (DWORD) e.CurrentString); } else { // // This is a 16-bit ID // GrowBufAppendDword (IndexArray, (DWORD) _ttoi (_tcsinc (e.CurrentString))); } } while (EnumNextMultiSz (&e)); } } else { _ftprintf (stderr, TEXT("No icons found in %s\n"), SourceFile); } return IndexArray->End != 0; } #define BLANK_ID 0xFFFFFFFF BOOL pFindUniqueIcons ( IN PCTSTR SourceFile, OUT PGROWBUFFER WorkBuffer, OUT PGROWBUFFER UniqueIndexArray, OUT PUINT OriginalMax ) { GROWBUFFER IndexArray = GROWBUF_INIT; BOOL b; UINT i, j; UINT Count; PDWORD IdPtr; UniqueIndexArray->End = 0; b = pMakeNameIndex (SourceFile, WorkBuffer, &IndexArray); if (b) { *OriginalMax = 0; Count = IndexArray.End / sizeof (DWORD); IdPtr = (PDWORD) IndexArray.Buf; for (i = 0 ; i < Count ; i++) { if (IdPtr[i] == BLANK_ID) { continue; } if (IdPtr[i] < 0x10000) { _ftprintf (stderr, TEXT("Processing ID %u\n"), IdPtr[i]); if (IdPtr[i] > *OriginalMax) { *OriginalMax = IdPtr[i]; } } else { _ftprintf (stderr, TEXT("Processing ID %s\n"), IdPtr[i]); } for (j = i + 1 ; j < Count ; j++) { if (IdPtr[j] == BLANK_ID) { continue; } if (pCompareIconImages (SourceFile, (PCTSTR) (IdPtr[i]), (PCTSTR) (IdPtr[j]))) { IdPtr[j] = BLANK_ID; } } } for (i = 0 ; i < Count ; i++) { if (IdPtr[i] != BLANK_ID) { GrowBufAppendDword (UniqueIndexArray, IdPtr[i]); } } } FreeGrowBuffer (&IndexArray); return b; } UINT pRemoveIcons ( IN PICON_EXTRACT_CONTEXT Context, IN UINT Start, IN UINT End ) { UINT Count = 0; GROWBUFFER Names = GROWBUF_INIT; PCTSTR IconList; MULTISZ_ENUM e; UINT id; if (Start > End) { return 0; } if (Start == End) { _ftprintf (stderr, TEXT("Removing icon %u\n"), Start); } else { _ftprintf (stderr, TEXT("Removing icon range %u through %u\n"), Start, End); } pOpenIconImage (Context, Context->DestFile, NULL, NULL); IconList = ExtractIconNamesFromFileEx ( Context->ModuleName, &Names, Context->Module, Context->Module16 ); if (IconList) { if (EnumFirstMultiSz (&e, IconList)) { do { if (_tcsnextc (e.CurrentString) == TEXT('#')) { id = (DWORD) _ttoi (_tcsinc (e.CurrentString)); if (id >= Start && id <= End) { if (UpdateResource ( Context->Update, RT_ICON, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), NULL, 0 )) { Count++; } else { _ftprintf (stderr, TEXT("Can't remove icon ID %u; rc=%u\n"), id, GetLastError()); } } } } while (EnumNextMultiSz (&e)); } } else { _ftprintf (stderr, TEXT("Can't get icon names; rc=%u\n"), GetLastError()); } FreeGrowBuffer (&Names); return Count; } BOOL pRemoveDuplicateIcons ( IN PCTSTR SourcePeFile, IN PCTSTR DestPeFile ) { GROWBUFFER WorkBuffer = GROWBUF_INIT; GROWBUFFER UniqueIndexArray = GROWBUF_INIT; ICON_EXTRACT_CONTEXT Context; UINT Count = 0; UINT u; PDWORD IconId; BOOL b; UINT OriginalMax; _ftprintf (stderr, TEXT("Finding unique icons\n")); b = pFindUniqueIcons (SourcePeFile, &WorkBuffer, &UniqueIndexArray, &OriginalMax); if (b) { b = BeginIconExtraction (&Context, DestPeFile); if (!b) { _ftprintf (stderr, TEXT("Can't save icons to %s\n"), DestPeFile); } } if (b) { _ftprintf (stderr, TEXT("Updating icon resources\n")); Count = UniqueIndexArray.End / sizeof (DWORD); IconId = (PDWORD) UniqueIndexArray.Buf; for (u = 0 ; u < Count ; u++) { b = CopyIcon (&Context, SourcePeFile, (PCTSTR) (IconId[u]), 0); if (!b) { if (IconId[u] < 0x10000) { _ftprintf (stderr, TEXT("Can't copy icon %u\n"), IconId[u]); } else { _ftprintf (stderr, TEXT("Can't copy icon %s\n"), IconId[u]); } break; } } } if (b) { pRemoveIcons (&Context, Count + 1, OriginalMax); b = EndIconExtraction (&Context); if (!b) { _ftprintf (stderr, TEXT("Can't safe icons\n")); } } if (b) { _ftprintf (stderr, TEXT("Final icon count: %u\n"), Count); } FreeGrowBuffer (&WorkBuffer); FreeGrowBuffer (&UniqueIndexArray); return b; } BOOL pGetMinAndMax ( IN PICON_EXTRACT_CONTEXT Context, OUT PUINT Min, OUT PUINT Max ) { BOOL b = FALSE; GROWBUFFER Names = GROWBUF_INIT; PCTSTR IconList; UINT id; MULTISZ_ENUM e; *Min = (UINT) -1; *Max = 0; pOpenIconImage (Context, Context->DestFile, NULL, NULL); _ftprintf (stderr, TEXT("Getting min/max icon indexes from %s\n"), Context->ModuleName); IconList = ExtractIconNamesFromFileEx ( Context->ModuleName, &Names, Context->Module, Context->Module16 ); if (IconList) { if (EnumFirstMultiSz (&e, IconList)) { do { if (_tcsnextc (e.CurrentString) == TEXT('#')) { id = (DWORD) _ttoi (_tcsinc (e.CurrentString)); if (id < *Min) { *Min = id; } if (id > *Max) { *Max = id; } } } while (EnumNextMultiSz (&e)); } b = TRUE; } FreeGrowBuffer (&Names); if (b) { _ftprintf (stderr, TEXT("Min: %u Max: %u\n"), *Min, *Max); } else { _ftprintf (stderr, TEXT("Can't get min/max info, rc=%u\n"), GetLastError()); } return b; } UINT pCopyIconRange ( IN PICON_EXTRACT_CONTEXT Context, IN PCTSTR IconFile, IN UINT Start, IN UINT End ) { UINT Count = 0; GROWBUFFER Names = GROWBUF_INIT; PCTSTR IconList; UINT id; MULTISZ_ENUM e; pOpenIconImage (Context, IconFile, NULL, NULL); if (Start == End) { _ftprintf ( stderr, TEXT("Copying icon %u from %s to %s\n"), Start, Context->ModuleName, Context->IconImageFileName ); } else { _ftprintf ( stderr, TEXT("Copying icon range %u to %u from %s to %s\n"), Start, End, Context->ModuleName, Context->IconImageFileName ); } IconList = ExtractIconNamesFromFileEx ( Context->ModuleName, &Names, Context->Module, Context->Module16 ); if (IconList) { if (EnumFirstMultiSz (&e, IconList)) { do { if (_tcsnextc (e.CurrentString) == TEXT('#')) { id = (DWORD) _ttoi (_tcsinc (e.CurrentString)); if (id >= Start && id <= End) { if (!CopyIcon (Context, IconFile, e.CurrentString, 0)) { _ftprintf (stderr, TEXT("Can't copy %s [%i], error %u\n"), IconFile, id, GetLastError()); } else { Count++; } } } } while (EnumNextMultiSz (&e)); } } else { _ftprintf (stderr, TEXT("Can't get icon names from %s\n"), Context->ModuleName); } FreeGrowBuffer (&Names); return Count; }