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.

1465 lines
39 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: icon.cxx
  7. //
  8. // Contents: icon.cpp from OLE2
  9. //
  10. // History: 11-Apr-94 DrewB Copied from OLE2
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "headers.cxx"
  14. #pragma hdrstop
  15. /*
  16. * ICON.CPP
  17. *
  18. * Functions to create DVASPECT_ICON metafile from filename or classname.
  19. *
  20. * OleGetIconOfFile
  21. * OleGetIconOfClass
  22. * OleMetafilePictFromIconAndLabel
  23. *
  24. * HIconAndSourceFromClass Extracts the first icon in a class's server path
  25. * and returns the path and icon index to caller.
  26. * FIconFileFromClass Retrieves the path to the exe/dll containing the
  27. * default icon, and the index of the icon.
  28. * OleStdIconLabelTextOut
  29. * PointerToNthField
  30. * XformWidthInPixelsToHimetric Converts an int width into HiMetric units
  31. * XformWidthInHimetricToPixels Converts an int width from HiMetric units
  32. * XformHeightInPixelsToHimetric Converts an int height into HiMetric units
  33. * XformHeightInHimetricToPixels Converts an int height from HiMetric units
  34. *
  35. * (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved
  36. */
  37. #include <ole2int.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <commdlg.h>
  42. #include <memory.h>
  43. #include <cderr.h>
  44. #include "icon.h"
  45. static char szMaxWidth[] ="WWWWWWWWWW";
  46. //Strings for metafile comments.
  47. static char szIconOnly[]="IconOnly"; //Where to stop to exclude label.
  48. #define OLEUI_CCHKEYMAX 256
  49. #define OLEUI_CCHPATHMAX 256
  50. #define OLEUI_CCHLABELMAX 40
  51. #define ICONINDEX 0
  52. #define AUXUSERTYPE_SHORTNAME USERCLASSTYPE_SHORT // short name
  53. #define HIMETRIC_PER_INCH 2540 // number HIMETRIC units per inch
  54. #define PTS_PER_INCH 72 // number points (font size) per inch
  55. #define MAP_PIX_TO_LOGHIM(x,ppli) MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
  56. #define MAP_LOGHIM_TO_PIX(x,ppli) MulDiv((ppli), (x), HIMETRIC_PER_INCH)
  57. static char szVanillaDocIcon[] = "DefIcon";
  58. static char szDocument[OLEUI_CCHLABELMAX] = "";
  59. static char szSeparators[] = " \t\\/!:";
  60. static const char szDefIconLabelKey[] = "Software\\Microsoft\\OLE2\\DefaultIconLabel";
  61. #define IS_SEPARATOR(c) ( (c) == ' ' || (c) == '\\' || (c) == '/' || (c) == '\t' || (c) == '!' || (c) == ':' )
  62. #define IS_FILENAME_DELIM(c) ( (c) == '\\' || (c) == '/' || (c) == ':' )
  63. #define LSTRCPYN(lpdst, lpsrc, cch) \
  64. (\
  65. lpdst[cch-1] = '\0', \
  66. lstrcpyn(lpdst, lpsrc, cch-1)\
  67. )
  68. /*******
  69. *
  70. * ICON METAFILE FORMAT:
  71. *
  72. * The metafile generated with OleMetafilePictFromIconAndLabel contains
  73. * the following records which are used by the functions in DRAWICON.C
  74. * to draw the icon with and without the label and to extract the icon,
  75. * label, and icon source/index.
  76. *
  77. * SetWindowOrg
  78. * SetWindowExt
  79. * DrawIcon:
  80. * Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the
  81. * AND mask, one for the image bits.
  82. * Escape with the comment "IconOnly"
  83. * This indicates where to stop record enumeration to draw only
  84. * the icon.
  85. * SetTextColor
  86. * SetBkColor
  87. * CreateFont
  88. * SelectObject on the font.
  89. * ExtTextOut
  90. * One or more ExtTextOuts occur if the label is wrapped. The
  91. * text in these records is used to extract the label.
  92. * SelectObject on the old font.
  93. * DeleteObject on the font.
  94. * Escape with a comment that contains the path to the icon source.
  95. * Escape with a comment that is the ASCII of the icon index.
  96. *
  97. *******/
  98. /*
  99. * OleGetIconOfFile(LPSTR lpszPath, BOOL fUseFileAsLabel)
  100. *
  101. * Purpose:
  102. * Returns a hMetaPict containing an icon and label (filename) for the
  103. * specified filename.
  104. *
  105. * Parameters:
  106. * lpszPath LPSTR path including filename to use
  107. * fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if
  108. * there should be no label.
  109. *
  110. * Return Value:
  111. * HGLOBAL hMetaPict containing the icon and label - if there's no
  112. * class in reg db for the file in lpszPath, then we use
  113. * Document. If lpszPath is NULL, then we return NULL.
  114. */
  115. STDAPI_(HGLOBAL) OleGetIconOfFile(LPSTR lpszPath, BOOL fUseFileAsLabel)
  116. {
  117. char szIconFile[OLEUI_CCHPATHMAX];
  118. char szLabel[OLEUI_CCHLABELMAX];
  119. LPSTR lpszClsid = NULL;
  120. CLSID clsid;
  121. HICON hDefIcon = NULL;
  122. UINT IconIndex = 0;
  123. HGLOBAL hMetaPict;
  124. HRESULT hResult;
  125. if (NULL == lpszPath) // even if fUseFileAsLabel is FALSE, we still
  126. return NULL; // need a valid filename to get the class.
  127. hResult = GetClassFile(lpszPath, &clsid);
  128. if (NOERROR == hResult) // use the clsid we got to get to the icon
  129. {
  130. hDefIcon = HIconAndSourceFromClass(clsid,
  131. (LPSTR)szIconFile,
  132. &IconIndex);
  133. }
  134. if ( (NOERROR != hResult) || (NULL == hDefIcon) )
  135. {
  136. // Here, either GetClassFile failed or HIconAndSourceFromClass failed.
  137. LPSTR lpszTemp;
  138. lpszTemp = lpszPath;
  139. while ((*lpszTemp != '.') && (*lpszTemp != '\0'))
  140. lpszTemp++;
  141. if ('.' != *lpszTemp)
  142. goto UseVanillaDocument;
  143. if (FALSE == GetAssociatedExecutable(lpszTemp, (LPSTR)szIconFile))
  144. goto UseVanillaDocument;
  145. hDefIcon = ExtractIcon(hmodOLE2, szIconFile, IconIndex);
  146. }
  147. if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe,
  148. { // 0 if there are no icons.
  149. UseVanillaDocument:
  150. GetModuleFileName(hmodOLE2, (LPSTR)szIconFile, OLEUI_CCHPATHMAX);
  151. IconIndex = ICONINDEX;
  152. hDefIcon = LoadIcon(hmodOLE2, (LPSTR)szVanillaDocIcon);
  153. }
  154. // Now let's get the label we want to use.
  155. if (fUseFileAsLabel) // strip off path, so we just have the filename.
  156. {
  157. int istrlen;
  158. LPSTR lpszBeginFile;
  159. istrlen = lstrlen(lpszPath);
  160. // set pointer to END of path, so we can walk backwards through it.
  161. lpszBeginFile = lpszPath + istrlen -1;
  162. while ( (lpszBeginFile >= lpszPath)
  163. && (!IS_FILENAME_DELIM(*lpszBeginFile)) )
  164. lpszBeginFile--;
  165. lpszBeginFile++; // step back over the delimiter
  166. LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel));
  167. }
  168. else // use the short user type (AuxUserType2) for the label
  169. {
  170. if (0 == OleStdGetAuxUserType(clsid, AUXUSERTYPE_SHORTNAME,
  171. (LPSTR)szLabel, OLEUI_CCHLABELMAX, NULL)) {
  172. if ('\0'==szDocument[0]) {
  173. LONG cb = sizeof (szDocument);
  174. RegQueryValue (HKEY_CLASSES_ROOT, szDefIconLabelKey, szDocument,
  175. &cb);
  176. // if szDocument is not big enough, RegQueryValue puts a NULL
  177. // at the end so we are safe.
  178. // if RegQueryValue fails, szDocument[0]=='\0' so we'll use that.
  179. }
  180. lstrcpy(szLabel, szDocument);
  181. }
  182. }
  183. hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon,
  184. szLabel,
  185. (LPSTR)szIconFile,
  186. IconIndex);
  187. DestroyIcon(hDefIcon);
  188. return hMetaPict;
  189. }
  190. /*
  191. * GetAssociatedExecutable
  192. *
  193. * Purpose: Finds the executable associated with the provided extension
  194. *
  195. * Parameters:
  196. * lpszExtension LPSTR points to the extension we're trying to find an exe
  197. * for. Does **NO** validation.
  198. *
  199. * lpszExecutable LPSTR points to where the exe name will be returned.
  200. * No validation here either - pass in 128 char buffer.
  201. *
  202. * Return:
  203. * BOOL TRUE if we found an exe, FALSE if we didn't.
  204. *
  205. */
  206. BOOL FAR PASCAL GetAssociatedExecutable(LPSTR lpszExtension, LPSTR lpszExecutable)
  207. {
  208. HKEY hKey;
  209. LONG dw;
  210. LRESULT lRet;
  211. char szValue[OLEUI_CCHKEYMAX];
  212. char szKey[OLEUI_CCHKEYMAX];
  213. LPSTR lpszTemp, lpszExe;
  214. lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  215. if (ERROR_SUCCESS != lRet)
  216. return FALSE;
  217. dw = OLEUI_CCHPATHMAX;
  218. lRet = RegQueryValue(hKey, lpszExtension, (LPSTR)szValue, &dw); //ProgId
  219. if (ERROR_SUCCESS != lRet)
  220. {
  221. RegCloseKey(hKey);
  222. return FALSE;
  223. }
  224. // szValue now has ProgID
  225. lstrcpy(szKey, szValue);
  226. lstrcat(szKey, "\\Shell\\Open\\Command");
  227. dw = OLEUI_CCHPATHMAX;
  228. lRet = RegQueryValue(hKey, (LPSTR)szKey, (LPSTR)szValue, &dw);
  229. if (ERROR_SUCCESS != lRet)
  230. {
  231. RegCloseKey(hKey);
  232. return FALSE;
  233. }
  234. // szValue now has an executable name in it. Let's null-terminate
  235. // at the first post-executable space (so we don't have cmd line
  236. // args.
  237. lpszTemp = (LPSTR)szValue;
  238. while (('\0' != *lpszTemp) && (isspace(*lpszTemp)))
  239. lpszTemp++; // Strip off leading spaces
  240. lpszExe = lpszTemp;
  241. while (('\0' != *lpszTemp) && (!isspace(*lpszTemp)))
  242. lpszTemp++; // Set through exe name
  243. *lpszTemp = '\0'; // null terminate at first space (or at end).
  244. lstrcpy(lpszExecutable, lpszExe);
  245. return TRUE;
  246. }
  247. /*
  248. * OleGetIconOfClass(REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
  249. *
  250. * Purpose:
  251. * Returns a hMetaPict containing an icon and label (human-readable form
  252. * of class) for the specified clsid.
  253. *
  254. * Parameters:
  255. * rclsid REFCLSID pointing to clsid to use.
  256. * lpszLabel label to use for icon.
  257. * fUseTypeAsLabel Use the clsid's user type name as the icon's label.
  258. *
  259. * Return Value:
  260. * HGLOBAL hMetaPict containing the icon and label - if we
  261. * don't find the clsid in the reg db then we
  262. * return NULL.
  263. */
  264. STDAPI_(HGLOBAL) OleGetIconOfClass(REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
  265. {
  266. char szLabel[OLEUI_CCHLABELMAX];
  267. char szIconFile[OLEUI_CCHPATHMAX];
  268. HICON hDefIcon;
  269. UINT IconIndex;
  270. HGLOBAL hMetaPict;
  271. if (!fUseTypeAsLabel) // Use string passed in as label
  272. {
  273. if (NULL != lpszLabel)
  274. LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel));
  275. else
  276. *szLabel = '\0';
  277. }
  278. else // Use AuxUserType2 (short name) as label
  279. {
  280. if (0 == OleStdGetAuxUserType(rclsid,
  281. AUXUSERTYPE_SHORTNAME,
  282. (LPSTR)szLabel,
  283. OLEUI_CCHLABELMAX,
  284. NULL))
  285. // If we can't get the AuxUserType2, then try the long name
  286. if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX, NULL)) {
  287. if ('\0'==szDocument[0]) {
  288. LONG cb = sizeof (szDocument);
  289. RegQueryValue (HKEY_CLASSES_ROOT, szDefIconLabelKey, szDocument,
  290. &cb);
  291. // if RegQueryValue fails, szDocument=="" so we'll use that.
  292. }
  293. lstrcpy(szLabel, szDocument); // last resort
  294. }
  295. }
  296. // Get the icon, icon index, and path to icon file
  297. hDefIcon = HIconAndSourceFromClass(rclsid,
  298. (LPSTR)szIconFile,
  299. &IconIndex);
  300. if (NULL == hDefIcon) // Use Vanilla Document
  301. {
  302. GetModuleFileName(hmodOLE2, (LPSTR)szIconFile, OLEUI_CCHPATHMAX);
  303. IconIndex = ICONINDEX;
  304. hDefIcon = LoadIcon(hmodOLE2, (LPSTR)szVanillaDocIcon);
  305. }
  306. // Create the metafile
  307. hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel,
  308. (LPSTR)szIconFile, IconIndex);
  309. DestroyIcon(hDefIcon);
  310. return hMetaPict;
  311. }
  312. /*
  313. * HIconAndSourceFromClass
  314. *
  315. * Purpose:
  316. * Given an object class name, finds an associated executable in the
  317. * registration database and extracts the first icon from that
  318. * executable. If none is available or the class has no associated
  319. * executable, this function returns NULL.
  320. *
  321. * Parameters:
  322. * rclsid pointer to clsid to look up.
  323. * pszSource LPSTR in which to place the source of the icon.
  324. * This is assumed to be OLEUI_CCHPATHMAX
  325. * puIcon UINT FAR * in which to store the index of the
  326. * icon in pszSource.
  327. *
  328. * Return Value:
  329. * HICON Handle to the extracted icon if there is a module
  330. * associated to pszClass. NULL on failure to either
  331. * find the executable or extract and icon.
  332. */
  333. HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPSTR pszSource, UINT FAR *puIcon)
  334. {
  335. HICON hIcon;
  336. UINT IconIndex;
  337. if (CLSID_NULL==rclsid || NULL==pszSource)
  338. return NULL;
  339. if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex))
  340. return NULL;
  341. hIcon=ExtractIcon(hmodOLE2, pszSource, IconIndex);
  342. if ((HICON)32 > hIcon)
  343. hIcon=NULL;
  344. else
  345. *puIcon= IconIndex;
  346. return hIcon;
  347. }
  348. /*
  349. * FIconFileFromClass
  350. *
  351. * Purpose:
  352. * Looks up the path to executable that contains the class default icon.
  353. *
  354. * Parameters:
  355. * rclsid pointer to CLSID to look up.
  356. * pszEXE LPSTR at which to store the server name
  357. * cch UINT size of pszEXE
  358. * lpIndex LPUINT to index of icon within executable
  359. *
  360. * Return Value:
  361. * BOOL TRUE if one or more characters were loaded into pszEXE.
  362. * FALSE otherwise.
  363. */
  364. BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPSTR pszEXE, UINT cch, UINT FAR *lpIndex)
  365. {
  366. LONG dw;
  367. LONG lRet;
  368. HKEY hKey;
  369. LPMALLOC lpIMalloc;
  370. HRESULT hrErr;
  371. LPSTR lpBuffer;
  372. LPSTR lpIndexString;
  373. UINT cBufferSize = 136; // room for 128 char path and icon's index
  374. char szKey[64];
  375. LPSTR pszClass;
  376. if (CLSID_NULL==rclsid || NULL==pszEXE || 0==cch)
  377. return FALSE;
  378. //Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to
  379. //pass to RegQueryValue. Then, we copy the exe to pszEXE and the
  380. //index to *lpIndex.
  381. hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc);
  382. if (NOERROR != hrErr)
  383. return FALSE;
  384. lpBuffer = (LPSTR)lpIMalloc->Alloc(cBufferSize);
  385. if (NULL == lpBuffer)
  386. {
  387. lpIMalloc->Release();
  388. return FALSE;
  389. }
  390. if (CoIsOle1Class(rclsid))
  391. {
  392. LPSTR lpszProgID;
  393. // we've got an ole 1.0 class on our hands, so we look at
  394. // progID\protocol\stdfileedting\server to get the
  395. // name of the executable.
  396. ProgIDFromCLSID(rclsid, &lpszProgID);
  397. //Open up the class key
  398. lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);
  399. if (ERROR_SUCCESS != lRet)
  400. {
  401. lpIMalloc->Free(lpszProgID);
  402. lpIMalloc->Free(lpBuffer);
  403. lpIMalloc->Release();
  404. return FALSE;
  405. }
  406. dw=(LONG)cBufferSize;
  407. lRet = RegQueryValue(hKey, "Protocol\\StdFileEditing\\Server", lpBuffer, &dw);
  408. if (ERROR_SUCCESS != lRet)
  409. {
  410. RegCloseKey(hKey);
  411. lpIMalloc->Free(lpszProgID);
  412. lpIMalloc->Free(lpBuffer);
  413. lpIMalloc->Release();
  414. return FALSE;
  415. }
  416. // Use server and 0 as the icon index
  417. LSTRCPYN(pszEXE, lpBuffer, cch);
  418. *lpIndex = 0;
  419. RegCloseKey(hKey);
  420. lpIMalloc->Free(lpszProgID);
  421. lpIMalloc->Free(lpBuffer);
  422. lpIMalloc->Release();
  423. return TRUE;
  424. }
  425. /*
  426. * We have to go walking in the registration database under the
  427. * classname, so we first open the classname key and then check
  428. * under "\\DefaultIcon" to get the file that contains the icon.
  429. */
  430. StringFromCLSID(rclsid, &pszClass);
  431. lstrcpy(szKey, "CLSID\\");
  432. lstrcat(szKey, pszClass);
  433. //Open up the class key
  434. lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);
  435. if (ERROR_SUCCESS != lRet)
  436. {
  437. lpIMalloc->Free(lpBuffer);
  438. lpIMalloc->Free(pszClass);
  439. lpIMalloc->Release();
  440. return FALSE;
  441. }
  442. //Get the executable path and icon index.
  443. dw=(LONG)cBufferSize;
  444. lRet=RegQueryValue(hKey, "DefaultIcon", lpBuffer, &dw);
  445. if (ERROR_SUCCESS != lRet)
  446. {
  447. // no DefaultIcon key...try LocalServer
  448. dw=(LONG)cBufferSize;
  449. lRet=RegQueryValue(hKey, "LocalServer", lpBuffer, &dw);
  450. if (ERROR_SUCCESS != lRet)
  451. {
  452. // no LocalServer entry either...they're outta luck.
  453. RegCloseKey(hKey);
  454. lpIMalloc->Free(lpBuffer);
  455. lpIMalloc->Free(pszClass);
  456. lpIMalloc->Release();
  457. return FALSE;
  458. }
  459. // Use server from LocalServer or Server and 0 as the icon index
  460. LSTRCPYN(pszEXE, lpBuffer, cch);
  461. *lpIndex = 0;
  462. RegCloseKey(hKey);
  463. lpIMalloc->Free(lpBuffer);
  464. lpIMalloc->Free(pszClass);
  465. lpIMalloc->Release();
  466. return TRUE;
  467. }
  468. RegCloseKey(hKey);
  469. // lpBuffer contains a string that looks like "<pathtoexe>,<iconindex>",
  470. // so we need to separate the path and the icon index.
  471. lpIndexString = PointerToNthField(lpBuffer, 2, ',');
  472. if ('\0' == *lpIndexString) // no icon index specified - use 0 as default.
  473. {
  474. *lpIndex = 0;
  475. }
  476. else
  477. {
  478. LPSTR lpTemp;
  479. static char szTemp[16];
  480. lstrcpy((LPSTR)szTemp, lpIndexString);
  481. // Put the icon index part into *pIconIndex
  482. *lpIndex = atoi((const char *)szTemp);
  483. // Null-terminate the exe part.
  484. lpTemp = AnsiPrev(lpBuffer, lpIndexString);
  485. *lpTemp = '\0';
  486. }
  487. if (!LSTRCPYN(pszEXE, lpBuffer, cch))
  488. {
  489. lpIMalloc->Free(lpBuffer);
  490. lpIMalloc->Free(pszClass);
  491. lpIMalloc->Release();
  492. return FALSE;
  493. }
  494. // Free the memory we alloc'd and leave.
  495. lpIMalloc->Free(lpBuffer);
  496. lpIMalloc->Free(pszClass);
  497. lpIMalloc->Release();
  498. return TRUE;
  499. }
  500. /*
  501. * OleMetafilePictFromIconAndLabel
  502. *
  503. * Purpose:
  504. * Creates a METAFILEPICT structure that container a metafile in which
  505. * the icon and label are drawn. A comment record is inserted between
  506. * the icon and the label code so our special draw function can stop
  507. * playing before the label.
  508. *
  509. * Parameters:
  510. * hIcon HICON to draw into the metafile
  511. * pszLabel LPSTR to the label string.
  512. * pszSourceFile LPSTR containing the local pathname of the icon
  513. * as we either get from the user or from the reg DB.
  514. * iIcon UINT providing the index into pszSourceFile where
  515. * the icon came from.
  516. *
  517. * Return Value:
  518. * HGLOBAL Global memory handle containing a METAFILEPICT where
  519. * the metafile uses the MM_ANISOTROPIC mapping mode. The
  520. * extents reflect both icon and label.
  521. */
  522. STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabel(HICON hIcon, LPSTR pszLabel
  523. , LPSTR pszSourceFile, UINT iIcon)
  524. {
  525. HDC hDC, hDCScreen;
  526. HMETAFILE hMF;
  527. HGLOBAL hMem;
  528. LPMETAFILEPICT pMF;
  529. UINT cxIcon, cyIcon;
  530. UINT cxText, cyText;
  531. UINT cx, cy;
  532. UINT cchLabel = 0;
  533. HFONT hFont, hSysFont, hFontT;
  534. int cyFont;
  535. char szIndex[10];
  536. RECT TextRect;
  537. SIZE size;
  538. POINT point;
  539. LOGFONT logfont;
  540. if (NULL==hIcon) // null icon is valid
  541. return NULL;
  542. //Create a memory metafile
  543. hDC=(HDC)CreateMetaFile(NULL);
  544. if (NULL==hDC)
  545. return NULL;
  546. //Allocate the metafilepict
  547. hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
  548. if (NULL==hMem)
  549. {
  550. hMF=CloseMetaFile(hDC);
  551. DeleteMetaFile(hMF);
  552. return NULL;
  553. }
  554. if (NULL!=pszLabel)
  555. {
  556. cchLabel=lstrlen(pszLabel);
  557. if (cchLabel >= OLEUI_CCHLABELMAX)
  558. pszLabel[cchLabel] = '\0'; // truncate string
  559. }
  560. //Need to use the screen DC for these operations
  561. hDCScreen=GetDC(NULL);
  562. cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72;
  563. //cyFont was calculated to give us 8 point.
  564. // We use the system font as the basis for the character set,
  565. // allowing us to handle DBCS strings better
  566. hSysFont = GetStockObject( SYSTEM_FONT );
  567. GetObject(hSysFont, sizeof(LOGFONT), &logfont);
  568. hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, logfont.lfCharSet
  569. , OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY
  570. , FF_SWISS, "MS Sans Serif");
  571. hFontT=SelectObject(hDCScreen, hFont);
  572. GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size);
  573. SelectObject(hDCScreen, hFontT);
  574. cxText = size.cx;
  575. cyText = size.cy * 2;
  576. cxIcon = GetSystemMetrics(SM_CXICON);
  577. cyIcon = GetSystemMetrics(SM_CYICON);
  578. // If we have no label, then we want the metafile to be the width of
  579. // the icon (plus margin), not the width of the fattest string.
  580. if ( (NULL == pszLabel) || (NULL == *pszLabel) )
  581. cx = cxIcon + cxIcon / 4;
  582. else
  583. cx = max(cxText, cxIcon);
  584. cy=cyIcon+cyText+4;
  585. //Set the metafile size to fit the icon and label
  586. SetWindowOrgEx(hDC, 0, 0, &point);
  587. SetWindowExtEx(hDC, cx, cy, &size);
  588. //Set up rectangle to pass to OleStdIconLabelTextOut
  589. SetRectEmpty(&TextRect);
  590. TextRect.right = cx;
  591. TextRect.bottom = cy;
  592. //Draw the icon and the text, centered with respect to each other.
  593. DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon);
  594. //String that indicates where to stop if we're only doing icons
  595. Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL);
  596. SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  597. SetBkMode(hDC, TRANSPARENT);
  598. OleStdIconLabelTextOut(hDC,
  599. hFont,
  600. 0,
  601. cy - cyText,
  602. ETO_CLIPPED,
  603. &TextRect,
  604. pszLabel,
  605. cchLabel,
  606. NULL);
  607. //Write comments containing the icon source file and index.
  608. if (NULL!=pszSourceFile)
  609. {
  610. //+1 on string lengths insures the null terminator is embedded.
  611. Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL);
  612. cchLabel=wsprintf(szIndex, "%u", iIcon);
  613. Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL);
  614. }
  615. //All done with the metafile, now stuff it all into a METAFILEPICT.
  616. hMF=CloseMetaFile(hDC);
  617. if (NULL==hMF)
  618. {
  619. GlobalFree(hMem);
  620. ReleaseDC(NULL, hDCScreen);
  621. return NULL;
  622. }
  623. //Fill out the structure
  624. pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  625. //Transform to HIMETRICS
  626. cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
  627. cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
  628. ReleaseDC(NULL, hDCScreen);
  629. pMF->mm=MM_ANISOTROPIC;
  630. pMF->xExt=cx;
  631. pMF->yExt=cy;
  632. pMF->hMF=hMF;
  633. GlobalUnlock(hMem);
  634. DeleteObject(hFont);
  635. return hMem;
  636. }
  637. /*
  638. * OleStdIconLabelTextOut
  639. *
  640. * Purpose:
  641. * Replacement for DrawText to be used in the "Display as Icon" metafile.
  642. * Uses ExtTextOut to output a string center on (at most) two lines.
  643. * Uses a very simple word wrap algorithm to split the lines.
  644. *
  645. * Parameters: (same as for ExtTextOut, except for hFont)
  646. * hDC device context to draw into; if this is NULL, then we don't
  647. * ETO the text, we just return the index of the beginning
  648. * of the second line
  649. * hFont font to use
  650. * nXStart x-coordinate of starting position
  651. * nYStart y-coordinate of starting position
  652. * fuOptions rectangle type
  653. * lpRect rect far * containing rectangle to draw text in.
  654. * lpszString string to draw
  655. * cchString length of string (truncated if over OLEUI_CCHLABELMAX)
  656. * lpDX spacing between character cells
  657. *
  658. * Return Value:
  659. * UINT Index of beginning of last line (0 if there's only one
  660. * line of text).
  661. *
  662. */
  663. STDAPI_(UINT) OleStdIconLabelTextOut(HDC hDC,
  664. HFONT hFont,
  665. int nXStart,
  666. int nYStart,
  667. UINT fuOptions,
  668. RECT FAR * lpRect,
  669. LPSTR lpszString,
  670. UINT cchString,
  671. int FAR * lpDX)
  672. {
  673. HDC hDCScreen;
  674. static char szTempBuff[OLEUI_CCHLABELMAX];
  675. int cxString, cyString, cxMaxString;
  676. int cxFirstLine, cyFirstLine, cxSecondLine;
  677. int index;
  678. int cch = cchString;
  679. char chKeep;
  680. LPSTR lpszSecondLine;
  681. HFONT hFontT;
  682. BOOL fPrintText = TRUE;
  683. UINT iLastLineStart = 0;
  684. SIZE size;
  685. // Initialization stuff...
  686. if (NULL == hDC) // If we got NULL as the hDC, then we don't actually call ETO
  687. fPrintText = FALSE;
  688. // Make a copy of the string (NULL or non-NULL) that we're using
  689. if (NULL == lpszString)
  690. *szTempBuff = '\0';
  691. else
  692. LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff));
  693. // set maximum width
  694. cxMaxString = lpRect->right - lpRect->left;
  695. // get screen DC to do text size calculations
  696. hDCScreen = GetDC(NULL);
  697. hFontT=SelectObject(hDCScreen, hFont);
  698. // get the extent of our label
  699. GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);
  700. cxString = size.cx;
  701. cyString = size.cy;
  702. // Select in the font we want to use
  703. if (fPrintText)
  704. SelectObject(hDC, hFont);
  705. // String is smaller than max string - just center, ETO, and return.
  706. if (cxString <= cxMaxString)
  707. {
  708. if (fPrintText)
  709. ExtTextOut(hDC,
  710. nXStart + (lpRect->right - cxString) / 2,
  711. nYStart,
  712. fuOptions,
  713. lpRect,
  714. szTempBuff,
  715. cch,
  716. NULL);
  717. iLastLineStart = 0; // only 1 line of text
  718. goto CleanupAndLeave;
  719. }
  720. // String is too long...we've got to word-wrap it.
  721. // Are there any spaces, slashes, tabs, or bangs in string?
  722. if (lstrlen(szTempBuff) != (int)strcspn(szTempBuff, szSeparators))
  723. {
  724. // Yep, we've got spaces, so we'll try to find the largest
  725. // space-terminated string that will fit on the first line.
  726. index = cch;
  727. while (index >= 0)
  728. {
  729. char cchKeep;
  730. // scan the string backwards for spaces, slashes, tabs, or bangs
  731. while (!IS_SEPARATOR(szTempBuff[index]) )
  732. index--;
  733. if (index <= 0)
  734. break;
  735. cchKeep = szTempBuff[index]; // remember what char was there
  736. szTempBuff[index] = '\0'; // just for now
  737. GetTextExtentPoint(
  738. hDCScreen, (LPSTR)szTempBuff,lstrlen((LPSTR)szTempBuff),&size);
  739. cxFirstLine = size.cx;
  740. cyFirstLine = size.cy;
  741. szTempBuff[index] = cchKeep; // put the right char back
  742. if (cxFirstLine <= cxMaxString)
  743. {
  744. iLastLineStart = index + 1;
  745. if (!fPrintText)
  746. goto CleanupAndLeave;
  747. ExtTextOut(hDC,
  748. nXStart + (lpRect->right - cxFirstLine) / 2,
  749. nYStart,
  750. fuOptions,
  751. lpRect,
  752. (LPSTR)szTempBuff,
  753. index + 1,
  754. lpDX);
  755. lpszSecondLine = (LPSTR)szTempBuff;
  756. lpszSecondLine += index + 1;
  757. GetTextExtentPoint(hDCScreen,
  758. lpszSecondLine,
  759. lstrlen(lpszSecondLine),
  760. &size);
  761. // If the second line is wider than the rectangle, we
  762. // just want to clip the text.
  763. cxSecondLine = min(size.cx, cxMaxString);
  764. ExtTextOut(hDC,
  765. nXStart + (lpRect->right - cxSecondLine) / 2,
  766. nYStart + cyFirstLine,
  767. fuOptions,
  768. lpRect,
  769. lpszSecondLine,
  770. lstrlen(lpszSecondLine),
  771. lpDX);
  772. goto CleanupAndLeave;
  773. } // end if
  774. index--;
  775. } // end while
  776. } // end if
  777. // Here, there are either no spaces in the string (strchr(szTempBuff, ' ')
  778. // returned NULL), or there spaces in the string, but they are
  779. // positioned so that the first space terminated string is still
  780. // longer than one line. So, we walk backwards from the end of the
  781. // string until we find the largest string that will fit on the first
  782. // line , and then we just clip the second line.
  783. cch = lstrlen((LPSTR)szTempBuff);
  784. chKeep = szTempBuff[cch];
  785. szTempBuff[cch] = '\0';
  786. GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size);
  787. cxFirstLine = size.cx;
  788. cyFirstLine = size.cy;
  789. while (cxFirstLine > cxMaxString)
  790. {
  791. // We allow 40 characters in the label, but the metafile is
  792. // only as wide as 10 W's (for aesthetics - 20 W's wide looked
  793. // dumb. This means that if we split a long string in half (in
  794. // terms of characters), then we could still be wider than the
  795. // metafile. So, if this is the case, we just step backwards
  796. // from the halfway point until we get something that will fit.
  797. // Since we just let ETO clip the second line
  798. szTempBuff[cch--] = chKeep;
  799. if (0 == cch)
  800. goto CleanupAndLeave;
  801. chKeep = szTempBuff[cch];
  802. szTempBuff[cch] = '\0';
  803. GetTextExtentPoint(
  804. hDCScreen, szTempBuff, lstrlen(szTempBuff), &size);
  805. cxFirstLine = size.cx;
  806. }
  807. iLastLineStart = cch;
  808. if (!fPrintText)
  809. goto CleanupAndLeave;
  810. ExtTextOut(hDC,
  811. nXStart + (lpRect->right - cxFirstLine) / 2,
  812. nYStart,
  813. fuOptions,
  814. lpRect,
  815. (LPSTR)szTempBuff,
  816. lstrlen((LPSTR)szTempBuff),
  817. lpDX);
  818. szTempBuff[cch] = chKeep;
  819. lpszSecondLine = szTempBuff;
  820. lpszSecondLine += cch;
  821. GetTextExtentPoint(
  822. hDCScreen, (LPSTR)lpszSecondLine, lstrlen(lpszSecondLine), &size);
  823. // If the second line is wider than the rectangle, we
  824. // just want to clip the text.
  825. cxSecondLine = min(size.cx, cxMaxString);
  826. ExtTextOut(hDC,
  827. nXStart + (lpRect->right - cxSecondLine) / 2,
  828. nYStart + cyFirstLine,
  829. fuOptions,
  830. lpRect,
  831. lpszSecondLine,
  832. lstrlen(lpszSecondLine),
  833. lpDX);
  834. CleanupAndLeave:
  835. SelectObject(hDCScreen, hFontT);
  836. ReleaseDC(NULL, hDCScreen);
  837. return iLastLineStart;
  838. }
  839. /*
  840. * OleStdGetUserTypeOfClass(REFCLSID, LPSTR, UINT, HKEY)
  841. *
  842. * Purpose:
  843. * Returns the user type (human readable class name) of the specified class.
  844. *
  845. * Parameters:
  846. * rclsid pointer to the clsid to retrieve user type of.
  847. * lpszUserType pointer to buffer to return user type in.
  848. * cch length of buffer pointed to by lpszUserType
  849. * hKey hKey for reg db - if this is NULL, then we
  850. * open and close the reg db within this function. If it
  851. * is non-NULL, then we assume it's a valid key to the
  852. * \ root and use it without closing it. (useful
  853. * if you're doing lots of reg db stuff).
  854. *
  855. * Return Value:
  856. * UINT Number of characters in returned string. 0 on error.
  857. *
  858. */
  859. STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPSTR lpszUserType, UINT cch, HKEY hKey)
  860. {
  861. LONG dw;
  862. LONG lRet;
  863. LPSTR lpszCLSID, lpszProgID;
  864. BOOL fFreeProgID = FALSE;
  865. BOOL bCloseRegDB = FALSE;
  866. char szKey[128];
  867. LPMALLOC lpIMalloc;
  868. if (hKey == NULL)
  869. {
  870. //Open up the root key.
  871. lRet=RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  872. if ((LONG)ERROR_SUCCESS!=lRet)
  873. return (UINT)FALSE;
  874. bCloseRegDB = TRUE;
  875. }
  876. // Get a string containing the class name
  877. StringFromCLSID(rclsid, &lpszCLSID);
  878. wsprintf(szKey, "CLSID\\%s", lpszCLSID);
  879. dw=cch;
  880. lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw);
  881. if ((LONG)ERROR_SUCCESS!=lRet)
  882. dw = 0;
  883. if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) )
  884. {
  885. // We've got an OLE 1.0 class, so let's try to get the user type
  886. // name from the ProgID entry.
  887. ProgIDFromCLSID(rclsid, &lpszProgID);
  888. fFreeProgID = TRUE;
  889. dw = cch;
  890. lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw);
  891. if ((LONG)ERROR_SUCCESS != lRet)
  892. dw = 0;
  893. }
  894. if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))
  895. {
  896. if (fFreeProgID)
  897. lpIMalloc->Free((LPVOID)lpszProgID);
  898. lpIMalloc->Free((LPVOID)lpszCLSID);
  899. lpIMalloc->Release();
  900. }
  901. if (bCloseRegDB)
  902. RegCloseKey(hKey);
  903. return (UINT)dw;
  904. }
  905. /*
  906. * OleStdGetAuxUserType(RCLSID, WORD, LPSTR, int, HKEY)
  907. *
  908. * Purpose:
  909. * Returns the specified AuxUserType from the reg db.
  910. *
  911. * Parameters:
  912. * rclsid pointer to the clsid to retrieve aux user type of.
  913. * hKey hKey for reg db - if this is NULL, then we
  914. * open and close the reg db within this function. If it
  915. * is non-NULL, then we assume it's a valid key to the
  916. * \ root and use it without closing it. (useful
  917. * if you're doing lots of reg db stuff).
  918. * wAuxUserType which aux user type field to look for. In 4/93 release
  919. * 2 is short name and 3 is exe name.
  920. * lpszUserType pointer to buffer to return user type in.
  921. * cch length of buffer pointed to by lpszUserType
  922. *
  923. * Return Value:
  924. * UINT Number of characters in returned string. 0 on error.
  925. *
  926. */
  927. STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,
  928. WORD wAuxUserType,
  929. LPSTR lpszAuxUserType,
  930. int cch,
  931. HKEY hKey)
  932. {
  933. HKEY hThisKey;
  934. BOOL fCloseRegDB = FALSE;
  935. LONG dw;
  936. LRESULT lRet;
  937. LPSTR lpszCLSID;
  938. LPMALLOC lpIMalloc;
  939. char szKey[OLEUI_CCHKEYMAX];
  940. char szTemp[32];
  941. lpszAuxUserType[0] = '\0';
  942. if (NULL == hKey)
  943. {
  944. lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hThisKey);
  945. if (ERROR_SUCCESS != lRet)
  946. return 0;
  947. }
  948. else
  949. hThisKey = hKey;
  950. StringFromCLSID(rclsid, &lpszCLSID);
  951. lstrcpy(szKey, "CLSID\\");
  952. lstrcat(szKey, lpszCLSID);
  953. wsprintf(szTemp, "\\AuxUserType\\%d", wAuxUserType);
  954. lstrcat(szKey, szTemp);
  955. dw = cch;
  956. lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw);
  957. if (ERROR_SUCCESS != lRet) {
  958. dw = 0;
  959. lpszAuxUserType[0] = '\0';
  960. }
  961. if (fCloseRegDB)
  962. RegCloseKey(hThisKey);
  963. if (NOERROR == CoGetMalloc(MEMCTX_TASK, &lpIMalloc))
  964. {
  965. lpIMalloc->Free((LPVOID)lpszCLSID);
  966. lpIMalloc->Release();
  967. }
  968. return (UINT)dw;
  969. }
  970. /*
  971. * PointerToNthField
  972. *
  973. * Purpose:
  974. * Returns a pointer to the beginning of the nth field.
  975. * Assumes null-terminated string.
  976. *
  977. * Parameters:
  978. * lpszString string to parse
  979. * nField field to return starting index of.
  980. * chDelimiter char that delimits fields
  981. *
  982. * Return Value:
  983. * LPSTR pointer to beginning of nField field.
  984. * NOTE: If the null terminator is found
  985. * Before we find the Nth field, then
  986. * we return a pointer to the null terminator -
  987. * calling app should be sure to check for
  988. * this case.
  989. *
  990. */
  991. LPSTR FAR PASCAL PointerToNthField(LPSTR lpszString, int nField, char chDelimiter)
  992. {
  993. LPSTR lpField = lpszString;
  994. int cFieldFound = 1;
  995. if (1 ==nField)
  996. return lpszString;
  997. while (*lpField != '\0')
  998. {
  999. if (*lpField++ == chDelimiter)
  1000. {
  1001. cFieldFound++;
  1002. if (nField == cFieldFound)
  1003. return lpField;
  1004. }
  1005. }
  1006. return lpField;
  1007. }
  1008. /*
  1009. * XformWidthInPixelsToHimetric
  1010. * XformWidthInHimetricToPixels
  1011. * XformHeightInPixelsToHimetric
  1012. * XformHeightInHimetricToPixels
  1013. *
  1014. * Functions to convert an int between a device coordinate system and
  1015. * logical HiMetric units.
  1016. *
  1017. * Parameters:
  1018. * hDC HDC providing reference to the pixel mapping. If
  1019. * NULL, a screen DC is used.
  1020. *
  1021. * Size Functions:
  1022. * lpSizeSrc LPSIZEL providing the structure to convert. This
  1023. * contains pixels in XformSizeInPixelsToHimetric and
  1024. * logical HiMetric units in the complement function.
  1025. * lpSizeDst LPSIZEL providing the structure to receive converted
  1026. * units. This contains pixels in
  1027. * XformSizeInPixelsToHimetric and logical HiMetric
  1028. * units in the complement function.
  1029. *
  1030. * Width Functions:
  1031. * iWidth int containing the value to convert.
  1032. *
  1033. * Return Value:
  1034. * Size Functions: None
  1035. * Width Functions: Converted value of the input parameters.
  1036. *
  1037. * NOTE:
  1038. * When displaying on the screen, Window apps display everything enlarged
  1039. * from its actual size so that it is easier to read. For example, if an
  1040. * app wants to display a 1in. horizontal line, that when printed is
  1041. * actually a 1in. line on the printed page, then it will display the line
  1042. * on the screen physically larger than 1in. This is described as a line
  1043. * that is "logically" 1in. along the display width. Windows maintains as
  1044. * part of the device-specific information about a given display device:
  1045. * LOGPIXELSX -- no. of pixels per logical in along the display width
  1046. * LOGPIXELSY -- no. of pixels per logical in along the display height
  1047. *
  1048. * The following formula converts a distance in pixels into its equivalent
  1049. * logical HIMETRIC units:
  1050. *
  1051. * DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
  1052. * -------------------------------
  1053. * PIXELS_PER_LOGICAL_IN
  1054. *
  1055. */
  1056. STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix)
  1057. {
  1058. int iXppli; //Pixels per logical inch along width
  1059. int iWidthInHiMetric;
  1060. BOOL fSystemDC=FALSE;
  1061. if (NULL==hDC)
  1062. {
  1063. hDC=GetDC(NULL);
  1064. fSystemDC=TRUE;
  1065. }
  1066. iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  1067. //We got pixel units, convert them to logical HIMETRIC along the display
  1068. iWidthInHiMetric = MAP_PIX_TO_LOGHIM(iWidthInPix, iXppli);
  1069. if (fSystemDC)
  1070. ReleaseDC(NULL, hDC);
  1071. return iWidthInHiMetric;
  1072. }
  1073. STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)
  1074. {
  1075. int iXppli; //Pixels per logical inch along width
  1076. int iWidthInPix;
  1077. BOOL fSystemDC=FALSE;
  1078. if (NULL==hDC)
  1079. {
  1080. hDC=GetDC(NULL);
  1081. fSystemDC=TRUE;
  1082. }
  1083. iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  1084. //We got logical HIMETRIC along the display, convert them to pixel units
  1085. iWidthInPix = MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);
  1086. if (fSystemDC)
  1087. ReleaseDC(NULL, hDC);
  1088. return iWidthInPix;
  1089. }
  1090. STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix)
  1091. {
  1092. int iYppli; //Pixels per logical inch along height
  1093. int iHeightInHiMetric;
  1094. BOOL fSystemDC=FALSE;
  1095. if (NULL==hDC)
  1096. {
  1097. hDC=GetDC(NULL);
  1098. fSystemDC=TRUE;
  1099. }
  1100. iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  1101. //* We got pixel units, convert them to logical HIMETRIC along the display
  1102. iHeightInHiMetric = MAP_PIX_TO_LOGHIM(iHeightInPix, iYppli);
  1103. if (fSystemDC)
  1104. ReleaseDC(NULL, hDC);
  1105. return iHeightInHiMetric;
  1106. }
  1107. STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)
  1108. {
  1109. int iYppli; //Pixels per logical inch along height
  1110. int iHeightInPix;
  1111. BOOL fSystemDC=FALSE;
  1112. if (NULL==hDC)
  1113. {
  1114. hDC=GetDC(NULL);
  1115. fSystemDC=TRUE;
  1116. }
  1117. iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  1118. //* We got logical HIMETRIC along the display, convert them to pixel units
  1119. iHeightInPix = MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);
  1120. if (fSystemDC)
  1121. ReleaseDC(NULL, hDC);
  1122. return iHeightInPix;
  1123. }