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.

1332 lines
42 KiB

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