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.

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