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.

2461 lines
54 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. icons.c
  5. Abstract:
  6. Icon extraction and manipulation routines
  7. Author:
  8. Jim Schmidt (jimschm) 04-May-1998
  9. Revision History:
  10. jimschm 23-Sep-1998 String icon ID bug fixes, error path bug fixes
  11. --*/
  12. #include "pch.h"
  13. #include "migutilp.h"
  14. #define MAX_RESOLUTIONS 32 // 8 sizes times 4 color palettes
  15. #pragma pack(push)
  16. #pragma pack(2)
  17. typedef struct {
  18. BYTE Width; // Width, in pixels, of the image
  19. BYTE Height; // Height, in pixels, of the image
  20. BYTE ColorCount; // Number of colors in image (0 if >=8bpp)
  21. BYTE Reserved; // Reserved ( must be 0)
  22. WORD Planes; // Color Planes
  23. WORD BitCount; // Bits per pixel
  24. DWORD BytesInRes; // How many bytes in this resource?
  25. DWORD ImageOffset; // Where in the file is this image?
  26. } ICONDIRENTRY, *PICONDIRENTRY;
  27. typedef struct {
  28. WORD Reserved; // Reserved (must be 0)
  29. WORD Type; // Resource Type (1 for icons)
  30. WORD Count; // How many images?
  31. ICONDIRENTRY Entries[1]; // An entry for each image (idCount of 'em)
  32. } ICONDIR, *PICONDIR;
  33. typedef struct {
  34. BYTE Width; // Width, in pixels, of the image
  35. BYTE Height; // Height, in pixels, of the image
  36. BYTE ColorCount; // Number of colors in image (0 if >=8bpp)
  37. BYTE Reserved; // Reserved
  38. WORD Planes; // Color Planes
  39. WORD BitCount; // Bits per pixel
  40. DWORD BytesInRes; // how many bytes in this resource?
  41. WORD ID; // the ID
  42. } GRPICONDIRENTRY, *PGRPICONDIRENTRY;
  43. typedef struct {
  44. WORD Reserved; // Reserved (must be 0)
  45. WORD Type; // Resource type (1 for icons)
  46. WORD Count; // How many images?
  47. GRPICONDIRENTRY Entries[1]; // The entries for each image
  48. } GRPICONDIR, *PGRPICONDIR;
  49. typedef struct {
  50. WORD Reserved; // Reserved (must be 0)
  51. WORD Type; // Resource type (1 for icons)
  52. WORD Count; // How many images?
  53. } GRPICONDIRBASE, *PGRPICONDIRBASE;
  54. #pragma pack( pop )
  55. #define PICONIMAGE PBYTE
  56. BOOL
  57. ReadBinaryBlock (
  58. HANDLE File,
  59. PVOID Buffer,
  60. UINT Size
  61. )
  62. {
  63. DWORD BytesRead;
  64. if (!ReadFile (File, Buffer, Size, &BytesRead, NULL)) {
  65. return FALSE;
  66. }
  67. return Size == BytesRead;
  68. }
  69. BOOL
  70. pWriteBinaryBlock (
  71. HANDLE File,
  72. PVOID Buffer,
  73. UINT Size
  74. )
  75. {
  76. DWORD BytesWritten;
  77. if (!WriteFile (File, Buffer, Size, &BytesWritten, NULL)) {
  78. return FALSE;
  79. }
  80. return Size == BytesWritten;
  81. }
  82. UINT
  83. Power (
  84. UINT x,
  85. UINT e
  86. )
  87. {
  88. UINT r;
  89. r = 1;
  90. while (e > 0) {
  91. r = r * x;
  92. e--;
  93. }
  94. return r;
  95. }
  96. UINT
  97. pComputeSizeOfIconImage (
  98. IN PICONIMAGE IconImage
  99. )
  100. {
  101. PBITMAPINFOHEADER Header;
  102. UINT Size;
  103. UINT Bits;
  104. UINT Colors;
  105. UINT BytesInImage;
  106. Header = (PBITMAPINFOHEADER) IconImage;
  107. Size = Header->biSize;
  108. Bits = Header->biBitCount * Header->biPlanes;
  109. if (Bits > 32) {
  110. Bits = 4;
  111. }
  112. Colors = Power (2, Bits);
  113. if (Bits < 24) {
  114. Size += Colors * sizeof (RGBQUAD);
  115. }
  116. BytesInImage = (Header->biWidth + 7) / 8 * (Header->biHeight / 2);
  117. Size += BytesInImage * Bits; // XOR mask
  118. //
  119. // The following computation is very strange, but it was added based on
  120. // test comparisons.
  121. //
  122. if (Header->biWidth == 32) {
  123. Size += BytesInImage; // AND mask
  124. } else {
  125. Size += BytesInImage + Header->biHeight; // AND mask plus who knows what
  126. }
  127. MYASSERT (Size);
  128. return Size;
  129. }
  130. BOOL
  131. pAddIconImagesToGrowBuffer (
  132. IN OUT PGROWBUFFER Buffer,
  133. IN HANDLE File,
  134. IN PICONDIRENTRY IconDirEntryBase,
  135. IN WORD Count,
  136. IN DWORD Pos,
  137. IN DWORD Size
  138. )
  139. {
  140. WORD w;
  141. PICONDIRENTRY IconDirEntry;
  142. PBYTE Dest;
  143. DWORD Offset;
  144. for (w = 0 ; w < Count ; w++) {
  145. IconDirEntry = &IconDirEntryBase[w];
  146. Offset = IconDirEntry->ImageOffset & 0x0fffffff;
  147. if (Offset < Pos || Offset >= Size) {
  148. return FALSE;
  149. }
  150. SetFilePointer (File, Offset, NULL, FILE_BEGIN);
  151. Dest = GrowBuffer (Buffer, IconDirEntry->BytesInRes);
  152. if (!Dest) {
  153. return FALSE;
  154. }
  155. if (!ReadBinaryBlock (File, Dest, IconDirEntry->BytesInRes)) {
  156. return FALSE;
  157. }
  158. if (IconDirEntry->BytesInRes != pComputeSizeOfIconImage (Dest)) {
  159. return FALSE;
  160. }
  161. }
  162. return TRUE;
  163. }
  164. BOOL
  165. pGetIconImageArrayFromIcoFileExW (
  166. IN PCWSTR ModuleContainingIcon,
  167. IN OUT PGROWBUFFER Buffer,
  168. IN HANDLE File
  169. )
  170. {
  171. BOOL b = FALSE;
  172. ICONDIR IconDir;
  173. PICONDIRENTRY IconDirEntryBase = NULL;
  174. DWORD Size;
  175. DWORD Pos;
  176. UINT IconDirEntrySize;
  177. Size = GetFileSize (File, NULL);
  178. SetFilePointer (File, 0, NULL, FILE_BEGIN);
  179. Buffer->End = 0;
  180. __try {
  181. if (!ReadBinaryBlock (File, &IconDir, sizeof (WORD) * 3)) {
  182. __leave;
  183. }
  184. IconDirEntrySize = (UINT) IconDir.Count * sizeof (ICONDIRENTRY);
  185. if (IconDirEntrySize > (UINT) Size) {
  186. __leave;
  187. }
  188. IconDirEntryBase = (PICONDIRENTRY) MemAlloc (g_hHeap, 0, IconDirEntrySize);
  189. if (!IconDirEntryBase) {
  190. __leave;
  191. }
  192. if (!ReadBinaryBlock (File, IconDirEntryBase, IconDirEntrySize)) {
  193. __leave;
  194. }
  195. Pos = SetFilePointer (File, 0, NULL, FILE_CURRENT);
  196. if (!pAddIconImagesToGrowBuffer (Buffer, File, IconDirEntryBase, IconDir.Count, Pos, Size)) {
  197. DEBUGMSG ((DBG_WARNING, "Icon file %ls has a bogus offset", ModuleContainingIcon));
  198. __leave;
  199. }
  200. b = TRUE;
  201. }
  202. __finally {
  203. if (IconDirEntryBase) {
  204. MemFree (g_hHeap, 0, IconDirEntryBase);
  205. }
  206. }
  207. return b;
  208. }
  209. BOOL
  210. pGetIconImageArrayFromIcoFileExA (
  211. IN PCSTR ModuleContainingIcon,
  212. IN OUT PGROWBUFFER Buffer,
  213. IN HANDLE File
  214. )
  215. {
  216. PCWSTR UnicodeFileName;
  217. BOOL b;
  218. UnicodeFileName = ConvertAtoW (ModuleContainingIcon);
  219. if (!UnicodeFileName) {
  220. return FALSE;
  221. }
  222. b = pGetIconImageArrayFromIcoFileExW (UnicodeFileName, Buffer, File);
  223. PushError();
  224. FreeConvertedStr (UnicodeFileName);
  225. PopError();
  226. return b;
  227. }
  228. BOOL
  229. pGetIconImageArrayFromIcoFileW (
  230. IN PCWSTR ModuleContainingIcon,
  231. IN OUT PGROWBUFFER Buffer
  232. )
  233. {
  234. HANDLE File;
  235. BOOL b = FALSE;
  236. File = CreateFileW (ModuleContainingIcon, GENERIC_READ, 0, NULL,
  237. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  238. if (File == INVALID_HANDLE_VALUE) {
  239. DEBUGMSG ((DBG_WARNING, "%ls could not be opened", ModuleContainingIcon));
  240. return FALSE;
  241. }
  242. __try {
  243. b = pGetIconImageArrayFromIcoFileExW (ModuleContainingIcon, Buffer, File);
  244. }
  245. __finally {
  246. CloseHandle (File);
  247. }
  248. return b;
  249. }
  250. BOOL
  251. pGetIconImageArrayFromIcoFileA (
  252. IN PCSTR ModuleContainingIcon,
  253. IN OUT PGROWBUFFER Buffer
  254. )
  255. {
  256. PCWSTR UnicodeFileName;
  257. BOOL b;
  258. UnicodeFileName = ConvertAtoW (ModuleContainingIcon);
  259. if (!UnicodeFileName) {
  260. return FALSE;
  261. }
  262. b = pGetIconImageArrayFromIcoFileW (UnicodeFileName, Buffer);
  263. PushError();
  264. FreeConvertedStr (UnicodeFileName);
  265. PopError();
  266. return b;
  267. }
  268. BOOL
  269. pGetIconImageArrayFromBinaryExW (
  270. IN PCWSTR ModuleContainingIcon,
  271. IN PCWSTR GroupIconId,
  272. IN OUT PGROWBUFFER Buffer,
  273. IN HANDLE Library,
  274. IN HANDLE Library16
  275. )
  276. {
  277. HRSRC ResourceHandle;
  278. HGLOBAL ResourceBlock;
  279. PBYTE ResourceData;
  280. DWORD ResourceSize;
  281. PBYTE Dest;
  282. BOOL b = FALSE;
  283. PGRPICONDIR GroupIconDir;
  284. WORD w;
  285. if (!GroupIconId) {
  286. return FALSE;
  287. }
  288. __try {
  289. Buffer->End = 0;
  290. if (Library) {
  291. //
  292. // Get icon from PE file
  293. //
  294. ResourceHandle = FindResourceW (Library, GroupIconId, (PCWSTR) RT_GROUP_ICON);
  295. if (!ResourceHandle) {
  296. __leave;
  297. }
  298. ResourceBlock = LoadResource (Library, ResourceHandle);
  299. if (!ResourceBlock) {
  300. __leave;
  301. }
  302. GroupIconDir = (PGRPICONDIR) LockResource (ResourceBlock);
  303. if (!GroupIconDir) {
  304. __leave;
  305. }
  306. if (GroupIconDir->Type != 1) {
  307. DEBUGMSGW_IF ((
  308. (UINT_PTR) GroupIconId < 0x10000,
  309. DBG_ERROR,
  310. "icon type for resource %u is not 1 in %s",
  311. GroupIconId,
  312. ModuleContainingIcon
  313. ));
  314. DEBUGMSGW_IF ((
  315. (UINT_PTR) GroupIconId >= 0x10000,
  316. DBG_ERROR,
  317. "icon type for resource %s is not 1 in %s",
  318. GroupIconId,
  319. ModuleContainingIcon
  320. ));
  321. __leave;
  322. }
  323. if (GroupIconDir->Count > MAX_RESOLUTIONS) {
  324. DEBUGMSGW ((DBG_ERROR, "%u resolutions found in %s", GroupIconDir->Count, ModuleContainingIcon));
  325. __leave;
  326. }
  327. //
  328. // Add the ICONIMAGE array to the grow buffer
  329. //
  330. for (w = 0 ; w < GroupIconDir->Count ; w++) {
  331. ResourceHandle = FindResourceW (
  332. Library,
  333. (PCWSTR) (GroupIconDir->Entries[w].ID),
  334. (PCWSTR) RT_ICON
  335. );
  336. if (ResourceHandle) {
  337. ResourceBlock = LoadResource (Library, ResourceHandle);
  338. if (!ResourceBlock) {
  339. continue;
  340. }
  341. ResourceData = (PBYTE) LockResource (ResourceBlock);
  342. if (!ResourceData) {
  343. continue;
  344. }
  345. ResourceSize = pComputeSizeOfIconImage ((PICONIMAGE) ResourceData);
  346. if (!ResourceSize) {
  347. DEBUGMSG ((DBG_WARNING, "Zero-length icon in %s", ModuleContainingIcon));
  348. continue;
  349. }
  350. if (ResourceSize > 0x10000) {
  351. // too big for an icon
  352. __leave;
  353. }
  354. Dest = GrowBuffer (Buffer, ResourceSize);
  355. if (!Dest) {
  356. __leave;
  357. }
  358. CopyMemory (Dest, ResourceData, ResourceSize);
  359. }
  360. ELSE_DEBUGMSG ((DBG_WARNING, "Indexed icon could not be loaded from resource"));
  361. }
  362. }
  363. else if (Library16) {
  364. //
  365. // Get icon from NE file
  366. //
  367. GroupIconDir = (PGRPICONDIR) FindNeResourceExW (Library16, (PCWSTR) RT_GROUP_ICON, GroupIconId);
  368. if (!GroupIconDir) {
  369. DEBUGMSG ((DBG_WHOOPS, "NE group icon %u not found", GroupIconId));
  370. __leave;
  371. }
  372. DEBUGMSG_IF ((GroupIconDir->Count > MAX_RESOLUTIONS, DBG_WHOOPS, "%u resolutions found in %hs", GroupIconDir->Count, ModuleContainingIcon));
  373. //
  374. // Add the ICONIMAGE array to the grow buffer
  375. //
  376. for (w = 0 ; w < GroupIconDir->Count ; w++) {
  377. ResourceData = FindNeResourceExA (
  378. Library16,
  379. (PCSTR) RT_ICON,
  380. (PCSTR) GroupIconDir->Entries[w].ID
  381. );
  382. if (!ResourceData) {
  383. DEBUGMSG ((DBG_WHOOPS, "NE Icon ID %u not found", GroupIconDir->Entries[w].ID));
  384. __leave;
  385. }
  386. ResourceSize = pComputeSizeOfIconImage ((PICONIMAGE) ResourceData);
  387. if (!ResourceSize) {
  388. DEBUGMSG ((DBG_WARNING, "Zero-length icon in %s", ModuleContainingIcon));
  389. continue;
  390. }
  391. if (ResourceSize > 0x10000) {
  392. // too big for an icon
  393. __leave;
  394. }
  395. Dest = GrowBuffer (Buffer, ResourceSize);
  396. if (!Dest) {
  397. __leave;
  398. }
  399. CopyMemory (Dest, ResourceData, ResourceSize);
  400. }
  401. }
  402. b = TRUE;
  403. }
  404. __finally {
  405. // empty
  406. }
  407. return b;
  408. }
  409. BOOL
  410. pGenerateUnicodeArgs (
  411. IN PCSTR ModuleContainingIcon, OPTIONAL
  412. IN PCSTR GroupIconId, OPTIONAL
  413. OUT PCWSTR *UnicodeFileName, OPTIONAL
  414. OUT PCWSTR *UnicodeGroupIconId OPTIONAL
  415. )
  416. {
  417. if (UnicodeFileName) {
  418. if (ModuleContainingIcon) {
  419. *UnicodeFileName = ConvertAtoW (ModuleContainingIcon);
  420. if (!(*UnicodeFileName)) {
  421. return FALSE;
  422. }
  423. } else {
  424. *UnicodeFileName = NULL;
  425. }
  426. }
  427. if (UnicodeGroupIconId) {
  428. if (GroupIconId) {
  429. if ((DWORD) GroupIconId & 0xffff0000) {
  430. *UnicodeGroupIconId = ConvertAtoW (GroupIconId);
  431. if (!(*UnicodeGroupIconId)) {
  432. if (UnicodeFileName && *UnicodeFileName) {
  433. FreeConvertedStr (*UnicodeFileName);
  434. }
  435. return FALSE;
  436. }
  437. } else {
  438. *UnicodeGroupIconId = (PCWSTR) GroupIconId;
  439. }
  440. } else {
  441. *UnicodeGroupIconId = NULL;
  442. }
  443. }
  444. return TRUE;
  445. }
  446. VOID
  447. DestroyAnsiResourceId (
  448. IN PCSTR AnsiId
  449. )
  450. {
  451. if (HIWORD (AnsiId)) {
  452. FreeConvertedStr (AnsiId);
  453. }
  454. }
  455. VOID
  456. DestroyUnicodeResourceId (
  457. IN PCWSTR UnicodeId
  458. )
  459. {
  460. if (HIWORD (UnicodeId)) {
  461. FreeConvertedStr (UnicodeId);
  462. }
  463. }
  464. BOOL
  465. pGetIconImageArrayFromBinaryExA (
  466. IN PCSTR ModuleContainingIcon,
  467. IN PCSTR GroupIconId,
  468. IN OUT PGROWBUFFER Buffer,
  469. IN HANDLE Library,
  470. IN HANDLE Library16
  471. )
  472. {
  473. PCWSTR UnicodeFileName;
  474. PCWSTR UnicodeGroupIconId;
  475. BOOL b;
  476. if (!pGenerateUnicodeArgs (
  477. ModuleContainingIcon,
  478. GroupIconId,
  479. &UnicodeFileName,
  480. &UnicodeGroupIconId
  481. )) {
  482. return FALSE;
  483. }
  484. b = pGetIconImageArrayFromBinaryExW (UnicodeFileName, UnicodeGroupIconId, Buffer, Library, Library16);
  485. PushError();
  486. FreeConvertedStr (UnicodeFileName);
  487. DestroyUnicodeResourceId (UnicodeGroupIconId);
  488. PopError();
  489. return b;
  490. }
  491. BOOL
  492. pGetIconImageArrayFromBinaryW (
  493. IN PCWSTR ModuleContainingIcon,
  494. IN PCWSTR GroupIconId,
  495. IN OUT PGROWBUFFER Buffer
  496. )
  497. {
  498. HANDLE Library;
  499. HANDLE Library16 = NULL;
  500. BOOL b = FALSE;
  501. Library = LoadLibraryExW (ModuleContainingIcon, NULL, LOAD_LIBRARY_AS_DATAFILE);
  502. __try {
  503. if (!Library) {
  504. Library16 = OpenNeFileW (ModuleContainingIcon);
  505. if (!Library16) {
  506. return FALSE;
  507. }
  508. }
  509. b = pGetIconImageArrayFromBinaryExW (ModuleContainingIcon, GroupIconId, Buffer, Library, Library16);
  510. }
  511. __finally {
  512. if (Library) {
  513. FreeLibrary (Library);
  514. }
  515. if (Library16) {
  516. CloseNeFile (Library16);
  517. }
  518. }
  519. return b;
  520. }
  521. BOOL
  522. pGetIconImageArrayFromBinaryA (
  523. IN PCSTR ModuleContainingIcon,
  524. IN PCSTR GroupIconId,
  525. IN OUT PGROWBUFFER Buffer
  526. )
  527. {
  528. HANDLE Library;
  529. HANDLE Library16 = NULL;
  530. BOOL b = FALSE;
  531. Library = LoadLibraryExA (ModuleContainingIcon, NULL, LOAD_LIBRARY_AS_DATAFILE);
  532. __try {
  533. if (!Library) {
  534. Library16 = OpenNeFileA (ModuleContainingIcon);
  535. if (!Library16) {
  536. return FALSE;
  537. }
  538. }
  539. b = pGetIconImageArrayFromBinaryExA (ModuleContainingIcon, GroupIconId, Buffer, Library, Library16);
  540. }
  541. __finally {
  542. if (Library) {
  543. FreeLibrary (Library);
  544. }
  545. if (Library16) {
  546. CloseNeFile (Library16);
  547. }
  548. }
  549. return b;
  550. }
  551. BOOL
  552. WriteIconImageArrayToIcoFileEx (
  553. IN PGROWBUFFER Buffer,
  554. IN HANDLE File
  555. )
  556. {
  557. WORD w;
  558. BOOL b = FALSE;
  559. PICONIMAGE IconImage, IconImageEnd;
  560. PICONIMAGE p;
  561. INT ImageCount;
  562. ICONDIRENTRY Entry;
  563. PBITMAPINFOHEADER Header;
  564. UINT ColorCount;
  565. DWORD Offset;
  566. if (!Buffer->End) {
  567. return FALSE;
  568. }
  569. __try {
  570. SetFilePointer (File, 0, NULL, FILE_BEGIN);
  571. //
  572. // Count the images
  573. //
  574. IconImage = (PICONIMAGE) Buffer->Buf;
  575. IconImageEnd = (PICONIMAGE) (Buffer->Buf + Buffer->End);
  576. p = IconImage;
  577. ImageCount = 0;
  578. while (p < IconImageEnd) {
  579. ImageCount++;
  580. p = (PICONIMAGE) ((PBYTE) p + pComputeSizeOfIconImage (p));
  581. }
  582. //
  583. // Write the icon header
  584. //
  585. w = 0; // reserved
  586. if (!pWriteBinaryBlock (File, &w, sizeof (WORD))) {
  587. __leave;
  588. }
  589. w = 1; // type (1 == icon)
  590. if (!pWriteBinaryBlock (File, &w, sizeof (WORD))) {
  591. __leave;
  592. }
  593. w = (WORD) ImageCount;
  594. if (!pWriteBinaryBlock (File, &w, sizeof (WORD))) {
  595. __leave;
  596. }
  597. //
  598. // For each icon image, write the directory entry
  599. //
  600. p = IconImage;
  601. Offset = 0;
  602. while (p < IconImageEnd) {
  603. ZeroMemory (&Entry, sizeof (Entry));
  604. Header = (PBITMAPINFOHEADER) p;
  605. Entry.Width = (BYTE) Header->biWidth;
  606. Entry.Height = (BYTE) Header->biHeight / 2;
  607. ColorCount = Header->biPlanes * Header->biBitCount;
  608. if (ColorCount >= 8) {
  609. Entry.ColorCount = 0;
  610. } else {
  611. Entry.ColorCount = (BYTE) Power (2, ColorCount);
  612. }
  613. Entry.Planes = Header->biPlanes;
  614. Entry.BitCount = Header->biBitCount;
  615. Entry.BytesInRes = pComputeSizeOfIconImage (p);
  616. Entry.ImageOffset = sizeof (WORD) * 3 + sizeof (Entry) * ImageCount + Offset;
  617. if (!pWriteBinaryBlock (File, &Entry, sizeof (Entry))) {
  618. __leave;
  619. }
  620. Offset += Entry.BytesInRes;
  621. p = (PICONIMAGE) ((PBYTE) p + Entry.BytesInRes);
  622. }
  623. //
  624. // Write the image array
  625. //
  626. if (!pWriteBinaryBlock (File, IconImage, Buffer->End)) {
  627. __leave;
  628. }
  629. b = TRUE;
  630. }
  631. __finally {
  632. // empty
  633. }
  634. return b;
  635. }
  636. BOOL
  637. WriteIconImageArrayToIcoFileW (
  638. IN PCWSTR DestinationFile,
  639. IN PGROWBUFFER Buffer
  640. )
  641. {
  642. HANDLE File;
  643. BOOL b = FALSE;
  644. if (!Buffer->End) {
  645. return FALSE;
  646. }
  647. File = CreateFileW (DestinationFile, GENERIC_WRITE, 0, NULL,
  648. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  649. if (File == INVALID_HANDLE_VALUE) {
  650. DEBUGMSG ((DBG_WARNING, "%ls could not be created", DestinationFile));
  651. return FALSE;
  652. }
  653. __try {
  654. b = WriteIconImageArrayToIcoFileEx (Buffer, File);
  655. }
  656. __finally {
  657. CloseHandle (File);
  658. if (!b) {
  659. DeleteFileW (DestinationFile);
  660. }
  661. }
  662. return b;
  663. }
  664. BOOL
  665. WriteIconImageArrayToIcoFileA (
  666. IN PCSTR DestinationFile,
  667. IN PGROWBUFFER Buffer
  668. )
  669. {
  670. HANDLE File;
  671. BOOL b = FALSE;
  672. if (!Buffer->End) {
  673. return FALSE;
  674. }
  675. File = CreateFileA (DestinationFile, GENERIC_WRITE, 0, NULL,
  676. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  677. if (File == INVALID_HANDLE_VALUE) {
  678. DEBUGMSG ((DBG_WARNING, "%hs could not be created", DestinationFile));
  679. return FALSE;
  680. }
  681. __try {
  682. b = WriteIconImageArrayToIcoFileEx (Buffer, File);
  683. }
  684. __finally {
  685. CloseHandle (File);
  686. if (!b) {
  687. DeleteFileA (DestinationFile);
  688. }
  689. }
  690. return b;
  691. }
  692. BOOL
  693. WriteIconImageArrayToPeFileExW (
  694. IN PCWSTR DestinationFile,
  695. IN PGROWBUFFER Buffer,
  696. IN PCWSTR GroupIconId,
  697. IN PWORD NextIconId, OPTIONAL
  698. IN HANDLE UpdateHandle
  699. )
  700. {
  701. BOOL b = FALSE;
  702. GROWBUFFER GroupIcon = GROWBUF_INIT;
  703. PGRPICONDIRBASE IconDir;
  704. PGRPICONDIRENTRY Entry;
  705. PICONIMAGE IconImage, IconImageEnd;
  706. PICONIMAGE p;
  707. PBITMAPINFOHEADER Header;
  708. UINT ColorCount;
  709. if (!Buffer->End) {
  710. return TRUE;
  711. }
  712. __try {
  713. //
  714. // Make a group icon directory for all icon images in Buffer
  715. //
  716. IconDir = (PGRPICONDIRBASE) GrowBuffer (&GroupIcon, sizeof (GRPICONDIRBASE));
  717. if (!IconDir) {
  718. __leave;
  719. }
  720. IconDir->Reserved = 0;
  721. IconDir->Type = 1;
  722. IconDir->Count = 0;
  723. IconImage = (PICONIMAGE) Buffer->Buf;
  724. IconImageEnd = (PICONIMAGE) (Buffer->Buf + Buffer->End);
  725. p = IconImage;
  726. while (p < IconImageEnd) {
  727. Entry = (PGRPICONDIRENTRY) GrowBuffer (&GroupIcon, sizeof (GRPICONDIRENTRY));
  728. if (!Entry) {
  729. __leave;
  730. }
  731. Header = (PBITMAPINFOHEADER) p;
  732. Entry->Width = (BYTE) Header->biWidth;
  733. Entry->Height = (BYTE) Header->biHeight / 2;
  734. ColorCount = Header->biPlanes * Header->biBitCount;
  735. if (ColorCount >= 8) {
  736. Entry->ColorCount = 0;
  737. } else {
  738. Entry->ColorCount = (BYTE) Power (2, ColorCount);
  739. }
  740. Entry->Planes = Header->biPlanes;
  741. Entry->BitCount = Header->biBitCount;
  742. Entry->BytesInRes = pComputeSizeOfIconImage (p);
  743. if (!NextIconId) {
  744. Entry->ID = 1 + (WORD) ((DWORD) GroupIconId & (0xffff / MAX_RESOLUTIONS)) * MAX_RESOLUTIONS + IconDir->Count;
  745. } else {
  746. Entry->ID = *NextIconId;
  747. }
  748. //
  749. // Add icon to the PE file
  750. //
  751. b = UpdateResourceA (
  752. UpdateHandle,
  753. RT_ICON,
  754. MAKEINTRESOURCE(Entry->ID),
  755. MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
  756. p,
  757. Entry->BytesInRes
  758. );
  759. if (!b) {
  760. LOGA ((LOG_ERROR, "Could not add icon to %s", DestinationFile));
  761. __leave;
  762. }
  763. IconDir->Count += 1;
  764. if (NextIconId) {
  765. *NextIconId += 1;
  766. }
  767. p = (PICONIMAGE) ((PBYTE) p + Entry->BytesInRes);
  768. }
  769. //
  770. // Add the group icon to the PE
  771. //
  772. b = UpdateResourceW (
  773. UpdateHandle,
  774. (PCWSTR) RT_GROUP_ICON,
  775. GroupIconId,
  776. MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
  777. GroupIcon.Buf,
  778. GroupIcon.End
  779. );
  780. if (!b) {
  781. LOGA ((LOG_ERROR, "Unable to add icon to %s", DestinationFile));
  782. __leave;
  783. }
  784. b = TRUE;
  785. }
  786. __finally {
  787. FreeGrowBuffer (&GroupIcon);
  788. }
  789. return b;
  790. }
  791. BOOL
  792. WriteIconImageArrayToPeFileExA (
  793. IN PCSTR DestinationFile,
  794. IN PGROWBUFFER Buffer,
  795. IN PCSTR GroupIconId,
  796. IN PWORD NextIconId, OPTIONAL
  797. IN HANDLE UpdateHandle
  798. )
  799. {
  800. PCWSTR UnicodeDestinationFile;
  801. PCWSTR UnicodeGroupIconId;
  802. BOOL b;
  803. if (!pGenerateUnicodeArgs (
  804. DestinationFile,
  805. GroupIconId,
  806. &UnicodeDestinationFile,
  807. &UnicodeGroupIconId
  808. )) {
  809. return FALSE;
  810. }
  811. b = WriteIconImageArrayToPeFileExW (
  812. UnicodeDestinationFile,
  813. Buffer,
  814. UnicodeGroupIconId,
  815. NextIconId,
  816. UpdateHandle
  817. );
  818. PushError();
  819. FreeConvertedStr (UnicodeDestinationFile);
  820. DestroyUnicodeResourceId (UnicodeGroupIconId);
  821. PopError();
  822. return b;
  823. }
  824. BOOL
  825. WriteIconImageArrayToPeFileW (
  826. IN PCWSTR DestinationFile,
  827. IN PGROWBUFFER Buffer,
  828. IN PCWSTR GroupIconId
  829. )
  830. {
  831. HANDLE UpdateHandle = NULL;
  832. BOOL b = FALSE;
  833. if (!Buffer->End) {
  834. return TRUE;
  835. }
  836. __try {
  837. //
  838. // Open PE file for update
  839. //
  840. UpdateHandle = BeginUpdateResourceW (DestinationFile, FALSE);
  841. if (!UpdateHandle) {
  842. LOGW ((LOG_ERROR, "Unable to begin resource update of %s", DestinationFile));
  843. __leave;
  844. }
  845. //
  846. // Update the PE file
  847. //
  848. b = WriteIconImageArrayToPeFileExW (DestinationFile, Buffer, (PCWSTR) GroupIconId, NULL, UpdateHandle);
  849. }
  850. __finally {
  851. EndUpdateResource (UpdateHandle, !b);
  852. }
  853. return b;
  854. }
  855. BOOL
  856. WriteIconImageArrayToPeFileA (
  857. IN PCSTR DestinationFile,
  858. IN PGROWBUFFER Buffer,
  859. IN PCSTR GroupIconId
  860. )
  861. {
  862. PCWSTR UnicodeDestinationFile;
  863. PCWSTR UnicodeGroupIconId;
  864. BOOL b;
  865. if (!pGenerateUnicodeArgs (
  866. DestinationFile,
  867. GroupIconId,
  868. &UnicodeDestinationFile,
  869. &UnicodeGroupIconId
  870. )) {
  871. return FALSE;
  872. }
  873. b = WriteIconImageArrayToPeFileW (
  874. UnicodeDestinationFile,
  875. Buffer,
  876. UnicodeGroupIconId
  877. );
  878. PushError();
  879. FreeConvertedStr (UnicodeDestinationFile);
  880. DestroyUnicodeResourceId (UnicodeGroupIconId);
  881. PopError();
  882. return b;
  883. }
  884. BOOL
  885. IsFileAnIcoW (
  886. IN PCWSTR FileInQuestion
  887. )
  888. {
  889. PCWSTR p;
  890. DWORD magic;
  891. DWORD bytesRead;
  892. HANDLE icoFileHandle = INVALID_HANDLE_VALUE;
  893. BOOL result = FALSE;
  894. p = wcsrchr (FileInQuestion, L'.');
  895. if (p) {
  896. if (StringIMatchW (p, L".ico")) {
  897. return TRUE;
  898. }
  899. }
  900. icoFileHandle = CreateFileW (
  901. FileInQuestion,
  902. GENERIC_READ,
  903. 0,
  904. NULL,
  905. OPEN_EXISTING,
  906. FILE_ATTRIBUTE_NORMAL,
  907. NULL
  908. );
  909. if (icoFileHandle != INVALID_HANDLE_VALUE) {
  910. if (ReadFile (icoFileHandle, (PBYTE)(&magic), sizeof (magic), &bytesRead, NULL)) {
  911. if (bytesRead == sizeof (magic)) {
  912. if (magic != IMAGE_DOS_SIGNATURE) {
  913. result = TRUE;
  914. }
  915. }
  916. }
  917. CloseHandle (icoFileHandle);
  918. }
  919. return result;
  920. }
  921. BOOL
  922. IsFileAnIcoA (
  923. IN PCSTR FileInQuestion
  924. )
  925. {
  926. PCSTR p;
  927. WORD magic;
  928. DWORD bytesRead;
  929. HANDLE icoFileHandle = INVALID_HANDLE_VALUE;
  930. BOOL result = FALSE;
  931. p = _mbsrchr (FileInQuestion, '.');
  932. if (p) {
  933. if (StringIMatchA (p, ".ico")) {
  934. return TRUE;
  935. }
  936. }
  937. icoFileHandle = CreateFileA (
  938. FileInQuestion,
  939. GENERIC_READ,
  940. 0,
  941. NULL,
  942. OPEN_EXISTING,
  943. FILE_ATTRIBUTE_NORMAL,
  944. NULL
  945. );
  946. if (icoFileHandle != INVALID_HANDLE_VALUE) {
  947. if (ReadFile (icoFileHandle, (PBYTE)(&magic), sizeof (magic), &bytesRead, NULL)) {
  948. if (bytesRead == sizeof (magic)) {
  949. if (magic != IMAGE_DOS_SIGNATURE) {
  950. result = TRUE;
  951. }
  952. }
  953. }
  954. CloseHandle (icoFileHandle);
  955. }
  956. return result;
  957. }
  958. BOOL
  959. ExtractIconImageFromFileExW (
  960. IN PCWSTR ModuleContainingIcon,
  961. IN PCWSTR GroupIconId,
  962. IN OUT PGROWBUFFER Buffer,
  963. IN HANDLE IcoFileHandle, OPTIONAL
  964. IN HANDLE PeModuleHandle, OPTIONAL
  965. IN HANDLE NeModuleHandle OPTIONAL
  966. )
  967. {
  968. if (IsFileAnIcoW (ModuleContainingIcon)) {
  969. if (IcoFileHandle) {
  970. return pGetIconImageArrayFromIcoFileExW (ModuleContainingIcon, Buffer, IcoFileHandle);
  971. } else {
  972. return pGetIconImageArrayFromIcoFileW (ModuleContainingIcon, Buffer);
  973. }
  974. }
  975. if (PeModuleHandle) {
  976. return pGetIconImageArrayFromBinaryExW (
  977. ModuleContainingIcon,
  978. GroupIconId,
  979. Buffer,
  980. PeModuleHandle,
  981. NeModuleHandle
  982. );
  983. } else {
  984. return pGetIconImageArrayFromBinaryW (ModuleContainingIcon, GroupIconId, Buffer);
  985. }
  986. }
  987. BOOL
  988. ExtractIconImageFromFileExA (
  989. IN PCSTR ModuleContainingIcon,
  990. IN PCSTR GroupIconId,
  991. IN OUT PGROWBUFFER Buffer,
  992. IN HANDLE IcoFileHandle, OPTIONAL
  993. IN HANDLE PeModuleHandle, OPTIONAL
  994. IN HANDLE NeModuleHandle OPTIONAL
  995. )
  996. {
  997. if (IsFileAnIcoA (ModuleContainingIcon)) {
  998. if (IcoFileHandle) {
  999. return pGetIconImageArrayFromIcoFileExA (ModuleContainingIcon, Buffer, IcoFileHandle);
  1000. } else {
  1001. return pGetIconImageArrayFromIcoFileA (ModuleContainingIcon, Buffer);
  1002. }
  1003. }
  1004. if (PeModuleHandle) {
  1005. return pGetIconImageArrayFromBinaryExA (
  1006. ModuleContainingIcon,
  1007. GroupIconId,
  1008. Buffer,
  1009. PeModuleHandle,
  1010. NeModuleHandle
  1011. );
  1012. } else {
  1013. return pGetIconImageArrayFromBinaryA (ModuleContainingIcon, GroupIconId, Buffer);
  1014. }
  1015. }
  1016. BOOL
  1017. ExtractIconImageFromFileW (
  1018. IN PCWSTR ModuleContainingIcon,
  1019. IN PCWSTR GroupIconId,
  1020. IN OUT PGROWBUFFER Buffer
  1021. )
  1022. {
  1023. return ExtractIconImageFromFileExW (
  1024. ModuleContainingIcon,
  1025. GroupIconId,
  1026. Buffer,
  1027. NULL,
  1028. NULL,
  1029. NULL
  1030. );
  1031. }
  1032. BOOL
  1033. ExtractIconImageFromFileA (
  1034. IN PCSTR ModuleContainingIcon,
  1035. IN PCSTR GroupIconId,
  1036. IN OUT PGROWBUFFER Buffer
  1037. )
  1038. {
  1039. return ExtractIconImageFromFileExA (
  1040. ModuleContainingIcon,
  1041. GroupIconId,
  1042. Buffer,
  1043. NULL,
  1044. NULL,
  1045. NULL
  1046. );
  1047. }
  1048. BOOL
  1049. CALLBACK
  1050. pEnumIconNameProcA (
  1051. HANDLE Module,
  1052. PCSTR Type,
  1053. PSTR Name,
  1054. LONG lParam
  1055. )
  1056. {
  1057. PGROWBUFFER Buf;
  1058. PCSTR Num;
  1059. CHAR NumBuf[32];
  1060. Buf = (PGROWBUFFER) lParam;
  1061. if ((DWORD) Name & 0xffff0000) {
  1062. Num = Name;
  1063. } else {
  1064. Num = NumBuf;
  1065. wsprintfA (NumBuf, "#%u", Name);
  1066. }
  1067. MultiSzAppendA (Buf, Num);
  1068. return TRUE;
  1069. }
  1070. BOOL
  1071. CALLBACK
  1072. pEnumIconNameProcW (
  1073. HANDLE Module,
  1074. PCWSTR Type,
  1075. PWSTR Name,
  1076. LONG lParam
  1077. )
  1078. {
  1079. PGROWBUFFER Buf;
  1080. PCWSTR Num;
  1081. WCHAR NumBuf[32];
  1082. Buf = (PGROWBUFFER) lParam;
  1083. if ((DWORD) Name & 0xffff0000) {
  1084. Num = Name;
  1085. } else {
  1086. Num = NumBuf;
  1087. wsprintfW (NumBuf, L"#%u", Name);
  1088. }
  1089. MultiSzAppendW (Buf, Num);
  1090. return TRUE;
  1091. }
  1092. PCSTR
  1093. ExtractIconNamesFromFileExA (
  1094. IN PCSTR ModuleContainingIcons,
  1095. IN OUT PGROWBUFFER NameBuf,
  1096. IN HANDLE Module,
  1097. IN HANDLE Module16
  1098. )
  1099. {
  1100. PCSTR ReturnBuf;
  1101. NameBuf->End = 0;
  1102. if (Module) {
  1103. if (!EnumResourceNamesA (Module, RT_GROUP_ICON, pEnumIconNameProcA, (LONG) NameBuf)) {
  1104. return NULL;
  1105. }
  1106. } else if (Module16) {
  1107. if (!EnumNeResourceNamesA (Module16, RT_GROUP_ICON, pEnumIconNameProcA, (LONG) NameBuf)) {
  1108. return NULL;
  1109. }
  1110. } else {
  1111. return NULL;
  1112. }
  1113. MultiSzAppendA (NameBuf, "");
  1114. ReturnBuf = (PCSTR) NameBuf->Buf;
  1115. return ReturnBuf;
  1116. }
  1117. PCWSTR
  1118. ExtractIconNamesFromFileExW (
  1119. IN PCWSTR ModuleContainingIcons,
  1120. IN OUT PGROWBUFFER NameBuf,
  1121. IN HANDLE Module,
  1122. IN HANDLE Module16
  1123. )
  1124. {
  1125. PCWSTR ReturnBuf;
  1126. NameBuf->End = 0;
  1127. if (Module) {
  1128. if (!EnumResourceNamesW (Module, (PCWSTR) RT_GROUP_ICON, pEnumIconNameProcW, (LONG) NameBuf)) {
  1129. return NULL;
  1130. }
  1131. } else if (Module16) {
  1132. if (!EnumNeResourceNamesW (Module16, (PWSTR) RT_GROUP_ICON, pEnumIconNameProcW, (LONG) NameBuf)) {
  1133. return NULL;
  1134. }
  1135. } else {
  1136. return NULL;
  1137. }
  1138. MultiSzAppendW (NameBuf, L"");
  1139. ReturnBuf = (PCWSTR) NameBuf->Buf;
  1140. return ReturnBuf;
  1141. }
  1142. PCSTR
  1143. ExtractIconNamesFromFileA (
  1144. IN PCSTR ModuleContainingIcons,
  1145. IN OUT PGROWBUFFER NameBuf
  1146. )
  1147. {
  1148. HANDLE Module = NULL;
  1149. HANDLE Module16 = NULL;
  1150. PCSTR ReturnBuf = NULL;
  1151. __try {
  1152. Module = LoadLibraryExA (ModuleContainingIcons, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1153. if (!Module) {
  1154. Module16 = OpenNeFileA (ModuleContainingIcons);
  1155. if (!Module16) {
  1156. DEBUGMSGA ((DBG_WARNING, "Can't load %s, error %u", ModuleContainingIcons, GetLastError()));
  1157. __leave;
  1158. }
  1159. }
  1160. ReturnBuf = ExtractIconNamesFromFileExA (ModuleContainingIcons, NameBuf, Module, Module16);
  1161. }
  1162. __finally {
  1163. if (Module) {
  1164. FreeLibrary (Module);
  1165. }
  1166. if (Module16) {
  1167. CloseNeFile (Module16);
  1168. }
  1169. }
  1170. return ReturnBuf;
  1171. }
  1172. PCWSTR
  1173. ExtractIconNamesFromFileW (
  1174. IN PCWSTR ModuleContainingIcons,
  1175. IN OUT PGROWBUFFER NameBuf
  1176. )
  1177. {
  1178. HANDLE Module = NULL;
  1179. HANDLE Module16 = NULL;
  1180. PCWSTR ReturnBuf = NULL;
  1181. __try {
  1182. Module = LoadLibraryExW (ModuleContainingIcons, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1183. if (!Module) {
  1184. Module16 = OpenNeFileW (ModuleContainingIcons);
  1185. if (!Module16) {
  1186. DEBUGMSGW ((DBG_WARNING, "Can't load %s, error %u", ModuleContainingIcons, GetLastError()));
  1187. __leave;
  1188. }
  1189. }
  1190. ReturnBuf = ExtractIconNamesFromFileExW (ModuleContainingIcons, NameBuf, Module, Module16);
  1191. }
  1192. __finally {
  1193. if (Module) {
  1194. FreeLibrary (Module);
  1195. }
  1196. if (Module16) {
  1197. CloseNeFile (Module16);
  1198. }
  1199. }
  1200. return ReturnBuf;
  1201. }
  1202. VOID
  1203. pInitContextA (
  1204. PICON_EXTRACT_CONTEXTA Context
  1205. )
  1206. {
  1207. ZeroMemory (Context, sizeof (ICON_EXTRACT_CONTEXTA));
  1208. Context->GroupId = 1;
  1209. Context->IconId = 1;
  1210. Context->IconImageFile = INVALID_HANDLE_VALUE;
  1211. }
  1212. VOID
  1213. pInitContextW (
  1214. PICON_EXTRACT_CONTEXTW Context
  1215. )
  1216. {
  1217. ZeroMemory (Context, sizeof (ICON_EXTRACT_CONTEXTW));
  1218. Context->GroupId = 1;
  1219. Context->IconId = 1;
  1220. Context->IconImageFile = INVALID_HANDLE_VALUE;
  1221. }
  1222. BOOL
  1223. BeginIconExtractionA (
  1224. OUT PICON_EXTRACT_CONTEXTA Context,
  1225. IN PCSTR DestFile OPTIONAL
  1226. )
  1227. {
  1228. pInitContextA (Context);
  1229. if (DestFile) {
  1230. Context->Update = BeginUpdateResourceA (DestFile, FALSE);
  1231. if (!Context->Update) {
  1232. LOGA ((LOG_ERROR, "Unable to begin resource update of %s", DestFile));
  1233. return FALSE;
  1234. }
  1235. StringCopyA (Context->DestFile, DestFile);
  1236. }
  1237. return TRUE;
  1238. }
  1239. BOOL
  1240. BeginIconExtractionW (
  1241. OUT PICON_EXTRACT_CONTEXTW Context,
  1242. IN PCWSTR DestFile OPTIONAL
  1243. )
  1244. {
  1245. pInitContextW (Context);
  1246. if (DestFile) {
  1247. Context->Update = BeginUpdateResourceW (DestFile, FALSE);
  1248. if (!Context->Update) {
  1249. LOGW ((LOG_ERROR, "Unable to begin resource update of %s", DestFile));
  1250. return FALSE;
  1251. }
  1252. StringCopyW (Context->DestFile, DestFile);
  1253. }
  1254. return TRUE;
  1255. }
  1256. BOOL
  1257. pLoadBinaryImageA (
  1258. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1259. IN PCSTR IconFile
  1260. )
  1261. {
  1262. if (Context->Module || Context->Module16) {
  1263. if (StringIMatchA (Context->ModuleName, IconFile)) {
  1264. return TRUE;
  1265. }
  1266. }
  1267. if (Context->Module) {
  1268. FreeLibrary (Context->Module);
  1269. Context->Module = NULL;
  1270. }
  1271. if (Context->Module16) {
  1272. CloseNeFile (Context->Module16);
  1273. Context->Module16 = NULL;
  1274. }
  1275. Context->Module = LoadLibraryExA (IconFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1276. if (Context->Module) {
  1277. StringCopyA (Context->ModuleName, IconFile);
  1278. } else {
  1279. Context->Module16 = OpenNeFileA (IconFile);
  1280. if (Context->Module16) {
  1281. StringCopyA (Context->ModuleName, IconFile);
  1282. } else {
  1283. Context->ModuleName[0] = 0;
  1284. }
  1285. }
  1286. return Context->Module != NULL || Context->Module16 != NULL;
  1287. }
  1288. BOOL
  1289. pLoadBinaryImageW (
  1290. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1291. IN PCWSTR IconFile
  1292. )
  1293. {
  1294. if (Context->Module || Context->Module16) {
  1295. if (StringIMatchW (Context->ModuleName, IconFile)) {
  1296. return TRUE;
  1297. }
  1298. }
  1299. if (Context->Module) {
  1300. FreeLibrary (Context->Module);
  1301. }
  1302. if (Context->Module16) {
  1303. CloseNeFile (Context->Module16);
  1304. Context->Module16 = NULL;
  1305. }
  1306. Context->Module = LoadLibraryExW (IconFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
  1307. if (Context->Module) {
  1308. StringCopyW (Context->ModuleName, IconFile);
  1309. } else {
  1310. Context->Module16 = OpenNeFileW (IconFile);
  1311. if (Context->Module16) {
  1312. StringCopyW (Context->ModuleName, IconFile);
  1313. } else {
  1314. Context->ModuleName[0] = 0;
  1315. }
  1316. }
  1317. return Context->Module != NULL || Context->Module16 != NULL;
  1318. }
  1319. BOOL
  1320. pOpenIcoFileA (
  1321. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1322. IN PCSTR IconFile
  1323. )
  1324. {
  1325. if (Context->IcoFile) {
  1326. if (StringIMatchA (Context->IcoFileName, IconFile)) {
  1327. return TRUE;
  1328. }
  1329. }
  1330. if (Context->IcoFile) {
  1331. CloseHandle (Context->IcoFile);
  1332. }
  1333. Context->IcoFile = CreateFileA (IconFile, GENERIC_READ, 0, NULL,
  1334. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1335. if (Context->IcoFile == INVALID_HANDLE_VALUE) {
  1336. Context->IcoFile = NULL;
  1337. Context->IcoFileName[0] = 0;
  1338. } else {
  1339. StringCopyA (Context->IcoFileName, IconFile);
  1340. }
  1341. return Context->IcoFile != NULL;
  1342. }
  1343. BOOL
  1344. pOpenIcoFileW (
  1345. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1346. IN PCWSTR IconFile
  1347. )
  1348. {
  1349. if (Context->IcoFile) {
  1350. if (StringIMatchW (Context->IcoFileName, IconFile)) {
  1351. return TRUE;
  1352. }
  1353. }
  1354. if (Context->IcoFile) {
  1355. CloseHandle (Context->IcoFile);
  1356. }
  1357. Context->IcoFile = CreateFileW (IconFile, GENERIC_READ, 0, NULL,
  1358. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  1359. if (Context->IcoFile == INVALID_HANDLE_VALUE) {
  1360. Context->IcoFile = NULL;
  1361. Context->IcoFileName[0] = 0;
  1362. } else {
  1363. StringCopyW (Context->IcoFileName, IconFile);
  1364. }
  1365. return Context->IcoFile != NULL;
  1366. }
  1367. BOOL
  1368. pOpenIconImageA (
  1369. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1370. IN PCSTR FileToOpen,
  1371. OUT PBOOL IsIco, OPTIONAL
  1372. OUT PBOOL Is16Bit OPTIONAL
  1373. )
  1374. {
  1375. if (Is16Bit) {
  1376. *Is16Bit = FALSE;
  1377. }
  1378. if (IsFileAnIcoA (FileToOpen)) {
  1379. if (IsIco) {
  1380. *IsIco = TRUE;
  1381. }
  1382. return pOpenIcoFileA (Context, FileToOpen);
  1383. }
  1384. if (IsIco) {
  1385. *IsIco = FALSE;
  1386. }
  1387. if (pLoadBinaryImageA (Context, FileToOpen)) {
  1388. if (Context->Module16 && Is16Bit) {
  1389. *Is16Bit = TRUE;
  1390. }
  1391. return TRUE;
  1392. }
  1393. return FALSE;
  1394. }
  1395. BOOL
  1396. pOpenIconImageW (
  1397. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1398. IN PCWSTR FileToOpen,
  1399. OUT PBOOL IsIco, OPTIONAL
  1400. OUT PBOOL Is16Bit OPTIONAL
  1401. )
  1402. {
  1403. if (Is16Bit) {
  1404. *Is16Bit = FALSE;
  1405. }
  1406. if (IsFileAnIcoW (FileToOpen)) {
  1407. if (IsIco) {
  1408. *IsIco = TRUE;
  1409. }
  1410. return pOpenIcoFileW (Context, FileToOpen);
  1411. }
  1412. if (IsIco) {
  1413. *IsIco = FALSE;
  1414. }
  1415. if (pLoadBinaryImageW (Context, FileToOpen)) {
  1416. if (Context->Module16 && Is16Bit) {
  1417. *Is16Bit = TRUE;
  1418. }
  1419. return TRUE;
  1420. }
  1421. return FALSE;
  1422. }
  1423. BOOL
  1424. OpenIconImageFileA (
  1425. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1426. IN PCSTR FileName,
  1427. IN BOOL SaveMode
  1428. )
  1429. {
  1430. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1431. CloseHandle (Context->IconImageFile);
  1432. Context->IconImageFileName[0] = 0;
  1433. }
  1434. if (SaveMode) {
  1435. Context->IconImageFile = CreateFileA (
  1436. FileName,
  1437. GENERIC_WRITE,
  1438. 0,
  1439. NULL,
  1440. CREATE_ALWAYS,
  1441. FILE_ATTRIBUTE_NORMAL,
  1442. NULL
  1443. );
  1444. } else {
  1445. Context->IconImageFile = CreateFileA (
  1446. FileName,
  1447. GENERIC_READ,
  1448. 0,
  1449. NULL,
  1450. OPEN_EXISTING,
  1451. FILE_ATTRIBUTE_NORMAL,
  1452. NULL
  1453. );
  1454. }
  1455. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1456. StringCopyA (Context->IconImageFileName, FileName);
  1457. Context->SaveMode = SaveMode;
  1458. return TRUE;
  1459. }
  1460. return FALSE;
  1461. }
  1462. BOOL
  1463. OpenIconImageFileW (
  1464. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1465. IN PCWSTR FileName,
  1466. IN BOOL SaveMode
  1467. )
  1468. {
  1469. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1470. CloseHandle (Context->IconImageFile);
  1471. Context->IconImageFileName[0] = 0;
  1472. }
  1473. if (SaveMode) {
  1474. Context->IconImageFile = CreateFileW (
  1475. FileName,
  1476. GENERIC_WRITE,
  1477. 0,
  1478. NULL,
  1479. CREATE_ALWAYS,
  1480. FILE_ATTRIBUTE_NORMAL,
  1481. NULL
  1482. );
  1483. } else {
  1484. Context->IconImageFile = CreateFileW (
  1485. FileName,
  1486. GENERIC_READ,
  1487. 0,
  1488. NULL,
  1489. OPEN_EXISTING,
  1490. FILE_ATTRIBUTE_NORMAL,
  1491. NULL
  1492. );
  1493. }
  1494. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1495. StringCopyW (Context->IconImageFileName, FileName);
  1496. Context->SaveMode = SaveMode;
  1497. return TRUE;
  1498. }
  1499. return FALSE;
  1500. }
  1501. BOOL
  1502. pGetIconImageArrayFromFileA (
  1503. IN PICON_EXTRACT_CONTEXTA Context
  1504. )
  1505. {
  1506. DWORD Size;
  1507. PBYTE Dest;
  1508. HANDLE File;
  1509. File = Context->IconImageFile;
  1510. if (!ReadBinaryBlock (File, &Size, sizeof (DWORD))) {
  1511. return FALSE;
  1512. }
  1513. Context->IconImages.End = 0;
  1514. Dest = GrowBuffer (&Context->IconImages, Size);
  1515. if (!Dest) {
  1516. return FALSE;
  1517. }
  1518. return ReadBinaryBlock (File, Dest, Size);
  1519. }
  1520. BOOL
  1521. pGetIconImageArrayFromFileW (
  1522. IN PICON_EXTRACT_CONTEXTW Context
  1523. )
  1524. {
  1525. DWORD Size;
  1526. PBYTE Dest;
  1527. HANDLE File;
  1528. File = Context->IconImageFile;
  1529. if (!ReadBinaryBlock (File, &Size, sizeof (DWORD))) {
  1530. return FALSE;
  1531. }
  1532. Context->IconImages.End = 0;
  1533. Dest = GrowBuffer (&Context->IconImages, Size);
  1534. if (!Dest) {
  1535. return FALSE;
  1536. }
  1537. return ReadBinaryBlock (File, Dest, Size);
  1538. }
  1539. BOOL
  1540. pPutIconImageArrayInFileA (
  1541. IN PICON_EXTRACT_CONTEXTA Context
  1542. )
  1543. {
  1544. HANDLE File;
  1545. File = Context->IconImageFile;
  1546. if (!Context->IconImages.End) {
  1547. DEBUGMSGA_IF ((
  1548. Context->ModuleName[0],
  1549. DBG_WARNING,
  1550. "Ignoring empty icon in %s",
  1551. Context->ModuleName
  1552. ));
  1553. return TRUE;
  1554. }
  1555. if (!pWriteBinaryBlock (File, &Context->IconImages.End, sizeof (DWORD))) {
  1556. return FALSE;
  1557. }
  1558. return pWriteBinaryBlock (File, Context->IconImages.Buf, Context->IconImages.End);
  1559. }
  1560. BOOL
  1561. pPutIconImageArrayInFileW (
  1562. IN PICON_EXTRACT_CONTEXTW Context
  1563. )
  1564. {
  1565. HANDLE File;
  1566. File = Context->IconImageFile;
  1567. if (!Context->IconImages.End) {
  1568. DEBUGMSGW_IF ((
  1569. Context->ModuleName[0],
  1570. DBG_WARNING,
  1571. "Ignoring empty icon in %s",
  1572. Context->ModuleName
  1573. ));
  1574. return TRUE;
  1575. }
  1576. if (!pWriteBinaryBlock (File, &Context->IconImages.End, sizeof (DWORD))) {
  1577. return FALSE;
  1578. }
  1579. return pWriteBinaryBlock (File, Context->IconImages.Buf, Context->IconImages.End);
  1580. }
  1581. PCSTR
  1582. pFindResourceIdFromIndexA (
  1583. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1584. IN PCSTR FileContainingIcon,
  1585. IN INT ResourceIndex,
  1586. OUT PSTR Buffer
  1587. )
  1588. {
  1589. PCSTR ImageList;
  1590. if (!pLoadBinaryImageA (Context, FileContainingIcon)) {
  1591. return NULL;
  1592. }
  1593. if (ResourceIndex < 0) {
  1594. wsprintfA (Buffer, "#%i", -ResourceIndex);
  1595. return Buffer;
  1596. } else {
  1597. *Buffer = 0;
  1598. }
  1599. ImageList = ExtractIconNamesFromFileExA (
  1600. FileContainingIcon,
  1601. &Context->IconList,
  1602. Context->Module,
  1603. Context->Module16
  1604. );
  1605. while (ImageList) {
  1606. if (!ResourceIndex) {
  1607. StringCopyA (Buffer, ImageList);
  1608. break;
  1609. }
  1610. ResourceIndex--;
  1611. }
  1612. return *Buffer ? Buffer : NULL;
  1613. }
  1614. PCWSTR
  1615. pFindResourceIdFromIndexW (
  1616. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1617. IN PCWSTR FileContainingIcon,
  1618. IN INT ResourceIndex,
  1619. OUT PWSTR Buffer
  1620. )
  1621. {
  1622. PCWSTR ImageList;
  1623. if (!pLoadBinaryImageW (Context, FileContainingIcon)) {
  1624. return NULL;
  1625. }
  1626. if (ResourceIndex < 0) {
  1627. wsprintfW (Buffer, L"#%i", -ResourceIndex);
  1628. return Buffer;
  1629. } else {
  1630. *Buffer = 0;
  1631. }
  1632. ImageList = ExtractIconNamesFromFileExW (
  1633. FileContainingIcon,
  1634. &Context->IconList,
  1635. Context->Module,
  1636. Context->Module16
  1637. );
  1638. while (ImageList) {
  1639. if (!ResourceIndex) {
  1640. StringCopyW (Buffer, ImageList);
  1641. break;
  1642. }
  1643. ResourceIndex--;
  1644. }
  1645. return *Buffer ? Buffer : NULL;
  1646. }
  1647. BOOL
  1648. CopyIconA (
  1649. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1650. IN PCSTR FileContainingIcon, OPTIONAL
  1651. IN PCSTR ResourceId, OPTIONAL
  1652. IN INT ResourceIndex OPTIONAL
  1653. )
  1654. {
  1655. BOOL IsIco;
  1656. BOOL b;
  1657. CHAR Buffer[256];
  1658. if (Context->Error) {
  1659. return FALSE;
  1660. }
  1661. if (!ResourceId && FileContainingIcon) {
  1662. if (!IsFileAnIco (FileContainingIcon)) {
  1663. ResourceId = pFindResourceIdFromIndexA (
  1664. Context,
  1665. FileContainingIcon,
  1666. ResourceIndex,
  1667. Buffer
  1668. );
  1669. if (!ResourceId) {
  1670. return FALSE;
  1671. }
  1672. }
  1673. }
  1674. if (Context->IconImageFile != INVALID_HANDLE_VALUE &&
  1675. !Context->SaveMode
  1676. ) {
  1677. //
  1678. // Get icon image from the icon image array file
  1679. //
  1680. b = pGetIconImageArrayFromFileA (Context);
  1681. } else {
  1682. //
  1683. // Get icon image from source file
  1684. //
  1685. if (!pOpenIconImageA (Context, FileContainingIcon, &IsIco, NULL)) {
  1686. return FALSE;
  1687. }
  1688. if (IsIco) {
  1689. b = pGetIconImageArrayFromIcoFileExA (
  1690. Context->IcoFileName,
  1691. &Context->IconImages,
  1692. Context->IcoFile
  1693. );
  1694. } else {
  1695. b = pGetIconImageArrayFromBinaryExA (
  1696. Context->ModuleName,
  1697. ResourceId,
  1698. &Context->IconImages,
  1699. Context->Module,
  1700. Context->Module16
  1701. );
  1702. }
  1703. }
  1704. if (b) {
  1705. if (Context->IconImageFile != INVALID_HANDLE_VALUE &&
  1706. Context->SaveMode
  1707. ) {
  1708. //
  1709. // Save icon to icon image array file
  1710. //
  1711. b = pPutIconImageArrayInFileA (Context);
  1712. } else {
  1713. //
  1714. // Save icon to PE file
  1715. //
  1716. b = WriteIconImageArrayToPeFileExA (
  1717. Context->DestFile,
  1718. &Context->IconImages,
  1719. (PCSTR) Context->GroupId,
  1720. &Context->IconId,
  1721. Context->Update
  1722. );
  1723. }
  1724. if (!b) {
  1725. Context->Error = TRUE;
  1726. } else {
  1727. Context->GroupId++;
  1728. }
  1729. }
  1730. return b;
  1731. }
  1732. BOOL
  1733. CopyIconW (
  1734. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1735. IN PCWSTR FileContainingIcon, // OPTIONAL if using an icon image file
  1736. IN PCWSTR ResourceId, // OPTIONAL if FileContainingIcon is an ico
  1737. IN INT ResourceIndex OPTIONAL
  1738. )
  1739. {
  1740. BOOL IsIco;
  1741. BOOL b;
  1742. WCHAR Buffer[256];
  1743. if (Context->Error) {
  1744. return FALSE;
  1745. }
  1746. if (!ResourceId && FileContainingIcon) {
  1747. if (!IsFileAnIcoW (FileContainingIcon)) {
  1748. ResourceId = pFindResourceIdFromIndexW (
  1749. Context,
  1750. FileContainingIcon,
  1751. ResourceIndex,
  1752. Buffer
  1753. );
  1754. if (!ResourceId) {
  1755. return FALSE;
  1756. }
  1757. }
  1758. }
  1759. if (Context->IconImageFile != INVALID_HANDLE_VALUE &&
  1760. !Context->SaveMode
  1761. ) {
  1762. //
  1763. // Get icon image from the icon image array file
  1764. //
  1765. b = pGetIconImageArrayFromFileW (Context);
  1766. } else {
  1767. //
  1768. // Get icon image from source file
  1769. //
  1770. if (!pOpenIconImageW (Context, FileContainingIcon, &IsIco, NULL)) {
  1771. return FALSE;
  1772. }
  1773. if (IsIco) {
  1774. b = pGetIconImageArrayFromIcoFileExW (
  1775. Context->IcoFileName,
  1776. &Context->IconImages,
  1777. Context->IcoFile
  1778. );
  1779. } else {
  1780. b = pGetIconImageArrayFromBinaryExW (
  1781. Context->ModuleName,
  1782. ResourceId,
  1783. &Context->IconImages,
  1784. Context->Module,
  1785. Context->Module16
  1786. );
  1787. }
  1788. }
  1789. if (b) {
  1790. if (Context->IconImageFile != INVALID_HANDLE_VALUE &&
  1791. Context->SaveMode
  1792. ) {
  1793. //
  1794. // Save icon to icon image array file
  1795. //
  1796. b = pPutIconImageArrayInFileW (Context);
  1797. } else {
  1798. //
  1799. // Save icon to PE file
  1800. //
  1801. b = WriteIconImageArrayToPeFileExW (
  1802. Context->DestFile,
  1803. &Context->IconImages,
  1804. (PCWSTR) Context->GroupId,
  1805. &Context->IconId,
  1806. Context->Update
  1807. );
  1808. }
  1809. if (!b) {
  1810. Context->Error = TRUE;
  1811. } else {
  1812. Context->GroupId++;
  1813. }
  1814. }
  1815. return b;
  1816. }
  1817. BOOL
  1818. CopyAllIconsA (
  1819. IN OUT PICON_EXTRACT_CONTEXTA Context,
  1820. IN PCSTR FileContainingIcons
  1821. )
  1822. {
  1823. MULTISZ_ENUMA e;
  1824. BOOL IsIco;
  1825. PCSTR IconList;
  1826. BOOL b = TRUE;
  1827. if (Context->Error) {
  1828. return FALSE;
  1829. }
  1830. if (!pOpenIconImageA (Context, FileContainingIcons, &IsIco, NULL)) {
  1831. return FALSE;
  1832. }
  1833. if (IsIco) {
  1834. return CopyIconA (Context, FileContainingIcons, NULL, 0);
  1835. }
  1836. IconList = ExtractIconNamesFromFileExA (
  1837. FileContainingIcons,
  1838. &Context->IconList,
  1839. Context->Module,
  1840. Context->Module16
  1841. );
  1842. if (!IconList) {
  1843. return FALSE;
  1844. }
  1845. if (EnumFirstMultiSzA (&e, IconList)) {
  1846. do {
  1847. b = CopyIconA (Context, FileContainingIcons, e.CurrentString, 0);
  1848. if (!b) {
  1849. break;
  1850. }
  1851. } while (EnumNextMultiSzA (&e));
  1852. }
  1853. return b;
  1854. }
  1855. BOOL
  1856. CopyAllIconsW (
  1857. IN OUT PICON_EXTRACT_CONTEXTW Context,
  1858. IN PCWSTR FileContainingIcons
  1859. )
  1860. {
  1861. MULTISZ_ENUMW e;
  1862. BOOL IsIco;
  1863. PCWSTR IconList;
  1864. BOOL b = TRUE;
  1865. if (Context->Error) {
  1866. return FALSE;
  1867. }
  1868. if (!pOpenIconImageW (Context, FileContainingIcons, &IsIco, NULL)) {
  1869. return FALSE;
  1870. }
  1871. if (IsIco) {
  1872. return CopyIconW (Context, FileContainingIcons, NULL, 0);
  1873. }
  1874. IconList = ExtractIconNamesFromFileExW (
  1875. FileContainingIcons,
  1876. &Context->IconList,
  1877. Context->Module,
  1878. Context->Module16
  1879. );
  1880. if (!IconList) {
  1881. return FALSE;
  1882. }
  1883. if (EnumFirstMultiSzW (&e, IconList)) {
  1884. do {
  1885. b = CopyIconW (Context, FileContainingIcons, e.CurrentString, 0);
  1886. if (!b) {
  1887. break;
  1888. }
  1889. } while (EnumNextMultiSzW (&e));
  1890. }
  1891. return b;
  1892. }
  1893. BOOL
  1894. EndIconExtractionA (
  1895. IN OUT PICON_EXTRACT_CONTEXTA Context
  1896. )
  1897. {
  1898. BOOL b = FALSE;
  1899. if (Context->Update) {
  1900. b = EndUpdateResource (Context->Update, Context->Error);
  1901. }
  1902. if (Context->Module) {
  1903. FreeLibrary (Context->Module);
  1904. }
  1905. if (Context->Module16) {
  1906. CloseNeFile (Context->Module16);
  1907. }
  1908. if (Context->IcoFile) {
  1909. FreeLibrary (Context->IcoFile);
  1910. }
  1911. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1912. CloseHandle (Context->IconImageFile);
  1913. }
  1914. FreeGrowBuffer (&Context->IconImages);
  1915. FreeGrowBuffer (&Context->IconList);
  1916. pInitContextA (Context);
  1917. return b;
  1918. }
  1919. BOOL
  1920. EndIconExtractionW (
  1921. IN OUT PICON_EXTRACT_CONTEXTW Context
  1922. )
  1923. {
  1924. BOOL b = FALSE;
  1925. if (Context->Update) {
  1926. b = EndUpdateResource (Context->Update, Context->Error);
  1927. }
  1928. if (Context->Module) {
  1929. FreeLibrary (Context->Module);
  1930. }
  1931. if (Context->Module16) {
  1932. CloseNeFile (Context->Module16);
  1933. }
  1934. if (Context->IcoFile) {
  1935. FreeLibrary (Context->IcoFile);
  1936. }
  1937. if (Context->IconImageFile != INVALID_HANDLE_VALUE) {
  1938. CloseHandle (Context->IconImageFile);
  1939. }
  1940. FreeGrowBuffer (&Context->IconImages);
  1941. FreeGrowBuffer (&Context->IconList);
  1942. pInitContextW (Context);
  1943. return b;
  1944. }