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.

2369 lines
68 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: icon.cpp
  7. //
  8. // Contents: Functions to create DVASPECT_ICON metafile from a filename
  9. // or class ID
  10. //
  11. // Classes:
  12. //
  13. // Functions:
  14. // OleGetIconOfFile
  15. // OleGetIconOfClass
  16. // OleMetafilePictFromIconAndLabel
  17. //
  18. // HIconAndSourceFromClass: Extracts the first icon in a class's
  19. // server path and returns the path and icon index to
  20. // caller.
  21. // FIconFileFromClass: Retrieves the path to the exe/dll
  22. // containing the default icon, and the index of the icon.
  23. // IconLabelTextOut
  24. // XformWidthInPixelsToHimetric
  25. // Converts an int width into HiMetric units
  26. // XformWidthInHimetricToPixels
  27. // Converts an int width from HiMetric units
  28. // XformHeightInPixelsToHimetric
  29. // Converts an int height into HiMetric units
  30. // XformHeightInHimetricToPixels
  31. // Converts an int height from HiMetric units
  32. //
  33. // History: dd-mmm-yy Author Comment
  34. // 24-Nov-93 alexgo 32bit port
  35. // 15-Dec-93 alexgo fixed some bad UNICODE string handling
  36. // 11-Jan-94 alexgo added VDATEHEAP macros to every function
  37. // 25-Jan-94 alexgo first pass at converting to Cairo-style
  38. // memory allocations.
  39. // 26-Apr-94 AlexT Add tracing, fix bugs, etc
  40. // 27-Dec-94 alexgo fixed multithreading problems, added
  41. // support for quoted icon names
  42. //
  43. // Notes:
  44. //
  45. //--------------------------------------------------------------------------
  46. #include <le2int.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include <commdlg.h>
  51. #include <memory.h>
  52. #include <cderr.h>
  53. #include <resource.h>
  54. #define STRSAFE_NO_DEPRECATE
  55. #include <strsafe.h>
  56. #include "icon.h"
  57. #define OLEUI_CCHKEYMAX 256
  58. #define OLEUI_CCHPATHMAX 256
  59. #define OLEUI_CCHLABELMAX 42
  60. #define ICONINDEX 0
  61. #define AUXUSERTYPE_SHORTNAME USERCLASSTYPE_SHORT // short name
  62. #define HIMETRIC_PER_INCH 2540 // number HIMETRIC units per inch
  63. #define PTS_PER_INCH 72 // number points (font size) per inch
  64. #define MAP_PIX_TO_LOGHIM(x,ppli) MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
  65. #define MAP_LOGHIM_TO_PIX(x,ppli) MulDiv((ppli), (x), HIMETRIC_PER_INCH)
  66. static OLECHAR const gszDefIconLabelKey[] =
  67. OLESTR( "Software\\Microsoft\\OLE2\\DefaultIconLabel");
  68. #define IS_SEPARATOR(c) ( (c) == OLESTR(' ') || (c) == OLESTR('\\') || (c) == OLESTR('/') || (c) == OLESTR('\t') || (c) == OLESTR('!') || (c) == OLESTR(':') )
  69. //REVIEW: what about the \\ case for UNC filenames, could it be considered a delimter also?
  70. #define IS_FILENAME_DELIM(c) ( (c) == OLESTR('\\') || (c) == OLESTR('/') || (c) == OLESTR(':') )
  71. #ifdef WIN32
  72. #define LSTRCPYN(lpdst, lpsrc, cch) \
  73. (\
  74. lpdst[cch-1] = OLESTR('\0'), \
  75. lstrcpynW(lpdst, lpsrc, cch-1)\
  76. )
  77. #else
  78. #define LSTRCPYN(lpdst, lpsrc, cch) \
  79. (\
  80. lpdst[cch-1] = OLESTR('\0'), \
  81. lstrncpy(lpdst, lpsrc, cch-1)\
  82. )
  83. #endif
  84. void IconLabelTextOut(HDC hDC, HFONT hFont, int nXStart, int nYStart,
  85. UINT fuOptions, RECT FAR * lpRect, LPCSTR lpszString,
  86. UINT cchString);
  87. /*******
  88. *
  89. * ICON METAFILE FORMAT:
  90. *
  91. * The metafile generated with OleMetafilePictFromIconAndLabel contains
  92. * the following records which are used by the functions in DRAWICON.C
  93. * to draw the icon with and without the label and to extract the icon,
  94. * label, and icon source/index.
  95. *
  96. * SetWindowOrg
  97. * SetWindowExt
  98. * DrawIcon:
  99. * Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the
  100. * AND mask, one for the image bits.
  101. * Escape with the comment "IconOnly"
  102. * This indicates where to stop record enumeration to draw only
  103. * the icon.
  104. * SetTextColor
  105. * SetBkColor
  106. * CreateFont
  107. * SelectObject on the font.
  108. * ExtTextOut
  109. * One or more ExtTextOuts occur if the label is wrapped. The
  110. * text in these records is used to extract the label.
  111. * SelectObject on the old font.
  112. * DeleteObject on the font.
  113. * Escape with a comment that contains the path to the icon source (ANSI).
  114. * Escape with a comment that is the string of the icon index (ANSI).
  115. *
  116. * Additional optional fields (new for 32-bit OLE, and only present if icon
  117. * source or label was not translatable):
  118. *
  119. * Escape with a comment that contains the string
  120. * "OLE: Icon label next (Unicode)" (ANSI string)
  121. * Escape with a comment that contains the Unicode label
  122. *
  123. * Escape with a comment that contains the string
  124. * "OLE: Icon source next (Unicode)" (ANSI string)
  125. * Escape with a comment that contains the path to the icon source (UNICODE)
  126. *
  127. *******/
  128. //+-------------------------------------------------------------------------
  129. //
  130. // Function: OleGetIconOfFile (public)
  131. //
  132. // Synopsis: Returns a hMetaPict containing an icon and label (filename)
  133. // for the specified filename
  134. //
  135. // Effects:
  136. //
  137. // Arguments: [lpszPath] -- LPOLESTR path including filename to use
  138. // [fUseAsLabel] -- if TRUE, use the filename as the icon's
  139. // label; no label if FALSE
  140. //
  141. // Requires: lpszPath != NULL
  142. //
  143. // Returns: HGLOBAL to the hMetaPict
  144. //
  145. // Signals:
  146. //
  147. // Modifies:
  148. //
  149. // Algorithm: tries to get the icon from the class ID or from the
  150. // exe associated with the file extension.
  151. //
  152. // History: dd-mmm-yy Author Comment
  153. // 27-Nov-93 alexgo first 32bit port (minor cleanup)
  154. // 15-Dec-93 alexgo changed lstrlen to _xstrlen
  155. // 27-Dec-93 erikgav chicago port
  156. // 28-Dec-94 alexgo fixed multithreading problems
  157. //
  158. // Notes:
  159. //
  160. //--------------------------------------------------------------------------
  161. STDAPI_(HGLOBAL) OleGetIconOfFile(LPOLESTR lpszPath, BOOL fUseFileAsLabel)
  162. {
  163. OLETRACEIN((API_OleGetIconOfFile, PARAMFMT("lpszPath= %ws, fUseFileAsLabel= %B"),
  164. lpszPath, fUseFileAsLabel));
  165. VDATEHEAP();
  166. HGLOBAL hMetaPict = NULL;
  167. BOOL fUseGenericDocIcon = FALSE;
  168. BOOL bRet;
  169. OLECHAR szIconFile[OLEUI_CCHPATHMAX+1];
  170. OLECHAR szLabel[OLEUI_CCHLABELMAX];
  171. OLECHAR szDocument[OLEUI_CCHLABELMAX];
  172. CLSID clsid;
  173. HICON hDefIcon = NULL;
  174. UINT IconIndex = 0;
  175. UINT cchPath;
  176. BOOL fGotLabel = FALSE;
  177. HRESULT hResult = E_FAIL;
  178. UINT uFlags;
  179. LEDebugOut((DEB_TRACE, "%p _IN OleGetIconOfFile (%p, %d)\n",
  180. NULL, lpszPath, fUseFileAsLabel));
  181. *szIconFile = OLESTR('\0');
  182. *szDocument = OLESTR('\0');
  183. if (NULL == lpszPath)
  184. {
  185. // The spec allows a NULL lpszPath...
  186. hMetaPict = NULL;
  187. goto ErrRtn;
  188. }
  189. SHFILEINFO shfi;
  190. uFlags = (SHGFI_ICON | SHGFI_LARGEICON | SHGFI_DISPLAYNAME |
  191. SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES);
  192. _xmemset(&shfi, 0, sizeof(shfi));
  193. if (fUseFileAsLabel)
  194. uFlags |= SHGFI_LINKOVERLAY;
  195. if (SHGetFileInfo( lpszPath, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), uFlags))
  196. {
  197. if (shfi.iIcon == 0)
  198. {
  199. // Destroy the returned icon
  200. DestroyIcon(shfi.hIcon);
  201. // REVIEW: if non-NULL path str, do we want parameter validation?
  202. hResult = GetClassFile(lpszPath, &clsid);
  203. // use the clsid we got to get to the icon
  204. if( NOERROR == hResult )
  205. {
  206. hDefIcon = HIconAndSourceFromClass(clsid, szIconFile, &IconIndex);
  207. }
  208. }
  209. else
  210. {
  211. hDefIcon = shfi.hIcon;
  212. hResult = NOERROR;
  213. OLECHAR szUnicodeLabel[OLEUI_CCHLABELMAX];
  214. if (fUseFileAsLabel)
  215. LSTRCPYN(szLabel, shfi.szDisplayName, sizeof(szLabel)/sizeof(OLECHAR));
  216. else
  217. LSTRCPYN(szLabel, shfi.szTypeName, sizeof(szLabel)/sizeof(OLECHAR));
  218. fGotLabel = TRUE;
  219. // need to fill out szIconFile, which is the path to the file in which the icon
  220. // was extracted. Unfortunately, the shell can't return this value to us, so we
  221. // must get the file that OLE would have used in the fallback case. This could
  222. // be inconsistant with the shell if the application has installed a custom icon
  223. // handler.
  224. hResult = GetClassFile(lpszPath, &clsid);
  225. if( NOERROR == hResult )
  226. {
  227. FIconFileFromClass(clsid, szIconFile, OLEUI_CCHPATHMAX, &IconIndex);
  228. }
  229. }
  230. }
  231. cchPath = _xstrlen(lpszPath);
  232. if ((NOERROR != hResult) || (NULL == hDefIcon))
  233. {
  234. WORD index = 0;
  235. // we need to copy into a large buffer because the second
  236. // parameter of ExtractAssociatedIcon (the path name) is an
  237. // in/out
  238. lstrcpyn(szIconFile, lpszPath, sizeof(szIconFile)/sizeof(*szIconFile));
  239. hDefIcon = ExtractAssociatedIcon(g_hmodOLE2, szIconFile, &index);
  240. IconIndex = index;
  241. }
  242. if (fUseGenericDocIcon || hDefIcon <= (HICON)1)
  243. {
  244. DWORD dwLen;
  245. dwLen = GetModuleFileName(g_hmodOLE2,
  246. szIconFile,
  247. sizeof(szIconFile) / sizeof(OLECHAR));
  248. if (0 == dwLen)
  249. {
  250. LEDebugOut((DEB_WARN,
  251. "OleGetIconOfFile: GetModuleFileName failed - %ld",
  252. GetLastError()));
  253. goto ErrRtn;
  254. }
  255. szIconFile[sizeof(szIconFile)/sizeof(szIconFile[0])-1] = L'\0';
  256. IconIndex = ICONINDEX;
  257. hDefIcon = LoadIcon(g_hmodOLE2, MAKEINTRESOURCE(DEFICON));
  258. }
  259. // Now let's get the label we want to use.
  260. if (fGotLabel)
  261. {
  262. // Do nothing
  263. }
  264. else if (fUseFileAsLabel)
  265. {
  266. // This assumes the path uses only '\', '/', and '.' as separators
  267. // strip off path, so we just have the filename.
  268. LPOLESTR lpszBeginFile;
  269. // set pointer to END of path, so we can walk backwards
  270. // through it.
  271. lpszBeginFile = lpszPath + cchPath - 1;
  272. while ((lpszBeginFile >= lpszPath) &&
  273. (!IS_FILENAME_DELIM(*lpszBeginFile)))
  274. {
  275. #ifdef WIN32
  276. lpszBeginFile--;
  277. #else
  278. lpszBeginFile = CharPrev(lpszPath, lpszBeginFile);
  279. #endif
  280. }
  281. lpszBeginFile++; // step back over the delimiter
  282. // LSTRCPYN takes count of characters!
  283. LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel) / sizeof(OLECHAR));
  284. }
  285. // use the short user type (AuxUserType2) for the label
  286. else if (0 == OleStdGetAuxUserType(clsid, AUXUSERTYPE_SHORTNAME,
  287. szLabel, OLEUI_CCHLABELMAX, NULL))
  288. {
  289. if (OLESTR('\0')==szDocument[0]) // review, this is always true
  290. {
  291. LONG lRet;
  292. LONG lcb;
  293. lcb = sizeof (szDocument);
  294. lRet = QueryClassesRootValue(gszDefIconLabelKey, szDocument, &lcb);
  295. #if DBG==1
  296. if (ERROR_SUCCESS != lRet)
  297. {
  298. LEDebugOut((DEB_WARN,
  299. "RegQueryValue for default icon label failed - %d\n",
  300. GetLastError()));
  301. }
  302. #endif
  303. // NULL out last byte of string so don't rely on Reg behavior if buffer isn't big enough
  304. szDocument[OLEUI_CCHLABELMAX -1] = OLESTR('\0');
  305. }
  306. _xstrcpy(szLabel, szDocument);
  307. }
  308. hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel,
  309. szIconFile, IconIndex);
  310. bRet = DestroyIcon(hDefIcon);
  311. Win4Assert(bRet && "DestroyIcon failed");
  312. ErrRtn:
  313. LEDebugOut((DEB_TRACE, "%p OUT OleGetIconOfFile( %lx )\n",
  314. hMetaPict ));
  315. OLETRACEOUTEX((API_OleGetIconOfFile, RETURNFMT("%h"), hMetaPict));
  316. return hMetaPict;
  317. }
  318. //+-------------------------------------------------------------------------
  319. //
  320. // Function: GetAssociatedExectutable
  321. //
  322. // Synopsis: Finds the executables associated with the provided extension
  323. //
  324. // Effects:
  325. //
  326. // Arguments: [lpszExtension] -- pointer to the extension
  327. // [lpszExecutable] -- where to put the executable name
  328. // (assumes OLEUIPATHMAX OLECHAR buffer
  329. // from calling function)
  330. //
  331. // Requires: lpszExecutable must be large enough to hold the path
  332. //
  333. // Returns: TRUE if exe found, FALSE otherwise
  334. //
  335. // Signals:
  336. //
  337. // Modifies:
  338. //
  339. // Algorithm: Queries reg database
  340. //
  341. // History: dd-mmm-yy Author Comment
  342. // 27-Nov-93 alexgo 32bit port
  343. // 15-Dec-93 alexgo fixed bug calculating size of strings
  344. // 26-Apr-94 AlexT Tracing, bug fixes
  345. //
  346. // Notes:
  347. //
  348. //--------------------------------------------------------------------------
  349. BOOL FAR PASCAL GetAssociatedExecutable(LPOLESTR lpszExtension,
  350. LPOLESTR lpszExecutable)
  351. {
  352. VDATEHEAP();
  353. BOOL bRet = FALSE;
  354. HKEY hKey;
  355. LONG dw;
  356. LRESULT lRet;
  357. OLECHAR szValue[OLEUI_CCHKEYMAX];
  358. OLECHAR szKey[OLEUI_CCHKEYMAX];
  359. LPOLESTR lpszTemp, lpszExe;
  360. LEDebugOut((DEB_ITRACE, "%p _IN GetAssociatedExecutable (%p, %p)\n",
  361. NULL, lpszExtension, lpszExecutable));
  362. // REVIEW: actually returns a LONG, which is indeed an LRESULT, not
  363. // sure why the distinction here
  364. lRet = OpenClassesRootKey(NULL, &hKey);
  365. if (ERROR_SUCCESS != lRet)
  366. {
  367. goto ErrRtn;
  368. }
  369. dw = sizeof(szValue);
  370. lRet = RegQueryValue(hKey, lpszExtension, szValue, &dw);
  371. if (ERROR_SUCCESS != lRet)
  372. {
  373. RegCloseKey(hKey);
  374. goto ErrRtn;
  375. }
  376. // szValue now has ProgID
  377. StringCbCopy(szKey, sizeof(szKey), szValue);
  378. StringCbCat(szKey, sizeof(szKey), OLESTR("\\Shell\\Open\\Command"));
  379. // RegQueryValue wants *bytes*, not characters
  380. dw = sizeof(szValue);
  381. lRet = RegQueryValue(hKey, szKey, szValue, &dw);
  382. RegCloseKey(hKey);
  383. if (ERROR_SUCCESS != lRet)
  384. {
  385. goto ErrRtn;
  386. }
  387. // szValue now has an executable name in it. Let's null-terminate
  388. // at the first post-executable space (so we don't have cmd line
  389. // args.
  390. lpszTemp = szValue;
  391. PUSHORT pCharTypes;
  392. pCharTypes = (PUSHORT)_alloca (sizeof (USHORT) * (lstrlenW(lpszTemp) + 1));
  393. if (pCharTypes == NULL)
  394. {
  395. goto ErrRtn;
  396. }
  397. GetStringTypeW (CT_CTYPE1, lpszTemp, -1, pCharTypes);
  398. while ((OLESTR('\0') != *lpszTemp) && (pCharTypes[lpszTemp - szValue] & C1_SPACE))
  399. {
  400. lpszTemp++; // Strip off leading spaces
  401. }
  402. lpszExe = lpszTemp;
  403. while ((OLESTR('\0') != *lpszTemp) && ((pCharTypes[lpszTemp - szValue] & C1_SPACE) == 0))
  404. {
  405. lpszTemp++; // Set through exe name
  406. }
  407. // null terminate at first space (or at end).
  408. *lpszTemp = OLESTR('\0');
  409. Win4Assert(_xstrlen(lpszExe) < OLEUI_CCHPATHMAX &&
  410. "GetAssociatedFile too long");
  411. _xstrcpy(lpszExecutable, lpszExe);
  412. bRet = TRUE;
  413. ErrRtn:
  414. LEDebugOut((DEB_ITRACE, "%p OUT GetAssociatedExecutable( %d )\n",
  415. bRet ));
  416. return bRet;
  417. }
  418. //+-------------------------------------------------------------------------
  419. //
  420. // Function: OleGetIconOfClass (public)
  421. //
  422. // Synopsis: returns a hMetaPict containing an icon and label for the
  423. // specified class ID
  424. //
  425. // Effects:
  426. //
  427. // Arguments: [rclsid] -- the class ID to use
  428. // [lpszLabel] -- the label for the icon
  429. // [fUseTypeAsLabel] -- if TRUE, use the clsid's user type
  430. // as the label
  431. //
  432. // Requires:
  433. //
  434. // Returns: HGLOBAL
  435. //
  436. // Signals:
  437. //
  438. // Modifies:
  439. //
  440. // Algorithm:
  441. //
  442. // History: dd-mmm-yy Author Comment
  443. // 15-Dec-93 alexgo fixed small bugs with Unicode strings
  444. // 27-Nov-93 alexgo 32bit port
  445. //
  446. // Notes:
  447. //
  448. //--------------------------------------------------------------------------
  449. STDAPI_(HGLOBAL) OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel,
  450. BOOL fUseTypeAsLabel)
  451. {
  452. OLETRACEIN((API_OleGetIconOfClass,
  453. PARAMFMT("rclisd= %I, lpszLabel= %p, fUseTypeAsLabel= %B"),
  454. &rclsid, lpszLabel, fUseTypeAsLabel));
  455. VDATEHEAP();
  456. BOOL bRet;
  457. OLECHAR szLabel[OLEUI_CCHLABELMAX];
  458. OLECHAR szIconFile[OLEUI_CCHPATHMAX];
  459. OLECHAR szDocument[OLEUI_CCHLABELMAX];
  460. HICON hDefIcon;
  461. UINT IconIndex;
  462. HGLOBAL hMetaPict = NULL;
  463. LEDebugOut((DEB_TRACE, "%p _IN OleGetIconOfClass (%p, %p, %d)\n",
  464. NULL, &rclsid, lpszLabel, fUseTypeAsLabel));
  465. *szLabel = OLESTR('\0');
  466. *szDocument = OLESTR('\0');
  467. #if DBG==1
  468. if (fUseTypeAsLabel && (NULL != lpszLabel))
  469. {
  470. LEDebugOut((DEB_WARN,
  471. "Ignoring non-NULL lpszLabel passed to OleGetIconOfClass\n"));
  472. }
  473. #endif
  474. if (!fUseTypeAsLabel) // Use string passed in as label
  475. {
  476. if (NULL != lpszLabel)
  477. {
  478. // LSTRCPYN takes count of characters!
  479. LSTRCPYN(szLabel, lpszLabel, sizeof(szLabel) / sizeof(OLECHAR));
  480. }
  481. }
  482. // Use AuxUserType2 (short name) as label
  483. else if (0 == OleStdGetAuxUserType(rclsid, AUXUSERTYPE_SHORTNAME,
  484. szLabel,
  485. sizeof(szLabel) / sizeof(OLECHAR),
  486. NULL))
  487. {
  488. // If we can't get the AuxUserType2, then try the long name
  489. if (0 == OleStdGetUserTypeOfClass(rclsid,
  490. szLabel,
  491. sizeof(szLabel) / sizeof(OLECHAR),
  492. NULL))
  493. {
  494. if (OLESTR('\0') == szDocument[0])
  495. {
  496. // RegQueryValue expects number of *bytes*
  497. LONG lRet;
  498. LONG lcb;
  499. lcb = sizeof(szDocument);
  500. lRet = QueryClassesRootValue(gszDefIconLabelKey, szDocument, &lcb);
  501. #if DBG==1
  502. if (ERROR_SUCCESS != lRet)
  503. {
  504. LEDebugOut((DEB_WARN,
  505. "RegQueryValue for default icon label failed - %d\n",
  506. GetLastError()));
  507. }
  508. #endif
  509. // NULL out last byte of string so don't rely on Reg behavior if buffer isn't big enough
  510. szDocument[OLEUI_CCHLABELMAX -1] = OLESTR('\0');
  511. }
  512. _xstrcpy(szLabel, szDocument); // last resort
  513. }
  514. }
  515. // Get the icon, icon index, and path to icon file
  516. hDefIcon = HIconAndSourceFromClass(rclsid, szIconFile, &IconIndex);
  517. if (NULL == hDefIcon) // Use Vanilla Document
  518. {
  519. DWORD dwLen;
  520. dwLen = GetModuleFileName(g_hmodOLE2,
  521. szIconFile,
  522. sizeof(szIconFile) / sizeof(OLECHAR));
  523. if (0 == dwLen)
  524. {
  525. LEDebugOut((DEB_WARN,
  526. "OleGetIconOfClass: GetModuleFileName failed - %ld",
  527. GetLastError()));
  528. goto ErrRtn;
  529. }
  530. IconIndex = ICONINDEX;
  531. hDefIcon = LoadIcon(g_hmodOLE2, MAKEINTRESOURCE(DEFICON));
  532. }
  533. // Create the metafile
  534. hMetaPict = OleMetafilePictFromIconAndLabel(hDefIcon, szLabel,
  535. szIconFile, IconIndex);
  536. if(hDefIcon)
  537. {
  538. bRet = DestroyIcon(hDefIcon);
  539. Win4Assert(bRet && "DestroyIcon failed");
  540. }
  541. ErrRtn:
  542. LEDebugOut((DEB_TRACE, "%p OUT OleGetIconOfClass( %p )\n",
  543. NULL, hMetaPict ));
  544. OLETRACEOUTEX((API_OleGetIconOfClass, RETURNFMT("%h"), hMetaPict));
  545. return hMetaPict;
  546. }
  547. //+-------------------------------------------------------------------------
  548. //
  549. // Function: HIconAndSourceFromClass
  550. //
  551. // Synopsis:
  552. // Given an object class name, finds an associated executable in the
  553. // registration database and extracts the first icon from that
  554. // executable. If none is available or the class has no associated
  555. // executable, this function returns NULL.
  556. //
  557. // Effects:
  558. //
  559. // Arguments: [rclsid] -- pointer the class id
  560. // [pszSource] -- where to put the source of the icon
  561. // [puIcon] -- where to store the index of the icon
  562. // -- in [pszSource]
  563. //
  564. // Requires:
  565. //
  566. // Returns: HICON -- handle to the extracted icon
  567. //
  568. // Signals:
  569. //
  570. // Modifies:
  571. //
  572. // Algorithm:
  573. //
  574. // History: dd-mmm-yy Author Comment
  575. // 27-Nov-93 alexgo 32bit port
  576. //
  577. // Notes:
  578. //
  579. //--------------------------------------------------------------------------
  580. HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPOLESTR pszSource,
  581. UINT FAR *puIcon)
  582. {
  583. VDATEHEAP();
  584. HICON hIcon = NULL;
  585. UINT IconIndex;
  586. LEDebugOut((DEB_ITRACE, "%p _IN HIconAndSourceFromClass (%p, %p, %p)\n",
  587. NULL, &rclsid, pszSource, puIcon));
  588. if (IsEqualCLSID(CLSID_NULL, rclsid) || NULL==pszSource)
  589. {
  590. goto ErrRtn;
  591. }
  592. if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX, &IconIndex))
  593. {
  594. goto ErrRtn;
  595. }
  596. hIcon = ExtractIcon(g_hmodOLE2, pszSource, IconIndex);
  597. // REVIEW: What's special about icon handles > 32 ?
  598. if ((HICON)32 > hIcon)
  599. {
  600. // REVIEW: any cleanup or releasing of handle needed before we lose
  601. // the ptr?
  602. hIcon=NULL;
  603. }
  604. else
  605. {
  606. *puIcon= IconIndex;
  607. }
  608. ErrRtn:
  609. LEDebugOut((DEB_ITRACE, "%p OUT HIconAndSourceFromClass( %lx ) [ %d ]\n",
  610. NULL, hIcon, *puIcon));
  611. return hIcon;
  612. }
  613. //+-------------------------------------------------------------------------
  614. //
  615. // Function: ExtractNameAndIndex
  616. //
  617. // Synopsis: from the given string, extract the file name and icon index
  618. //
  619. // Effects:
  620. //
  621. // Arguments: [pszInfo] -- the starting string
  622. // [pszEXE] -- where to put the name (already allocated)
  623. // [cchEXE] -- sizeof pszEXE
  624. // [pIndex] -- where to put the icon index
  625. //
  626. // Requires: pszInfo != NULL
  627. // pszEXE != NULL
  628. // cchEXE != 0
  629. // pIndex != NULL
  630. //
  631. // Returns: BOOL -- TRUE on success, FALSE on error
  632. //
  633. // Signals:
  634. //
  635. // Modifies:
  636. //
  637. // Algorithm: takes strings of the form '"name",index' or 'name,index'
  638. // from the DefaultIcon registry entry
  639. //
  640. // parsing is very simple: if the name is enclosed in quotes,
  641. // take that as the exe name. If any other characters exist,
  642. // they must be a comma followed by digits (for the icon index)
  643. //
  644. // if the name is not enclosed by quotes, assume the name is
  645. // the entire string up until the last comma (if it exists).
  646. //
  647. // History: dd-mmm-yy Author Comment
  648. // 27-Dec-94 alexgo author
  649. //
  650. // Notes: legal filenames in NT and Win95 can include commas, but not
  651. // quotation marks.
  652. //
  653. //--------------------------------------------------------------------------
  654. BOOL ExtractNameAndIndex( LPOLESTR pszInfo, LPOLESTR pszEXE, UINT cchEXE,
  655. UINT *pIndex)
  656. {
  657. BOOL fRet = FALSE;
  658. LPOLESTR pszStart = pszInfo;
  659. LPOLESTR pszIndex = NULL;
  660. LPOLESTR pszDest = pszEXE;
  661. UINT cchName = 0;
  662. DWORD i = 0;
  663. Assert(pszInfo);
  664. Assert(pszEXE);
  665. Assert(cchEXE != 0);
  666. Assert(pIndex);
  667. VDATEHEAP();
  668. LEDebugOut((DEB_ITRACE, "%p _IN ExtractNameAndIndex ( \"%ws\" , \"%ws\" ,"
  669. " %d , %p )\n", NULL, pszInfo, pszEXE, cchEXE, pIndex));
  670. *pIndex = 0;
  671. if( *pszStart == OLESTR('\"') )
  672. {
  673. // name enclosed by quotes; just zoom down til the very last quote
  674. pszStart++;
  675. while( *pszStart != OLESTR('\0') && *pszStart != OLESTR('\"') &&
  676. pszDest < (pszEXE + cchEXE))
  677. {
  678. *pszDest = *pszStart;
  679. pszDest++;
  680. pszStart++;
  681. }
  682. *pszDest = OLESTR('\0');
  683. if( *pszStart == OLESTR('\"') )
  684. {
  685. pszIndex = pszStart + 1;
  686. }
  687. else
  688. {
  689. pszIndex = pszStart;
  690. }
  691. fRet = TRUE;
  692. }
  693. else
  694. {
  695. // find the last comma (if available)
  696. pszIndex = pszStart + _xstrlen(pszStart);
  697. while( *pszIndex != OLESTR(',') && pszIndex > pszStart )
  698. {
  699. pszIndex--;
  700. }
  701. // if no comma was found, just reset the index pointer to the end
  702. if( pszIndex == pszStart )
  703. {
  704. pszIndex = pszStart + _xstrlen(pszStart);
  705. }
  706. cchName = (ULONG) (pszIndex - pszStart)/sizeof(OLECHAR);
  707. if( cchEXE > cchName )
  708. {
  709. while( pszStart < pszIndex )
  710. {
  711. *pszDest = *pszStart;
  712. pszDest++;
  713. pszStart++;
  714. }
  715. *pszDest = OLESTR('\0');
  716. fRet = TRUE;
  717. }
  718. }
  719. // now fetch the index value
  720. if( *pszIndex == OLESTR(',') )
  721. {
  722. pszIndex++;
  723. }
  724. *pIndex = wcstol(pszIndex, NULL, 10);
  725. LEDebugOut((DEB_ITRACE, "%p OUT ExtractNameAndIndex ( %d ) [ \"%ws\" , "
  726. " %d ]\n", NULL, fRet, pszEXE, *pIndex));
  727. return fRet;
  728. }
  729. #if DBG == 1
  730. //+-------------------------------------------------------------------------
  731. //
  732. // Function: VerifyExtractNameAndIndex
  733. //
  734. // Synopsis: verifies the functioning of ExtractNameAndIndex (DEBUG only)
  735. //
  736. // Effects:
  737. //
  738. // Arguments: void
  739. //
  740. // Requires:
  741. //
  742. // Returns: void
  743. //
  744. // Signals:
  745. //
  746. // Modifies:
  747. //
  748. // Algorithm:
  749. //
  750. // History: dd-mmm-yy Author Comment
  751. // 27-Dec-94 alexgo author
  752. //
  753. // Notes:
  754. //
  755. //--------------------------------------------------------------------------
  756. void VerifyExtractNameAndIndex( void )
  757. {
  758. OLECHAR szName[256];
  759. UINT index = 0;
  760. BOOL fRet = FALSE;
  761. VDATEHEAP();
  762. fRet = ExtractNameAndIndex( OLESTR("\"foo,8\",8"), szName, 256, &index);
  763. Assert(fRet);
  764. Assert(_xstrcmp(szName, OLESTR("foo,8")) == 0);
  765. Assert(index == 8);
  766. fRet = ExtractNameAndIndex( OLESTR("foo,8,8,89"), szName, 256, &index);
  767. Assert(fRet);
  768. Assert(_xstrcmp(szName, OLESTR("foo,8,8")) == 0);
  769. Assert(index == 89);
  770. fRet = ExtractNameAndIndex( OLESTR("progman.exe"), szName, 256, &index);
  771. Assert(fRet);
  772. Assert(_xstrcmp(szName, OLESTR("progman.exe")) == 0);
  773. Assert(index == 0);
  774. fRet = ExtractNameAndIndex( OLESTR("\"progman.exe\""), szName, 256,
  775. &index);
  776. Assert(fRet);
  777. Assert(_xstrcmp(szName, OLESTR("progman.exe")) == 0);
  778. Assert(index == 0);
  779. VDATEHEAP();
  780. }
  781. #endif // DBG == 1
  782. LONG RegReadDefValue(HKEY hKey, LPOLESTR pszKey, LPOLESTR *ppszValue)
  783. {
  784. HKEY hSubKey = NULL;
  785. DWORD dw = 0;
  786. LONG lRet;
  787. LPOLESTR pszValue = NULL;
  788. lRet = RegOpenKeyEx(hKey, pszKey, 0, KEY_READ, &hSubKey);
  789. if(lRet != ERROR_SUCCESS) goto ErrRtn;
  790. lRet = RegQueryValueEx(hSubKey, NULL, NULL, NULL, NULL, &dw);
  791. if(lRet != ERROR_SUCCESS) goto ErrRtn;
  792. pszValue = (LPOLESTR) CoTaskMemAlloc(dw);
  793. if(!pszValue)
  794. {
  795. lRet = ERROR_OUTOFMEMORY;
  796. goto ErrRtn;
  797. }
  798. lRet = RegQueryValueEx(hSubKey, NULL, NULL, NULL, (PBYTE) pszValue, &dw);
  799. ErrRtn:
  800. if(lRet != ERROR_SUCCESS && pszValue)
  801. {
  802. CoTaskMemFree(pszValue);
  803. pszValue = NULL;
  804. }
  805. if(hSubKey)
  806. RegCloseKey(hSubKey);
  807. *ppszValue = pszValue;
  808. return lRet;
  809. }
  810. //+-------------------------------------------------------------------------
  811. //
  812. // Function: FIconFileFromClass, private
  813. //
  814. // Synopsis: Looks up the path to the exectuble that contains the class
  815. // default icon
  816. //
  817. // Effects:
  818. //
  819. // Arguments: [rclsid] -- the class ID to lookup
  820. // [pszEXE] -- where to put the server name
  821. // [cch] -- UINT size of [pszEXE]
  822. // [lpIndex] -- where to put the index of the icon
  823. // in the executable
  824. //
  825. // Requires: pszEXE != NULL
  826. // cch != 0
  827. //
  828. // Returns: TRUE if one or more characters where found for [pszEXE],
  829. // FALSE otherwise
  830. //
  831. // Signals:
  832. //
  833. // Modifies:
  834. //
  835. // Algorithm:
  836. //
  837. // History: dd-mmm-yy Author Comment
  838. // 27-Nov-93 alexgo 32bit port
  839. // 15-Dec-93 alexgo fixed memory allocation bug and
  840. // some UNICODE string manip stuff
  841. // 27-Apr-94 AlexT Tracing, clean up memory allocation
  842. //
  843. // Notes:
  844. //
  845. //--------------------------------------------------------------------------
  846. BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPOLESTR pszEXE,
  847. UINT cch, UINT FAR *lpIndex)
  848. {
  849. VDATEHEAP();
  850. LEDebugOut((DEB_ITRACE, "%p _IN FIconFileFromClass (%p, %p, %d, %p)\n",
  851. NULL, &rclsid, pszEXE, cch, lpIndex));
  852. Win4Assert(NULL != pszEXE && "Bad argument to FIconFileFromClass");
  853. Win4Assert(cch != 0 && "Bad argument to FIconFileFromClass");
  854. BOOL bRet;
  855. LPOLESTR lpBuffer = NULL;
  856. LPOLESTR lpBufferExp = NULL;
  857. LONG dw;
  858. LONG lRet;
  859. HKEY hKey;
  860. LPOLESTR lpIndexString;
  861. if (IsEqualCLSID(CLSID_NULL, rclsid))
  862. {
  863. bRet = FALSE;
  864. goto ErrRtn;
  865. }
  866. //Here, we alloc a buffer (maxpathlen + 8) to
  867. //pass to RegQueryValue. Then, we copy the exe to pszEXE and the
  868. //index to *lpIndex.
  869. if (CoIsOle1Class(rclsid))
  870. {
  871. LPOLESTR lpszProgID;
  872. // we've got an ole 1.0 class on our hands, so we look at
  873. // progID\protocol\stdfileedting\server to get the
  874. // name of the executable.
  875. // REVIEW: could this possibly fail and leave you with an
  876. // invalid ptr passed into regopenkey?
  877. ProgIDFromCLSID(rclsid, &lpszProgID);
  878. //Open up the class key
  879. lRet=OpenClassesRootKey(lpszProgID, &hKey);
  880. PubMemFree(lpszProgID);
  881. if (ERROR_SUCCESS != lRet)
  882. {
  883. bRet = FALSE;
  884. goto ErrRtn;
  885. }
  886. // RegQueryValue expects number of *bytes*
  887. lRet = RegReadDefValue(hKey, OLESTR("Protocol\\StdFileEditing\\Server"), &lpBuffer);
  888. RegCloseKey(hKey);
  889. if (ERROR_SUCCESS != lRet)
  890. {
  891. bRet = FALSE;
  892. goto ErrRtn;
  893. }
  894. // Use server and 0 as the icon index
  895. dw = ExpandEnvironmentStringsW(lpBuffer, pszEXE, cch);
  896. if(dw == 0 || dw > (LONG)cch)
  897. {
  898. bRet = FALSE;
  899. goto ErrRtn;
  900. }
  901. // REVIEW: is this internally trusted? No validation...
  902. // (same for rest of writes to it this fn)
  903. *lpIndex = 0;
  904. bRet = TRUE;
  905. goto ErrRtn;
  906. }
  907. /*
  908. * We have to go walking in the registration database under the
  909. * classname, so we first open the classname key and then check
  910. * under "\\DefaultIcon" to get the file that contains the icon.
  911. */
  912. {
  913. LPOLESTR pszClass;
  914. OLECHAR szKey[64];
  915. StringFromCLSID(rclsid, &pszClass);
  916. _xstrcpy(szKey, OLESTR("CLSID\\"));
  917. _xstrcat(szKey, pszClass);
  918. PubMemFree(pszClass);
  919. //Open up the class key
  920. lRet=OpenClassesRootKey(szKey, &hKey);
  921. }
  922. if (ERROR_SUCCESS != lRet)
  923. {
  924. bRet = FALSE;
  925. goto ErrRtn;
  926. }
  927. //Get the executable path and icon index.
  928. // RegQueryValue expects number of bytes
  929. lRet = RegReadDefValue(hKey, OLESTR("DefaultIcon"), &lpBuffer);
  930. if (ERROR_SUCCESS != lRet)
  931. {
  932. // no DefaultIcon key...try LocalServer
  933. lRet = RegReadDefValue(hKey, OLESTR("LocalServer32"), &lpBuffer);
  934. }
  935. if (ERROR_SUCCESS != lRet)
  936. {
  937. lRet = RegReadDefValue(hKey, OLESTR("LocalServer"), &lpBuffer);
  938. }
  939. RegCloseKey(hKey);
  940. if (ERROR_SUCCESS != lRet)
  941. {
  942. // no LocalServer entry either...they're outta luck.
  943. bRet = FALSE;
  944. goto ErrRtn;
  945. }
  946. // Nt #335548
  947. dw = ExpandEnvironmentStringsW(lpBuffer, NULL, 0);
  948. if(dw)
  949. {
  950. lpBufferExp = (LPOLESTR) CoTaskMemAlloc(dw * sizeof(OLECHAR));
  951. dw = ExpandEnvironmentStringsW(lpBuffer, lpBufferExp, dw);
  952. }
  953. if(!dw)
  954. {
  955. LEDebugOut((DEB_WARN, "ExpandEnvStrings failure!"));
  956. bRet = FALSE;
  957. goto ErrRtn;
  958. }
  959. // lpBuffer contains a string that looks like
  960. // "<pathtoexe>,<iconindex>",
  961. // so we need to separate the path and the icon index.
  962. bRet = ExtractNameAndIndex(lpBufferExp, pszEXE, cch, lpIndex);
  963. #if DBG == 1
  964. // do some quick checking while we're at it.
  965. VerifyExtractNameAndIndex();
  966. #endif // DBG == 1
  967. ErrRtn:
  968. if(lpBuffer)
  969. CoTaskMemFree(lpBuffer);
  970. if(lpBufferExp)
  971. CoTaskMemFree(lpBufferExp);
  972. LEDebugOut((DEB_ITRACE, "%p OUT FIconFileFromClass ( %d ) [%d]\n",
  973. NULL, bRet, *lpIndex));
  974. return bRet;
  975. }
  976. //+-------------------------------------------------------------------------
  977. //
  978. // Function: OleMetafilePictFromIconAndLabel (public)
  979. //
  980. // Synopsis:
  981. // Creates a METAFILEPICT structure that container a metafile in which
  982. // the icon and label are drawn. A comment record is inserted between
  983. // the icon and the label code so our special draw function can stop
  984. // playing before the label.
  985. //
  986. // Effects:
  987. //
  988. // Arguments: [hIcon] -- icon to draw into the metafile
  989. // [pszLabel] -- the label string
  990. // [pszSourceFile] -- local pathname of the icon
  991. // [iIcon] -- index into [pszSourceFile] for the icon
  992. //
  993. // Requires:
  994. //
  995. // Returns: HGLOBAL to a METAFILEPICT structure (using MM_ANISOTROPIC
  996. // mapping mode)
  997. //
  998. // Signals:
  999. //
  1000. // Modifies:
  1001. //
  1002. // Algorithm:
  1003. //
  1004. // History: dd-mmm-yy Author Comment
  1005. // 27-Nov-93 alexgo first 32bit port
  1006. // 15-Dec-93 alexgo fixed bugs with UNICODE strings
  1007. // 09-Mar-94 AlexT Make this backwards compatible
  1008. //
  1009. // Notes: REVIEW32:: need to fix font grabbing etc, to be international
  1010. // friendly, see comments below
  1011. //
  1012. //--------------------------------------------------------------------------
  1013. STDAPI_(HGLOBAL) OleMetafilePictFromIconAndLabel(HICON hIcon,
  1014. LPOLESTR pwcsLabel, LPOLESTR pwcsSourceFile, UINT iIcon)
  1015. {
  1016. OLETRACEIN((API_OleMetafilePictFromIconAndLabel,
  1017. PARAMFMT("hIcon= %h, pwcsLabel= %ws, pwcsSourceFile= %ws, iIcon= %d"),
  1018. hIcon, pwcsLabel, pwcsSourceFile, iIcon));
  1019. VDATEHEAP();
  1020. LEDebugOut((DEB_TRACE, "%p _IN OleMetafilePictFromIconAndLabel (%p, %p, %p, %d)\n",
  1021. NULL, hIcon, pwcsLabel, pwcsSourceFile, iIcon));
  1022. //Where to stop to exclude label (explicitly ANSI)
  1023. static char szIconOnly[] = "IconOnly";
  1024. static char szIconLabelNext[] = "OLE: Icon label next (Unicode)";
  1025. static char szIconSourceNext[] = "OLE: Icon source next (Unicode)";
  1026. static char szDefaultChar[] = "?";
  1027. // REVIEW: Mein Got! This is a huge fn, could it be broken up?
  1028. HGLOBAL hMem = NULL;
  1029. HDC hDC, hDCScreen = NULL;
  1030. HMETAFILE hMF;
  1031. LPMETAFILEPICT pMF;
  1032. OLECHAR wszIconLabel[OLEUI_CCHLABELMAX + 1];
  1033. char szIconLabel[OLEUI_CCHLABELMAX + 1];
  1034. UINT cchLabelW;
  1035. UINT cchLabelA;
  1036. UINT cchIndex;
  1037. BOOL bUsedDefaultChar;
  1038. TEXTMETRICA textMetric;
  1039. UINT cxIcon, cyIcon;
  1040. UINT cxText, cyText;
  1041. UINT cx, cy;
  1042. HFONT hFont, hSysFont, hFontT;
  1043. int cyFont;
  1044. char szIndex[10];
  1045. RECT TextRect;
  1046. char * pszSourceFile;
  1047. UINT cchSourceFile = 0;
  1048. int iRet;
  1049. BOOL bWriteUnicodeLabel;
  1050. BOOL bWriteUnicodeSource;
  1051. LOGFONT logfont;
  1052. if (NULL == hIcon) // null icon is valid
  1053. {
  1054. goto ErrRtn;
  1055. }
  1056. //Need to use the screen DC for these operations
  1057. hDCScreen = GetDC(NULL);
  1058. if (!hDCScreen)
  1059. goto ErrRtn;
  1060. // REVIEW: ptr validation on IN params?
  1061. bWriteUnicodeSource = FALSE;
  1062. pszSourceFile = NULL;
  1063. if (NULL != pwcsSourceFile)
  1064. {
  1065. // Prepare source file string
  1066. cchSourceFile = _xstrlen(pwcsSourceFile) + 1;
  1067. #if defined(WIN32)
  1068. pszSourceFile = (char *) PrivMemAlloc(cchSourceFile * sizeof(WCHAR));
  1069. #else
  1070. pszSourceFile = (char *) PrivMemAlloc(cchSourceFile);
  1071. #endif // WIN32
  1072. if (NULL == pszSourceFile)
  1073. {
  1074. LEDebugOut((DEB_WARN, "PrivMemAlloc(%d) failed\n",
  1075. cchSourceFile));
  1076. goto ErrRtn;
  1077. }
  1078. #if defined(WIN32)
  1079. iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
  1080. pwcsSourceFile, cchSourceFile,
  1081. pszSourceFile, cchSourceFile * sizeof(WCHAR),
  1082. szDefaultChar, &bUsedDefaultChar);
  1083. #else
  1084. iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
  1085. pwcsSourceFile, cchSourceFile,
  1086. pszSourceFile, cchSourceFile,
  1087. szDefaultChar, &bUsedDefaultChar);
  1088. #endif // WIN32
  1089. bWriteUnicodeSource = bUsedDefaultChar;
  1090. if (0 == iRet)
  1091. {
  1092. // Unexpected failure, since at worst we should have
  1093. // just filled in pszSourceFile with default characters.
  1094. LEDebugOut((DEB_WARN, "WideCharToMultiByte failed - %lx\n",
  1095. GetLastError()));
  1096. }
  1097. }
  1098. // Create a memory metafile. We explicitly make it an ANSI metafile for
  1099. // backwards compatibility.
  1100. #ifdef WIN32
  1101. hDC = CreateMetaFileA(NULL);
  1102. #else
  1103. hDC = CreateMetaFile(NULL);
  1104. #endif
  1105. if (NULL == hDC)
  1106. {
  1107. LEDebugOut((DEB_WARN, "CreateMetaFile failed - %lx\n",
  1108. GetLastError()));
  1109. PrivMemFree(pszSourceFile);
  1110. goto ErrRtn;
  1111. }
  1112. //Allocate the metafilepict
  1113. hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
  1114. if (NULL == hMem)
  1115. {
  1116. LEDebugOut((DEB_WARN, "GlobalAlloc failed - %lx\n",
  1117. GetLastError()));
  1118. hMF = CloseMetaFile(hDC);
  1119. DeleteMetaFile(hMF);
  1120. PrivMemFree(pszSourceFile);
  1121. goto ErrRtn;
  1122. }
  1123. // Prepare ANSI label
  1124. szIconLabel[0] = '\0';
  1125. cchLabelW = 0;
  1126. cchLabelA = 0;
  1127. // REVIEW: don't follow the logic here: you conditionally set it above
  1128. // and explicity clear it here?
  1129. bWriteUnicodeLabel = FALSE;
  1130. if (NULL != pwcsLabel)
  1131. {
  1132. cchLabelW = _xstrlen(pwcsLabel) + 1;
  1133. if (OLEUI_CCHLABELMAX < cchLabelW)
  1134. {
  1135. //REVIEW: would it be worth warning of the truncation in debug builds?
  1136. // or is this a common case?
  1137. LSTRCPYN(wszIconLabel, pwcsLabel, OLEUI_CCHLABELMAX);
  1138. wszIconLabel[OLEUI_CCHLABELMAX] = L'\0';
  1139. pwcsLabel = wszIconLabel;
  1140. cchLabelW = OLEUI_CCHLABELMAX;
  1141. }
  1142. #if defined(WIN32)
  1143. cchLabelA = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
  1144. pwcsLabel, cchLabelW,
  1145. szIconLabel, 0,
  1146. NULL, NULL);
  1147. #else
  1148. cchLabelA = cchLabelW;
  1149. #endif // WIN32
  1150. // We have a label - translate it to ANSI for the TextOut's...
  1151. iRet = WideCharToMultiByte(AreFileApisANSI() ? CP_ACP : CP_OEMCP, 0,
  1152. pwcsLabel, cchLabelW,
  1153. szIconLabel, sizeof(szIconLabel),
  1154. szDefaultChar, &bUsedDefaultChar);
  1155. if (0 == iRet)
  1156. {
  1157. // Unexpected failure, since at worst we should have
  1158. // just filled in pszSourceFile with default characters.
  1159. LEDebugOut((DEB_WARN, "WideCharToMultiByte failed - %lx\n",
  1160. GetLastError()));
  1161. }
  1162. bWriteUnicodeLabel = bUsedDefaultChar;
  1163. }
  1164. LOGFONT lf;
  1165. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, FALSE);
  1166. hFont = CreateFontIndirect(&lf);
  1167. hFontT= (HFONT) SelectObject(hDCScreen, hFont);
  1168. GetTextMetricsA(hDCScreen, &textMetric);
  1169. // We use double the height to provide some margin space
  1170. cyText = textMetric.tmHeight*3; //max 2 lines & some space
  1171. SelectObject(hDCScreen, hFontT);
  1172. cxIcon = GetSystemMetrics(SM_CXICON);
  1173. cyIcon = GetSystemMetrics(SM_CYICON);
  1174. cxText = cxIcon*3; //extent of text based upon icon width causes
  1175. //the label to look nice and proportionate.
  1176. // If we have no label, then we want the metafile to be the width of
  1177. // the icon (plus margin), not the width of the fattest string.
  1178. if ('\0' == szIconLabel[0])
  1179. {
  1180. cx = cxIcon + cxIcon / 4;
  1181. }
  1182. else
  1183. {
  1184. cx = max(cxText, cxIcon);
  1185. }
  1186. cy = cyIcon + cyText + 4; // Why 4?
  1187. //Set the metafile size to fit the icon and label
  1188. SetMapMode(hDC, MM_ANISOTROPIC);
  1189. SetWindowOrgEx(hDC, 0, 0, NULL);
  1190. SetWindowExtEx(hDC, cx, cy, NULL);
  1191. //Set up rectangle to pass to IconLabelTextOut
  1192. SetRectEmpty(&TextRect);
  1193. TextRect.right = cx;
  1194. TextRect.bottom = cy;
  1195. //Draw the icon and the text, centered with respect to each other.
  1196. DrawIcon(hDC, (cx - cxIcon) / 2, 0, hIcon);
  1197. //String that indicates where to stop if we're only doing icons
  1198. Escape(hDC, MFCOMMENT, sizeof(szIconOnly), szIconOnly, NULL);
  1199. SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  1200. SetBkMode(hDC, TRANSPARENT);
  1201. IconLabelTextOut(hDC, hFont, 0, cy - cyText, ETO_CLIPPED,
  1202. &TextRect, szIconLabel, cchLabelA);
  1203. // Write comments containing the icon source file and index.
  1204. if (NULL != pwcsSourceFile)
  1205. {
  1206. AssertSz(pszSourceFile != NULL, "Unicode source existed");
  1207. //Escape wants number of *bytes*
  1208. Escape(hDC, MFCOMMENT,
  1209. cchSourceFile, pszSourceFile, NULL);
  1210. cchIndex = wsprintfA(szIndex, "%u", iIcon);
  1211. // Escape wants number of *bytes*
  1212. Escape(hDC, MFCOMMENT, cchIndex + 1, szIndex, NULL);
  1213. }
  1214. else if (bWriteUnicodeLabel || bWriteUnicodeSource)
  1215. {
  1216. // We're going to write out comment records for the Unicode
  1217. // strings, so we need to emit dummy ANSI source comments.
  1218. //Escape wants number of *bytes*
  1219. Escape(hDC, MFCOMMENT, sizeof(""), "", NULL);
  1220. // Escape wants number of *bytes*
  1221. Escape(hDC, MFCOMMENT, sizeof("0"), "0", NULL);
  1222. }
  1223. if (bWriteUnicodeLabel)
  1224. {
  1225. // Now write out the UNICODE label
  1226. Escape(hDC, MFCOMMENT,
  1227. sizeof(szIconLabelNext), szIconLabelNext, NULL);
  1228. Escape(hDC, MFCOMMENT,
  1229. cchLabelW * sizeof(OLECHAR), (LPSTR) pwcsLabel,
  1230. NULL);
  1231. }
  1232. if (bWriteUnicodeSource)
  1233. {
  1234. // Now write out the UNICODE label
  1235. Escape(hDC, MFCOMMENT,
  1236. sizeof(szIconSourceNext), szIconSourceNext, NULL);
  1237. Escape(hDC, MFCOMMENT,
  1238. cchSourceFile * sizeof(OLECHAR), (LPSTR) pwcsSourceFile,
  1239. NULL);
  1240. }
  1241. //All done with the metafile, now stuff it all into a METAFILEPICT.
  1242. hMF = CloseMetaFile(hDC);
  1243. if (NULL==hMF)
  1244. {
  1245. GlobalFree(hMem);
  1246. hMem = NULL;
  1247. goto ErrRtn;
  1248. }
  1249. pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  1250. //Transform to HIMETRICS
  1251. cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
  1252. cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
  1253. pMF->mm=MM_ANISOTROPIC;
  1254. pMF->xExt=cx;
  1255. pMF->yExt=cy;
  1256. pMF->hMF=hMF;
  1257. GlobalUnlock(hMem);
  1258. if(hFont)
  1259. DeleteObject(hFont);
  1260. PrivMemFree(pszSourceFile);
  1261. // REVIEW: any need to release the font resource?
  1262. ErrRtn:
  1263. if(hDCScreen)
  1264. ReleaseDC(NULL, hDCScreen);
  1265. LEDebugOut((DEB_TRACE, "%p OUT OleMetafilePictFromIconAndLabel ( %p )\n",
  1266. NULL, hMem));
  1267. OLETRACEOUTEX((API_OleMetafilePictFromIconAndLabel,
  1268. RETURNFMT("%h"), hMem));
  1269. return hMem;
  1270. }
  1271. //+-------------------------------------------------------------------------
  1272. //
  1273. // Function: IconLabelTextOut (internal)
  1274. //
  1275. // Synopsis:
  1276. // Replacement for DrawText to be used in the "Display as Icon" metafile.
  1277. // Uses ExtTextOutA to output a string center on (at most) two lines.
  1278. // Uses a very simple word wrap algorithm to split the lines.
  1279. //
  1280. // Effects:
  1281. //
  1282. // Arguments: [hDC] -- device context (cannot be NULL)
  1283. // [hFont] -- font to use
  1284. // [nXStart] -- x-coordinate of starting position
  1285. // [nYStart] -- y-coordinate of starting position
  1286. // [fuOptions] -- rectangle type
  1287. // [lpRect] -- rect far * containing rectangle to draw
  1288. // text in.
  1289. // [lpszString] -- string to draw
  1290. // [cchString] -- length of string (truncated if over
  1291. // OLEUI_CCHLABELMAX), including terminating
  1292. // NULL
  1293. //
  1294. // Requires:
  1295. //
  1296. // Signals:
  1297. //
  1298. // Modifies:
  1299. //
  1300. // Algorithm:
  1301. //
  1302. // History: dd-mmm-yy Author Comment
  1303. // 28-Nov-93 alexgo initial 32bit port
  1304. // 09-Mar-94 AlexT Use ANSI strings
  1305. //
  1306. // Notes:
  1307. //
  1308. //--------------------------------------------------------------------------
  1309. // POSTPPC: The parameter 'cchString' is superfluous since lpszString
  1310. // is guaranteed to be null terminated
  1311. void IconLabelTextOut(HDC hDC, HFONT hFont, int nXStart, int nYStart,
  1312. UINT fuOptions, RECT FAR * lpRect, LPCSTR lpszString,
  1313. UINT cchString)
  1314. {
  1315. VDATEHEAP();
  1316. LEDebugOut((DEB_ITRACE, "%p _IN IconLabelTextOut (%lx, %lx, %d, %d, %d, %p, %p, %d)\n",
  1317. NULL, hDC, hFont,
  1318. nXStart, nYStart, fuOptions, lpRect, lpszString, cchString));
  1319. AssertSz(hDC != NULL, "Bad arg to IconLabelTextOut");
  1320. AssertSz(lpszString != NULL, "Bad arg to IconLabelTextOut");
  1321. AssertSz(strlen(lpszString) < OLEUI_CCHLABELMAX,
  1322. "Bad arg to IconLabelTextOut");
  1323. // REVIEW: does our compiler have to initialize static function scoped
  1324. // data? I know old versions did...
  1325. static char szSeparators[] = " \t\\/!:";
  1326. static char szTempBuff[OLEUI_CCHLABELMAX];
  1327. HDC hDCScreen;
  1328. int cxString, cyString, cxMaxString;
  1329. int cxFirstLine, cyFirstLine, cxSecondLine;
  1330. int index;
  1331. char chKeep;
  1332. LPSTR lpszSecondLine;
  1333. LPSTR lpstrLast;
  1334. HFONT hFontT;
  1335. SIZE size;
  1336. int cch = (int) strlen(lpszString);
  1337. UINT uiAlign = GDI_ERROR;
  1338. // Initialization stuff...
  1339. StringCbCopyA(szTempBuff, sizeof(szTempBuff), lpszString);
  1340. // set maximum width
  1341. cxMaxString = lpRect->right - lpRect->left;
  1342. // get screen DC to do text size calculations
  1343. hDCScreen = GetDC(NULL);
  1344. if(!hDCScreen)
  1345. return;
  1346. hFontT= (HFONT)SelectObject(hDCScreen, hFont);
  1347. // get the extent of our label
  1348. GetTextExtentPointA(hDCScreen, szTempBuff, cch, &size);
  1349. cxString = size.cx;
  1350. cyString = size.cy;
  1351. // Select in the font we want to use
  1352. SelectObject(hDC, hFont);
  1353. // Center the string
  1354. uiAlign = SetTextAlign(hDC, TA_CENTER);
  1355. // String is smaller than max string - just center, ETO, and return.
  1356. if (cxString <= cxMaxString)
  1357. {
  1358. ExtTextOutA(hDC,
  1359. nXStart + lpRect->right / 2,
  1360. nYStart,
  1361. fuOptions,
  1362. lpRect,
  1363. szTempBuff,
  1364. cch,
  1365. NULL);
  1366. goto CleanupAndLeave;
  1367. }
  1368. // String is too long...we've got to word-wrap it.
  1369. // Are there any spaces, slashes, tabs, or bangs in string?
  1370. if (strlen(szTempBuff) != strcspn(szTempBuff, szSeparators))
  1371. {
  1372. // Yep, we've got spaces, so we'll try to find the largest
  1373. // space-terminated string that will fit on the first line.
  1374. index = cch;
  1375. while (index >= 0)
  1376. {
  1377. // scan the string backwards for spaces, slashes,
  1378. // tabs, or bangs
  1379. // REVIEW: scary. Could this result in a negative
  1380. // index, or is it guarnateed to hit a separator
  1381. // before that?
  1382. while (!IS_SEPARATOR(szTempBuff[index]) )
  1383. {
  1384. index--;
  1385. }
  1386. if (index <= 0)
  1387. {
  1388. break;
  1389. }
  1390. // remember what char was there
  1391. chKeep = szTempBuff[index];
  1392. szTempBuff[index] = '\0'; // just for now
  1393. GetTextExtentPointA(hDCScreen, szTempBuff,
  1394. index,&size);
  1395. cxFirstLine = size.cx;
  1396. cyFirstLine = size.cy;
  1397. // REVIEW: but chKeep is NOT an OLECHAR
  1398. // put the right OLECHAR back
  1399. szTempBuff[index] = chKeep;
  1400. if (cxFirstLine <= cxMaxString)
  1401. {
  1402. ExtTextOutA(hDC,
  1403. nXStart + lpRect->right / 2,
  1404. nYStart,
  1405. fuOptions,
  1406. lpRect,
  1407. szTempBuff,
  1408. index + 1,
  1409. NULL);
  1410. lpszSecondLine = szTempBuff;
  1411. lpszSecondLine += index + 1;
  1412. GetTextExtentPointA(hDCScreen,
  1413. lpszSecondLine,
  1414. (int) strlen(lpszSecondLine),
  1415. &size);
  1416. // If the second line is wider than the
  1417. // rectangle, we just want to clip the text.
  1418. cxSecondLine = min(size.cx, cxMaxString);
  1419. ExtTextOutA(hDC,
  1420. nXStart + lpRect->right / 2,
  1421. nYStart + cyFirstLine,
  1422. fuOptions,
  1423. lpRect,
  1424. lpszSecondLine,
  1425. (int) strlen(lpszSecondLine),
  1426. NULL);
  1427. goto CleanupAndLeave;
  1428. } // end if
  1429. index--;
  1430. } // end while
  1431. } // end if
  1432. // Here, there are either no spaces in the string
  1433. // (strchr(szTempBuff, ' ') returned NULL), or there spaces in the
  1434. // string, but they are positioned so that the first space
  1435. // terminated string is still longer than one line.
  1436. // So, we walk backwards from the end of the string until we
  1437. // find the largest string that will fit on the first
  1438. // line , and then we just clip the second line.
  1439. // We allow 40 characters in the label, but the metafile is
  1440. // only as wide as 10 W's (for aesthetics - 20 W's wide looked
  1441. // dumb. This means that if we split a long string in half (in
  1442. // terms of characters), then we could still be wider than the
  1443. // metafile. So, if this is the case, we just step backwards
  1444. // from the halfway point until we get something that will fit.
  1445. // Since we just let ETO clip the second line
  1446. cch = (int) strlen(szTempBuff);
  1447. lpstrLast = &szTempBuff[cch];
  1448. chKeep = *lpstrLast;
  1449. *lpstrLast = '\0';
  1450. GetTextExtentPointA(hDCScreen, szTempBuff, cch, &size);
  1451. cxFirstLine = size.cx;
  1452. cyFirstLine = size.cy;
  1453. while (cxFirstLine > cxMaxString)
  1454. {
  1455. *lpstrLast = chKeep;
  1456. // The string is always ansi, so always use CharPrevA.
  1457. lpstrLast = CharPrevA(szTempBuff, lpstrLast);
  1458. if (szTempBuff == lpstrLast)
  1459. {
  1460. goto CleanupAndLeave;
  1461. }
  1462. chKeep = *lpstrLast;
  1463. *lpstrLast = '\0';
  1464. // need to calculate the new length of the string
  1465. cch = (int) strlen(szTempBuff);
  1466. GetTextExtentPointA(hDCScreen, szTempBuff,
  1467. cch, &size);
  1468. cxFirstLine = size.cx;
  1469. }
  1470. ExtTextOutA(hDC,
  1471. nXStart + lpRect->right / 2,
  1472. nYStart,
  1473. fuOptions,
  1474. lpRect,
  1475. szTempBuff,
  1476. (int) strlen(szTempBuff),
  1477. NULL);
  1478. szTempBuff[cch] = chKeep;
  1479. lpszSecondLine = szTempBuff;
  1480. lpszSecondLine += cch;
  1481. GetTextExtentPointA(hDCScreen, lpszSecondLine,
  1482. (int) strlen(lpszSecondLine), &size);
  1483. // If the second line is wider than the rectangle, we
  1484. // just want to clip the text.
  1485. cxSecondLine = min(size.cx, cxMaxString);
  1486. ExtTextOutA(hDC,
  1487. nXStart + lpRect->right / 2,
  1488. nYStart + cyFirstLine,
  1489. fuOptions,
  1490. lpRect,
  1491. lpszSecondLine,
  1492. (int) strlen(lpszSecondLine),
  1493. NULL);
  1494. CleanupAndLeave:
  1495. // If we changed the alignment we restore it here
  1496. if (uiAlign != GDI_ERROR)
  1497. {
  1498. SetTextAlign(hDC, uiAlign);
  1499. }
  1500. SelectObject(hDCScreen, hFontT);
  1501. ReleaseDC(NULL, hDCScreen);
  1502. LEDebugOut((DEB_ITRACE, "%p OUT IconLabelTextOut ()\n"));
  1503. }
  1504. //+-------------------------------------------------------------------------
  1505. //
  1506. // Function: OleStdGetUserTypeOfClass, private
  1507. //
  1508. // Synopsis: Returns the user type info of the specified class
  1509. //
  1510. // Effects:
  1511. //
  1512. // Arguments: [rclsid] -- the class ID in question
  1513. // [lpszUserType] -- where to put the user type string
  1514. // [cch] -- the length of [lpszUserType] (in
  1515. // *characters*, not bytes)
  1516. // [hKey] -- handle to the reg db (may be NULL)
  1517. //
  1518. // Requires:
  1519. //
  1520. // Returns: UINT -- the number of characters put into the return string
  1521. //
  1522. // Signals:
  1523. //
  1524. // Modifies:
  1525. //
  1526. // Algorithm:
  1527. //
  1528. // History: dd-mmm-yy Author Comment
  1529. // 29-Nov-93 alexgo 32bit port
  1530. //
  1531. // Notes:
  1532. //
  1533. //--------------------------------------------------------------------------
  1534. STDAPI_(UINT) OleStdGetUserTypeOfClass(REFCLSID rclsid, LPOLESTR lpszUserType, UINT cch, HKEY hKey)
  1535. {
  1536. VDATEHEAP();
  1537. LEDebugOut((DEB_ITRACE, "%p _IN OleStdGetUserTypeOfClass (%p, %p, %d, %lx)\n",
  1538. NULL, &rclsid, lpszUserType, cch, hKey));
  1539. LONG dw = 0;
  1540. LONG lRet;
  1541. // REVIEW: would make more sense to set this when the reg is opened
  1542. BOOL bCloseRegDB = FALSE;
  1543. if (hKey == NULL)
  1544. {
  1545. //Open up the root key.
  1546. lRet=OpenClassesRootKey(NULL, &hKey);
  1547. if ((LONG)ERROR_SUCCESS!=lRet)
  1548. {
  1549. goto ErrRtn;
  1550. }
  1551. bCloseRegDB = TRUE;
  1552. }
  1553. // Get a string containing the class name
  1554. {
  1555. LPOLESTR lpszCLSID;
  1556. OLECHAR szKey[128];
  1557. StringFromCLSID(rclsid, &lpszCLSID);
  1558. _xstrcpy(szKey, OLESTR("CLSID\\"));
  1559. _xstrcat(szKey, lpszCLSID);
  1560. PubMemFree((LPVOID)lpszCLSID);
  1561. dw = cch * sizeof(OLECHAR);
  1562. lRet = RegQueryValue(hKey, szKey, lpszUserType, &dw);
  1563. dw = dw / sizeof(OLECHAR);
  1564. }
  1565. if ((LONG)ERROR_SUCCESS!=lRet)
  1566. {
  1567. dw = 0;
  1568. }
  1569. if ( ((LONG)ERROR_SUCCESS!=lRet) && (CoIsOle1Class(rclsid)) )
  1570. {
  1571. LPOLESTR lpszProgID;
  1572. // We've got an OLE 1.0 class, so let's try to get the user
  1573. // type name from the ProgID entry.
  1574. ProgIDFromCLSID(rclsid, &lpszProgID);
  1575. // REVIEW: will progidfromclsid always set your ptr for you?
  1576. dw = cch * sizeof(OLECHAR);
  1577. lRet = RegQueryValue(hKey, lpszProgID, lpszUserType, &dw);
  1578. dw = dw / sizeof(OLECHAR);
  1579. PubMemFree((LPVOID)lpszProgID);
  1580. if ((LONG)ERROR_SUCCESS != lRet)
  1581. {
  1582. dw = 0;
  1583. }
  1584. }
  1585. if (bCloseRegDB)
  1586. {
  1587. RegCloseKey(hKey);
  1588. }
  1589. ErrRtn:
  1590. LEDebugOut((DEB_ITRACE, "%p OUT OleStdGetUserTypeOfClass ( %d )\n",
  1591. NULL, dw));
  1592. return (UINT)dw;
  1593. }
  1594. //+-------------------------------------------------------------------------
  1595. //
  1596. // Function: OleStdGetAuxUserType, private
  1597. //
  1598. // Synopsis: Returns the specified AuxUserType from the reg db
  1599. //
  1600. // Effects:
  1601. //
  1602. // Arguments: [rclsid] -- the class ID in question
  1603. // [hKey] -- handle to the reg db root (may be NULL)
  1604. // [wAuxUserType] -- which field to look for (name, exe, etc)
  1605. // [lpszUserType] -- where to put the returned string
  1606. // [cch] -- size of [lpszUserType] in *characters*
  1607. //
  1608. // Requires:
  1609. //
  1610. // Returns: UINT -- number of characters in returned string.
  1611. //
  1612. // Signals:
  1613. //
  1614. // Modifies:
  1615. //
  1616. // Algorithm:
  1617. //
  1618. // History: dd-mmm-yy Author Comment
  1619. // 29-Nov-93 alexgo 32bit port
  1620. // 27-Apr-94 AlexT Tracing, clean up
  1621. //
  1622. // Notes:
  1623. //
  1624. //--------------------------------------------------------------------------
  1625. STDAPI_(UINT) OleStdGetAuxUserType(REFCLSID rclsid,
  1626. WORD wAuxUserType,
  1627. LPOLESTR lpszAuxUserType,
  1628. int cch,
  1629. HKEY hKey)
  1630. {
  1631. VDATEHEAP();
  1632. LEDebugOut((DEB_ITRACE, "%p _IN OleStdGetAuxUserType (%p, %hu, %p, %d, %lx)\n",
  1633. NULL, &rclsid, wAuxUserType, lpszAuxUserType, cch, hKey));
  1634. LONG dw = 0;
  1635. HKEY hThisKey;
  1636. BOOL bCloseRegDB = FALSE;
  1637. LRESULT lRet;
  1638. LPOLESTR lpszCLSID;
  1639. OLECHAR szKey[OLEUI_CCHKEYMAX];
  1640. OLECHAR szTemp[32];
  1641. lpszAuxUserType[0] = OLESTR('\0');
  1642. if (NULL == hKey)
  1643. {
  1644. lRet = OpenClassesRootKey(NULL, &hThisKey);
  1645. if (ERROR_SUCCESS != lRet)
  1646. {
  1647. goto ErrRtn;
  1648. }
  1649. bCloseRegDB = TRUE;
  1650. }
  1651. else
  1652. {
  1653. hThisKey = hKey;
  1654. }
  1655. StringFromCLSID(rclsid, &lpszCLSID);
  1656. _xstrcpy(szKey, OLESTR("CLSID\\"));
  1657. _xstrcat(szKey, lpszCLSID);
  1658. wsprintf(szTemp, OLESTR("\\AuxUserType\\%d"), wAuxUserType);
  1659. _xstrcat(szKey, szTemp);
  1660. PubMemFree(lpszCLSID);
  1661. dw = cch * sizeof(OLECHAR);
  1662. lRet = RegQueryValue(hThisKey, szKey, lpszAuxUserType, &dw);
  1663. // Convert dw from byte count to OLECHAR count
  1664. dw = dw / sizeof(OLECHAR);
  1665. if (ERROR_SUCCESS != lRet)
  1666. {
  1667. dw = 0;
  1668. lpszAuxUserType[0] = '\0';
  1669. }
  1670. if (bCloseRegDB)
  1671. {
  1672. RegCloseKey(hThisKey);
  1673. }
  1674. ErrRtn:
  1675. // dw is
  1676. LEDebugOut((DEB_ITRACE, "%p OUT OleStdGetAuxUserType ( %d )\n",
  1677. NULL, dw));
  1678. return (UINT)dw;
  1679. }
  1680. //REVIEW: these seem redundant, could the fns be mereged creatively?
  1681. //+-------------------------------------------------------------------------
  1682. //
  1683. // Function:
  1684. // XformWidthInPixelsToHimetric
  1685. // XformWidthInHimetricToPixels
  1686. // XformHeightInPixelsToHimetric
  1687. // XformHeightInHimetricToPixels
  1688. //
  1689. // Synopsis:
  1690. // Functions to convert an int between a device coordinate system and
  1691. // logical HiMetric units.
  1692. //
  1693. // Effects:
  1694. //
  1695. // Arguments:
  1696. //
  1697. // [hDC] HDC providing reference to the pixel mapping. If
  1698. // NULL, a screen DC is used.
  1699. //
  1700. // Size Functions:
  1701. // [lpSizeSrc] LPSIZEL providing the structure to convert. This
  1702. // contains pixels in XformSizeInPixelsToHimetric and
  1703. // logical HiMetric units in the complement function.
  1704. // [lpSizeDst] LPSIZEL providing the structure to receive converted
  1705. // units. This contains pixels in
  1706. // XformSizeInPixelsToHimetric and logical HiMetric
  1707. // units in the complement function.
  1708. //
  1709. // Width Functions:
  1710. // [iWidth] int containing the value to convert.
  1711. //
  1712. // Requires:
  1713. //
  1714. // Returns:
  1715. // Size Functions: None
  1716. // Width Functions: Converted value of the input parameters.
  1717. //
  1718. // Signals:
  1719. //
  1720. // Modifies:
  1721. //
  1722. // Algorithm:
  1723. //
  1724. // History: dd-mmm-yy Author Comment
  1725. // 29-Nov-93 alexgo 32bit port (initial)
  1726. //
  1727. // Notes:
  1728. //
  1729. // When displaying on the screen, Window apps display everything enlarged
  1730. // from its actual size so that it is easier to read. For example, if an
  1731. // app wants to display a 1in. horizontal line, that when printed is
  1732. // actually a 1in. line on the printed page, then it will display the line
  1733. // on the screen physically larger than 1in. This is described as a line
  1734. // that is "logically" 1in. along the display width. Windows maintains as
  1735. // part of the device-specific information about a given display device:
  1736. // LOGPIXELSX -- no. of pixels per logical in along the display width
  1737. // LOGPIXELSY -- no. of pixels per logical in along the display height
  1738. //
  1739. // The following formula converts a distance in pixels into its equivalent
  1740. // logical HIMETRIC units:
  1741. //
  1742. // DistInHiMetric = (HIMETRIC_PER_INCH * DistInPix)
  1743. // -------------------------------
  1744. // PIXELS_PER_LOGICAL_IN
  1745. //
  1746. //
  1747. // REVIEW32:: merge all these functions into one, as they all do
  1748. // basically the same thing
  1749. //
  1750. //--------------------------------------------------------------------------
  1751. STDAPI_(int) XformWidthInPixelsToHimetric(HDC hDC, int iWidthInPix)
  1752. {
  1753. VDATEHEAP();
  1754. LEDebugOut((DEB_ITRACE, "%p _IN XformWidthInPixelsToHimetric (%lx, %d)\n",
  1755. NULL, hDC, iWidthInPix));
  1756. int iXppli; // Pixels per logical inch along width
  1757. int iWidthInHiMetric;
  1758. BOOL fSystemDC=FALSE;
  1759. if (NULL==hDC)
  1760. {
  1761. hDC=GetDC(NULL);
  1762. fSystemDC=TRUE;
  1763. if(!hDC)
  1764. return 0;
  1765. }
  1766. iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  1767. // We got pixel units, convert them to logical HIMETRIC along
  1768. // the display
  1769. iWidthInHiMetric = MAP_PIX_TO_LOGHIM(iWidthInPix, iXppli);
  1770. if (fSystemDC)
  1771. {
  1772. ReleaseDC(NULL, hDC);
  1773. }
  1774. LEDebugOut((DEB_ITRACE, "%p OUT XformWidthInPixelsToHimetric (%d)\n",
  1775. NULL, iWidthInHiMetric));
  1776. return iWidthInHiMetric;
  1777. }
  1778. //+-------------------------------------------------------------------------
  1779. //
  1780. // Function: XformWidthInHimetricToPixels
  1781. //
  1782. // Synopsis: see XformWidthInPixelsToHimetric
  1783. //
  1784. // Effects:
  1785. //
  1786. // Arguments:
  1787. //
  1788. // Requires:
  1789. //
  1790. // Returns:
  1791. //
  1792. // Signals:
  1793. //
  1794. // Modifies:
  1795. //
  1796. // Algorithm:
  1797. //
  1798. // History: dd-mmm-yy Author Comment
  1799. // 29-Nov-93 alexgo 32bit port
  1800. //
  1801. // Notes:
  1802. //
  1803. //--------------------------------------------------------------------------
  1804. STDAPI_(int) XformWidthInHimetricToPixels(HDC hDC, int iWidthInHiMetric)
  1805. {
  1806. VDATEHEAP();
  1807. LEDebugOut((DEB_ITRACE, "%p _IN XformWidthInHimetricToPixels (%lx, %d)\n",
  1808. NULL, hDC, iWidthInHiMetric));
  1809. int iXppli; //Pixels per logical inch along width
  1810. int iWidthInPix;
  1811. BOOL fSystemDC=FALSE;
  1812. if (NULL==hDC)
  1813. {
  1814. hDC=GetDC(NULL);
  1815. fSystemDC=TRUE;
  1816. if(!hDC)
  1817. return 0;
  1818. }
  1819. iXppli = GetDeviceCaps (hDC, LOGPIXELSX);
  1820. // We got logical HIMETRIC along the display, convert them to
  1821. // pixel units
  1822. iWidthInPix = MAP_LOGHIM_TO_PIX(iWidthInHiMetric, iXppli);
  1823. if (fSystemDC)
  1824. {
  1825. ReleaseDC(NULL, hDC);
  1826. }
  1827. LEDebugOut((DEB_ITRACE, "%p OUT XformWidthInHimetricToPixels (%d)\n",
  1828. NULL, iWidthInPix));
  1829. return iWidthInPix;
  1830. }
  1831. //+-------------------------------------------------------------------------
  1832. //
  1833. // Function: XformHeightInPixelsToHimetric
  1834. //
  1835. // Synopsis: see XformWidthInPixelsToHimetric
  1836. //
  1837. // Effects:
  1838. //
  1839. // Arguments:
  1840. //
  1841. // Requires:
  1842. //
  1843. // Returns:
  1844. //
  1845. // Signals:
  1846. //
  1847. // Modifies:
  1848. //
  1849. // Algorithm:
  1850. //
  1851. // History: dd-mmm-yy Author Comment
  1852. // 29-Nov-93 alexgo 32bit port
  1853. //
  1854. // Notes:
  1855. //
  1856. //--------------------------------------------------------------------------
  1857. STDAPI_(int) XformHeightInPixelsToHimetric(HDC hDC, int iHeightInPix)
  1858. {
  1859. VDATEHEAP();
  1860. LEDebugOut((DEB_ITRACE, "%p _IN XformHeightInPixelsToHimetric (%lx, %d)\n",
  1861. NULL, hDC, iHeightInPix));
  1862. int iYppli; //Pixels per logical inch along height
  1863. int iHeightInHiMetric;
  1864. BOOL fSystemDC=FALSE;
  1865. if (NULL==hDC)
  1866. {
  1867. hDC=GetDC(NULL);
  1868. fSystemDC=TRUE;
  1869. if(!hDC)
  1870. return 0;
  1871. }
  1872. iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  1873. // We got pixel units, convert them to logical HIMETRIC along the
  1874. // display
  1875. iHeightInHiMetric = MAP_PIX_TO_LOGHIM(iHeightInPix, iYppli);
  1876. if (fSystemDC)
  1877. {
  1878. ReleaseDC(NULL, hDC);
  1879. }
  1880. LEDebugOut((DEB_ITRACE, "%p OUT XformHeightInPixelsToHimetric (%d)\n",
  1881. NULL, hDC, iHeightInHiMetric));
  1882. return iHeightInHiMetric;
  1883. }
  1884. //+-------------------------------------------------------------------------
  1885. //
  1886. // Function: XformHeightInHimetricToPixels
  1887. //
  1888. // Synopsis: see XformWidthInPixelsToHimetric
  1889. //
  1890. // Effects:
  1891. //
  1892. // Arguments:
  1893. //
  1894. // Requires:
  1895. //
  1896. // Returns:
  1897. //
  1898. // Signals:
  1899. //
  1900. // Modifies:
  1901. //
  1902. // Algorithm:
  1903. //
  1904. // History: dd-mmm-yy Author Comment
  1905. // 29-Nov-93 alexgo 32bit port
  1906. //
  1907. // Notes:
  1908. //
  1909. //--------------------------------------------------------------------------
  1910. STDAPI_(int) XformHeightInHimetricToPixels(HDC hDC, int iHeightInHiMetric)
  1911. {
  1912. VDATEHEAP();
  1913. LEDebugOut((DEB_ITRACE, "%p _IN XformHeightInHimetricToPixels (%lx, %d)\n",
  1914. NULL, hDC, iHeightInHiMetric));
  1915. int iYppli; //Pixels per logical inch along height
  1916. int iHeightInPix;
  1917. BOOL fSystemDC=FALSE;
  1918. if (NULL==hDC)
  1919. {
  1920. hDC=GetDC(NULL);
  1921. fSystemDC=TRUE;
  1922. if(!hDC)
  1923. return 0;
  1924. }
  1925. iYppli = GetDeviceCaps (hDC, LOGPIXELSY);
  1926. // We got logical HIMETRIC along the display, convert them to pixel
  1927. // units
  1928. iHeightInPix = MAP_LOGHIM_TO_PIX(iHeightInHiMetric, iYppli);
  1929. if (fSystemDC)
  1930. {
  1931. ReleaseDC(NULL, hDC);
  1932. }
  1933. LEDebugOut((DEB_ITRACE, "%p OUT XformHeightInHimetricToPixels (%d)\n",
  1934. NULL, hDC, iHeightInPix));
  1935. return iHeightInPix;
  1936. }