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.

1545 lines
46 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #define ICON_MAGIC 0
  4. #define ICO_MAGIC1 1
  5. #define CUR_MAGIC1 2
  6. #define BMP_MAGIC ((WORD)'B'+((WORD)'M'<<8))
  7. #define ANI_MAGIC ((WORD)'R'+((WORD)'I'<<8))
  8. #define ANI_MAGIC1 ((WORD)'F'+((WORD)'F'<<8))
  9. #define ANI_MAGIC4 ((WORD)'A'+((WORD)'C'<<8))
  10. #define ANI_MAGIC5 ((WORD)'O'+((WORD)'N'<<8))
  11. #define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
  12. #define PEMAGIC ((WORD)'P'+((WORD)'E'<<8))
  13. #define LEMAGIC ((WORD)'L'+((WORD)'E'<<8))
  14. typedef struct new_exe NEWEXE, *LPNEWEXE;
  15. typedef struct exe_hdr EXEHDR, *LPEXEHDR;
  16. typedef struct rsrc_nameinfo RESNAMEINFO, *LPRESNAMEINFO;
  17. typedef struct rsrc_typeinfo RESTYPEINFO, *LPRESTYPEINFO;
  18. typedef struct new_rsrc RESTABLE, *LPRESTABLE;
  19. #define RESOURCE_VA(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
  20. #define RESOURCE_SIZE(x) ((x)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size)
  21. #define NUMBER_OF_SECTIONS(x) ((x)->FileHeader.NumberOfSections)
  22. #define FCC(c0,c1,c2,c3) ((DWORD)(c0)|((DWORD)(c1)<<8)|((DWORD)(c2)<<16)|((DWORD)(c3)<<24))
  23. #define COM_FILE FCC('.', 'c', 'o', 'm')
  24. #define BAT_FILE FCC('.', 'b', 'a', 't')
  25. #define CMD_FILE FCC('.', 'c', 'm', 'd')
  26. #define PIF_FILE FCC('.', 'p', 'i', 'f')
  27. #define LNK_FILE FCC('.', 'l', 'n', 'k')
  28. #define ICO_FILE FCC('.', 'i', 'c', 'o')
  29. #define EXE_FILE FCC('.', 'e', 'x', 'e')
  30. /****************************************************************************
  31. * extract a single icon from a exe file, or get the count.
  32. *
  33. * If nIconIndex != -1
  34. * Returns:
  35. * The handle of the icon, if successful.
  36. * 0, if the file does not exist or an icon with the "nIconIndex"
  37. * does not exist.
  38. * 1, if the given file is not an EXE or ICO file.
  39. *
  40. * If nIconIndex == -1
  41. * Returns:
  42. * The number of icons in the file if successful.
  43. * 0, if the file has no icons or isn't an icon file.
  44. *
  45. ****************************************************************************/
  46. HICON WINAPI ExtractIcon(HINSTANCE hInst, LPCTSTR szFileName, UINT nIconIndex)
  47. {
  48. HICON hIcon;
  49. if (nIconIndex == (UINT) -1)
  50. hIcon = (HICON)IntToPtr( ExtractIcons(szFileName, 0, 0, 0, NULL, NULL, 0, 0) );
  51. else
  52. ExtractIcons(szFileName, nIconIndex, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), &hIcon, NULL, 1, 0);
  53. return hIcon;
  54. }
  55. /****************************************************************************
  56. *
  57. * in:
  58. * lpIconPath path of thing to extract icon for (may be an exe
  59. * or something that is associated)
  60. * lpiIcon icon index to use
  61. *
  62. * lpIconPath filled in with the real path where the icon came from
  63. * lpiIcon filled in with the real icon index
  64. *
  65. * returns:
  66. *
  67. * note: if the caller is the shell it returns special icons
  68. * from within the shell.dll
  69. *
  70. ****************************************************************************/
  71. HICON WINAPI ExtractAssociatedIcon(HINSTANCE hInst, LPTSTR lpIconPath, WORD *lpiIcon)
  72. {
  73. HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
  74. if (hIcon == NULL)
  75. hIcon = SHGetFileIcon(NULL, lpIconPath, 0, SHGFI_LARGEICON);
  76. if (hIcon == NULL)
  77. {
  78. *lpiIcon = IDI_DOCUMENT;
  79. GetModuleFileName(HINST_THISDLL, lpIconPath, 128);
  80. hIcon = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(*lpiIcon));
  81. }
  82. return hIcon;
  83. }
  84. /****************************************************************************
  85. *
  86. * extracts 1 or more icons from a file.
  87. *
  88. * input:
  89. * szFileName - EXE/DLL/ICO file to extract from
  90. * nIconIndex - what icon to extract
  91. * 0 = first icon, 1=second icon, etc.
  92. * -N = icon with id==N
  93. * phiconLarge - place to return extracted icon(s)
  94. * phiconSmall - place to return extracted icon(s) (small size)
  95. * nIcons - number of icons to extract.
  96. *
  97. * returns:
  98. * number of icons extracted, or the count of icons if phiconLarge==NULL
  99. *
  100. * notes:
  101. * handles extraction from PE (Win32), NE (Win16), and ICO (Icon) files.
  102. * only Win16 3.x files are supported (not 2.x)
  103. *
  104. ****************************************************************************/
  105. UINT WINAPI ExtractIconExW(LPCWSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
  106. {
  107. return PrivateExtractIconExW( szFileName, nIconIndex, phiconLarge, phiconSmall, nIcons );
  108. }
  109. UINT WINAPI ExtractIconExA(LPCSTR szFileName, int nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIcons)
  110. {
  111. return PrivateExtractIconExA( szFileName, nIconIndex, phiconLarge, phiconSmall, nIcons );
  112. }
  113. /****************************************************************************
  114. *
  115. * extracts 1 or more icons from a file.
  116. *
  117. * input:
  118. * szFileName - EXE/DLL/ICO/CUR/ANI file to extract from
  119. * nIconIndex - what icon to extract
  120. * 0 = first icon, 1=second icon, etc.
  121. * -N = icon with id==N
  122. * cxIcon - icon size wanted (if HIWORD != 0 two sizes...)
  123. * cyIcon - icon size wanted (if HIWORD != 0 two sizes...)
  124. * 0,0 means extract at natural size.
  125. * phicon - place to return extracted icon(s)
  126. * nIcons - number of icons to extract.
  127. * flags - LoadImage LR_* flags
  128. *
  129. * returns:
  130. * if picon is NULL, number of icons in the file is returned.
  131. *
  132. * notes:
  133. * handles extraction from PE (Win32), NE (Win16), ICO (Icon),
  134. * CUR (Cursor), ANI (Animated Cursor), and BMP (Bitmap) files.
  135. * only Win16 3.x files are supported (not 2.x)
  136. *
  137. * cx/cyIcon are the size of the icon to extract, two sizes
  138. * can be extracted by putting size 1 in the loword and size 2 in the
  139. * hiword, ie MAKELONG(24, 48) would extract 24 and 48 size icons.
  140. * yea this is a hack. It is done so IExtractIcon::Extract
  141. * can be called by outside people with custom large/small icon
  142. * sizes that are not what the shell uses internaly.
  143. *
  144. ****************************************************************************/
  145. UINT WINAPI SHExtractIconsW(LPCWSTR wszFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags)
  146. {
  147. #ifdef UNICODE
  148. return ExtractIcons(wszFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags);
  149. #else // UNICODE
  150. TCHAR sz[MAX_PATH];
  151. SHUnicodeToTChar(wszFileName, sz, ARRAYSIZE(sz));
  152. return ExtractIcons(sz, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags);
  153. #endif // UNICODE
  154. }
  155. UINT WINAPI ExtractIcons(LPCTSTR szFileName, int nIconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT *piconid, UINT nIcons, UINT flags)
  156. {
  157. #ifdef UNICODE
  158. return PrivateExtractIconsW( szFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags );
  159. #else
  160. return PrivateExtractIconsA( szFileName, nIconIndex, cxIcon, cyIcon, phicon, piconid, nIcons, flags );
  161. #endif
  162. }
  163. DWORD HasExtension(LPCTSTR pszPath)
  164. {
  165. LPCTSTR p = PathFindExtension(pszPath);
  166. //
  167. //
  168. // PERF: BobDay - We could make this EXTKEY based like the extension
  169. // matching stuff elsewhere. EXTKEY is a QWORD value so UNICODE would fit.
  170. //
  171. if (*p == TEXT('.'))
  172. {
  173. #ifdef UNICODE
  174. WCHAR szExt[5];
  175. lstrcpyn(szExt,p,5);
  176. if ( lstrcmpi(szExt,TEXT(".com")) == 0 ) return COM_FILE;
  177. if ( lstrcmpi(szExt,TEXT(".bat")) == 0 ) return BAT_FILE;
  178. if ( lstrcmpi(szExt,TEXT(".cmd")) == 0 ) return CMD_FILE;
  179. if ( lstrcmpi(szExt,TEXT(".pif")) == 0 ) return PIF_FILE;
  180. if ( lstrcmpi(szExt,TEXT(".lnk")) == 0 ) return LNK_FILE;
  181. if ( lstrcmpi(szExt,TEXT(".ico")) == 0 ) return ICO_FILE;
  182. if ( lstrcmpi(szExt,TEXT(".exe")) == 0 ) return EXE_FILE;
  183. return 0;
  184. #else
  185. return *((UNALIGNED DWORD *)p) | 0x20202000; // make lower case
  186. #endif
  187. }
  188. else
  189. return 0;
  190. }
  191. /****************************************************************************
  192. * get the EXE type of the passed file (DOS, Win16, Win32)
  193. *
  194. * returns:
  195. * 0 = not a exe of any type.
  196. *
  197. * if a windows app
  198. * LOWORD = NE or PE
  199. * HIWORD = windows version 3.0, 3.5, 4.0
  200. *
  201. * if a DOS app (or a .com or batch file on non-NT)
  202. * LOWORD = MZ
  203. * HIWORD = 0
  204. *
  205. * if a Win32 console app (or a batch file on NT)
  206. * LOWORD = PE
  207. * HIWORD = 0
  208. *
  209. * this is so similar to the Win32 API GetBinaryType() too bad Win95
  210. * kernel does not support it.
  211. *
  212. ****************************************************************************/
  213. DWORD WINAPI GetExeType(LPCTSTR szFile)
  214. {
  215. HANDLE fh;
  216. DWORD dw;
  217. struct exe_hdr exehdr;
  218. struct new_exe newexe;
  219. FILETIME ftAccess;
  220. DWORD dwRead;
  221. //
  222. // check for special extensions, and fail quick
  223. //
  224. switch (HasExtension(szFile))
  225. {
  226. case COM_FILE:
  227. // handle the case like \\server.microsoft.com
  228. // PERF - Bobday - This does the same operation twice, we should really
  229. // make PathIsUNCServerShare return a code based on what it found...
  230. if (PathIsUNCServer(szFile) || PathIsUNCServerShare(szFile))
  231. return 0;
  232. return MAKELONG(MZMAGIC, 0); // DOS exe
  233. case BAT_FILE:
  234. case CMD_FILE:
  235. return MAKELONG(PEMAGIC, 0); // NT exe (pretend)
  236. case EXE_FILE: // we need to open it.
  237. break;
  238. default:
  239. return 0; // not a exe, or if it is we dont care
  240. }
  241. newexe.ne_expver = 0;
  242. fh = CreateFile(szFile, GENERIC_READ | FILE_WRITE_ATTRIBUTES,
  243. FILE_SHARE_READ | FILE_SHARE_WRITE,
  244. 0, OPEN_EXISTING, 0, 0);
  245. if (fh == INVALID_HANDLE_VALUE)
  246. {
  247. //
  248. // We may be trying to get properties for a file on a volume where
  249. // we don't have write access, so try opening the file for read
  250. // only access. This will mean we can't preserve the access
  251. // time (those calls will fail), but this is better than not returning
  252. // the exe type at all...
  253. //
  254. fh = CreateFile(szFile, GENERIC_READ,
  255. FILE_SHARE_READ | FILE_SHARE_WRITE,
  256. 0, OPEN_EXISTING, 0, 0);
  257. //
  258. // at this point if we get an INVALID_HANDLE_VALUE, we really
  259. // can't do much else, so now return a failure...
  260. //
  261. if (fh == INVALID_HANDLE_VALUE)
  262. {
  263. return 0;
  264. }
  265. }
  266. // preserve the access time
  267. if (GetFileTime(fh, NULL, &ftAccess, NULL))
  268. SetFileTime(fh, NULL, &ftAccess, NULL);
  269. if (!ReadFile(fh, &exehdr, sizeof(exehdr), &dwRead, NULL) ||
  270. (dwRead != sizeof(exehdr)))
  271. goto error;
  272. if (exehdr.e_magic != EMAGIC)
  273. goto error;
  274. SetFilePointer(fh, exehdr.e_lfanew, NULL, FILE_BEGIN);
  275. ReadFile(fh,&newexe, sizeof(newexe), &dwRead, NULL);
  276. if (newexe.ne_magic == PEMAGIC)
  277. {
  278. // read the SubsystemVersion
  279. SetFilePointer(fh, exehdr.e_lfanew+18*4, NULL, FILE_BEGIN);
  280. ReadFile(fh,&dw,4, &dwRead, NULL);
  281. newexe.ne_expver = LOBYTE(LOWORD(dw)) << 8 | LOBYTE(HIWORD(dw));
  282. // read the Subsystem
  283. SetFilePointer(fh, exehdr.e_lfanew+23*4, NULL, FILE_BEGIN);
  284. ReadFile(fh,&dw,4, &dwRead, NULL);
  285. // if it is not a Win32 GUI app return a version of 0
  286. if (LOWORD(dw) != 2) // IMAGE_SUBSYSTEM_WINDOWS_GUI
  287. newexe.ne_expver = 0;
  288. goto exit;
  289. }
  290. else if (newexe.ne_magic == LEMAGIC)
  291. {
  292. newexe.ne_magic = MZMAGIC; // just a DOS exe
  293. newexe.ne_expver = 0;
  294. }
  295. else if (newexe.ne_magic == NEMAGIC)
  296. {
  297. //
  298. // we found a 'NE' it still might not be a windows
  299. // app, it could be.....
  300. //
  301. // a OS/2 app ne_exetyp==NE_OS2
  302. // a DOS4 app ne_exetyp==NE_DOS4
  303. // a VxD ne_exetyp==DEV386
  304. //
  305. // only treat it as a Windows app if the exetype
  306. // is NE_WINDOWS or NE_UNKNOWN
  307. //
  308. if (newexe.ne_exetyp != NE_WINDOWS && newexe.ne_exetyp != NE_UNKNOWN)
  309. {
  310. newexe.ne_magic = MZMAGIC; // just a DOS exe
  311. newexe.ne_expver = 0;
  312. }
  313. //
  314. // if could also have a bogus expected windows version
  315. // (treat 0 as invalid)
  316. //
  317. if (newexe.ne_expver == 0)
  318. {
  319. newexe.ne_magic = MZMAGIC; // just a DOS exe
  320. newexe.ne_expver = 0;
  321. }
  322. }
  323. else // if (newexe.ne_magic != NEMAGIC)
  324. {
  325. newexe.ne_magic = MZMAGIC; // just a DOS exe
  326. newexe.ne_expver = 0;
  327. }
  328. exit:
  329. CloseHandle(fh);
  330. return MAKELONG(newexe.ne_magic, newexe.ne_expver);
  331. error:
  332. CloseHandle(fh);
  333. return 0;
  334. }
  335. #define M_llseek(fh, lOff, iOrg) SetFilePointer((HANDLE)IntToPtr( fh ), lOff, NULL, (DWORD)iOrg)
  336. #define M_lread(fh, lpBuf, cb) _lread((HFILE)fh, lpBuf, cb)
  337. #define MAGIC_ICON30 0
  338. #define MAGIC_MARKZIBO ((WORD)'M'+((WORD)'Z'<<8))
  339. typedef struct new_exe NEWEXEHDR;
  340. typedef NEWEXEHDR *PNEWEXEHDR;
  341. #define SEEK_FROMZERO 0
  342. #define SEEK_FROMCURRENT 1
  343. #define SEEK_FROMEND 2
  344. #define NSMOVE 0x0010
  345. #define VER 0x0300
  346. #define CCHICONPATHMAXLEN 128
  347. typedef struct
  348. {
  349. HANDLE hAppInst;
  350. HANDLE hFileName;
  351. HANDLE hIconList;
  352. INT nIcons;
  353. } EXTRACTICONINFO;
  354. EXTRACTICONINFO ExtractIconInfo = {NULL, NULL, NULL, 0};
  355. INT nIcons;
  356. typedef struct
  357. {
  358. HICON hIcon;
  359. INT iIconId;
  360. } MYICONINFO;
  361. HANDLE APIENTRY InternalExtractIconW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex, UINT nIcons);
  362. HICON APIENTRY DuplicateIcon(HINSTANCE hInst, HICON hIcon)
  363. {
  364. ICONINFO IconInfo;
  365. if (!GetIconInfo(hIcon, &IconInfo))
  366. return NULL;
  367. hIcon = CreateIconIndirect(&IconInfo);
  368. DeleteObject(IconInfo.hbmMask);
  369. DeleteObject(IconInfo.hbmColor);
  370. UNREFERENCED_PARAMETER(hInst);
  371. return hIcon;
  372. }
  373. // This returns a pointer to the rsrc_nameinfo of the resource with the
  374. // given index and type, if it is found, otherwise it returns NULL.
  375. LPBYTE FindResWithIndex(LPBYTE lpResTable, INT iResIndex, LPBYTE lpResType)
  376. {
  377. try
  378. {
  379. LPRESTYPEINFO lpResTypeInfo = (LPRESTYPEINFO)(lpResTable + sizeof(WORD));
  380. while (lpResTypeInfo->rt_id)
  381. {
  382. if ((lpResTypeInfo->rt_id & RSORDID) &&
  383. (MAKEINTRESOURCE(lpResTypeInfo->rt_id & ~RSORDID) == (LPTSTR)lpResType))
  384. {
  385. if (lpResTypeInfo->rt_nres > (WORD)iResIndex)
  386. return((LPBYTE)(lpResTypeInfo+1) + iResIndex * sizeof(RESNAMEINFO));
  387. else
  388. return NULL;
  389. }
  390. lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres * sizeof(RESNAMEINFO));
  391. }
  392. return NULL;
  393. }
  394. except (EXCEPTION_EXECUTE_HANDLER)
  395. {
  396. return NULL;
  397. }
  398. }
  399. /* This returns the index (1-relative) of the given resource-id
  400. * in the resource table, if it is found, otherwise it returns NULL.
  401. */
  402. INT GetResIndex(LPBYTE lpResTable, INT iResId, LPBYTE lpResType)
  403. {
  404. WORD w;
  405. LPRESNAMEINFO lpResNameInfo;
  406. LPRESTYPEINFO lpResTypeInfo = (LPRESTYPEINFO)(lpResTable + sizeof(WORD));
  407. while (lpResTypeInfo->rt_id)
  408. {
  409. if ((lpResTypeInfo->rt_id & RSORDID) && (MAKEINTRESOURCE(lpResTypeInfo->rt_id & ~RSORDID) == (LPTSTR)lpResType))
  410. {
  411. lpResNameInfo = (LPRESNAMEINFO)(lpResTypeInfo+1);
  412. for (w=0; w < lpResTypeInfo->rt_nres; w++, lpResNameInfo++)
  413. {
  414. if ((lpResNameInfo->rn_id & RSORDID) && ((lpResNameInfo->rn_id & ~RSORDID) == iResId))
  415. return(w+1);
  416. }
  417. return 0;
  418. }
  419. lpResTypeInfo = (LPRESTYPEINFO)((LPBYTE)(lpResTypeInfo+1) + lpResTypeInfo->rt_nres * sizeof(RESNAMEINFO));
  420. }
  421. return 0;
  422. }
  423. HANDLE SimpleLoadResource(HFILE fh, LPBYTE lpResTable, INT iResIndex, LPBYTE lpResType)
  424. {
  425. INT iShiftCount;
  426. HICON hIcon;
  427. LPBYTE lpIcon;
  428. DWORD dwSize;
  429. DWORD dwOffset;
  430. LPRESNAMEINFO lpResPtr;
  431. /* The first 2 bytes in ResTable indicate the amount other values should be
  432. * shifted left.
  433. */
  434. iShiftCount = *((WORD *)lpResTable);
  435. lpResPtr = (LPRESNAMEINFO)FindResWithIndex(lpResTable, iResIndex, lpResType);
  436. if (!lpResPtr)
  437. return NULL;
  438. /* Left shift the offset to form a LONG. */
  439. dwOffset = MAKELONG(lpResPtr->rn_offset << iShiftCount, (lpResPtr->rn_offset) >> (16 - iShiftCount));
  440. dwSize = lpResPtr->rn_length << iShiftCount;
  441. if (M_llseek(fh, dwOffset, SEEK_FROMZERO) == -1L)
  442. return NULL;
  443. if (!(hIcon = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, dwSize)))
  444. return NULL;
  445. if (!(lpIcon = GlobalLock(hIcon)))
  446. goto SLRErr1;
  447. if (_lread(fh, (LPVOID)lpIcon, dwSize) < dwSize)
  448. goto SLRErr2;
  449. GlobalUnlock(hIcon);
  450. return hIcon;
  451. SLRErr2:
  452. GlobalUnlock(hIcon);
  453. SLRErr1:
  454. GlobalFree(hIcon);
  455. return NULL;
  456. }
  457. INT __cdecl CompareIconId(MYICONINFO *lpIconInfo1, MYICONINFO *lpIconInfo2)
  458. {
  459. return lpIconInfo1->iIconId - lpIconInfo2->iIconId;
  460. }
  461. VOID FreeIconList(HANDLE hIconList, int iKeepIcon)
  462. {
  463. MYICONINFO *lpIconList;
  464. INT i;
  465. if (ExtractIconInfo.hIconList == hIconList) {
  466. ExtractIconInfo.hIconList = NULL;
  467. }
  468. if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(hIconList))) {
  469. for (i = 0; i < ExtractIconInfo.nIcons; i++) {
  470. if (i != iKeepIcon) {
  471. DestroyIcon((lpIconList + i)->hIcon);
  472. }
  473. }
  474. GlobalUnlock(hIconList);
  475. GlobalFree(hIconList);
  476. }
  477. }
  478. VOID FreeExtractIconInfo(INT iKeepIcon)
  479. {
  480. MYICONINFO *lpIconList;
  481. INT i;
  482. if (ExtractIconInfo.hIconList) {
  483. if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(ExtractIconInfo.hIconList))) {
  484. for (i = 0; i < ExtractIconInfo.nIcons; i++) {
  485. if (i != iKeepIcon) {
  486. DestroyIcon((lpIconList + i)->hIcon);
  487. }
  488. }
  489. GlobalUnlock(ExtractIconInfo.hIconList);
  490. }
  491. GlobalFree(ExtractIconInfo.hIconList);
  492. ExtractIconInfo.hIconList = NULL;
  493. }
  494. ExtractIconInfo.hAppInst = NULL;
  495. ExtractIconInfo.nIcons = 0;
  496. if (ExtractIconInfo.hFileName) {
  497. GlobalFree(ExtractIconInfo.hFileName);
  498. ExtractIconInfo.hFileName = NULL;
  499. }
  500. }
  501. #ifdef UNICODE
  502. HICON APIENTRY ExtractIconA(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT nIconIndex)
  503. {
  504. if (lpszExeFileName) {
  505. LPWSTR lpszExeFileNameW;
  506. WORD wLen = lstrlenA(lpszExeFileName) + 1;
  507. if (!(lpszExeFileNameW = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (wLen * sizeof(WCHAR))))) {
  508. return NULL;
  509. } else {
  510. HICON hIcon;
  511. MultiByteToWideChar(CP_ACP, 0, lpszExeFileName, -1, lpszExeFileNameW, wLen-1);
  512. hIcon = ExtractIconW(hInst, lpszExeFileNameW, nIconIndex);
  513. LocalFree(lpszExeFileNameW);
  514. return hIcon;
  515. }
  516. } else {
  517. return NULL;
  518. }
  519. }
  520. #else
  521. HICON APIENTRY ExtractIconW(HINSTANCE hInst, LPCWSTR lpszExeFileName, UINT nIconIndex)
  522. {
  523. return NULL;
  524. }
  525. #endif
  526. // Returns a handle to a list of icons
  527. #ifdef UNICODE
  528. HANDLE APIENTRY InternalExtractIconListW(HANDLE hInst, LPWSTR lpszExeFileName, LPINT lpnIcons)
  529. {
  530. UINT cIcons, uiResult, i;
  531. UINT * lpIDs = NULL;
  532. HICON * lpIcons = NULL;
  533. HGLOBAL hIconInfo = NULL;
  534. MYICONINFO *lpIconInfo = NULL;
  535. //
  536. // Determine the number of icons
  537. //
  538. cIcons = PtrToUlong( ExtractIconW(hInst, lpszExeFileName, (UINT)-1));
  539. if (cIcons <= 0)
  540. return NULL;
  541. //
  542. // Allocate space for an array of UINT's and HICON's
  543. //
  544. lpIDs = GlobalAlloc(GPTR, cIcons * sizeof(UINT));
  545. if (!lpIDs) {
  546. goto IconList_Exit;
  547. }
  548. lpIcons = GlobalAlloc(GPTR, cIcons * sizeof(HICON));
  549. if (!lpIcons) {
  550. goto IconList_Exit;
  551. }
  552. //
  553. // Allocate space for the array of icons
  554. //
  555. hIconInfo = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, cIcons * sizeof(MYICONINFO));
  556. if (!hIconInfo) {
  557. goto IconList_Exit;
  558. }
  559. //
  560. // This has to be GlobalLock'ed since the handle is going to
  561. // be passed back to the application.
  562. //
  563. lpIconInfo = GlobalLock(hIconInfo);
  564. if (!lpIconInfo) {
  565. goto IconList_Exit;
  566. }
  567. //
  568. // Call ExtractIcons to do the real work.
  569. //
  570. uiResult = ExtractIcons(lpszExeFileName,
  571. 0,
  572. GetSystemMetrics(SM_CXICON),
  573. GetSystemMetrics(SM_CYICON),
  574. lpIcons,
  575. lpIDs,
  576. cIcons,
  577. 0);
  578. if (uiResult <= 0) {
  579. goto IconList_Exit;
  580. }
  581. //
  582. // Loop through the icons and fill in the array.
  583. //
  584. for (i=0; i < cIcons; i++) {
  585. lpIconInfo[i].hIcon = lpIcons[i];
  586. lpIconInfo[i].iIconId = lpIDs[i];
  587. }
  588. //
  589. // Unlock the array handle.
  590. //
  591. GlobalUnlock(hIconInfo);
  592. //
  593. // Clean up allocations
  594. //
  595. GlobalFree(lpIDs);
  596. GlobalFree(lpIcons);
  597. //
  598. // Success.
  599. //
  600. return hIconInfo;
  601. IconList_Exit:
  602. //
  603. // Error case. Clean up and return NULL
  604. //
  605. if (lpIconInfo)
  606. GlobalUnlock(hIconInfo);
  607. if (hIconInfo)
  608. GlobalFree(hIconInfo);
  609. if (lpIcons)
  610. GlobalFree(lpIcons);
  611. if (lpIDs)
  612. GlobalFree(lpIDs);
  613. return NULL;
  614. }
  615. #else // Unicode
  616. HANDLE APIENTRY InternalExtractIconListW(HANDLE hInst, LPWSTR lpszExeFileName, LPINT lpnIcons)
  617. {
  618. return NULL;
  619. }
  620. #endif
  621. HANDLE APIENTRY InternalExtractIconListA(HANDLE hInst, LPSTR lpszExeFileName, LPINT lpnIcons)
  622. {
  623. return NULL;
  624. }
  625. #ifdef UNICODE
  626. HANDLE APIENTRY InternalExtractIconA(HINSTANCE hInst, LPCSTR lpszExeFileName, UINT wIconIndex, UINT nIcons)
  627. {
  628. return NULL;
  629. }
  630. #endif
  631. /* ExtractVersionResource16W
  632. * Retrieves a resource from win16 images. Most of this code
  633. * is stolen from ExtractIconResInfoW in ..\library\extract.c
  634. *
  635. * LPWSTR lpwstrFilename - file to extract
  636. * LPHANDLE lpData - return buffer for handle, NULL if not needed
  637. *
  638. * Returns: size of buffer needed
  639. */
  640. DWORD ExtractVersionResource16W(LPCWSTR lpwstrFilename, LPHANDLE lphData)
  641. {
  642. HFILE fh;
  643. WORD wMagic;
  644. INT iTableSize;
  645. LPBYTE lpResTable;
  646. DWORD lOffset;
  647. HANDLE hResTable;
  648. NEWEXEHDR NEHeader;
  649. HANDLE hRes;
  650. DWORD dwSize =0;
  651. //
  652. // Try to open the specified file.
  653. //
  654. fh = HandleToLong(CreateFileW(lpwstrFilename,
  655. GENERIC_READ,
  656. FILE_SHARE_READ,
  657. NULL,
  658. OPEN_EXISTING,
  659. FILE_ATTRIBUTE_NORMAL,
  660. NULL));
  661. if (fh == HandleToLong(INVALID_HANDLE_VALUE)) {
  662. fh = HandleToLong(CreateFileW(lpwstrFilename,
  663. GENERIC_READ,
  664. 0,
  665. NULL,
  666. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  667. }
  668. if (fh == HandleToLong(INVALID_HANDLE_VALUE))
  669. return 0;
  670. //
  671. // Read the first two bytes in the file.
  672. //
  673. if (_lread(fh, (LPVOID)&wMagic, 2) != 2)
  674. goto EIExit;
  675. switch (wMagic) {
  676. case MAGIC_MARKZIBO:
  677. //
  678. // Make sure that the file is in the NEW EXE format.
  679. //
  680. if (M_llseek(fh, (LONG)0x3C, SEEK_FROMZERO) == -1L)
  681. goto EIExit;
  682. if (_lread(fh, (LPVOID)&lOffset, sizeof(LONG)) != sizeof(LONG))
  683. goto EIExit;
  684. if (lOffset == 0L)
  685. goto EIExit;
  686. //
  687. // Read in the EXE header.
  688. //
  689. if (M_llseek(fh, lOffset, SEEK_FROMZERO) == -1L)
  690. goto EIExit;
  691. if (_lread(fh, (LPVOID)&NEHeader, sizeof(NEWEXEHDR)) != sizeof(NEWEXEHDR))
  692. goto EIExit;
  693. //
  694. // Is it a NEW EXE?
  695. //
  696. if (NE_MAGIC(NEHeader) != NEMAGIC)
  697. goto EIExit;
  698. if ((NE_EXETYP(NEHeader) != NE_WINDOWS) &&
  699. (NE_EXETYP(NEHeader) != NE_DEV386) &&
  700. (NE_EXETYP(NEHeader) != NE_UNKNOWN)) /* Some Win2.X apps have NE_UNKNOWN in this field */
  701. goto EIExit;
  702. //
  703. // Are there any resources?
  704. //
  705. if (NE_RSRCTAB(NEHeader) == NE_RESTAB(NEHeader))
  706. goto EIExit;
  707. //
  708. // Allocate space for the resource table.
  709. //
  710. iTableSize = NE_RESTAB(NEHeader) - NE_RSRCTAB(NEHeader);
  711. hResTable = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, (DWORD)iTableSize);
  712. if (!hResTable)
  713. goto EIExit;
  714. //
  715. // Lock down the resource table.
  716. lpResTable = GlobalLock(hResTable);
  717. if (!lpResTable) {
  718. GlobalFree(hResTable);
  719. goto EIExit;
  720. }
  721. //
  722. // Copy the resource table into memory.
  723. //
  724. if (M_llseek(fh,
  725. (LONG)(lOffset + NE_RSRCTAB(NEHeader)),
  726. SEEK_FROMZERO) == -1) {
  727. goto EIErrExit;
  728. }
  729. if (_lread(fh, (LPBYTE)lpResTable, iTableSize) != (DWORD)iTableSize)
  730. goto EIErrExit;
  731. //
  732. // Simply load the specified icon.
  733. //
  734. hRes = SimpleLoadResource(fh, lpResTable, 0, (LPBYTE)RT_VERSION);
  735. if (hRes) {
  736. dwSize = (DWORD) GlobalSize(hRes);
  737. if (lphData) {
  738. *lphData = hRes;
  739. } else {
  740. GlobalFree(hRes);
  741. }
  742. }
  743. EIErrExit:
  744. GlobalUnlock(hResTable);
  745. GlobalFree(hResTable);
  746. break;
  747. }
  748. EIExit:
  749. _lclose(fh);
  750. return dwSize;
  751. }
  752. /* Returns the file's format: 2 for WIndows 2.X, 3 for WIndows 3.X, */
  753. /* 0 if error. */
  754. /* Returns the handle to the Icon resource corresponding to wIconIndex */
  755. /* in lphIconRes, and the size of the resource in lpwSize. */
  756. /* This is used only by Progman which needs to save the icon resource */
  757. /* itself in the .GRP files (the actual icon handle is not wanted). */
  758. /* */
  759. /* 08-04-91 JohanneC Created. */
  760. WORD APIENTRY ExtractIconResInfoW(HANDLE hInst, LPWSTR lpszFileName, WORD wIconIndex, LPWORD lpwSize, LPHANDLE lphIconRes)
  761. {
  762. HFILE fh;
  763. WORD wMagic;
  764. BOOL bNewResFormat;
  765. HANDLE hIconDir; /* Icon directory */
  766. LPBYTE lpIconDir;
  767. HICON hIcon = NULL;
  768. BOOL bFormatOK = FALSE;
  769. INT nIconId;
  770. WCHAR szFullPath[MAX_PATH];
  771. int cbPath;
  772. /* Try to open the specified file. */
  773. /* Try to open the specified file. */
  774. cbPath = SearchPathW(NULL, lpszFileName, NULL, MAX_PATH, szFullPath, NULL);
  775. if (cbPath == 0 || cbPath >= MAX_PATH)
  776. return 0;
  777. fh = HandleToLong(CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, FILE_SHARE_READ, NULL,
  778. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  779. if (fh == HandleToLong(INVALID_HANDLE_VALUE)) {
  780. fh = HandleToLong(CreateFileW((LPCWSTR)szFullPath, GENERIC_READ, 0, NULL,
  781. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
  782. }
  783. if (fh == HandleToLong(INVALID_HANDLE_VALUE))
  784. return 0;
  785. /* Read the first two bytes in the file. */
  786. if (_lread(fh, (LPVOID)&wMagic, 2) != 2)
  787. goto EIExit;
  788. switch (wMagic) {
  789. case MAGIC_ICON30:
  790. {
  791. INT i;
  792. LPVOID lpIcon;
  793. NEWHEADER NewHeader;
  794. LPNEWHEADER lpHeader;
  795. LPRESDIR lpResDir;
  796. RESDIRDISK ResDirDisk;
  797. #define MAXICONS 10
  798. DWORD Offsets[MAXICONS];
  799. /* Only one icon per .ICO file. */
  800. if (wIconIndex) {
  801. break;
  802. }
  803. /* Read the header and check if it is a valid ICO file. */
  804. if (_lread(fh, ((LPBYTE)&NewHeader)+2, sizeof(NEWHEADER)-2) != sizeof(NEWHEADER)-2)
  805. goto EICleanup1;
  806. NewHeader.Reserved = MAGIC_ICON30;
  807. /* Check if the file is in correct format */
  808. if (NewHeader.ResType != 1)
  809. goto EICleanup1;
  810. /* Allocate enough space to create a Global Directory Resource. */
  811. hIconDir = GlobalAlloc(GHND, (LONG)(sizeof(NEWHEADER)+NewHeader.ResCount*sizeof(RESDIR)));
  812. if (hIconDir == NULL)
  813. goto EICleanup1;
  814. if ((lpHeader = (LPNEWHEADER)GlobalLock(hIconDir)) == NULL)
  815. goto EICleanup2;
  816. NewHeader.ResCount = (WORD)min((int)NewHeader.ResCount, MAXICONS);
  817. // fill in this structure for user
  818. *lpHeader = NewHeader;
  819. // read in the stuff from disk, transfer it to a memory structure
  820. // that user can deal with
  821. lpResDir = (LPRESDIR)(lpHeader + 1);
  822. for (i = 0; (WORD)i < NewHeader.ResCount; i++) {
  823. if (_lread(fh, (LPVOID)&ResDirDisk, sizeof(RESDIRDISK)) < sizeof(RESDIR))
  824. goto EICleanup3;
  825. Offsets[i] = ResDirDisk.Offset;
  826. *lpResDir = *((LPRESDIR)&ResDirDisk);
  827. lpResDir->idIcon = (WORD)(i+1); // fill in the id
  828. lpResDir++;
  829. }
  830. /* Now that we have the Complete resource directory, let us find out the
  831. * suitable form of icon (that matches the current display driver).
  832. */
  833. lpIconDir = GlobalLock(hIconDir);
  834. if (!lpIconDir) {
  835. GlobalFree(hIconDir);
  836. goto EIErrExit;
  837. }
  838. wIconIndex = (WORD)(LookupIconIdFromDirectory(lpIconDir, TRUE) - 1);
  839. GlobalUnlock(hIconDir);
  840. lpResDir = (LPRESDIR)(lpHeader+1) + wIconIndex;
  841. /* Allocate memory for the Resource to be loaded. */
  842. if ((hIcon = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE, (DWORD)lpResDir->BytesInRes)) == NULL)
  843. goto EICleanup3;
  844. if ((lpIcon = GlobalLock(hIcon)) == NULL)
  845. goto EICleanup4;
  846. /* Seek to the correct place and read in the resource */
  847. if (M_llseek(fh, Offsets[wIconIndex], SEEK_FROMZERO) == -1L)
  848. goto EICleanup5;
  849. if (_lread(fh, (LPVOID)lpIcon, (DWORD)lpResDir->BytesInRes) < lpResDir->BytesInRes)
  850. goto EICleanup5;
  851. GlobalUnlock(hIcon);
  852. *lphIconRes = hIcon;
  853. *lpwSize = (WORD)lpResDir->BytesInRes;
  854. bFormatOK = TRUE;
  855. bNewResFormat = TRUE;
  856. goto EICleanup3;
  857. EICleanup5:
  858. GlobalUnlock(hIcon);
  859. EICleanup4:
  860. GlobalFree(hIcon);
  861. hIcon = (HICON)1;
  862. EICleanup3:
  863. GlobalUnlock(hIconDir);
  864. EICleanup2:
  865. GlobalFree(hIconDir);
  866. EICleanup1:
  867. break;
  868. }
  869. case MAGIC_MARKZIBO:
  870. {
  871. INT iTableSize;
  872. LPBYTE lpResTable;
  873. DWORD lOffset;
  874. HANDLE hResTable;
  875. NEWEXEHDR NEHeader;
  876. /* Make sure that the file is in the NEW EXE format. */
  877. if (M_llseek(fh, (LONG)0x3C, SEEK_FROMZERO) == -1L)
  878. goto EIExit;
  879. if (_lread(fh, (LPVOID)&lOffset, sizeof(LONG)) != sizeof(LONG))
  880. goto EIExit;
  881. if (lOffset == 0L)
  882. goto EIExit;
  883. /* Read in the EXE header. */
  884. if (M_llseek(fh, lOffset, SEEK_FROMZERO) == -1L)
  885. goto EIExit;
  886. if (_lread(fh, (LPVOID)&NEHeader, sizeof(NEWEXEHDR)) != sizeof(NEWEXEHDR))
  887. goto EIExit;
  888. /* Is it a NEW EXE? */
  889. if (NE_MAGIC(NEHeader) != NEMAGIC)
  890. goto EIExit;
  891. if ((NE_EXETYP(NEHeader) != NE_WINDOWS) &&
  892. (NE_EXETYP(NEHeader) != NE_DEV386) &&
  893. (NE_EXETYP(NEHeader) != NE_UNKNOWN)) /* Some Win2.X apps have NE_UNKNOWN in this field */
  894. goto EIExit;
  895. hIcon = NULL;
  896. /* Are there any resources? */
  897. if (NE_RSRCTAB(NEHeader) == NE_RESTAB(NEHeader))
  898. goto EIExit;
  899. /* Remember whether or not this is a Win3.0 EXE. */
  900. bNewResFormat = (NEHeader.ne_expver >= VER);
  901. /* Allocate space for the resource table. */
  902. iTableSize = NE_RESTAB(NEHeader) - NE_RSRCTAB(NEHeader);
  903. hResTable = GlobalAlloc(GMEM_ZEROINIT, (DWORD)iTableSize);
  904. if (!hResTable)
  905. goto EIExit;
  906. /* Lock down the resource table. */
  907. lpResTable = GlobalLock(hResTable);
  908. if (!lpResTable) {
  909. GlobalFree(hResTable);
  910. goto EIExit;
  911. }
  912. /* Copy the resource table into memory. */
  913. if (M_llseek(fh, (LONG)(lOffset + NE_RSRCTAB(NEHeader)), SEEK_FROMZERO) == -1)
  914. goto EIErrExit;
  915. if (_lread(fh, (LPBYTE)lpResTable, iTableSize) != (DWORD)iTableSize)
  916. goto EIErrExit;
  917. /* Is this a Win3.0 EXE? */
  918. if (bNewResFormat) {
  919. /* First, load the Icon directory. */
  920. hIconDir = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_GROUP_ICON);
  921. if (!hIconDir)
  922. goto EIErrExit;
  923. lpIconDir = GlobalLock(hIconDir);
  924. if (!lpIconDir) {
  925. GlobalFree(hIconDir);
  926. goto EIErrExit;
  927. }
  928. nIconId = LookupIconIdFromDirectory(lpIconDir, TRUE);
  929. wIconIndex = (WORD)(GetResIndex(lpResTable, nIconId, (LPBYTE)RT_ICON) - 1);
  930. GlobalUnlock(hIconDir);
  931. /* We're finished with the icon directory. */
  932. GlobalFree(hIconDir);
  933. /* Now load the selected icon. */
  934. *lphIconRes = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_ICON);
  935. }
  936. else {
  937. /* Simply load the specified icon. */
  938. *lphIconRes = SimpleLoadResource(fh, lpResTable, (int)wIconIndex, (LPBYTE)RT_ICON);
  939. }
  940. if (*lphIconRes) {
  941. *lpwSize = (WORD)GlobalSize(*lphIconRes);
  942. }
  943. bFormatOK = TRUE;
  944. EIErrExit:
  945. GlobalUnlock(hResTable);
  946. GlobalFree(hResTable);
  947. break;
  948. }
  949. }
  950. EIExit:
  951. _lclose(fh);
  952. hInst;
  953. if (bFormatOK)
  954. return (WORD)(bNewResFormat ? 3 : 2);
  955. else
  956. return 0;
  957. }
  958. WORD APIENTRY ExtractIconResInfoA(HANDLE hInst, LPSTR lpszFileName, WORD wIconIndex, LPWORD lpwSize, LPHANDLE lphIconRes)
  959. {
  960. if (lpszFileName)
  961. {
  962. LPWSTR lpszFileNameW;
  963. WORD wLen = lstrlenA(lpszFileName) + 1;
  964. if (!(lpszFileNameW = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, (wLen * sizeof(WCHAR)))))
  965. {
  966. return 0;
  967. }
  968. else
  969. {
  970. WORD wRet;
  971. MultiByteToWideChar(CP_ACP, 0, lpszFileName, -1, lpszFileNameW, wLen - 1);
  972. wRet = ExtractIconResInfoW(hInst, lpszFileNameW, wIconIndex, lpwSize, lphIconRes);
  973. LocalFree(lpszFileNameW);
  974. return wRet;
  975. }
  976. }
  977. else
  978. {
  979. return 0;
  980. }
  981. }
  982. LPCWSTR HasAnyExtension(LPCWSTR lpszPath)
  983. {
  984. LPCWSTR p;
  985. for (p = lpszPath + lstrlenW(lpszPath); p > lpszPath && *p != L'.' && *p != L'\\'; p--)
  986. {
  987. // do nothing
  988. }
  989. if (*p == L'.')
  990. return p+1;
  991. else
  992. return NULL;
  993. }
  994. //
  995. // in:
  996. // lpIconPath path of thing to extract icon for (may be an exe
  997. // or something that is associated)
  998. // lpiIconIndex icon index to use
  999. //
  1000. // out:
  1001. // lpIconPath filled in with the real path where the icon came from
  1002. // lpiIconIndex filled in with the real icon index
  1003. // lpiIconId filled in with the icon id
  1004. //
  1005. // returns:
  1006. // icon handle
  1007. //
  1008. // note: if the caller is progman it returns special icons from within progman
  1009. //
  1010. //
  1011. #if defined(UNICODE)
  1012. HICON APIENTRY ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
  1013. {
  1014. WCHAR wszExePath[MAX_PATH];
  1015. HICON hIcon;
  1016. UINT idIcon = (UINT)-1; // Don't know value
  1017. BOOL fAssociated = FALSE;
  1018. if ((INT)*lpiIconIndex == -1)
  1019. return (HICON)NULL;
  1020. Retry:
  1021. ExtractIcons(lpIconPath, *lpiIconIndex, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
  1022. &hIcon, &idIcon, 1, 0);
  1023. if (hIcon == NULL)
  1024. {
  1025. wszExePath[0] = TEXT('\0');
  1026. FindExecutable(lpIconPath,NULL,wszExePath);
  1027. //
  1028. // If FindExecutable fails, or fAssociated
  1029. // is true, or FindExecutable returns the
  1030. // extact same filename it was looking for,
  1031. // then issue the default icon from progman.
  1032. //
  1033. if (!*wszExePath || fAssociated ||
  1034. (*wszExePath && (lstrcmpi(lpIconPath, wszExePath) == 0)))
  1035. {
  1036. LPTSTR lpId;
  1037. WORD wDefIconId;
  1038. HANDLE h;
  1039. LPVOID p;
  1040. //
  1041. // Magic values from NT's old progman
  1042. //
  1043. #define ITEMICON 7
  1044. #define DOSAPPICON 2
  1045. #define ITEMICONINDEX 6
  1046. #define DOSAPPICONINDEX 1
  1047. if ( *wszExePath && (HasExtension(wszExePath) == 0) )
  1048. {
  1049. //
  1050. // Generic Document icon processing
  1051. //
  1052. lpId = MAKEINTRESOURCE(ITEMICON);
  1053. wDefIconId = ITEMICONINDEX;
  1054. }
  1055. else
  1056. {
  1057. //
  1058. // Generic Program icon processing
  1059. //
  1060. lpId = MAKEINTRESOURCE(DOSAPPICON);
  1061. wDefIconId = DOSAPPICONINDEX;
  1062. }
  1063. GetModuleFileName(hInst, lpIconPath, CCHICONPATHMAXLEN);
  1064. /*
  1065. * Look up the icon id from the directory.
  1066. */
  1067. if (NULL != (h = FindResource(hInst, lpId, RT_GROUP_ICON))) {
  1068. h = LoadResource(hInst, h);
  1069. p = LockResource(h);
  1070. *lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
  1071. UnlockResource(h);
  1072. FreeResource(h);
  1073. }
  1074. *lpiIconIndex = wDefIconId;
  1075. return LoadIcon(hInst, lpId);
  1076. }
  1077. SheRemoveQuotes(wszExePath);
  1078. lstrcpy(lpIconPath,wszExePath);
  1079. fAssociated = TRUE;
  1080. goto Retry;
  1081. }
  1082. *lpiIconId = (WORD) idIcon; // Fill in with whatever we've found (or -1)
  1083. return hIcon;
  1084. }
  1085. #else // defined(UNICODE)
  1086. HICON APIENTRY ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
  1087. {
  1088. HICON hIcon = NULL;
  1089. WCHAR szIconExe[MAX_PATH];
  1090. HANDLE hIconList = NULL;
  1091. MYICONINFO *lpIconList;
  1092. HANDLE h;
  1093. PBYTE p;
  1094. DWORD dwBinaryType;
  1095. BOOL bRet;
  1096. int cIcons;
  1097. #define ITEMICON 7 // taken from progman!
  1098. #define DOSAPPICON 2
  1099. #define ITEMICONINDEX 6
  1100. #define DOSAPPICONINDEX 1
  1101. if (!lpIconPath)
  1102. return NULL;
  1103. FreeExtractIconInfo(-1);
  1104. hIcon = ExtractIconW(hInst, lpIconPath, (UINT)*lpiIconIndex);
  1105. if (!hIcon)
  1106. {
  1107. // lpIconPath is a windows EXE, no icons found
  1108. GenericDocument:
  1109. FreeExtractIconInfo(-1);
  1110. GetModuleFileNameW(hInst, lpIconPath, CCHICONPATHMAXLEN);
  1111. // Look up the icon id from the directory.
  1112. if (NULL != (h = FindResource(hInst, MAKEINTRESOURCE(ITEMICON), RT_GROUP_ICON)))
  1113. {
  1114. h = LoadResource(hInst, h);
  1115. if (h != NULL)
  1116. {
  1117. p = LockResource(h);
  1118. if (p != NULL)
  1119. {
  1120. *lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
  1121. UnlockResource(h);
  1122. }
  1123. FreeResource(h);
  1124. }
  1125. }
  1126. *lpiIconIndex = ITEMICONINDEX;
  1127. return LoadIcon(hInst, MAKEINTRESOURCE(ITEMICON));
  1128. }
  1129. if ((int)hIcon == 1)
  1130. {
  1131. // lpIconPath is not a windows EXE
  1132. // this fills in szIconExe with the thing that would be exected
  1133. // for lpIconPath (applying associations)
  1134. FindExecutableW(lpIconPath, NULL, szIconExe);
  1135. if (!*szIconExe)
  1136. {
  1137. // not associated, assume things with extension are
  1138. // programs, things without are documents
  1139. if (!HasAnyExtension(lpIconPath))
  1140. goto GenericDocument;
  1141. else
  1142. goto GenericProgram;
  1143. }
  1144. //
  1145. // If FindExecutable returned an icon path with quotes, we must
  1146. // remove them because ExtractIcon fails with quoted paths.
  1147. //
  1148. SheRemoveQuotesW(szIconExe);
  1149. lstrcpyW(lpIconPath, szIconExe);
  1150. if (!HasAnyExtension(lpIconPath))
  1151. lstrcatW(lpIconPath, L".EXE");
  1152. hIcon = ExtractIconW(hInst, lpIconPath, (UINT)*lpiIconIndex);
  1153. if (!hIcon)
  1154. goto GenericDocument;
  1155. if ((int)hIcon == 1)
  1156. {
  1157. // this is a DOS exe
  1158. GenericProgram:
  1159. FreeExtractIconInfo(-1);
  1160. GetModuleFileNameW(hInst, lpIconPath, CCHICONPATHMAXLEN);
  1161. // Look up the icon id from the directory.
  1162. if (NULL != (h = FindResource(hInst, MAKEINTRESOURCE(DOSAPPICON), RT_GROUP_ICON)))
  1163. {
  1164. h = LoadResource(hInst, h);
  1165. if (h != NULL)
  1166. {
  1167. p = LockResource(h);
  1168. if ( p != NULL)
  1169. {
  1170. *lpiIconId = (WORD)LookupIconIdFromDirectory(p, TRUE);
  1171. UnlockResource(h);
  1172. }
  1173. FreeResource(h);
  1174. }
  1175. }
  1176. *lpiIconIndex = DOSAPPICONINDEX;
  1177. return LoadIcon(hInst, MAKEINTRESOURCE(DOSAPPICON));
  1178. }
  1179. else
  1180. {
  1181. goto GotIcon;
  1182. }
  1183. }
  1184. else
  1185. {
  1186. GotIcon:
  1187. bRet = GetBinaryTypeW(lpIconPath, &dwBinaryType);
  1188. if (bRet)
  1189. {
  1190. if (dwBinaryType != SCS_32BIT_BINARY)
  1191. {
  1192. *lpiIconId = *lpiIconIndex;
  1193. return hIcon;
  1194. }
  1195. }
  1196. ExtractIconW(hInst, lpIconPath, (UINT)-1);
  1197. if (NULL == (hIconList = ExtractIconInfo.hIconList))
  1198. return hIcon;
  1199. // since the icon exe is a WIN32 app, then we must update *lpiIcon.
  1200. if (NULL != (hIconList = InternalExtractIconListW(hInst, lpIconPath, &cIcons)))
  1201. {
  1202. if (NULL != (lpIconList = (MYICONINFO *)GlobalLock(hIconList)))
  1203. {
  1204. hIcon = (lpIconList + *lpiIconIndex)->hIcon;
  1205. *lpiIconId = (lpIconList + *lpiIconIndex)->iIconId;
  1206. GlobalUnlock(hIconList);
  1207. }
  1208. FreeIconList(hIconList, *lpiIconIndex);
  1209. return hIcon;
  1210. }
  1211. }
  1212. return hIcon;
  1213. }
  1214. #endif
  1215. HICON APIENTRY ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIndex, LPWORD lpiIconId)
  1216. {
  1217. HICON hIcon = NULL;
  1218. if (lpIconPath)
  1219. {
  1220. BOOL fDefCharUsed;
  1221. WCHAR IconPathW[MAX_PATH] = L"";
  1222. MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1 , (LPWSTR)IconPathW, MAX_PATH);
  1223. hIcon = ExtractAssociatedIconExW(hInst, (LPWSTR)IconPathW, lpiIconIndex, lpiIconId);
  1224. try
  1225. {
  1226. WideCharToMultiByte(CP_ACP, 0, (LPWSTR)IconPathW, -1, lpIconPath, CCHICONPATHMAXLEN,
  1227. NULL, &fDefCharUsed);
  1228. }
  1229. except(EXCEPTION_EXECUTE_HANDLER)
  1230. {
  1231. hIcon = NULL;
  1232. }
  1233. }
  1234. return hIcon;
  1235. }
  1236. //
  1237. // in:
  1238. // lpIconPath path of thing to extract icon for (may be an exe
  1239. // or something that is associated)
  1240. // lpiIcon icon index to use
  1241. //
  1242. // out:
  1243. // lpIconPath filled in with the real path where the icon came from
  1244. // lpiIcon filled in with the real icon index
  1245. //
  1246. // returns:
  1247. // icon handle
  1248. //
  1249. // note: if the caller is progman it returns special icons from within progman
  1250. //
  1251. //
  1252. #ifdef UNICODE
  1253. HICON APIENTRY ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
  1254. {
  1255. HICON hIcon = NULL;
  1256. if (lpIconPath)
  1257. {
  1258. BOOL fDefCharUsed;
  1259. WCHAR IconPathW[MAX_PATH] = L"";
  1260. MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1 , (LPWSTR)IconPathW, MAX_PATH);
  1261. hIcon = ExtractAssociatedIconW(hInst, (LPWSTR)IconPathW, lpiIcon);
  1262. try
  1263. {
  1264. WideCharToMultiByte(CP_ACP, 0, (LPWSTR)IconPathW, -1, lpIconPath, CCHICONPATHMAXLEN,
  1265. NULL, &fDefCharUsed);
  1266. }
  1267. except(EXCEPTION_EXECUTE_HANDLER)
  1268. {
  1269. hIcon = NULL;
  1270. }
  1271. }
  1272. return hIcon;
  1273. }
  1274. #endif