Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1801 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. icontool.c
  5. Abstract:
  6. Extracts icons in a variety of ways to test the icon extraction code.
  7. Author:
  8. Jim Schmidt (jimschm) 22-Apr-1998
  9. Revision History:
  10. <alias> <date> <comments>
  11. --*/
  12. #include "pch.h"
  13. INT g_ErrorLevel;
  14. VOID
  15. pLaunchCompareDlg (
  16. IN PCTSTR FileName1,
  17. IN PCTSTR FileName2
  18. );
  19. UINT
  20. pRemoveIcons (
  21. IN PICON_EXTRACT_CONTEXT Context,
  22. IN UINT Start,
  23. IN UINT End
  24. );
  25. UINT
  26. pCopyIconRange (
  27. IN PICON_EXTRACT_CONTEXT Context,
  28. IN PCTSTR IconFile,
  29. IN UINT Start,
  30. IN UINT End
  31. );
  32. //
  33. // This routine is in migutil\icons.c
  34. //
  35. BOOL
  36. pOpenIconImageA (
  37. IN OUT PICON_EXTRACT_CONTEXTA Context,
  38. IN PCSTR FileToOpen,
  39. OUT PBOOL IsIco, OPTIONAL
  40. OUT PBOOL Is16Bit OPTIONAL
  41. );
  42. BOOL
  43. pOpenIconImageW (
  44. IN OUT PICON_EXTRACT_CONTEXTW Context,
  45. IN PCWSTR FileToOpen,
  46. OUT PBOOL IsIco, OPTIONAL
  47. OUT PBOOL Is16Bit OPTIONAL
  48. );
  49. #ifdef UNICODE
  50. #define pOpenIconImage pOpenIconImageW
  51. #else
  52. #define pOpenIconImage pOpenIconImageA
  53. #endif
  54. typedef enum {
  55. NONE,
  56. CREATE_ICO,
  57. EXTRACT,
  58. EXTRACT_ALL,
  59. IMPLANT,
  60. EXTRACT_ONE,
  61. LIST,
  62. COMPARE,
  63. MAKE_UNIQUE,
  64. KILL
  65. } MODE;
  66. VOID
  67. HelpAndExit (
  68. VOID
  69. )
  70. {
  71. printf ("Command line syntax:\n\n"
  72. "icontool -a [-r] <pe-file>\n"
  73. "icontool -c <pe-file-1> <pe-file-2>\n"
  74. "icontool -d [i:<index>] <in-file> <migicons.dat>\n"
  75. "icontool -e[:range] <in-file> <migicons.dat>\n"
  76. "icontool [-i:<index>] <in-file> <ico-file>\n"
  77. "icontool -k <pe-file> <index range>\n"
  78. "icontool -l[i] [-q] [-n] [-p:<path>] <in-file> [<in-file>] [...]\n"
  79. "icontool -u <pe-file>\n"
  80. "icontool -x <migicons.dat> <pe-file>\n"
  81. "\n"
  82. "<in-file> Specifies the file to extract an icon from (.ICO, NE or PE)\n"
  83. "<ico-file> Specifies the file to save the icon to (.ICO only)\n"
  84. "<pe-file> Specifies the file to save the icon(s) to (PE only)\n"
  85. "<migicons.dat> Specifies the path to migicons.dat (note: same as what\n"
  86. " is generated by WINNT32)\n"
  87. "-a Scans all files for icons\n"
  88. "-c Compare pe-file-1 to pe-file-2 visually\n"
  89. "-d Extracts icon from a file into dat file\n"
  90. "-e Extracts all icons from <in-file>, or a range of icons. The\n"
  91. " range must be simple (as in these three examples: 152 or 1-4\n"
  92. " or 10-)\n"
  93. "-i Specifies the index or string ID of the icon to extract, default\n"
  94. " is 0\n"
  95. "-k Kill icon where <index range> is in the form of 1,4-5,10\n"
  96. "-l Lists icon resource names\n"
  97. "-li Produces output for [Compatible Icon Indexes]\n"
  98. "-n No header (used with -li only)\n"
  99. "-p Specifies a path to compare the same-named <in-file>, used to\n"
  100. " produce [Compatible Icon Index] that have binaries with icons\n"
  101. " in common.\n"
  102. "-q Quiet (no error output)\n"
  103. "-r Enables recursion\n"
  104. "-u Makes all icons unique, removes duplicates\n"
  105. "-x Extracts icons from a dat file into a pe file\n"
  106. );
  107. exit(0);
  108. }
  109. BOOL
  110. pRemoveDuplicateIcons (
  111. IN PCTSTR SourcePeFile,
  112. IN PCTSTR DestPeFile
  113. );
  114. BOOL
  115. pGetMinAndMax (
  116. IN PICON_EXTRACT_CONTEXT Context,
  117. OUT PUINT Min,
  118. OUT PUINT Max
  119. );
  120. HANDLE g_hHeap;
  121. HINSTANCE g_hInst;
  122. BOOL
  123. pIsErrorOk (
  124. DWORD Error
  125. )
  126. {
  127. if (Error != ERROR_SUCCESS &&
  128. Error != ERROR_FILE_INVALID &&
  129. Error != ERROR_ACCESS_DENIED &&
  130. Error != ERROR_BAD_FORMAT &&
  131. Error != ERROR_RESOURCE_TYPE_NOT_FOUND &&
  132. Error != ERROR_SHARING_VIOLATION &&
  133. Error != ERROR_NO_MORE_FILES &&
  134. Error != ERROR_RESOURCE_DATA_NOT_FOUND &&
  135. Error != ERROR_NOACCESS &&
  136. Error != ERROR_INVALID_EXE_SIGNATURE &&
  137. Error != ERROR_CANT_ACCESS_FILE
  138. ) {
  139. return TRUE;
  140. }
  141. return FALSE;
  142. }
  143. BOOL
  144. WINAPI
  145. MigUtil_Entry (
  146. HINSTANCE hinstDLL,
  147. DWORD fdwReason,
  148. LPVOID lpvReserved
  149. );
  150. VOID
  151. Init (
  152. VOID
  153. )
  154. {
  155. MigUtil_Entry (g_hInst, DLL_PROCESS_ATTACH, NULL);
  156. }
  157. VOID
  158. Terminate (
  159. VOID
  160. )
  161. {
  162. MigUtil_Entry (g_hInst, DLL_PROCESS_DETACH, NULL);
  163. }
  164. INT
  165. __cdecl
  166. _tmain (
  167. INT argc,
  168. TCHAR *argv[]
  169. )
  170. {
  171. PCTSTR IconFile = NULL;
  172. PCTSTR DestFile = NULL;
  173. PCTSTR IconId = NULL;
  174. INT IconIndex = 0;
  175. INT i;
  176. GROWBUFFER Buf = GROWBUF_INIT;
  177. GROWBUFFER Buf2 = GROWBUF_INIT;
  178. MODE Mode = NONE;
  179. BOOL RecurseMode = FALSE;
  180. INT Id = 1;
  181. ICON_EXTRACT_CONTEXT Context;
  182. WORD Icon;
  183. DWORD Error;
  184. UINT Count;
  185. BOOL UseIconIndex = TRUE;
  186. TCHAR IconIndexStr[128];
  187. MULTISZ_ENUM MultiSz;
  188. PCTSTR IconList;
  189. PCTSTR IconList2;
  190. BOOL InfOutput = FALSE;
  191. INT ResourceId;
  192. UINT Column;
  193. UINT Indent;
  194. TCHAR Buffer[2048];
  195. MULTISZ_ENUM LookAhead;
  196. INT Range;
  197. PCTSTR LastValidString;
  198. BOOL NeedsHeader = TRUE;
  199. GROWBUFFER FileList = GROWBUF_INIT;
  200. MULTISZ_ENUM FileListEnum;
  201. FILE_ENUM FileEnum;
  202. UINT Files = 0;
  203. TCHAR RootPath[MAX_TCHAR_PATH];
  204. PCTSTR comparePath = NULL;
  205. PCTSTR FileName;
  206. PCTSTR RootPathPtr;
  207. BOOL Quiet = FALSE;
  208. PCTSTR NextNum;
  209. UINT Start = 0;
  210. UINT End = 0xFFFF;
  211. UINT Min;
  212. UINT Max;
  213. TCHAR workPath[MAX_TCHAR_PATH];
  214. PCTSTR fileSpec;
  215. MULTISZ_ENUM compareEnum;
  216. BOOL match;
  217. BOOL noHeader = FALSE;
  218. g_hHeap = GetProcessHeap();
  219. g_hInst = GetModuleHandle (NULL);
  220. Init();
  221. for (i = 1 ; i < argc ; i++) {
  222. if (argv[i][0] == TEXT('-') || argv[i][0] == TEXT('/')) {
  223. switch (_totlower (argv[i][1])) {
  224. case TEXT('x'):
  225. if (Mode != NONE) {
  226. HelpAndExit();
  227. }
  228. Mode = IMPLANT;
  229. break;
  230. case TEXT('d'):
  231. if (Mode != NONE) {
  232. HelpAndExit();
  233. }
  234. Mode = EXTRACT_ONE;
  235. break;
  236. case TEXT('l'):
  237. if (Mode != NONE) {
  238. HelpAndExit();
  239. }
  240. if (_totlower (argv[i][2]) == TEXT('i')) {
  241. InfOutput = TRUE;
  242. } else if (argv[i][2]) {
  243. HelpAndExit();
  244. }
  245. Mode = LIST;
  246. break;
  247. case TEXT('n'):
  248. if (noHeader) {
  249. HelpAndExit();
  250. }
  251. noHeader = TRUE;
  252. break;
  253. case TEXT('c'):
  254. if (Mode != NONE) {
  255. HelpAndExit();
  256. }
  257. Mode = COMPARE;
  258. break;
  259. case TEXT('u'):
  260. if (Mode != NONE) {
  261. HelpAndExit();
  262. }
  263. Mode = MAKE_UNIQUE;
  264. break;
  265. case TEXT('p'):
  266. if (comparePath) {
  267. HelpAndExit();
  268. }
  269. if (argv[i][2] == ':') {
  270. comparePath = &argv[i][3];
  271. } else if (i + 1 < argc) {
  272. i++;
  273. comparePath = argv[i];
  274. } else {
  275. HelpAndExit();
  276. }
  277. break;
  278. case TEXT('i'):
  279. if (argv[i][2] == ':') {
  280. IconId = &argv[i][3];
  281. } else if (i + 1 < argc) {
  282. i++;
  283. IconId= argv[i];
  284. } else {
  285. HelpAndExit();
  286. }
  287. IconIndex = _ttoi (IconId);
  288. while (_istspace ((TCHAR)_tcsnextc (IconId))) {
  289. IconId = _tcsinc (IconId);
  290. }
  291. if (*IconId) {
  292. if (!IconIndex && iscsymf(_tcsnextc (IconId))) {
  293. UseIconIndex = FALSE;
  294. }
  295. }
  296. break;
  297. case TEXT('k'):
  298. if (Mode != NONE) {
  299. HelpAndExit();
  300. }
  301. Mode = KILL;
  302. break;
  303. case TEXT('a'):
  304. if (Mode != NONE) {
  305. HelpAndExit();
  306. }
  307. Mode = EXTRACT_ALL;
  308. break;
  309. case TEXT('q'):
  310. if (Quiet) {
  311. HelpAndExit();
  312. }
  313. Quiet = TRUE;
  314. break;
  315. case TEXT('e'):
  316. if (Mode != NONE) {
  317. HelpAndExit();
  318. }
  319. if (argv[i][2] == ':') {
  320. NextNum = &argv[i][3];
  321. if (_tcsnextc (NextNum) != TEXT('-')) {
  322. Start = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10);
  323. }
  324. if (_tcsnextc (NextNum) == TEXT('-')) {
  325. NextNum = _tcsinc (NextNum);
  326. if (*NextNum) {
  327. End = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10);
  328. }
  329. } else {
  330. End = Start;
  331. }
  332. if (*NextNum) {
  333. HelpAndExit();
  334. }
  335. }
  336. Mode = EXTRACT;
  337. break;
  338. case TEXT('r'):
  339. if (RecurseMode) {
  340. HelpAndExit();
  341. }
  342. RecurseMode = TRUE;
  343. break;
  344. default:
  345. HelpAndExit();
  346. }
  347. }
  348. else {
  349. Files++;
  350. MultiSzAppend (&FileList, argv[i]);
  351. if (IconFile) {
  352. DestFile = argv[i];
  353. }
  354. else {
  355. IconFile = argv[i];
  356. }
  357. }
  358. }
  359. MultiSzAppend (&FileList, S_EMPTY);
  360. //
  361. // Enforce syntax
  362. //
  363. if (Quiet && Mode != LIST) {
  364. HelpAndExit();
  365. }
  366. if (Mode == EXTRACT_ALL && DestFile) {
  367. HelpAndExit();
  368. }
  369. if (Mode == EXTRACT_ALL || Mode == LIST) {
  370. DestFile = IconFile;
  371. }
  372. if (Mode == MAKE_UNIQUE) {
  373. if (!DestFile) {
  374. DestFile = IconFile;
  375. }
  376. }
  377. if (!DestFile) {
  378. HelpAndExit();
  379. }
  380. if (RecurseMode && Mode != EXTRACT_ALL) {
  381. HelpAndExit();
  382. }
  383. if (Files > 2 && Mode != LIST) {
  384. HelpAndExit();
  385. }
  386. if ((comparePath || noHeader) && Mode != LIST) {
  387. HelpAndExit();
  388. }
  389. if (UseIconIndex) {
  390. IconId = (PCTSTR) (WORD) IconIndex;
  391. wsprintf (IconIndexStr, TEXT("%i"), IconIndex);
  392. } else {
  393. StringCopy (IconIndexStr, IconId);
  394. }
  395. if (Mode == KILL) {
  396. fprintf (stderr, "Beginning icon processing\n");
  397. if (!BeginIconExtraction (&Context, IconFile)) {
  398. fprintf (stderr, "Can't begin icon extraction\n");
  399. return 0;
  400. }
  401. //
  402. // Get the min and max IDs
  403. //
  404. if (!pGetMinAndMax (&Context, &Min, &Max)) {
  405. fprintf (stderr, "Can't kill icons without min/max info\n");
  406. return 0;
  407. }
  408. //
  409. // Evaluate the range and remove the icons
  410. //
  411. NextNum = DestFile;
  412. Count = 0;
  413. fprintf (stderr, "Removing icons\n");
  414. for (;;) {
  415. NextNum = SkipSpace (NextNum);
  416. if (!(*NextNum)) {
  417. break;
  418. }
  419. if (_tcsnextc (NextNum) == TEXT('-')) {
  420. Start = Min;
  421. } else {
  422. Start = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10);
  423. NextNum = SkipSpace (NextNum);
  424. }
  425. if (_tcsnextc (NextNum) == TEXT('-')) {
  426. NextNum = SkipSpace (_tcsinc (NextNum));
  427. if (_tcsnextc (NextNum) == TEXT(',') || !(*NextNum)) {
  428. End = Max;
  429. } else {
  430. End = _tcstoul (NextNum, (PTSTR *) (&NextNum), 10);
  431. NextNum = SkipSpace (NextNum);
  432. }
  433. } else {
  434. End = Start;
  435. }
  436. Count += pRemoveIcons (&Context, Start, End);
  437. if (_tcsnextc (NextNum) == TEXT(',')) {
  438. NextNum = _tcsinc (NextNum);
  439. } else {
  440. break;
  441. }
  442. }
  443. fprintf (stderr, "Saving\n");
  444. if (EndIconExtraction (&Context)) {
  445. printf ("Icons removed: %u\n", Count);
  446. }
  447. return 0;
  448. }
  449. else if (Mode == IMPLANT) {
  450. //
  451. // Use IconFile as a source to generate a PE file of icons
  452. //
  453. if (!BeginIconExtraction (&Context, DestFile)) {
  454. fprintf (stderr, "Can't begin icon extraction\n");
  455. return 0;
  456. }
  457. if (!OpenIconImageFile (&Context, IconFile, FALSE)) {
  458. _ftprintf (stderr, TEXT("Can't open %s\n"), IconFile);
  459. EndIconExtraction (&Context);
  460. return 0;
  461. }
  462. Count = 0;
  463. while (CopyIcon (&Context, NULL, NULL, 0)) {
  464. Count++;
  465. }
  466. if (EndIconExtraction (&Context)) {
  467. printf ("Icons extracted: %u\n", Count);
  468. }
  469. }
  470. else if (Mode == EXTRACT || Mode == EXTRACT_ONE) {
  471. //
  472. // Use IconFile as a source to generate a PE file of icons
  473. //
  474. if (!BeginIconExtraction (&Context, NULL)) {
  475. fprintf (stderr, "Can't begin icon extraction\n");
  476. return 0;
  477. }
  478. if (!OpenIconImageFile (&Context, DestFile, TRUE)) {
  479. _ftprintf (stderr, TEXT("Can't create %s\n"), DestFile);
  480. EndIconExtraction (&Context);
  481. return 0;
  482. }
  483. if (Mode == EXTRACT) {
  484. //
  485. // If no range is specified, use the CopyAllIcons api
  486. //
  487. if (Start == 0 && End == 0xFFFF) {
  488. if (!CopyAllIcons (&Context, IconFile)) {
  489. _ftprintf (stderr, TEXT("Can't copy all icons from %s, error %u\n"), IconFile, GetLastError());
  490. } else {
  491. _tprintf (TEXT("Extracted all icons from %s\n"), IconFile);
  492. }
  493. }
  494. //
  495. // If a range is specified, get the names and copy them
  496. // if they are in the range.
  497. //
  498. else {
  499. Count = pCopyIconRange (&Context, IconFile, Start, End);
  500. _tprintf (TEXT("Icons extracted: %u\n"), Count);
  501. }
  502. } else {
  503. if (!CopyIcon (&Context, IconFile, NULL, IconIndex)) {
  504. _ftprintf (stderr, TEXT("Can't copy %s [%i], error %u\n"), IconFile, IconIndex, GetLastError());
  505. } else {
  506. _tprintf (TEXT("Extracted %s [%i]\n"), IconFile, IconIndex);
  507. }
  508. }
  509. EndIconExtraction (&Context);
  510. }
  511. else if (Mode == MAKE_UNIQUE) {
  512. pRemoveDuplicateIcons (IconFile, DestFile);
  513. }
  514. else if (Mode == LIST) {
  515. EnumFirstMultiSz (&FileListEnum, (PCTSTR) FileList.Buf);
  516. do {
  517. //
  518. // Separate the path and file pattern
  519. //
  520. FileName = GetFileNameFromPath (FileListEnum.CurrentString);
  521. if (FileName == FileListEnum.CurrentString) {
  522. RootPathPtr = TEXT(".");
  523. } else {
  524. _tcssafecpyab (
  525. RootPath,
  526. FileListEnum.CurrentString,
  527. FileName,
  528. sizeof (RootPath) / sizeof (RootPath[0])
  529. );
  530. RootPathPtr = RootPath;
  531. if (CharCount (RootPath) > 3) {
  532. RemoveWackAtEnd (RootPath);
  533. }
  534. }
  535. //
  536. // Process all files specified
  537. //
  538. if (EnumFirstFile (&FileEnum, RootPathPtr, FileName)) {
  539. do {
  540. if (FileEnum.Directory) {
  541. continue;
  542. }
  543. //
  544. // Process IconFile
  545. //
  546. IconFile = FileEnum.FullPath;
  547. IconList = ExtractIconNamesFromFile (IconFile, &Buf);
  548. Count = 0;
  549. if (comparePath) {
  550. //
  551. // Prepare a list of resources in a binary located
  552. // in an alternate path
  553. //
  554. fileSpec = GetFileNameFromPath (IconFile);
  555. StringCopy (workPath, comparePath);
  556. StringCopy (AppendWack (workPath), fileSpec);
  557. IconList2 = ExtractIconNamesFromFile (workPath, &Buf2);
  558. } else {
  559. IconList2 = IconList;
  560. }
  561. if (IconList && IconList2) {
  562. if (!InfOutput) {
  563. //
  564. // Simple output
  565. //
  566. if (EnumFirstMultiSz (&MultiSz, IconList)) {
  567. do {
  568. if (IconList != IconList2) {
  569. match = FALSE;
  570. if (EnumFirstMultiSz (&compareEnum, IconList2)) {
  571. do {
  572. if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) {
  573. match = TRUE;
  574. break;
  575. }
  576. } while (EnumNextMultiSz (&compareEnum));
  577. }
  578. if (!match) {
  579. continue;
  580. }
  581. }
  582. if (!Count) {
  583. if (IconList != IconList2) {
  584. _tprintf (TEXT("Icon resources in both %s and %s:\n\n"), IconFile, workPath);
  585. } else {
  586. _tprintf (TEXT("Icon resources in %s:\n\n"), IconFile);
  587. }
  588. }
  589. _tprintf (TEXT(" %s\n"), MultiSz.CurrentString);
  590. Count++;
  591. } while (EnumNextMultiSz (&MultiSz));
  592. if (Count) {
  593. _tprintf (TEXT("\n"));
  594. }
  595. }
  596. if (IconList != IconList2) {
  597. if (EnumFirstMultiSz (&MultiSz, IconList)) {
  598. Count = 0;
  599. do {
  600. match = FALSE;
  601. if (EnumFirstMultiSz (&compareEnum, IconList2)) {
  602. do {
  603. if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) {
  604. match = TRUE;
  605. break;
  606. }
  607. } while (EnumNextMultiSz (&compareEnum));
  608. }
  609. if (match) {
  610. continue;
  611. }
  612. if (!Count) {
  613. _tprintf (TEXT("Icon resources in only in %s:\n\n"), IconFile);
  614. }
  615. _tprintf (TEXT(" %s\n"), MultiSz.CurrentString);
  616. Count++;
  617. } while (EnumNextMultiSz (&MultiSz));
  618. if (Count) {
  619. _tprintf (TEXT("\n"));
  620. }
  621. }
  622. if (EnumFirstMultiSz (&MultiSz, IconList2)) {
  623. Count = 0;
  624. do {
  625. match = FALSE;
  626. if (EnumFirstMultiSz (&compareEnum, IconList)) {
  627. do {
  628. if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) {
  629. match = TRUE;
  630. break;
  631. }
  632. } while (EnumNextMultiSz (&compareEnum));
  633. }
  634. if (match) {
  635. continue;
  636. }
  637. if (!Count) {
  638. _tprintf (TEXT("Icon resources in only in %s:\n\n"), workPath);
  639. }
  640. _tprintf (TEXT(" %s\n"), MultiSz.CurrentString);
  641. Count++;
  642. } while (EnumNextMultiSz (&MultiSz));
  643. if (Count) {
  644. _tprintf (TEXT("\n"));
  645. }
  646. }
  647. Count = 1;
  648. }
  649. } else {
  650. //
  651. // INF output
  652. //
  653. //
  654. // Count the numeric resources
  655. //
  656. if (EnumFirstMultiSz (&MultiSz, IconList)) {
  657. do {
  658. if (IconList != IconList2) {
  659. match = FALSE;
  660. if (EnumFirstMultiSz (&compareEnum, IconList2)) {
  661. do {
  662. if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) {
  663. match = TRUE;
  664. break;
  665. }
  666. } while (EnumNextMultiSz (&compareEnum));
  667. }
  668. if (!match) {
  669. continue;
  670. }
  671. }
  672. if (_tcsnextc (MultiSz.CurrentString) == TEXT('#')) {
  673. Count++;
  674. }
  675. } while (EnumNextMultiSz (&MultiSz));
  676. }
  677. //
  678. // If at least one numeric resource, print it
  679. //
  680. if (Count) {
  681. if (NeedsHeader) {
  682. if (!noHeader) {
  683. _tprintf (TEXT("[%s]\n"), S_KNOWN_GOOD_ICON_MODULES);
  684. }
  685. NeedsHeader = FALSE;
  686. }
  687. wsprintf (Buffer, TEXT("%s="), GetFileNameFromPath (IconFile));
  688. Indent = TcharCount (Buffer);
  689. wsprintf (GetEndOfString (Buffer), TEXT("%u"), Count);
  690. Column = TcharCount (Buffer);
  691. _tprintf (TEXT("%s"), Buffer);
  692. if (EnumFirstMultiSz (&MultiSz, IconList)) {
  693. do {
  694. if (IconList != IconList2) {
  695. match = FALSE;
  696. if (EnumFirstMultiSz (&compareEnum, IconList2)) {
  697. do {
  698. if (StringMatch (MultiSz.CurrentString, compareEnum.CurrentString)) {
  699. match = TRUE;
  700. break;
  701. }
  702. } while (EnumNextMultiSz (&compareEnum));
  703. }
  704. if (!match) {
  705. continue;
  706. }
  707. }
  708. if (_tcsnextc (MultiSz.CurrentString) == TEXT('#')) {
  709. ResourceId = _ttoi (_tcsinc (MultiSz.CurrentString));
  710. //
  711. // Determine if this is a range
  712. //
  713. Range = ResourceId;
  714. EnumFirstMultiSz (&LookAhead, MultiSz.CurrentString);
  715. LastValidString = MultiSz.CurrentString;
  716. while (EnumNextMultiSz (&LookAhead)) {
  717. if (_tcsnextc (LookAhead.CurrentString) != TEXT('#')) {
  718. continue;
  719. }
  720. i = _ttoi (_tcsinc (LookAhead.CurrentString));
  721. if (Range + 1 == i) {
  722. Range = i;
  723. LastValidString = LookAhead.CurrentString;
  724. } else {
  725. break;
  726. }
  727. }
  728. //
  729. // Add separator
  730. //
  731. _tprintf (TEXT(","));
  732. Column++;
  733. if (Range > ResourceId + 1) {
  734. wsprintf (Buffer, TEXT("%u-%u"), ResourceId, Range);
  735. MultiSz.CurrentString = LastValidString;
  736. } else {
  737. wsprintf (Buffer, TEXT("%u"), ResourceId);
  738. }
  739. if (TcharCount (Buffer) + Column > 78) {
  740. _tprintf (TEXT("\\\n"));
  741. for (Column = 0 ; Column < Indent ; Column++) {
  742. _tprintf (TEXT(" "));
  743. }
  744. }
  745. Column += TcharCount (Buffer);
  746. _tprintf (TEXT("%s"), Buffer);
  747. }
  748. } while (EnumNextMultiSz (&MultiSz));
  749. }
  750. _tprintf (TEXT("\n"));
  751. }
  752. }
  753. }
  754. if (!Count && !Quiet) {
  755. _ftprintf (stderr, TEXT("No icons in %s\n"), IconFile);
  756. }
  757. if (Count) {
  758. g_ErrorLevel = 1;
  759. }
  760. } while (EnumNextFile (&FileEnum));
  761. }
  762. } while (EnumNextMultiSz (&FileListEnum));
  763. }
  764. else if (Mode == EXTRACT_ONE) {
  765. //
  766. // Extract one icon
  767. //
  768. if (ExtractIconImageFromFile (IconFile, IconId, &Buf)) {
  769. if (WriteIconImageArrayToIcoFile (DestFile, &Buf)) {
  770. _ftprintf (stderr, TEXT("Icon %s from %s written successfully to %s.\n"), IconIndexStr, IconFile, DestFile);
  771. } else {
  772. _ftprintf (stderr, TEXT("Can't write icon to %s (error %u)\n"), DestFile, GetLastError());
  773. }
  774. } else {
  775. _ftprintf (stderr, TEXT("Can't extract icon %s from %s (error %u)\n"), IconIndexStr, IconFile, GetLastError());
  776. }
  777. }
  778. else if (Mode == EXTRACT_ALL) {
  779. //
  780. // Extract default icon of every file
  781. //
  782. if (!BeginIconExtraction (&Context, DestFile)) {
  783. fprintf (stderr, "Can't begin icon extraction\n");
  784. return 0;
  785. }
  786. if (RecurseMode) {
  787. TREE_ENUM e;
  788. if (EnumFirstFileInTree (&e, TEXT("."), NULL, FALSE)) {
  789. do {
  790. if (StringIMatch (e.FullPath, DestFile)) {
  791. continue;
  792. }
  793. Icon = Context.IconId;
  794. if (!CopyAllIcons (&Context, e.FullPath)) {
  795. Error = GetLastError();
  796. if (pIsErrorOk (Error)) {
  797. _ftprintf (stderr, TEXT("Can't copy icons from %s, error %u\n"), e.FullPath, Error);
  798. break;
  799. }
  800. } else {
  801. _tprintf (TEXT("%u: %s\n"), Icon, e.FullPath);
  802. }
  803. } while (EnumNextFileInTree (&e));
  804. }
  805. } else {
  806. WIN32_FIND_DATA fd;
  807. HANDLE FindHandle;
  808. TCHAR FullPath[MAX_TCHAR_PATH];
  809. PTSTR p;
  810. GetCurrentDirectory (MAX_TCHAR_PATH, FullPath);
  811. p = AppendWack (FullPath);
  812. StringCopy (p, TEXT("*.*"));
  813. FindHandle = FindFirstFile (FullPath, &fd);
  814. if (FindHandle != INVALID_HANDLE_VALUE) {
  815. do {
  816. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  817. continue;
  818. }
  819. StringCopy (p, fd.cFileName);
  820. if (StringIMatch (FullPath, DestFile)) {
  821. continue;
  822. }
  823. Icon = Context.IconId;
  824. if (!CopyAllIcons (&Context, fd.cFileName)) {
  825. Error = GetLastError();
  826. if (pIsErrorOk (Error)) {
  827. _ftprintf (stderr, TEXT("Can't copy icons from %s, error %u\n"), fd.cFileName, Error);
  828. break;
  829. }
  830. } else {
  831. _tprintf (TEXT("%u: %s\n"), Icon, fd.cFileName);
  832. }
  833. } while (FindNextFile (FindHandle, &fd));
  834. FindClose (FindHandle);
  835. }
  836. }
  837. if (EndIconExtraction (&Context)) {
  838. printf ("Icons extracted.\n");
  839. }
  840. }
  841. else if (Mode == COMPARE) {
  842. pLaunchCompareDlg (IconFile, DestFile);
  843. }
  844. FreeGrowBuffer (&Buf);
  845. FreeGrowBuffer (&Buf2);
  846. FreeGrowBuffer (&FileList);
  847. Terminate();
  848. return g_ErrorLevel;
  849. }
  850. BOOL
  851. pSetIconInWindow (
  852. IN HWND IconWnd1,
  853. IN HWND IconWnd2,
  854. IN PCTSTR FileName1,
  855. IN PCTSTR FileName2,
  856. IN INT ResourceId
  857. )
  858. {
  859. HANDLE Instance1;
  860. HANDLE Instance2;
  861. BOOL b = FALSE;
  862. HICON Icon1 = NULL;
  863. HICON Icon2 = NULL;
  864. Instance1 = LoadLibraryEx (FileName1, NULL, LOAD_LIBRARY_AS_DATAFILE);
  865. if (Instance1) {
  866. //
  867. // Get the icon
  868. //
  869. Icon1 = LoadIcon (Instance1, MAKEINTRESOURCE (ResourceId));
  870. }
  871. Instance2 = LoadLibraryEx (FileName2, NULL, LOAD_LIBRARY_AS_DATAFILE);
  872. if (Instance2) {
  873. //
  874. // Get the icon
  875. //
  876. Icon2 = LoadIcon (Instance2, MAKEINTRESOURCE (ResourceId));
  877. }
  878. if (Icon1 && Icon2) {
  879. SendMessage (IconWnd1, STM_SETICON, (WPARAM) Icon1, 0);
  880. SendMessage (IconWnd2, STM_SETICON, (WPARAM) Icon2, 0);
  881. b = TRUE;
  882. }
  883. if (Instance1) {
  884. FreeLibrary (Instance1);
  885. }
  886. if (Instance2) {
  887. FreeLibrary (Instance2);
  888. }
  889. return b;
  890. }
  891. typedef struct {
  892. GROWBUFFER IdArray;
  893. UINT CurrentId;
  894. UINT IdCount;
  895. PCTSTR FileName1;
  896. PCTSTR FileName2;
  897. } DLGARGS, *PDLGARGS;
  898. #define WMX_UPDATE_ICONS (WM_APP+1)
  899. BOOL
  900. CALLBACK
  901. IconCompareDlgProc (
  902. HWND hdlg,
  903. UINT uMsg,
  904. WPARAM wParam,
  905. LPARAM lParam
  906. )
  907. {
  908. static PDLGARGS Args;
  909. TCHAR Number[32];
  910. INT ResourceId;
  911. switch (uMsg) {
  912. case WM_INITDIALOG:
  913. Args = (PDLGARGS) lParam;
  914. SetDlgItemText (hdlg, IDC_FILE_NAME1, Args->FileName1);
  915. SetDlgItemText (hdlg, IDC_FILE_NAME2, Args->FileName2);
  916. SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0);
  917. switch (g_ErrorLevel) {
  918. case 0:
  919. ResourceId = IDC_NO_MATCH;
  920. break;
  921. case 1:
  922. ResourceId = IDC_PARTIAL;
  923. break;
  924. case 2:
  925. ResourceId = IDC_MATCH;
  926. break;
  927. }
  928. CheckDlgButton (hdlg, ResourceId, BST_CHECKED);
  929. break;
  930. case WMX_UPDATE_ICONS:
  931. ResourceId = (INT) (*((PDWORD) Args->IdArray.Buf + Args->CurrentId));
  932. pSetIconInWindow (
  933. GetDlgItem (hdlg, IDC_ICON1),
  934. GetDlgItem (hdlg, IDC_ICON2),
  935. Args->FileName1,
  936. Args->FileName2,
  937. ResourceId
  938. );
  939. wsprintf (Number, TEXT("%i"), ResourceId);
  940. SetDlgItemText (hdlg, IDC_RESOURCE_ID, Number);
  941. break;
  942. case WM_COMMAND:
  943. switch (LOWORD(wParam)) {
  944. case IDOK:
  945. case IDCANCEL:
  946. if (IsDlgButtonChecked (hdlg, IDC_NO_MATCH) == BST_CHECKED) {
  947. g_ErrorLevel = 0;
  948. } else if (IsDlgButtonChecked (hdlg, IDC_PARTIAL) == BST_CHECKED) {
  949. g_ErrorLevel = 1;
  950. } else if (IsDlgButtonChecked (hdlg, IDC_MATCH) == BST_CHECKED) {
  951. g_ErrorLevel = 2;
  952. }
  953. EndDialog (hdlg, 0);
  954. break;
  955. case IDC_NEXT:
  956. if (Args->CurrentId < (Args->IdCount - 1)) {
  957. Args->CurrentId++;
  958. SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0);
  959. }
  960. break;
  961. case IDC_PREV:
  962. if (Args->CurrentId > 0) {
  963. Args->CurrentId--;
  964. SendMessage (hdlg, WMX_UPDATE_ICONS, 0, 0);
  965. }
  966. break;
  967. }
  968. break;
  969. }
  970. return FALSE;
  971. }
  972. VOID
  973. pLaunchCompareDlg (
  974. IN PCTSTR FileName1,
  975. IN PCTSTR FileName2
  976. )
  977. {
  978. DLGARGS Args;
  979. PCTSTR IconList1;
  980. PCTSTR IconList2;
  981. GROWBUFFER Buf1 = GROWBUF_INIT;
  982. GROWBUFFER Buf2 = GROWBUF_INIT;
  983. MULTISZ_ENUM Enum1, Enum2;
  984. BOOL Match;
  985. //
  986. // Obtain the resource ID list from both FileName1 and FileName2.
  987. // Put the union in a grow buffer.
  988. //
  989. ZeroMemory (&Args, sizeof (Args));
  990. Args.FileName1 = FileName1;
  991. Args.FileName2 = FileName2;
  992. IconList1 = ExtractIconNamesFromFile (FileName1, &Buf1);
  993. IconList2 = ExtractIconNamesFromFile (FileName2, &Buf2);
  994. if (IconList1 && IconList2) {
  995. //
  996. // Enumerate list one, then scan list two for a match
  997. //
  998. if (EnumFirstMultiSz (&Enum1, IconList1)) {
  999. do {
  1000. if (_tcsnextc (Enum1.CurrentString) != TEXT('#')) {
  1001. continue;
  1002. }
  1003. Match = FALSE;
  1004. if (EnumFirstMultiSz (&Enum2, IconList2)) {
  1005. do {
  1006. if (StringMatch (Enum1.CurrentString, Enum2.CurrentString)) {
  1007. Match = TRUE;
  1008. break;
  1009. }
  1010. } while (EnumNextMultiSz (&Enum2));
  1011. }
  1012. if (Match) {
  1013. GrowBufAppendDword (
  1014. &Args.IdArray,
  1015. (DWORD) _ttoi (_tcsinc (Enum1.CurrentString))
  1016. );
  1017. Args.IdCount++;
  1018. } else {
  1019. _ftprintf (
  1020. stderr,
  1021. TEXT("Resource ID %s is not in %s\n"),
  1022. Enum1.CurrentString,
  1023. FileName2
  1024. );
  1025. }
  1026. } while (EnumNextMultiSz (&Enum1));
  1027. }
  1028. //
  1029. // Enumerate list two, then scan list one for a match
  1030. //
  1031. if (EnumFirstMultiSz (&Enum2, IconList2)) {
  1032. do {
  1033. if (_tcsnextc (Enum2.CurrentString) != TEXT('#')) {
  1034. continue;
  1035. }
  1036. Match = FALSE;
  1037. if (EnumFirstMultiSz (&Enum1, IconList1)) {
  1038. do {
  1039. if (StringMatch (Enum1.CurrentString, Enum2.CurrentString)) {
  1040. Match = TRUE;
  1041. break;
  1042. }
  1043. } while (EnumNextMultiSz (&Enum1));
  1044. }
  1045. if (!Match) {
  1046. _ftprintf (
  1047. stderr,
  1048. TEXT("Resource ID %s is not in %s\n"),
  1049. Enum2.CurrentString,
  1050. FileName1
  1051. );
  1052. }
  1053. } while (EnumNextMultiSz (&Enum2));
  1054. }
  1055. //
  1056. // Now present the dialog
  1057. //
  1058. if (Args.IdCount) {
  1059. DialogBoxParam (
  1060. g_hInst,
  1061. MAKEINTRESOURCE(IDD_COMPARE),
  1062. NULL,
  1063. IconCompareDlgProc,
  1064. (LPARAM) &Args
  1065. );
  1066. } else {
  1067. _ftprintf (stderr, TEXT("No common icon resources found.\n"));
  1068. }
  1069. } else {
  1070. if (!IconList1) {
  1071. _ftprintf (stderr, TEXT("Can't get icon list from %s\n"), FileName1);
  1072. }
  1073. if (!IconList2) {
  1074. _ftprintf (stderr, TEXT("Can't get icon list from %s\n"), FileName2);
  1075. }
  1076. }
  1077. FreeGrowBuffer (&Buf1);
  1078. FreeGrowBuffer (&Buf2);
  1079. }
  1080. BOOL
  1081. pCompareIconImages (
  1082. IN PCTSTR SourceFile,
  1083. IN PCTSTR Name1,
  1084. IN PCTSTR Name2
  1085. )
  1086. {
  1087. GROWBUFFER SrcBuf = GROWBUF_INIT;
  1088. GROWBUFFER DestBuf = GROWBUF_INIT;
  1089. BOOL b;
  1090. b = ExtractIconImageFromFile (SourceFile, Name1, &SrcBuf);
  1091. if (b) {
  1092. b = ExtractIconImageFromFile (SourceFile, Name2, &DestBuf);
  1093. }
  1094. if (b) {
  1095. if (SrcBuf.End != DestBuf.End) {
  1096. b = FALSE;
  1097. } else {
  1098. b = (memcmp (SrcBuf.Buf, DestBuf.Buf, SrcBuf.End) == 0);
  1099. }
  1100. }
  1101. FreeGrowBuffer (&SrcBuf);
  1102. FreeGrowBuffer (&DestBuf);
  1103. return b;
  1104. }
  1105. BOOL
  1106. pMakeNameIndex (
  1107. IN PCTSTR SourceFile,
  1108. OUT PGROWBUFFER IndexBuf,
  1109. OUT PGROWBUFFER IndexArray
  1110. )
  1111. {
  1112. PCTSTR IconList;
  1113. MULTISZ_ENUM e;
  1114. IndexBuf->End = 0;
  1115. IndexArray->End = 0;
  1116. IconList = ExtractIconNamesFromFile (SourceFile, IndexBuf);
  1117. if (IconList) {
  1118. //
  1119. // Build an index array
  1120. //
  1121. if (EnumFirstMultiSz (&e, IconList)) {
  1122. do {
  1123. if (_tcsnextc (e.CurrentString) != TEXT('#')) {
  1124. //
  1125. // This is a named string
  1126. //
  1127. GrowBufAppendDword (IndexArray, (DWORD) e.CurrentString);
  1128. } else {
  1129. //
  1130. // This is a 16-bit ID
  1131. //
  1132. GrowBufAppendDword (IndexArray, (DWORD) _ttoi (_tcsinc (e.CurrentString)));
  1133. }
  1134. } while (EnumNextMultiSz (&e));
  1135. }
  1136. } else {
  1137. _ftprintf (stderr, TEXT("No icons found in %s\n"), SourceFile);
  1138. }
  1139. return IndexArray->End != 0;
  1140. }
  1141. #define BLANK_ID 0xFFFFFFFF
  1142. BOOL
  1143. pFindUniqueIcons (
  1144. IN PCTSTR SourceFile,
  1145. OUT PGROWBUFFER WorkBuffer,
  1146. OUT PGROWBUFFER UniqueIndexArray,
  1147. OUT PUINT OriginalMax
  1148. )
  1149. {
  1150. GROWBUFFER IndexArray = GROWBUF_INIT;
  1151. BOOL b;
  1152. UINT i, j;
  1153. UINT Count;
  1154. PDWORD IdPtr;
  1155. UniqueIndexArray->End = 0;
  1156. b = pMakeNameIndex (SourceFile, WorkBuffer, &IndexArray);
  1157. if (b) {
  1158. *OriginalMax = 0;
  1159. Count = IndexArray.End / sizeof (DWORD);
  1160. IdPtr = (PDWORD) IndexArray.Buf;
  1161. for (i = 0 ; i < Count ; i++) {
  1162. if (IdPtr[i] == BLANK_ID) {
  1163. continue;
  1164. }
  1165. if (IdPtr[i] < 0x10000) {
  1166. _ftprintf (stderr, TEXT("Processing ID %u\n"), IdPtr[i]);
  1167. if (IdPtr[i] > *OriginalMax) {
  1168. *OriginalMax = IdPtr[i];
  1169. }
  1170. } else {
  1171. _ftprintf (stderr, TEXT("Processing ID %s\n"), IdPtr[i]);
  1172. }
  1173. for (j = i + 1 ; j < Count ; j++) {
  1174. if (IdPtr[j] == BLANK_ID) {
  1175. continue;
  1176. }
  1177. if (pCompareIconImages (SourceFile, (PCTSTR) (IdPtr[i]), (PCTSTR) (IdPtr[j]))) {
  1178. IdPtr[j] = BLANK_ID;
  1179. }
  1180. }
  1181. }
  1182. for (i = 0 ; i < Count ; i++) {
  1183. if (IdPtr[i] != BLANK_ID) {
  1184. GrowBufAppendDword (UniqueIndexArray, IdPtr[i]);
  1185. }
  1186. }
  1187. }
  1188. FreeGrowBuffer (&IndexArray);
  1189. return b;
  1190. }
  1191. UINT
  1192. pRemoveIcons (
  1193. IN PICON_EXTRACT_CONTEXT Context,
  1194. IN UINT Start,
  1195. IN UINT End
  1196. )
  1197. {
  1198. UINT Count = 0;
  1199. GROWBUFFER Names = GROWBUF_INIT;
  1200. PCTSTR IconList;
  1201. MULTISZ_ENUM e;
  1202. UINT id;
  1203. if (Start > End) {
  1204. return 0;
  1205. }
  1206. if (Start == End) {
  1207. _ftprintf (stderr, TEXT("Removing icon %u\n"), Start);
  1208. } else {
  1209. _ftprintf (stderr, TEXT("Removing icon range %u through %u\n"), Start, End);
  1210. }
  1211. pOpenIconImage (Context, Context->DestFile, NULL, NULL);
  1212. IconList = ExtractIconNamesFromFileEx (
  1213. Context->ModuleName,
  1214. &Names,
  1215. Context->Module,
  1216. Context->Module16
  1217. );
  1218. if (IconList) {
  1219. if (EnumFirstMultiSz (&e, IconList)) {
  1220. do {
  1221. if (_tcsnextc (e.CurrentString) == TEXT('#')) {
  1222. id = (DWORD) _ttoi (_tcsinc (e.CurrentString));
  1223. if (id >= Start && id <= End) {
  1224. if (UpdateResource (
  1225. Context->Update,
  1226. RT_ICON,
  1227. MAKEINTRESOURCE(id),
  1228. MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
  1229. NULL,
  1230. 0
  1231. )) {
  1232. Count++;
  1233. } else {
  1234. _ftprintf (stderr, TEXT("Can't remove icon ID %u; rc=%u\n"), id, GetLastError());
  1235. }
  1236. }
  1237. }
  1238. } while (EnumNextMultiSz (&e));
  1239. }
  1240. } else {
  1241. _ftprintf (stderr, TEXT("Can't get icon names; rc=%u\n"), GetLastError());
  1242. }
  1243. FreeGrowBuffer (&Names);
  1244. return Count;
  1245. }
  1246. BOOL
  1247. pRemoveDuplicateIcons (
  1248. IN PCTSTR SourcePeFile,
  1249. IN PCTSTR DestPeFile
  1250. )
  1251. {
  1252. GROWBUFFER WorkBuffer = GROWBUF_INIT;
  1253. GROWBUFFER UniqueIndexArray = GROWBUF_INIT;
  1254. ICON_EXTRACT_CONTEXT Context;
  1255. UINT Count = 0;
  1256. UINT u;
  1257. PDWORD IconId;
  1258. BOOL b;
  1259. UINT OriginalMax;
  1260. _ftprintf (stderr, TEXT("Finding unique icons\n"));
  1261. b = pFindUniqueIcons (SourcePeFile, &WorkBuffer, &UniqueIndexArray, &OriginalMax);
  1262. if (b) {
  1263. b = BeginIconExtraction (&Context, DestPeFile);
  1264. if (!b) {
  1265. _ftprintf (stderr, TEXT("Can't save icons to %s\n"), DestPeFile);
  1266. }
  1267. }
  1268. if (b) {
  1269. _ftprintf (stderr, TEXT("Updating icon resources\n"));
  1270. Count = UniqueIndexArray.End / sizeof (DWORD);
  1271. IconId = (PDWORD) UniqueIndexArray.Buf;
  1272. for (u = 0 ; u < Count ; u++) {
  1273. b = CopyIcon (&Context, SourcePeFile, (PCTSTR) (IconId[u]), 0);
  1274. if (!b) {
  1275. if (IconId[u] < 0x10000) {
  1276. _ftprintf (stderr, TEXT("Can't copy icon %u\n"), IconId[u]);
  1277. } else {
  1278. _ftprintf (stderr, TEXT("Can't copy icon %s\n"), IconId[u]);
  1279. }
  1280. break;
  1281. }
  1282. }
  1283. }
  1284. if (b) {
  1285. pRemoveIcons (&Context, Count + 1, OriginalMax);
  1286. b = EndIconExtraction (&Context);
  1287. if (!b) {
  1288. _ftprintf (stderr, TEXT("Can't safe icons\n"));
  1289. }
  1290. }
  1291. if (b) {
  1292. _ftprintf (stderr, TEXT("Final icon count: %u\n"), Count);
  1293. }
  1294. FreeGrowBuffer (&WorkBuffer);
  1295. FreeGrowBuffer (&UniqueIndexArray);
  1296. return b;
  1297. }
  1298. BOOL
  1299. pGetMinAndMax (
  1300. IN PICON_EXTRACT_CONTEXT Context,
  1301. OUT PUINT Min,
  1302. OUT PUINT Max
  1303. )
  1304. {
  1305. BOOL b = FALSE;
  1306. GROWBUFFER Names = GROWBUF_INIT;
  1307. PCTSTR IconList;
  1308. UINT id;
  1309. MULTISZ_ENUM e;
  1310. *Min = (UINT) -1;
  1311. *Max = 0;
  1312. pOpenIconImage (Context, Context->DestFile, NULL, NULL);
  1313. _ftprintf (stderr, TEXT("Getting min/max icon indexes from %s\n"), Context->ModuleName);
  1314. IconList = ExtractIconNamesFromFileEx (
  1315. Context->ModuleName,
  1316. &Names,
  1317. Context->Module,
  1318. Context->Module16
  1319. );
  1320. if (IconList) {
  1321. if (EnumFirstMultiSz (&e, IconList)) {
  1322. do {
  1323. if (_tcsnextc (e.CurrentString) == TEXT('#')) {
  1324. id = (DWORD) _ttoi (_tcsinc (e.CurrentString));
  1325. if (id < *Min) {
  1326. *Min = id;
  1327. }
  1328. if (id > *Max) {
  1329. *Max = id;
  1330. }
  1331. }
  1332. } while (EnumNextMultiSz (&e));
  1333. }
  1334. b = TRUE;
  1335. }
  1336. FreeGrowBuffer (&Names);
  1337. if (b) {
  1338. _ftprintf (stderr, TEXT("Min: %u Max: %u\n"), *Min, *Max);
  1339. } else {
  1340. _ftprintf (stderr, TEXT("Can't get min/max info, rc=%u\n"), GetLastError());
  1341. }
  1342. return b;
  1343. }
  1344. UINT
  1345. pCopyIconRange (
  1346. IN PICON_EXTRACT_CONTEXT Context,
  1347. IN PCTSTR IconFile,
  1348. IN UINT Start,
  1349. IN UINT End
  1350. )
  1351. {
  1352. UINT Count = 0;
  1353. GROWBUFFER Names = GROWBUF_INIT;
  1354. PCTSTR IconList;
  1355. UINT id;
  1356. MULTISZ_ENUM e;
  1357. pOpenIconImage (Context, IconFile, NULL, NULL);
  1358. if (Start == End) {
  1359. _ftprintf (
  1360. stderr,
  1361. TEXT("Copying icon %u from %s to %s\n"),
  1362. Start,
  1363. Context->ModuleName,
  1364. Context->IconImageFileName
  1365. );
  1366. } else {
  1367. _ftprintf (
  1368. stderr,
  1369. TEXT("Copying icon range %u to %u from %s to %s\n"),
  1370. Start,
  1371. End,
  1372. Context->ModuleName,
  1373. Context->IconImageFileName
  1374. );
  1375. }
  1376. IconList = ExtractIconNamesFromFileEx (
  1377. Context->ModuleName,
  1378. &Names,
  1379. Context->Module,
  1380. Context->Module16
  1381. );
  1382. if (IconList) {
  1383. if (EnumFirstMultiSz (&e, IconList)) {
  1384. do {
  1385. if (_tcsnextc (e.CurrentString) == TEXT('#')) {
  1386. id = (DWORD) _ttoi (_tcsinc (e.CurrentString));
  1387. if (id >= Start && id <= End) {
  1388. if (!CopyIcon (Context, IconFile, e.CurrentString, 0)) {
  1389. _ftprintf (stderr, TEXT("Can't copy %s [%i], error %u\n"), IconFile, id, GetLastError());
  1390. } else {
  1391. Count++;
  1392. }
  1393. }
  1394. }
  1395. } while (EnumNextMultiSz (&e));
  1396. }
  1397. } else {
  1398. _ftprintf (stderr, TEXT("Can't get icon names from %s\n"), Context->ModuleName);
  1399. }
  1400. FreeGrowBuffer (&Names);
  1401. return Count;
  1402. }