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.

690 lines
23 KiB

  1. /*
  2. * DRAWICON.CPP
  3. *
  4. * Functions to handle creation of metafiles with icons and labels
  5. * as well as functions to draw such metafiles with or without the label.
  6. *
  7. * The metafile is created with a comment that marks the records containing
  8. * the label code. Drawing the metafile enumerates the records, draws
  9. * all records up to that point, then decides to either skip the label
  10. * or draw it.
  11. *
  12. * Copyright (c)1992 Microsoft Corporation, All Right Reserved
  13. */
  14. #include "precomp.h"
  15. #include "utility.h"
  16. #include "malloc.h"
  17. // Private implementation
  18. //Structure for label and source extraction from a metafile
  19. typedef struct tagLABELEXTRACT
  20. {
  21. LPTSTR lpsz;
  22. UINT Index; // index in lpsz (so we can retrieve 2+ lines)
  23. DWORD PrevIndex; // index of last line (so we can mimic word wrap)
  24. union
  25. {
  26. UINT cch; //Length of label for label extraction
  27. UINT iIcon; //Index of icon in source extraction.
  28. } u;
  29. //For internal use in enum procs
  30. BOOL fFoundIconOnly;
  31. BOOL fFoundSource;
  32. BOOL fFoundIndex;
  33. } LABELEXTRACT, FAR * LPLABELEXTRACT;
  34. //Structure for extracting icons from a metafile (CreateIcon parameters)
  35. typedef struct tagICONEXTRACT
  36. {
  37. HICON hIcon; //Icon created in the enumeration proc.
  38. /*
  39. * Since we want to handle multitasking well we have the caller
  40. * of the enumeration proc instantiate these variables instead of
  41. * using statics in the enum proc (which would be bad).
  42. */
  43. BOOL fAND;
  44. HGLOBAL hMemAND; //Enumeration proc allocates and copies
  45. } ICONEXTRACT, FAR * LPICONEXTRACT;
  46. //Structure to use to pass info to EnumMetafileDraw
  47. typedef struct tagDRAWINFO
  48. {
  49. RECT Rect;
  50. BOOL fIconOnly;
  51. } DRAWINFO, FAR * LPDRAWINFO;
  52. int CALLBACK EnumMetafileIconDraw(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPARAM);
  53. int CALLBACK EnumMetafileExtractLabel(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);
  54. int CALLBACK EnumMetafileExtractIcon(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPICONEXTRACT);
  55. int CALLBACK EnumMetafileExtractIconSource(HDC, HANDLETABLE FAR *, METARECORD FAR *, int, LPLABELEXTRACT);
  56. /*
  57. * Strings for metafile comments. KEEP THESE IN SYNC WITH THE
  58. * STRINGS IN GETICON.CPP
  59. */
  60. static const char szIconOnly[] = "IconOnly"; // Where to stop to exclude label.
  61. /*
  62. * OleUIMetafilePictIconFree
  63. *
  64. * Purpose:
  65. * Deletes the metafile contained in a METAFILEPICT structure and
  66. * frees the memory for the structure itself.
  67. *
  68. * Parameters:
  69. * hMetaPict HGLOBAL metafilepict structure created in
  70. * OleMetafilePictFromIconAndLabel
  71. *
  72. * Return Value:
  73. * None
  74. */
  75. STDAPI_(void) OleUIMetafilePictIconFree(HGLOBAL hMetaPict)
  76. {
  77. if (NULL != hMetaPict)
  78. {
  79. STGMEDIUM stgMedium;
  80. stgMedium.tymed = TYMED_MFPICT;
  81. stgMedium.hMetaFilePict = hMetaPict;
  82. stgMedium.pUnkForRelease = NULL;
  83. ReleaseStgMedium(&stgMedium);
  84. }
  85. }
  86. /*
  87. * OleUIMetafilePictIconDraw
  88. *
  89. * Purpose:
  90. * Draws the metafile from OleMetafilePictFromIconAndLabel, either with
  91. * the label or without.
  92. *
  93. * Parameters:
  94. * hDC HDC on which to draw.
  95. * pRect LPRECT in which to draw the metafile.
  96. * hMetaPict HGLOBAL to the METAFILEPICT from
  97. * OleMetafilePictFromIconAndLabel
  98. * fIconOnly BOOL specifying to draw the label or not.
  99. *
  100. * Return Value:
  101. * BOOL TRUE if the function is successful, FALSE if the
  102. * given metafilepict is invalid.
  103. */
  104. STDAPI_(BOOL) OleUIMetafilePictIconDraw(HDC hDC, LPCRECT pRect,
  105. HGLOBAL hMetaPict, BOOL fIconOnly)
  106. {
  107. if (NULL == hMetaPict)
  108. return FALSE;
  109. LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMetaPict);
  110. if (NULL == pMF)
  111. return FALSE;
  112. DRAWINFO di;
  113. di.Rect = *pRect;
  114. di.fIconOnly = fIconOnly;
  115. //Transform to back to pixels
  116. int cx = XformWidthInHimetricToPixels(hDC, pMF->xExt);
  117. int cy = XformHeightInHimetricToPixels(hDC, pMF->yExt);
  118. SaveDC(hDC);
  119. SetMapMode(hDC, pMF->mm);
  120. SetViewportOrgEx(hDC, (pRect->right - cx) / 2, 0, NULL);
  121. SetViewportExtEx(hDC, min ((pRect->right - cx) / 2 + cx, cx), cy, NULL);
  122. if (fIconOnly)
  123. EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileIconDraw, (LPARAM)&di);
  124. else
  125. PlayMetaFile(hDC, pMF->hMF);
  126. RestoreDC(hDC, -1);
  127. GlobalUnlock(hMetaPict);
  128. return TRUE;
  129. }
  130. /*
  131. * EnumMetafileIconDraw
  132. *
  133. * Purpose:
  134. * EnumMetaFile callback function that draws either the icon only or
  135. * the icon and label depending on given flags.
  136. *
  137. * Parameters:
  138. * hDC HDC into which the metafile should be played.
  139. * phTable HANDLETABLE FAR * providing handles selected into the DC.
  140. * pMFR METARECORD FAR * giving the enumerated record.
  141. * lParam LPARAM flags passed in EnumMetaFile.
  142. *
  143. * Return Value:
  144. * int 0 to stop enumeration, 1 to continue.
  145. */
  146. int CALLBACK EnumMetafileIconDraw(HDC hDC, HANDLETABLE FAR *phTable,
  147. METARECORD FAR *pMFR, int cObj, LPARAM lParam)
  148. {
  149. LPDRAWINFO lpdi = (LPDRAWINFO)lParam;
  150. /*
  151. * We play everything blindly except for DIBBITBLT (or DIBSTRETCHBLT)
  152. * and ESCAPE with MFCOMMENT. For the BitBlts we change the x,y to
  153. * draw at (0,0) instead of wherever it was written to draw. The
  154. * comment tells us there to stop if we don't want to draw the label.
  155. */
  156. //If we're playing icon only, stop enumeration at the comment.
  157. if (lpdi->fIconOnly)
  158. {
  159. if (META_ESCAPE==pMFR->rdFunction && MFCOMMENT==pMFR->rdParm[0])
  160. {
  161. if (0 == lstrcmpiA(szIconOnly, (LPSTR)&pMFR->rdParm[2]))
  162. return 0;
  163. }
  164. /*
  165. * Check for the records in which we want to munge the coordinates.
  166. * destX is offset 6 for BitBlt, offset 9 for StretchBlt, either of
  167. * which may appear in the metafile.
  168. */
  169. if (META_DIBBITBLT == pMFR->rdFunction)
  170. pMFR->rdParm[6]=0;
  171. if (META_DIBSTRETCHBLT == pMFR->rdFunction)
  172. pMFR->rdParm[9] = 0;
  173. }
  174. PlayMetaFileRecord(hDC, phTable, pMFR, cObj);
  175. return 1;
  176. }
  177. /*
  178. * OleUIMetafilePictExtractLabel
  179. *
  180. * Purpose:
  181. * Retrieves the label string from metafile representation of an icon.
  182. *
  183. * Parameters:
  184. * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
  185. * lpszLabel LPSTR in which to store the label.
  186. * cchLabel UINT length of lpszLabel.
  187. * lpWrapIndex DWORD index of first character in last line. Can be NULL
  188. * if calling function doesn't care about word wrap.
  189. *
  190. * Return Value:
  191. * UINT Number of characters copied.
  192. */
  193. STDAPI_(UINT) OleUIMetafilePictExtractLabel(HGLOBAL hMetaPict, LPTSTR lpszLabel,
  194. UINT cchLabel, LPDWORD lpWrapIndex)
  195. {
  196. if (NULL == hMetaPict || NULL == lpszLabel || 0 == cchLabel)
  197. return FALSE;
  198. /*
  199. * We extract the label by getting a screen DC and walking the metafile
  200. * records until we see the ExtTextOut record we put there. That
  201. * record will have the string embedded in it which we then copy out.
  202. */
  203. LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMetaPict);
  204. if (NULL == pMF)
  205. return FALSE;
  206. LABELEXTRACT le;
  207. le.lpsz=lpszLabel;
  208. le.u.cch=cchLabel;
  209. le.Index=0;
  210. le.fFoundIconOnly=FALSE;
  211. le.fFoundSource=FALSE; //Unused for this function.
  212. le.fFoundIndex=FALSE; //Unused for this function.
  213. le.PrevIndex = 0;
  214. //Use a screen DC so we have something valid to pass in.
  215. HDC hDC = GetDC(NULL);
  216. if (hDC)
  217. {
  218. EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractLabel, (LPARAM)(LPLABELEXTRACT)&le);
  219. ReleaseDC(NULL, hDC);
  220. } else {
  221. le.u.cch = 0;
  222. lpszLabel[0] = NULL;
  223. }
  224. GlobalUnlock(hMetaPict);
  225. //Tell where we wrapped (if calling function cares)
  226. if (NULL != lpWrapIndex)
  227. *lpWrapIndex = le.PrevIndex;
  228. //Return amount of text copied
  229. return le.u.cch;
  230. }
  231. /*
  232. * EnumMetafileExtractLabel
  233. *
  234. * Purpose:
  235. * EnumMetaFile callback function that walks a metafile looking for
  236. * ExtTextOut, then concatenates the text from each one into a buffer
  237. * in lParam.
  238. *
  239. * Parameters:
  240. * hDC HDC into which the metafile should be played.
  241. * phTable HANDLETABLE FAR * providing handles selected into the DC.
  242. * pMFR METARECORD FAR * giving the enumerated record.
  243. * pLE LPLABELEXTRACT providing the destination buffer and length.
  244. *
  245. * Return Value:
  246. * int 0 to stop enumeration, 1 to continue.
  247. */
  248. int CALLBACK EnumMetafileExtractLabel(HDC hDC, HANDLETABLE FAR *phTable,
  249. METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)
  250. {
  251. /*
  252. * We don't allow anything to happen until we see "IconOnly"
  253. * in an MFCOMMENT that is used to enable everything else.
  254. */
  255. if (!pLE->fFoundIconOnly)
  256. {
  257. if (META_ESCAPE == pMFR->rdFunction && MFCOMMENT == pMFR->rdParm[0])
  258. {
  259. if (0 == lstrcmpiA(szIconOnly, (LPSTR)&pMFR->rdParm[2]))
  260. pLE->fFoundIconOnly=TRUE;
  261. }
  262. return 1;
  263. }
  264. //Enumerate all records looking for META_EXTTEXTOUT - there can be more
  265. //than one.
  266. if (META_EXTTEXTOUT == pMFR->rdFunction)
  267. {
  268. /*
  269. * If ExtTextOut has NULL fuOptions, then the rectangle is omitted
  270. * from the record, and the string starts at rdParm[4]. If
  271. * fuOptions is non-NULL, then the string starts at rdParm[8]
  272. * (since the rectange takes up four WORDs in the array). In
  273. * both cases, the string continues for (rdParm[2]+1) >> 1
  274. * words. We just cast a pointer to rdParm[8] to an LPSTR and
  275. * lstrcpyn into the buffer we were given.
  276. *
  277. * Note that we use element 8 in rdParm instead of 4 because we
  278. * passed ETO_CLIPPED in for the options on ExtTextOut--docs say
  279. * [4] which is rect doesn't exist if we passed zero there.
  280. *
  281. */
  282. UINT cchMax = min(pLE->u.cch - pLE->Index, (UINT)pMFR->rdParm[2]);
  283. LPTSTR lpszTemp = pLE->lpsz + pLE->Index;
  284. #ifdef _UNICODE
  285. MultiByteToWideChar(CP_ACP, 0, (LPSTR)&pMFR->rdParm[8], cchMax,
  286. lpszTemp, cchMax+1);
  287. #else
  288. lstrcpyn(lpszTemp, (LPSTR)&pMFR->rdParm[8], cchMax+1);
  289. #endif
  290. lpszTemp[cchMax+1] = 0;
  291. pLE->PrevIndex = pLE->Index;
  292. pLE->Index += cchMax;
  293. }
  294. return 1;
  295. }
  296. /*
  297. * OleUIMetafilePictExtractIcon
  298. *
  299. * Purpose:
  300. * Retrieves the icon from metafile into which DrawIcon was done before.
  301. *
  302. * Parameters:
  303. * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
  304. *
  305. * Return Value:
  306. * HICON Icon recreated from the data in the metafile.
  307. */
  308. STDAPI_(HICON) OleUIMetafilePictExtractIcon(HGLOBAL hMetaPict)
  309. {
  310. if (NULL == hMetaPict)
  311. return NULL;
  312. /*
  313. * We extract the label by getting a screen DC and walking the metafile
  314. * records until we see the ExtTextOut record we put there. That
  315. * record will have the string embedded in it which we then copy out.
  316. */
  317. LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMetaPict);
  318. if (NULL == pMF)
  319. return FALSE;
  320. ICONEXTRACT ie;
  321. ie.fAND = TRUE;
  322. ie.hIcon = NULL;
  323. //Use a screen DC so we have something valid to pass in.
  324. HDC hDC=GetDC(NULL);
  325. if (hDC != NULL)
  326. {
  327. EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIcon, (LPARAM)&ie);
  328. ReleaseDC(NULL, hDC);
  329. }
  330. GlobalUnlock(hMetaPict);
  331. return ie.hIcon;
  332. }
  333. /*
  334. * EnumMetafileExtractIcon
  335. *
  336. * Purpose:
  337. * EnumMetaFile callback function that walks a metafile looking for
  338. * StretchBlt (3.1) and BitBlt (3.0) records. We expect to see two
  339. * of them, the first being the AND mask and the second being the XOR
  340. * data. We
  341. * ExtTextOut, then copies the text into a buffer in lParam.
  342. *
  343. * Parameters:
  344. * hDC HDC into which the metafile should be played.
  345. * phTable HANDLETABLE FAR * providing handles selected into the DC.
  346. * pMFR METARECORD FAR * giving the enumerated record.
  347. * pIE LPICONEXTRACT providing the destination buffer and length.
  348. *
  349. * Return Value:
  350. * int 0 to stop enumeration, 1 to continue.
  351. */
  352. int CALLBACK EnumMetafileExtractIcon(HDC hDC, HANDLETABLE FAR *phTable,
  353. METARECORD FAR *pMFR, int cObj, LPICONEXTRACT pIE)
  354. {
  355. //Continue enumeration if we don't see the records we want.
  356. if (META_DIBBITBLT != pMFR->rdFunction && META_DIBSTRETCHBLT != pMFR->rdFunction)
  357. return 1;
  358. UNALIGNED BITMAPINFO* lpBI;
  359. UINT uWidth, uHeight;
  360. /*
  361. * Windows 3.0 DrawIcon uses META_DIBBITBLT in whereas 3.1 uses
  362. * META_DIBSTRETCHBLT so we have to handle each case separately.
  363. */
  364. if (META_DIBBITBLT==pMFR->rdFunction) //Win3.0
  365. {
  366. //Get dimensions and the BITMAPINFO struct.
  367. uHeight = pMFR->rdParm[1];
  368. uWidth = pMFR->rdParm[2];
  369. lpBI = (LPBITMAPINFO)&(pMFR->rdParm[8]);
  370. }
  371. if (META_DIBSTRETCHBLT == pMFR->rdFunction) //Win3.1
  372. {
  373. //Get dimensions and the BITMAPINFO struct.
  374. uHeight = pMFR->rdParm[2];
  375. uWidth = pMFR->rdParm[3];
  376. lpBI = (LPBITMAPINFO)&(pMFR->rdParm[10]);
  377. }
  378. UNALIGNED BITMAPINFOHEADER* lpBH=(LPBITMAPINFOHEADER)&(lpBI->bmiHeader);
  379. //Pointer to the bits which follows the BITMAPINFO structure.
  380. LPBYTE lpbSrc=(LPBYTE)lpBI+sizeof(BITMAPINFOHEADER);
  381. //Add the length of the color table (if one exists)
  382. if (0 != lpBH->biClrUsed)
  383. {
  384. // If we have an explicit count of colors used, we
  385. // can find the offset to the data directly
  386. lpbSrc += (lpBH->biClrUsed*sizeof(RGBQUAD));
  387. }
  388. else if (lpBH->biCompression == BI_BITFIELDS)
  389. {
  390. // 16 or 32 bpp, indicated by BI_BITFIELDS in the compression
  391. // field, have 3 DWORD masks for adjusting subsequent
  392. // direct-color values, and no palette
  393. lpbSrc += 3 * sizeof(DWORD);
  394. }
  395. else
  396. {
  397. // In other cases, there is an array of RGBQUAD entries
  398. // equal to 2^(biBitCount) where biBitCount is the number
  399. // of bits per pixel. The exception is 24 bpp bitmaps,
  400. // which have no color table and just use direct RGB values.
  401. lpbSrc += (lpBH->biBitCount == 24) ? 0 :
  402. (1 << (lpBH->biBitCount)) * sizeof(RGBQUAD);
  403. }
  404. // copy into aligned stack space (since SetDIBits needs aligned data)
  405. size_t nSize = (size_t)(lpbSrc - (LPBYTE)lpBI);
  406. LPBITMAPINFO lpTemp = (LPBITMAPINFO)_alloca(nSize);
  407. memcpy(lpTemp, lpBI, nSize);
  408. /*
  409. * All the bits we have in lpbSrc are device-independent, so we
  410. * need to change them over to be device-dependent using SetDIBits.
  411. * Once we have a bitmap with the device-dependent bits, we can
  412. * GetBitmapBits to have buffers with the real data.
  413. *
  414. * For each pass we have to allocate memory for the bits. We save
  415. * the memory for the mask between passes.
  416. */
  417. HBITMAP hBmp;
  418. //Use CreateBitmap for ANY monochrome bitmaps
  419. if (pIE->fAND || 1==lpBH->biBitCount)
  420. hBmp=CreateBitmap((UINT)lpBH->biWidth, (UINT)lpBH->biHeight, 1, 1, NULL);
  421. else
  422. hBmp=CreateCompatibleBitmap(hDC, (UINT)lpBH->biWidth, (UINT)lpBH->biHeight);
  423. if (!hBmp || !SetDIBits(hDC, hBmp, 0, (UINT)lpBH->biHeight, (LPVOID)lpbSrc, lpTemp, DIB_RGB_COLORS))
  424. {
  425. if (!pIE->fAND)
  426. GlobalFree(pIE->hMemAND);
  427. if (hBmp)
  428. DeleteObject(hBmp);
  429. return 0;
  430. }
  431. //Allocate memory and get the DDBits into it.
  432. BITMAP bm;
  433. GetObject(hBmp, sizeof(bm), &bm);
  434. DWORD cb = bm.bmHeight*bm.bmWidthBytes * bm.bmPlanes;
  435. HGLOBAL hMem = GlobalAlloc(GHND, cb);
  436. if (NULL==hMem)
  437. {
  438. if (NULL != pIE->hMemAND)
  439. GlobalFree(pIE->hMemAND);
  440. DeleteObject(hBmp);
  441. return 0;
  442. }
  443. LPBYTE lpbDst = (LPBYTE)GlobalLock(hMem);
  444. GetBitmapBits(hBmp, cb, (LPVOID)lpbDst);
  445. DeleteObject(hBmp);
  446. GlobalUnlock(hMem);
  447. /*
  448. * If this is the first pass (pIE->fAND==TRUE) then save the memory
  449. * of the AND bits for the next pass.
  450. */
  451. if (pIE->fAND)
  452. {
  453. pIE->fAND = FALSE;
  454. pIE->hMemAND = hMem;
  455. //Continue enumeration looking for the next blt record.
  456. return 1;
  457. }
  458. else
  459. {
  460. //Get the AND pointer again.
  461. lpbSrc=(LPBYTE)GlobalLock(pIE->hMemAND);
  462. /*
  463. * Create the icon now that we have all the data. lpbDst already
  464. * points to the XOR bits.
  465. */
  466. int cxIcon = GetSystemMetrics(SM_CXICON);
  467. int cyIcon = GetSystemMetrics(SM_CYICON);
  468. pIE->hIcon = CreateIcon(_g_hOleStdInst, uWidth, uHeight,
  469. (BYTE)bm.bmPlanes, (BYTE)bm.bmBitsPixel, lpbSrc, lpbDst);
  470. GlobalUnlock(pIE->hMemAND);
  471. GlobalFree(pIE->hMemAND);
  472. GlobalFree(hMem);
  473. return 0;
  474. }
  475. }
  476. /*
  477. * OleUIMetafilePictExtractIconSource
  478. *
  479. * Purpose:
  480. * Retrieves the filename and index of the icon source from a metafile
  481. * created with OleMetafilePictFromIconAndLabel.
  482. *
  483. * Parameters:
  484. * hMetaPict HGLOBAL to the METAFILEPICT containing the metafile.
  485. * lpszSource LPTSTR in which to store the source filename. This
  486. * buffer should be MAX_PATH characters.
  487. * piIcon UINT FAR * in which to store the icon's index
  488. * within lpszSource
  489. *
  490. * Return Value:
  491. * BOOL TRUE if the records were found, FALSE otherwise.
  492. */
  493. STDAPI_(BOOL) OleUIMetafilePictExtractIconSource(HGLOBAL hMetaPict,
  494. LPTSTR lpszSource, UINT FAR *piIcon)
  495. {
  496. if (NULL == hMetaPict || NULL == lpszSource || NULL == piIcon)
  497. return FALSE;
  498. /*
  499. * We will walk the metafile looking for the two comment records
  500. * following the IconOnly comment. The flags fFoundIconOnly and
  501. * fFoundSource indicate if we have found IconOnly and if we have
  502. * found the source comment already.
  503. */
  504. LPMETAFILEPICT pMF = (LPMETAFILEPICT)GlobalLock(hMetaPict);
  505. if (NULL == pMF)
  506. return FALSE;
  507. LABELEXTRACT le;
  508. le.lpsz = lpszSource;
  509. le.fFoundIconOnly = FALSE;
  510. le.fFoundSource = FALSE;
  511. le.fFoundIndex = FALSE;
  512. le.u.iIcon = NULL;
  513. //Use a screen DC so we have something valid to pass in.
  514. HDC hDC = GetDC(NULL);
  515. if (hDC)
  516. {
  517. EnumMetaFile(hDC, pMF->hMF, (MFENUMPROC)EnumMetafileExtractIconSource,
  518. (LPARAM)(LPLABELEXTRACT)&le);
  519. ReleaseDC(NULL, hDC);
  520. }
  521. GlobalUnlock(hMetaPict);
  522. //Copy the icon index to the caller's variable.
  523. *piIcon=le.u.iIcon;
  524. //Check that we found everything.
  525. return (le.fFoundIconOnly && le.fFoundSource && le.fFoundIndex);
  526. }
  527. /*
  528. * EnumMetafileExtractIconSource
  529. *
  530. * Purpose:
  531. * EnumMetaFile callback function that walks a metafile skipping the first
  532. * comment record, extracting the source filename from the second, and
  533. * the index of the icon in the third.
  534. *
  535. * Parameters:
  536. * hDC HDC into which the metafile should be played.
  537. * phTable HANDLETABLE FAR * providing handles selected into the DC.
  538. * pMFR METARECORD FAR * giving the enumerated record.
  539. * pLE LPLABELEXTRACT providing the destination buffer and
  540. * area to store the icon index.
  541. *
  542. * Return Value:
  543. * int 0 to stop enumeration, 1 to continue.
  544. */
  545. int CALLBACK EnumMetafileExtractIconSource(HDC hDC, HANDLETABLE FAR *phTable,
  546. METARECORD FAR *pMFR, int cObj, LPLABELEXTRACT pLE)
  547. {
  548. /*
  549. * We don't allow anything to happen until we see "IconOnly"
  550. * in an MFCOMMENT that is used to enable everything else.
  551. */
  552. if (!pLE->fFoundIconOnly)
  553. {
  554. if (META_ESCAPE == pMFR->rdFunction && MFCOMMENT == pMFR->rdParm[0])
  555. {
  556. if (0 == lstrcmpiA(szIconOnly, (LPSTR)&pMFR->rdParm[2]))
  557. pLE->fFoundIconOnly=TRUE;
  558. }
  559. return 1;
  560. }
  561. //Now see if we find the source string.
  562. if (!pLE->fFoundSource)
  563. {
  564. if (META_ESCAPE == pMFR->rdFunction && MFCOMMENT == pMFR->rdParm[0])
  565. {
  566. #ifdef _UNICODE
  567. MultiByteToWideChar(CP_ACP, 0, (LPSTR)&pMFR->rdParm[2], -1,
  568. pLE->lpsz, MAX_PATH);
  569. #else
  570. lstrcpyn(pLE->lpsz, (LPSTR)&pMFR->rdParm[2], MAX_PATH);
  571. #endif
  572. pLE->lpsz[MAX_PATH-1] = '\0';
  573. pLE->fFoundSource=TRUE;
  574. }
  575. return 1;
  576. }
  577. //Next comment will be the icon index.
  578. if (META_ESCAPE == pMFR->rdFunction && MFCOMMENT == pMFR->rdParm[0])
  579. {
  580. /*
  581. * This string contains the icon index in string form,
  582. * so we need to convert back to a UINT. After we see this
  583. * we can stop the enumeration. The comment will have
  584. * a null terminator because we made sure to save it.
  585. */
  586. LPSTR psz = (LPSTR)&pMFR->rdParm[2];
  587. pLE->u.iIcon = 0;
  588. //Do Ye Olde atoi
  589. while (*psz)
  590. pLE->u.iIcon = (10*pLE->u.iIcon)+((*psz++)-'0');
  591. pLE->fFoundIndex=TRUE;
  592. return 0;
  593. }
  594. return 1;
  595. }