windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/tools/extract/extract.c
2020-09-26 16:20:57 +08:00

1802 lines
49 KiB
C

/*++
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:
<alias> <date> <comments>
--*/
#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] <pe-file>\n"
"icontool -c <pe-file-1> <pe-file-2>\n"
"icontool -d [i:<index>] <in-file> <migicons.dat>\n"
"icontool -e[:range] <in-file> <migicons.dat>\n"
"icontool [-i:<index>] <in-file> <ico-file>\n"
"icontool -k <pe-file> <index range>\n"
"icontool -l[i] [-q] [-n] [-p:<path>] <in-file> [<in-file>] [...]\n"
"icontool -u <pe-file>\n"
"icontool -x <migicons.dat> <pe-file>\n"
"\n"
"<in-file> Specifies the file to extract an icon from (.ICO, NE or PE)\n"
"<ico-file> Specifies the file to save the icon to (.ICO only)\n"
"<pe-file> Specifies the file to save the icon(s) to (PE only)\n"
"<migicons.dat> 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 <in-file>, 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 <index range> 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 <in-file>, 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;
}