Leaked source code of windows server 2003
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.

1147 lines
33 KiB

  1. /****************************** Module Header ******************************\
  2. *
  3. * Module Name: extract.c
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Icon Extraction Routines
  8. *
  9. * History:
  10. \***************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include "newexe.h"
  14. /****************************************************************************
  15. ****************************************************************************/
  16. #define ICON_MAGIC 0
  17. #define ICO_MAGIC1 1
  18. #define CUR_MAGIC1 2
  19. #define BMP_MAGIC ((WORD)'B'+((WORD)'M'<<8))
  20. #define ANI_MAGIC ((WORD)'R'+((WORD)'I'<<8))
  21. #define ANI_MAGIC1 ((WORD)'F'+((WORD)'F'<<8))
  22. #define ANI_MAGIC4 ((WORD)'A'+((WORD)'C'<<8))
  23. #define ANI_MAGIC5 ((WORD)'O'+((WORD)'N'<<8))
  24. #define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
  25. #define PEMAGIC ((WORD)'P'+((WORD)'E'<<8))
  26. #define LEMAGIC ((WORD)'L'+((WORD)'E'<<8))
  27. typedef struct new_exe NEWEXE, *LPNEWEXE;
  28. typedef struct exe_hdr EXEHDR, *LPEXEHDR;
  29. typedef struct rsrc_nameinfo RESNAMEINFO, *LPRESNAMEINFO;
  30. typedef struct rsrc_typeinfo RESTYPEINFO, *LPRESTYPEINFO;
  31. typedef struct rsrc_typeinfo UNALIGNED *ULPRESTYPEINFO;
  32. typedef struct new_rsrc RESTABLE, *LPRESTABLE;
  33. #define NUMBER_OF_SECTIONS(x) ((x)->FileHeader.NumberOfSections)
  34. #define FCC(c0,c1,c2,c3) ((DWORD)(c0)|((DWORD)(c1)<<8)|((DWORD)(c2)<<16)|((DWORD)(c3)<<24))
  35. #define COM_FILE FCC('.', 'c', 'o', 'm')
  36. #define BAT_FILE FCC('.', 'b', 'a', 't')
  37. #define CMD_FILE FCC('.', 'c', 'm', 'd')
  38. #define PIF_FILE FCC('.', 'p', 'i', 'f')
  39. #define LNK_FILE FCC('.', 'l', 'n', 'k')
  40. #define ICO_FILE FCC('.', 'i', 'c', 'o')
  41. #define EXE_FILE FCC('.', 'e', 'x', 'e')
  42. #define WIN32VER30 0x00030000 // for CreateIconFromResource()
  43. #define GET_COUNT 424242
  44. /***************************************************************************\
  45. * PathIsUNC
  46. *
  47. * Inline function to check for a double-backslash at the
  48. * beginning of a string
  49. *
  50. \***************************************************************************/
  51. __inline BOOL PathIsUNC(
  52. LPWSTR psz)
  53. {
  54. return (psz[0] == L'\\' && psz[1] == L'\\');
  55. }
  56. /***************************************************************************\
  57. * ReadAByte
  58. *
  59. * This is used to touch memory to assure that if we page-fault, it is
  60. * outside win16lock. Most icons aren't more than two pages.
  61. *
  62. \***************************************************************************/
  63. BOOL ReadAByte(
  64. LPCVOID pMem)
  65. {
  66. return ((*(PBYTE)pMem) == 0);
  67. }
  68. /***************************************************************************\
  69. * RVAtoP
  70. *
  71. *
  72. \***************************************************************************/
  73. LPVOID RVAtoP(
  74. LPVOID pBase,
  75. DWORD rva)
  76. {
  77. LPEXEHDR pmz;
  78. IMAGE_NT_HEADERS *ppe;
  79. IMAGE_SECTION_HEADER *pSection; // section table
  80. int i;
  81. DWORD size;
  82. pmz = (LPEXEHDR)pBase;
  83. ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew);
  84. /*
  85. * Scan the section table looking for the RVA
  86. */
  87. pSection = IMAGE_FIRST_SECTION(ppe);
  88. for (i = 0; i < NUMBER_OF_SECTIONS(ppe); i++) {
  89. size = pSection[i].Misc.VirtualSize ?
  90. pSection[i].Misc.VirtualSize : pSection[i].SizeOfRawData;
  91. if (rva >= pSection[i].VirtualAddress &&
  92. rva < pSection[i].VirtualAddress + size) {
  93. return (LPBYTE)pBase + pSection[i].PointerToRawData + (rva - pSection[i].VirtualAddress);
  94. }
  95. }
  96. return NULL;
  97. }
  98. /***************************************************************************\
  99. * GetResourceTablePE
  100. *
  101. *
  102. \***************************************************************************/
  103. LPVOID GetResourceTablePE(
  104. LPVOID pBase)
  105. {
  106. LPEXEHDR pmz;
  107. IMAGE_NT_HEADERS *ppe;
  108. pmz = (LPEXEHDR)pBase;
  109. ppe = (IMAGE_NT_HEADERS*)((BYTE*)pBase + pmz->e_lfanew);
  110. if (pmz->e_magic != MZMAGIC)
  111. return 0;
  112. if (ppe->Signature != IMAGE_NT_SIGNATURE)
  113. return 0;
  114. if (ppe->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  115. {
  116. IMAGE_NT_HEADERS64* ppe64 = (IMAGE_NT_HEADERS64*)ppe;
  117. if (ppe64->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL64_HEADER)
  118. {
  119. return 0;
  120. }
  121. return RVAtoP(pBase, ppe64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
  122. }
  123. else
  124. {
  125. // assume a 32-bit image
  126. IMAGE_NT_HEADERS32* ppe32 = (IMAGE_NT_HEADERS32*)ppe;
  127. if (ppe32->FileHeader.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL32_HEADER)
  128. {
  129. return 0;
  130. }
  131. return RVAtoP(pBase, ppe32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
  132. }
  133. }
  134. /****************************************************************************
  135. * FindResourcePE
  136. *
  137. * given a PE resource directory will find a resource in it.
  138. *
  139. * if iResIndex < 0 we will search for the specific index
  140. * if iResIndex >= 0 we will return the Nth index
  141. * if iResIndex == GET_COUNT the count of resources will be returned
  142. *
  143. \*****************************************************************************/
  144. LPVOID FindResourcePE(
  145. LPVOID pBase,
  146. LPVOID prt,
  147. int iResIndex,
  148. int ResType,
  149. DWORD *pcb)
  150. {
  151. int i;
  152. int cnt;
  153. IMAGE_RESOURCE_DIRECTORY *pdir;
  154. IMAGE_RESOURCE_DIRECTORY_ENTRY *pres;
  155. IMAGE_RESOURCE_DATA_ENTRY UNALIGNED *pent;
  156. pdir = (IMAGE_RESOURCE_DIRECTORY *)prt;
  157. /*
  158. * First find the type always a ID so ignore strings totaly
  159. */
  160. cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries;
  161. pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1);
  162. for (i = 0; i < cnt; i++) {
  163. if (pres[i].Name == (DWORD)ResType)
  164. break;
  165. }
  166. if (i==cnt) // did not find the type
  167. return 0;
  168. /*
  169. * Now go find the actual resource either by id (iResIndex < 0) or
  170. * by ordinal (iResIndex >= 0)
  171. */
  172. pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt +
  173. (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY));
  174. cnt = pdir->NumberOfIdEntries + pdir->NumberOfNamedEntries;
  175. pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1);
  176. /*
  177. * If we just want size, do it.
  178. */
  179. if (iResIndex == GET_COUNT)
  180. return (LPVOID)UIntToPtr( cnt );
  181. /*
  182. * if we are to search for a specific id do it.
  183. */
  184. if (iResIndex < 0) {
  185. for (i = 0; i < cnt; i++)
  186. if (pres[i].Name == (DWORD)(-iResIndex))
  187. break;
  188. } else {
  189. i = iResIndex;
  190. }
  191. /*
  192. * is the index in range?
  193. */
  194. if (i >= cnt)
  195. return 0;
  196. /*
  197. * if we get this far the resource has a language part, ick!
  198. * We don't handle multi-language icons, so just return the first one.
  199. * Note, this isn't a problem since this function isn't called from
  200. * anywhere that could specify a language. As this is called from an
  201. * API (albeit a private one), changing this behavior is dangerous.
  202. */
  203. if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) {
  204. pdir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt +
  205. (pres[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY));
  206. pres = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pdir+1);
  207. i = 0; // choose first one
  208. }
  209. /*
  210. * Nested way to deep for me!
  211. */
  212. if (pres[i].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY)
  213. return 0;
  214. pent = (IMAGE_RESOURCE_DATA_ENTRY*)((LPBYTE)prt + pres[i].OffsetToData);
  215. /*
  216. * all OffsetToData fields except the final one are relative to
  217. * the start of the section. the final one is a virtual address
  218. * we need to go back to the header and get the virtual address
  219. * of the resource section to do this right.
  220. */
  221. *pcb = pent->Size;
  222. return RVAtoP(pBase, pent->OffsetToData);
  223. }
  224. /***************************************************************************\
  225. * GetResourceTableNE
  226. *
  227. *
  228. \***************************************************************************/
  229. LPVOID GetResourceTableNE(
  230. LPVOID pBase)
  231. {
  232. LPNEWEXE pne;
  233. LPEXEHDR pmz;
  234. pmz = (LPEXEHDR)pBase;
  235. pne = (LPNEWEXE)((LPBYTE)pBase + pmz->e_lfanew);
  236. if (pmz->e_magic != MZMAGIC)
  237. return 0;
  238. if (pne->ne_magic != NEMAGIC) // must be a NEWEXE
  239. return 0;
  240. if (pne->ne_exetyp != NE_WINDOWS && // must be a Win DLL/EXE/386
  241. pne->ne_exetyp != NE_DEV386)
  242. return 0;
  243. if (pne->ne_expver < 0x0300) // must be 3.0 or greater
  244. return 0;
  245. if (pne->ne_rsrctab == pne->ne_restab) // no resources
  246. return 0;
  247. return (LPBYTE)pne + pne->ne_rsrctab; // return resource table pointer
  248. }
  249. /***************************************************************************\
  250. * FindResourceNE
  251. *
  252. * This returns a pointer to the rsrc_nameinfo of the resource with the
  253. * given index and type, if it is found, otherwise it returns NULL.
  254. *
  255. * if iResIndex is < 0, then it is assumed to be a ID and the res table
  256. * will be searched for a matching id.
  257. *
  258. * if iResIndex is >= 0, then it is assumed to be a index and the Nth
  259. * resorce of the specifed type will be returned.
  260. *
  261. * if iResIndex == GET_COUNT the count of resources will be returned
  262. *
  263. \***************************************************************************/
  264. LPVOID FindResourceNE(
  265. LPVOID lpBase,
  266. LPVOID prt,
  267. int iResIndex,
  268. int iResType,
  269. DWORD *pcb)
  270. {
  271. LPRESTABLE lpResTable;
  272. ULPRESTYPEINFO ulpResTypeInfo;
  273. LPRESNAMEINFO lpResNameInfo; // 16 bit alignment ok - had ushorts only
  274. int i;
  275. lpResTable = (LPRESTABLE)prt;
  276. //ulpResTypeInfo = (ULPRESTYPEINFO)(LPWBYTE)&lpResTable->rs_typeinfo;
  277. ulpResTypeInfo = (ULPRESTYPEINFO)((LPBYTE)lpResTable + 2);
  278. while (ulpResTypeInfo->rt_id) {
  279. if (ulpResTypeInfo->rt_id == (iResType | RSORDID)) {
  280. lpResNameInfo = (LPRESNAMEINFO)(ulpResTypeInfo + 1);
  281. if (iResIndex == GET_COUNT)
  282. return (LPVOID)ulpResTypeInfo->rt_nres;
  283. if (iResIndex < 0) {
  284. for (i=0; i < (int)ulpResTypeInfo->rt_nres; i++) {
  285. if (lpResNameInfo[i].rn_id == ((-iResIndex) | RSORDID))
  286. break;
  287. }
  288. iResIndex = i;
  289. }
  290. if (iResIndex >= (int)ulpResTypeInfo->rt_nres)
  291. return NULL;
  292. *pcb = ((DWORD)lpResNameInfo[iResIndex].rn_length) << lpResTable->rs_align;
  293. return (LPBYTE)lpBase + ((long)lpResNameInfo[iResIndex].rn_offset << lpResTable->rs_align);
  294. }
  295. ulpResTypeInfo =
  296. (ULPRESTYPEINFO)((LPRESNAMEINFO)(ulpResTypeInfo + 1) +
  297. ulpResTypeInfo->rt_nres);
  298. }
  299. *pcb = 0;
  300. return NULL;
  301. }
  302. /***************************************************************************\
  303. * ExtractIconFromICO
  304. *
  305. *
  306. \***************************************************************************/
  307. UINT ExtractIconFromICO(
  308. LPTSTR szFile,
  309. int nIconIndex,
  310. int cxIcon,
  311. int cyIcon,
  312. HICON *phicon,
  313. UINT flags)
  314. {
  315. HICON hicon;
  316. if (nIconIndex >= 1)
  317. return 0;
  318. flags |= LR_LOADFROMFILE;
  319. again:
  320. hicon = LoadImage(NULL,
  321. szFile,
  322. IMAGE_ICON,
  323. LOWORD(cxIcon),
  324. LOWORD(cyIcon),
  325. flags);
  326. if (hicon == NULL)
  327. return 0;
  328. /*
  329. * Do we just want a count?
  330. */
  331. if (phicon == NULL)
  332. DestroyCursor((HCURSOR)hicon);
  333. else
  334. *phicon = hicon;
  335. /*
  336. * Check for large/small icon extract
  337. */
  338. if (HIWORD(cxIcon)) {
  339. cxIcon = HIWORD(cxIcon);
  340. cyIcon = HIWORD(cyIcon);
  341. phicon++;
  342. goto again;
  343. }
  344. return 1;
  345. }
  346. /***************************************************************************\
  347. * ExtractIconFromBMP
  348. *
  349. *
  350. \***************************************************************************/
  351. #define ROP_DSna 0x00220326
  352. UINT ExtractIconFromBMP(
  353. LPTSTR szFile,
  354. int nIconIndex,
  355. int cxIcon,
  356. int cyIcon,
  357. HICON *phicon,
  358. UINT flags)
  359. {
  360. HICON hicon;
  361. HBITMAP hbm;
  362. HBITMAP hbmMask;
  363. HDC hdc;
  364. HDC hdcMask;
  365. ICONINFO ii;
  366. if (nIconIndex >= 1)
  367. return 0;
  368. /*
  369. * BUGUS: don't use LR_CREATEDIBSECTION. USER can't make an icon out
  370. * of a DibSection.
  371. */
  372. flags |= LR_LOADFROMFILE;
  373. again:
  374. hbm = (HBITMAP)LoadImage(NULL,
  375. szFile,
  376. IMAGE_BITMAP,
  377. LOWORD(cxIcon),
  378. LOWORD(cyIcon),
  379. flags);
  380. if (hbm == NULL)
  381. return 0;
  382. /*
  383. * do we just want a count?
  384. */
  385. if (phicon == NULL) {
  386. DeleteObject(hbm);
  387. return 1;
  388. }
  389. hbmMask = CreateBitmap(LOWORD(cxIcon), LOWORD(cyIcon), 1, 1, NULL);
  390. hdc = CreateCompatibleDC(NULL);
  391. SelectObject(hdc, hbm);
  392. hdcMask = CreateCompatibleDC(NULL);
  393. SelectObject(hdcMask, hbmMask);
  394. SetBkColor(hdc, GetPixel(hdc, 0, 0));
  395. BitBlt(hdcMask, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdc, 0, 0, SRCCOPY);
  396. BitBlt(hdc, 0, 0, LOWORD(cxIcon), LOWORD(cyIcon), hdcMask, 0, 0, ROP_DSna);
  397. ii.fIcon = TRUE;
  398. ii.xHotspot = 0;
  399. ii.yHotspot = 0;
  400. ii.hbmColor = hbm;
  401. ii.hbmMask = hbmMask;
  402. hicon = CreateIconIndirect(&ii);
  403. DeleteObject(hdc);
  404. DeleteObject(hbm);
  405. DeleteObject(hdcMask);
  406. DeleteObject(hbmMask);
  407. *phicon = hicon;
  408. /*
  409. * Check for large/small icon extract
  410. */
  411. if (HIWORD(cxIcon)) {
  412. cxIcon = HIWORD(cxIcon);
  413. cyIcon = HIWORD(cyIcon);
  414. phicon++;
  415. goto again;
  416. }
  417. return 1;
  418. }
  419. /***************************************************************************\
  420. * ExtractIconFromEXE
  421. *
  422. *
  423. \***************************************************************************/
  424. UINT ExtractIconFromEXE(
  425. HANDLE hFile,
  426. int nIconIndex,
  427. int cxIconSize,
  428. int cyIconSize,
  429. HICON *phicon,
  430. UINT *piconid,
  431. UINT nIcons,
  432. UINT flags)
  433. {
  434. HANDLE hFileMap = INVALID_HANDLE_VALUE;
  435. LPVOID lpFile = NULL;
  436. EXEHDR *pmz;
  437. NEWEXE UNALIGNED *pne;
  438. LPVOID pBase;
  439. LPVOID pres = NULL;
  440. UINT result = 0;
  441. LONG FileLength;
  442. DWORD cbSize;
  443. int cxIcon;
  444. int cyIcon;
  445. LPVOID (*FindResourceX)(LPVOID pBase,
  446. LPVOID prt,
  447. int iResIndex,
  448. int iResType,
  449. DWORD *pcb);
  450. FileLength = (LONG)GetFileSize(hFile, NULL);
  451. hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  452. if (hFileMap == NULL)
  453. goto exit;
  454. lpFile = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  455. if (lpFile == NULL)
  456. goto exit;
  457. pBase = (LPVOID)lpFile;
  458. pmz = (struct exe_hdr *)pBase;
  459. _try {
  460. if (pmz->e_magic != MZMAGIC)
  461. goto exit;
  462. if (pmz->e_lfanew <= 0) // not a new exe
  463. goto exit;
  464. if (pmz->e_lfanew >= FileLength) // not a new exe
  465. goto exit;
  466. pne = (NEWEXE UNALIGNED *)((BYTE*)pmz + pmz->e_lfanew);
  467. switch (pne->ne_magic) {
  468. case NEMAGIC:
  469. pres = GetResourceTableNE(pBase);
  470. FindResourceX = FindResourceNE;
  471. break;
  472. case PEMAGIC:
  473. pres = GetResourceTablePE(pBase);
  474. FindResourceX = FindResourcePE;
  475. break;
  476. }
  477. /*
  478. * cant find the resource table, fail
  479. */
  480. if (pres == NULL)
  481. goto exit;
  482. /*
  483. * do we just want a count?
  484. */
  485. if (phicon == NULL) {
  486. result = PtrToUlong(FindResourceX(pBase,
  487. pres,
  488. GET_COUNT,
  489. (LONG_PTR)RT_GROUP_ICON,
  490. &cbSize));
  491. goto exit;
  492. }
  493. while (result < nIcons) {
  494. LPVOID lpIconDir;
  495. LPVOID lpIcon;
  496. int idIcon;
  497. cxIcon = cxIconSize;
  498. cyIcon = cyIconSize;
  499. /*
  500. * find the icon dir for this icon.
  501. */
  502. lpIconDir = FindResourceX(pBase,
  503. pres,
  504. nIconIndex,
  505. (LONG_PTR)RT_GROUP_ICON,
  506. &cbSize);
  507. if (lpIconDir == NULL)
  508. goto exit;
  509. if ((((LPNEWHEADER)lpIconDir)->Reserved != 0) ||
  510. (((LPNEWHEADER)lpIconDir)->ResType != FT_ICON)) {
  511. goto exit;
  512. }
  513. again:
  514. idIcon = LookupIconIdFromDirectoryEx((LPBYTE)lpIconDir,
  515. TRUE,
  516. LOWORD(cxIcon),
  517. LOWORD(cyIcon),
  518. flags);
  519. lpIcon = FindResourceX(pBase,
  520. pres,
  521. -idIcon,
  522. (LONG_PTR)RT_ICON,
  523. &cbSize);
  524. if (lpIcon == NULL)
  525. goto exit;
  526. if ((((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPINFOHEADER)) &&
  527. (((UPBITMAPINFOHEADER)lpIcon)->biSize != sizeof(BITMAPCOREHEADER))) {
  528. goto exit;
  529. }
  530. #ifndef WINNT
  531. /* touch this memory before calling USER
  532. * so if we page fault we will do it outside of the Win16Lock
  533. * most icons aren't more than 2 pages
  534. */
  535. ReadAByte(((BYTE *)lpIcon) + cbSize - 1);
  536. #endif
  537. if (piconid)
  538. piconid[result] = idIcon;
  539. phicon[result++] = CreateIconFromResourceEx((LPBYTE)lpIcon,
  540. cbSize,
  541. TRUE,
  542. WIN32VER30,
  543. LOWORD(cxIcon),
  544. LOWORD(cyIcon),
  545. flags);
  546. /*
  547. * check for large/small icon extract
  548. */
  549. if (HIWORD(cxIcon)) {
  550. cxIcon = HIWORD(cxIcon);
  551. cyIcon = HIWORD(cyIcon);
  552. goto again;
  553. }
  554. nIconIndex++; // next icon index
  555. }
  556. } _except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  557. result = 0;
  558. }
  559. exit:
  560. if (lpFile)
  561. UnmapViewOfFile(lpFile);
  562. if (hFileMap != INVALID_HANDLE_VALUE)
  563. CloseHandle(hFileMap);
  564. return result;
  565. }
  566. /***************************************************************************\
  567. * PathFindExtension
  568. *
  569. *
  570. \***************************************************************************/
  571. LPWSTR PathFindExtension(
  572. LPWSTR pszPath)
  573. {
  574. LPWSTR pszDot;
  575. for (pszDot = NULL; *pszPath; pszPath = CharNext(pszPath)) {
  576. switch (*pszPath) {
  577. case L'.':
  578. pszDot = pszPath; // remember the last dot
  579. break;
  580. case L'\\':
  581. case L' ': // extensions can't have spaces
  582. pszDot = NULL; // forget last dot, it was in a directory
  583. break;
  584. }
  585. }
  586. /*
  587. * if we found the extension, return ptr to the dot, else
  588. * ptr to end of the string (NULL extension) (cast->non const)
  589. */
  590. return pszDot ? (LPWSTR)pszDot : (LPWSTR)pszPath;
  591. }
  592. /***************************************************************************\
  593. * PrivateExtractIconExA
  594. *
  595. * Ansi version of PrivateExtractIconExW
  596. *
  597. \***************************************************************************/
  598. WINUSERAPI UINT PrivateExtractIconExA(
  599. LPCSTR szFileName,
  600. int nIconIndex,
  601. HICON *phiconLarge,
  602. HICON *phiconSmall,
  603. UINT nIcons)
  604. {
  605. LPWSTR szFileNameW;
  606. UINT uRet;
  607. if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE))
  608. return 0;
  609. uRet = PrivateExtractIconExW(szFileNameW,
  610. nIconIndex,
  611. phiconLarge,
  612. phiconSmall,
  613. nIcons);
  614. UserLocalFree(szFileNameW);
  615. return uRet;
  616. }
  617. /***************************************************************************\
  618. * HasExtension
  619. *
  620. *
  621. \***************************************************************************/
  622. DWORD HasExtension(
  623. LPWSTR pszPath)
  624. {
  625. LPWSTR p = PathFindExtension(pszPath);
  626. /*
  627. * (BobDay, emended by JasonSch):
  628. *
  629. * NOTE: This routine can produce false positives. E.g., "Fister.Bather"
  630. * would return .BAT. This doesn't currently hurt us in the instances where
  631. * this routine is used. However, people stealing this code should verify
  632. * that this is okay for them.
  633. *
  634. * NOTE: We could make this EXTKEY based like the extension matching
  635. * stuff elsewhere (e.g., shlwapi\urlpars.cpp). EXTKEY is a QWORD
  636. * so UNICODE would fit.
  637. */
  638. if (*p == L'.') {
  639. WCHAR szExt[5];
  640. lstrcpynW(szExt, p, 5);
  641. if (lstrcmpiW(szExt,TEXT(".com")) == 0) return COM_FILE;
  642. if (lstrcmpiW(szExt,TEXT(".bat")) == 0) return BAT_FILE;
  643. if (lstrcmpiW(szExt,TEXT(".cmd")) == 0) return CMD_FILE;
  644. if (lstrcmpiW(szExt,TEXT(".pif")) == 0) return PIF_FILE;
  645. if (lstrcmpiW(szExt,TEXT(".lnk")) == 0) return LNK_FILE;
  646. if (lstrcmpiW(szExt,TEXT(".ico")) == 0) return ICO_FILE;
  647. if (lstrcmpiW(szExt,TEXT(".exe")) == 0) return EXE_FILE;
  648. }
  649. return 0;
  650. }
  651. /***************************************************************************\
  652. * PrivateExtractIconsW
  653. *
  654. * Extracts 1 or more icons from a file.
  655. *
  656. * input:
  657. * szFileName - EXE/DLL/ICO/CUR/ANI file to extract from
  658. * nIconIndex - what icon to extract
  659. * 0 = first icon, 1=second icon, etc.
  660. * -N = icon with id==N
  661. * cxIcon - icon size wanted (if HIWORD != 0 two sizes...)
  662. * cyIcon - icon size wanted (if HIWORD != 0 two sizes...)
  663. * 0,0 means extract at natural size.
  664. * phicon - place to return extracted icon(s)
  665. * nIcons - number of icons to extract.
  666. * flags - LoadImage LR_* flags
  667. *
  668. * returns:
  669. * if picon is NULL, number of icons in the file is returned.
  670. *
  671. * notes:
  672. * handles extraction from PE (Win32), NE (Win16), ICO (Icon),
  673. * CUR (Cursor), ANI (Animated Cursor), and BMP (Bitmap) files.
  674. * only Win16 3.x files are supported (not 2.x)
  675. *
  676. * cx/cyIcon are the size of the icon to extract, two sizes
  677. * can be extracted by putting size 1 in the loword and size 2 in the
  678. * hiword, ie MAKELONG(24, 48) would extract 24 and 48 size icons.
  679. * This is a hack it is done so IExtractIcon::Extract can be called by
  680. * outside people with custom large/small icon sizes that are not what
  681. * the shell uses internaly.
  682. *
  683. \***************************************************************************/
  684. WINUSERAPI UINT WINAPI PrivateExtractIconsW(
  685. LPCWSTR szFileName,
  686. int nIconIndex,
  687. int cxIcon,
  688. int cyIcon,
  689. HICON *phicon,
  690. UINT *piconid,
  691. UINT nIcons,
  692. UINT flags)
  693. {
  694. HANDLE hFile = (HANDLE)INVALID_HANDLE_VALUE;
  695. UINT result = 0;
  696. WORD magic[6];
  697. WCHAR achFileName[MAX_PATH];
  698. FILETIME ftAccess;
  699. WCHAR szExpFileName[MAX_PATH];
  700. DWORD dwBytesRead;
  701. /*
  702. * Set failure defaults.
  703. */
  704. if (phicon)
  705. *phicon = NULL;
  706. /*
  707. * Check for special extensions, and fail quick
  708. */
  709. switch (HasExtension((LPWSTR)szFileName)) {
  710. case COM_FILE:
  711. case BAT_FILE:
  712. case CMD_FILE:
  713. case PIF_FILE:
  714. case LNK_FILE:
  715. goto exit;
  716. default:
  717. break;
  718. }
  719. /*
  720. * Try expanding environment variables in the file name we're passed.
  721. */
  722. ExpandEnvironmentStrings(szFileName, szExpFileName, MAX_PATH);
  723. szExpFileName[ MAX_PATH-1 ] = (WCHAR)0;
  724. /*
  725. * Open the file - First check to see if it is a UNC path. If it
  726. * is make sure that we have access to the path...
  727. */
  728. if (PathIsUNC(szExpFileName)) {
  729. lstrcpynW(achFileName, szExpFileName, ARRAYSIZE(achFileName));
  730. } else {
  731. if (SearchPath(NULL,
  732. szExpFileName,
  733. NULL,
  734. ARRAYSIZE(achFileName),
  735. achFileName, NULL) == 0) {
  736. goto error_file;
  737. }
  738. }
  739. hFile = CreateFile(achFileName,
  740. GENERIC_READ|FILE_WRITE_ATTRIBUTES,
  741. FILE_SHARE_WRITE | FILE_SHARE_READ,
  742. NULL,
  743. OPEN_EXISTING,
  744. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
  745. 0);
  746. if (hFile == INVALID_HANDLE_VALUE) {
  747. hFile = CreateFile(achFileName, GENERIC_READ,
  748. FILE_SHARE_READ,
  749. NULL,
  750. OPEN_EXISTING,
  751. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
  752. 0);
  753. if (hFile == INVALID_HANDLE_VALUE)
  754. goto error_file;
  755. } else {
  756. /*
  757. * Restore the Access Date
  758. */
  759. if (GetFileTime(hFile, NULL, &ftAccess, NULL))
  760. SetFileTime(hFile, NULL, &ftAccess, NULL);
  761. }
  762. ReadFile(hFile, &magic, sizeof(magic), &dwBytesRead, NULL);
  763. if (dwBytesRead != sizeof(magic))
  764. goto exit;
  765. if (piconid)
  766. *piconid = (UINT)-1; // Fill in "don't know" value
  767. switch (magic[0]) {
  768. case MZMAGIC:
  769. result = ExtractIconFromEXE(hFile,
  770. nIconIndex,
  771. cxIcon,
  772. cyIcon,
  773. phicon,
  774. piconid,
  775. nIcons,
  776. flags);
  777. break;
  778. case ANI_MAGIC: // possible .ani cursor
  779. /*
  780. * Ani cursors are easy they are RIFF files of type 'ACON'
  781. */
  782. if (magic[1] == ANI_MAGIC1 && magic[4] == ANI_MAGIC4 &&
  783. magic[5] == ANI_MAGIC5) {
  784. result = ExtractIconFromICO(achFileName,
  785. nIconIndex,
  786. cxIcon,
  787. cyIcon,
  788. phicon,
  789. flags);
  790. }
  791. break;
  792. case BMP_MAGIC: // possible bitmap
  793. result = ExtractIconFromBMP(achFileName,
  794. nIconIndex,
  795. cxIcon,
  796. cyIcon,
  797. phicon,
  798. flags);
  799. break;
  800. case ICON_MAGIC: // possible .ico or .cur
  801. /*
  802. * Icons and cursors look like this
  803. *
  804. * iReserved - always zero
  805. * iResourceType - 1 for icons 2 cor cursor.
  806. * cresIcons - number of resolutions in this file
  807. *
  808. * We only allow 1 <= cresIcons <= 10
  809. */
  810. if (magic[1] == ICO_MAGIC1 || magic[1] == CUR_MAGIC1) {
  811. result = ExtractIconFromICO(achFileName,
  812. nIconIndex,
  813. cxIcon,
  814. cyIcon,
  815. phicon,
  816. flags);
  817. }
  818. break;
  819. }
  820. exit:
  821. if (hFile!=INVALID_HANDLE_VALUE)
  822. CloseHandle(hFile);
  823. return result;
  824. /*
  825. * if we cant open the file, return a code saying we cant open the file
  826. * if phicon==NULL return the count of icons in the file 0
  827. */
  828. error_file:
  829. result = (phicon ? (UINT)-1 : 0);
  830. goto exit;
  831. }
  832. /***************************************************************************\
  833. * PrivateExtractIconsA
  834. *
  835. *
  836. \***************************************************************************/
  837. WINUSERAPI UINT WINAPI PrivateExtractIconsA(
  838. LPCSTR szFileName,
  839. int nIconIndex,
  840. int cxIcon,
  841. int cyIcon,
  842. HICON *phicon,
  843. UINT *piconid,
  844. UINT nIcons,
  845. UINT flags)
  846. {
  847. LPWSTR szFileNameW;
  848. UINT uRet;
  849. if (!MBToWCS(szFileName, -1, &szFileNameW, -1, TRUE))
  850. return 0;
  851. uRet = PrivateExtractIconsW(szFileNameW,
  852. nIconIndex,
  853. cxIcon,
  854. cyIcon,
  855. phicon,
  856. piconid,
  857. nIcons,
  858. flags);
  859. UserLocalFree(szFileNameW);
  860. return uRet;
  861. }
  862. /***************************************************************************\
  863. * PrivateExtractIconExW
  864. *
  865. * extracts 1 or more icons from a file.
  866. *
  867. * input:
  868. * szFileName - EXE/DLL/ICO file to extract from
  869. * nIconIndex - what icon to extract
  870. * 0 = first icon, 1=second icon, etc.
  871. * -N = icon with id==N
  872. * phiconLarge - place to return extracted icon(s)
  873. * phiconSmall - place to return extracted icon(s) (small size)
  874. * nIcons - number of icons to extract.
  875. *
  876. * returns:
  877. * number of icons extracted, or the count of icons if phiconLarge==NULL
  878. *
  879. * notes:
  880. * handles extraction from PE (Win32), NE (Win16), and ICO (Icon) files.
  881. * only Win16 3.x files are supported (not 2.x)
  882. *
  883. \***************************************************************************/
  884. WINUSERAPI UINT PrivateExtractIconExW(
  885. LPCWSTR szFileName,
  886. int nIconIndex,
  887. HICON *phiconLarge,
  888. HICON *phiconSmall,
  889. UINT nIcons)
  890. {
  891. UINT result = 0;
  892. if ((nIconIndex == -1) || ((phiconLarge == NULL) && (phiconSmall == NULL)))
  893. return PrivateExtractIconsW(szFileName, 0, 0, 0, NULL, NULL, 0, 0);
  894. if (phiconLarge && phiconSmall && (nIcons == 1)) {
  895. HICON ahicon[2];
  896. ahicon[0] = NULL;
  897. ahicon[1] = NULL;
  898. result = PrivateExtractIconsW(szFileName,
  899. nIconIndex,
  900. MAKELONG(GetSystemMetrics(SM_CXICON),
  901. GetSystemMetrics(SM_CXSMICON)),
  902. MAKELONG(GetSystemMetrics(SM_CYICON),
  903. GetSystemMetrics(SM_CYSMICON)),
  904. ahicon,
  905. NULL,
  906. 2,
  907. 0);
  908. *phiconLarge = ahicon[0];
  909. *phiconSmall = ahicon[1];
  910. } else {
  911. if (phiconLarge)
  912. result = PrivateExtractIconsW(szFileName,
  913. nIconIndex,
  914. GetSystemMetrics(SM_CXICON),
  915. GetSystemMetrics(SM_CYICON),
  916. phiconLarge,
  917. NULL,
  918. nIcons,
  919. 0);
  920. if (phiconSmall)
  921. result = PrivateExtractIconsW(szFileName,
  922. nIconIndex,
  923. GetSystemMetrics(SM_CXSMICON),
  924. GetSystemMetrics(SM_CYSMICON),
  925. phiconSmall,
  926. NULL,
  927. nIcons,
  928. 0);
  929. }
  930. return result;
  931. }