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