1802 lines
49 KiB
C
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|