Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1177 lines
32 KiB

  1. /*************************************************************************
  2. **
  3. ** The following API's are now OBSOLETE because equivalent API's have been
  4. ** added to the OLE2.DLL library
  5. ** GetIconOfFile superceeded by OleGetIconOfFile
  6. ** GetIconOfClass superceeded by OleGetIconOfClass
  7. ** OleUIMetafilePictFromIconAndLabel
  8. ** superceeded by OleMetafilePictFromIconAndLabel
  9. *************************************************************************/
  10. /*
  11. * GETICON.C
  12. *
  13. * Functions to create DVASPECT_ICON metafile from filename or classname.
  14. *
  15. * GetIconOfFile
  16. * GetIconOfClass
  17. * OleUIMetafilePictFromIconAndLabel
  18. * HIconAndSourceFromClass Extracts the first icon in a class's server path
  19. * and returns the path and icon index to caller.
  20. * FIconFileFromClass Retrieves the path to the exe/dll containing the
  21. * default icon, and the index of the icon.
  22. * OleStdIconLabelTextOut Draw icon label text (line break if necessary)
  23. *
  24. * (c) Copyright Microsoft Corp. 1992-1993 All Rights Reserved
  25. */
  26. /*******
  27. *
  28. * ICON (DVASPECT_ICON) METAFILE FORMAT:
  29. *
  30. * The metafile generated with OleUIMetafilePictFromIconAndLabel contains
  31. * the following records which are used by the functions in DRAWICON.C
  32. * to draw the icon with and without the label and to extract the icon,
  33. * label, and icon source/index.
  34. *
  35. * SetWindowOrg
  36. * SetWindowExt
  37. * DrawIcon:
  38. * Inserts records of DIBBITBLT or DIBSTRETCHBLT, once for the
  39. * AND mask, one for the image bits.
  40. * Escape with the comment "IconOnly"
  41. * This indicates where to stop record enumeration to draw only
  42. * the icon.
  43. * SetTextColor
  44. * SetTextAlign
  45. * SetBkColor
  46. * CreateFont
  47. * SelectObject on the font.
  48. * ExtTextOut
  49. * One or more ExtTextOuts occur if the label is wrapped. The
  50. * text in these records is used to extract the label.
  51. * SelectObject on the old font.
  52. * DeleteObject on the font.
  53. * Escape with a comment that contains the path to the icon source.
  54. * Escape with a comment that is the ASCII of the icon index.
  55. *
  56. *******/
  57. #define STRICT 1
  58. #include "ole2ui.h"
  59. #include <stdlib.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <commdlg.h>
  63. #include <memory.h>
  64. #include <cderr.h>
  65. #include "common.h"
  66. #include "utility.h"
  67. static TCHAR szSeparators[] = TEXT(" \t\\/!:");
  68. #define IS_SEPARATOR(c) ( (c) == TEXT(' ') || (c) == TEXT('\\') \
  69. || (c) == TEXT('/') || (c) == TEXT('\t') \
  70. || (c) == TEXT('!') || (c) == TEXT(':') )
  71. #define IS_FILENAME_DELIM(c) ( (c) == TEXT('\\') || (c) == TEXT('/') \
  72. || (c) == TEXT(':') )
  73. #if defined( OBSOLETE )
  74. static HINSTANCE s_hInst;
  75. static TCHAR szMaxWidth[] =TEXT("WWWWWWWWWW");
  76. //Strings for metafile comments.
  77. static TCHAR szIconOnly[]=TEXT("IconOnly"); //Where to stop to exclude label.
  78. #ifdef WIN32
  79. static TCHAR szOLE2DLL[] = TEXT("ole2w32.dll"); // name of OLE 2.0 library
  80. #else
  81. static TCHAR szOLE2DLL[] = TEXT("ole2.dll"); // name of OLE 2.0 library
  82. #endif
  83. #define ICONINDEX 0
  84. #define AUXUSERTYPE_SHORTNAME USERCLASSTYPE_SHORT // short name
  85. #define HIMETRIC_PER_INCH 2540 // number HIMETRIC units per inch
  86. #define PTS_PER_INCH 72 // number points (font size) per inch
  87. #define MAP_PIX_TO_LOGHIM(x,ppli) MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
  88. #define MAP_LOGHIM_TO_PIX(x,ppli) MulDiv((ppli), (x), HIMETRIC_PER_INCH)
  89. static TCHAR szVanillaDocIcon[] = TEXT("DefIcon");
  90. static TCHAR szDocument[40] = TEXT("");
  91. /*
  92. * GetIconOfFile(HINSTANCE hInst, LPSTR lpszPath, BOOL fUseFileAsLabel)
  93. *
  94. * Purpose:
  95. * Returns a hMetaPict containing an icon and label (filename) for the
  96. * specified filename.
  97. *
  98. * Parameters:
  99. * hinst
  100. * lpszPath LPTSTR path including filename to use
  101. * fUseFileAsLabel BOOL TRUE if the icon's label is the filename, FALSE if
  102. * there should be no label.
  103. *
  104. * Return Value:
  105. * HGLOBAL hMetaPict containing the icon and label - if there's no
  106. * class in reg db for the file in lpszPath, then we use
  107. * Document. If lpszPath is NULL, then we return NULL.
  108. */
  109. STDAPI_(HGLOBAL) GetIconOfFile(HINSTANCE hInst, LPTSTR lpszPath, BOOL fUseFileAsLabel)
  110. {
  111. TCHAR szIconFile[OLEUI_CCHPATHMAX];
  112. TCHAR szLabel[OLEUI_CCHLABELMAX];
  113. LPTSTR lpszClsid = NULL;
  114. CLSID clsid;
  115. HICON hDefIcon = NULL;
  116. UINT IconIndex = 0;
  117. HGLOBAL hMetaPict;
  118. HRESULT hResult;
  119. if (NULL == lpszPath) // even if fUseFileAsLabel is FALSE, we still
  120. return NULL; // need a valid filename to get the class.
  121. s_hInst = hInst;
  122. hResult = GetClassFileA(lpszPath, &clsid);
  123. if (NOERROR == hResult) // use the clsid we got to get to the icon
  124. {
  125. hDefIcon = HIconAndSourceFromClass(&clsid,
  126. (LPTSTR)szIconFile,
  127. &IconIndex);
  128. }
  129. if ( (NOERROR != hResult) || (NULL == hDefIcon) )
  130. {
  131. // Here, either GetClassFile failed or HIconAndSourceFromClass failed.
  132. LPTSTR lpszTemp;
  133. lpszTemp = lpszPath;
  134. while ((*lpszTemp != TEXT('.')) && (*lpszTemp != TEXT('\0')))
  135. lpszTemp++;
  136. if (TEXT('.') != *lpszTemp)
  137. goto UseVanillaDocument;
  138. if (FALSE == GetAssociatedExecutable(lpszTemp, (LPTSTR)szIconFile))
  139. goto UseVanillaDocument;
  140. hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
  141. }
  142. if (hDefIcon <= (HICON)1) // ExtractIcon returns 1 if szExecutable is not exe,
  143. { // 0 if there are no icons.
  144. UseVanillaDocument:
  145. lstrcpy((LPTSTR)szIconFile, (LPTSTR)szOLE2DLL);
  146. IconIndex = ICONINDEX;
  147. hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
  148. }
  149. // Now let's get the label we want to use.
  150. if (fUseFileAsLabel) // strip off path, so we just have the filename.
  151. {
  152. int istrlen;
  153. LPTSTR lpszBeginFile;
  154. istrlen = lstrlen(lpszPath);
  155. // set pointer to END of path, so we can walk backwards through it.
  156. lpszBeginFile = lpszPath + istrlen -1;
  157. while ( (lpszBeginFile >= lpszPath)
  158. && (!IS_FILENAME_DELIM(*lpszBeginFile)) )
  159. lpszBeginFile--;
  160. lpszBeginFile++; // step back over the delimiter
  161. LSTRCPYN(szLabel, lpszBeginFile, sizeof(szLabel)/sizeof(TCHAR));
  162. }
  163. else // use the short user type (AuxUserType2) for the label
  164. {
  165. if (0 == OleStdGetAuxUserType(&clsid, AUXUSERTYPE_SHORTNAME,
  166. (LPTSTR)szLabel, OLEUI_CCHLABELMAX_SIZE, NULL)) {
  167. if ('\0'==szDocument[0]) {
  168. LoadString(
  169. s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument)/sizeof(TCHAR));
  170. }
  171. lstrcpy(szLabel, szDocument);
  172. }
  173. }
  174. hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon,
  175. szLabel,
  176. (LPTSTR)szIconFile,
  177. IconIndex);
  178. DestroyIcon(hDefIcon);
  179. return hMetaPict;
  180. }
  181. /*
  182. * GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPSTR lpszLabel, BOOL fUseTypeAsLabel)
  183. *
  184. * Purpose:
  185. * Returns a hMetaPict containing an icon and label (human-readable form
  186. * of class) for the specified clsid.
  187. *
  188. * Parameters:
  189. * hinst
  190. * rclsid REFCLSID pointing to clsid to use.
  191. * lpszLabel label to use for icon.
  192. * fUseTypeAsLabel Use the clsid's user type name as the icon's label.
  193. *
  194. * Return Value:
  195. * HGLOBAL hMetaPict containing the icon and label - if we
  196. * don't find the clsid in the reg db then we
  197. * return NULL.
  198. */
  199. STDAPI_(HGLOBAL) GetIconOfClass(HINSTANCE hInst, REFCLSID rclsid, LPTSTR lpszLabel, BOOL fUseTypeAsLabel)
  200. {
  201. TCHAR szLabel[OLEUI_CCHLABELMAX];
  202. TCHAR szIconFile[OLEUI_CCHPATHMAX];
  203. HICON hDefIcon;
  204. UINT IconIndex;
  205. HGLOBAL hMetaPict;
  206. s_hInst = hInst;
  207. if (!fUseTypeAsLabel) // Use string passed in as label
  208. {
  209. if (NULL != lpszLabel)
  210. LSTRCPYN(szLabel, lpszLabel, OLEUI_CCHLABELMAX_SIZE);
  211. else
  212. *szLabel = TEXT('\0');
  213. }
  214. else // Use AuxUserType2 (short name) as label
  215. {
  216. if (0 == OleStdGetAuxUserType(rclsid,
  217. AUXUSERTYPE_SHORTNAME,
  218. (LPTSTR)szLabel,
  219. OLEUI_CCHLABELMAX_SIZE,
  220. NULL))
  221. // If we can't get the AuxUserType2, then try the long name
  222. if (0 == OleStdGetUserTypeOfClass(rclsid, szLabel, OLEUI_CCHKEYMAX_SIZE, NULL)) {
  223. if (TEXT('\0')==szDocument[0]) {
  224. LoadString(
  225. s_hInst,IDS_DEFICONLABEL,szDocument,sizeof(szDocument)/sizeof(TCHAR));
  226. }
  227. lstrcpy(szLabel, szDocument); // last resort
  228. }
  229. }
  230. // Get the icon, icon index, and path to icon file
  231. hDefIcon = HIconAndSourceFromClass(rclsid,
  232. (LPTSTR)szIconFile,
  233. &IconIndex);
  234. if (NULL == hDefIcon) // Use Vanilla Document
  235. {
  236. lstrcpy((LPTSTR)szIconFile, (LPTSTR)szOLE2DLL);
  237. IconIndex = ICONINDEX;
  238. hDefIcon = ExtractIcon(s_hInst, szIconFile, IconIndex);
  239. }
  240. // Create the metafile
  241. hMetaPict = OleUIMetafilePictFromIconAndLabel(hDefIcon, szLabel,
  242. (LPTSTR)szIconFile, IconIndex);
  243. DestroyIcon(hDefIcon);
  244. return hMetaPict;
  245. }
  246. /*
  247. * OleUIMetafilePictFromIconAndLabel
  248. *
  249. * Purpose:
  250. * Creates a METAFILEPICT structure that container a metafile in which
  251. * the icon and label are drawn. A comment record is inserted between
  252. * the icon and the label code so our special draw function can stop
  253. * playing before the label.
  254. *
  255. * Parameters:
  256. * hIcon HICON to draw into the metafile
  257. * pszLabel LPTSTR to the label string.
  258. * pszSourceFile LPTSTR containing the local pathname of the icon
  259. * as we either get from the user or from the reg DB.
  260. * iIcon UINT providing the index into pszSourceFile where
  261. * the icon came from.
  262. *
  263. * Return Value:
  264. * HGLOBAL Global memory handle containing a METAFILEPICT where
  265. * the metafile uses the MM_ANISOTROPIC mapping mode. The
  266. * extents reflect both icon and label.
  267. */
  268. STDAPI_(HGLOBAL) OleUIMetafilePictFromIconAndLabel(HICON hIcon, LPTSTR pszLabel
  269. , LPTSTR pszSourceFile, UINT iIcon)
  270. {
  271. HDC hDC, hDCScreen;
  272. HMETAFILE hMF;
  273. HGLOBAL hMem;
  274. LPMETAFILEPICT pMF;
  275. UINT cxIcon, cyIcon;
  276. UINT cxText, cyText;
  277. UINT cx, cy;
  278. UINT cchLabel = 0;
  279. HFONT hFont, hFontT;
  280. int cyFont;
  281. TCHAR szIndex[10];
  282. RECT TextRect;
  283. SIZE size;
  284. POINT point;
  285. UINT fuAlign;
  286. if (NULL==hIcon) // null label is valid but NOT a null icon
  287. return NULL;
  288. //Create a memory metafile
  289. hDC=(HDC)CreateMetaFile(NULL);
  290. if (NULL==hDC)
  291. return NULL;
  292. //Allocate the metafilepict
  293. hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
  294. if (NULL==hMem)
  295. {
  296. hMF=CloseMetaFile(hDC);
  297. DeleteMetaFile(hMF);
  298. return NULL;
  299. }
  300. if (NULL!=pszLabel)
  301. {
  302. cchLabel=lstrlen(pszLabel);
  303. if (cchLabel >= OLEUI_CCHLABELMAX)
  304. pszLabel[cchLabel] = TEXT('\0'); // truncate string
  305. }
  306. //Need to use the screen DC for these operations
  307. hDCScreen=GetDC(NULL);
  308. cyFont=-(8*GetDeviceCaps(hDCScreen, LOGPIXELSY))/72;
  309. //cyFont was calculated to give us 8 point.
  310. hFont=CreateFont(cyFont, 5, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET
  311. , OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY
  312. , FF_SWISS, TEXT("MS Sans Serif"));
  313. hFontT=SelectObject(hDCScreen, hFont);
  314. GetTextExtentPoint(hDCScreen,szMaxWidth,lstrlen(szMaxWidth),&size);
  315. SelectObject(hDCScreen, hFontT);
  316. cxText = size.cx;
  317. cyText = size.cy * 2;
  318. cxIcon = GetSystemMetrics(SM_CXICON);
  319. cyIcon = GetSystemMetrics(SM_CYICON);
  320. // If we have no label, then we want the metafile to be the width of
  321. // the icon (plus margin), not the width of the fattest string.
  322. if ( (NULL == pszLabel) || (TEXT('\0') == *pszLabel) )
  323. cx = cxIcon + cxIcon / 4;
  324. else
  325. cx = max(cxText, cxIcon);
  326. cy=cyIcon+cyText+4;
  327. //Set the metafile size to fit the icon and label
  328. SetWindowOrgEx(hDC, 0, 0, &point);
  329. SetWindowExtEx(hDC, cx, cy, &size);
  330. //Set up rectangle to pass to OleStdIconLabelTextOut
  331. SetRectEmpty(&TextRect);
  332. TextRect.right = cx;
  333. TextRect.bottom = cy;
  334. //Draw the icon and the text, centered with respect to each other.
  335. DrawIcon(hDC, (cx-cxIcon)/2, 0, hIcon);
  336. //String that indicates where to stop if we're only doing icons
  337. Escape(hDC, MFCOMMENT, lstrlen(szIconOnly)+1, szIconOnly, NULL);
  338. SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT));
  339. SetBkMode(hDC, TRANSPARENT);
  340. fuAlign = SetTextAlign(hDC, TA_LEFT | TA_TOP | TA_NOUPDATECP);
  341. OleStdIconLabelTextOut(hDC,
  342. hFont,
  343. 0,
  344. cy - cyText,
  345. ETO_CLIPPED,
  346. &TextRect,
  347. pszLabel,
  348. cchLabel,
  349. NULL);
  350. //Write comments containing the icon source file and index.
  351. if (NULL!=pszSourceFile)
  352. {
  353. //+1 on string lengths insures the null terminator is embedded.
  354. Escape(hDC, MFCOMMENT, lstrlen(pszSourceFile)+1, pszSourceFile, NULL);
  355. cchLabel=wsprintf(szIndex, TEXT("%u"), iIcon);
  356. Escape(hDC, MFCOMMENT, cchLabel+1, szIndex, NULL);
  357. }
  358. SetTextAlign(hDC, fuAlign);
  359. //All done with the metafile, now stuff it all into a METAFILEPICT.
  360. hMF=CloseMetaFile(hDC);
  361. if (NULL==hMF)
  362. {
  363. GlobalFree(hMem);
  364. ReleaseDC(NULL, hDCScreen);
  365. return NULL;
  366. }
  367. //Fill out the structure
  368. pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  369. //Transform to HIMETRICS
  370. cx=XformWidthInPixelsToHimetric(hDCScreen, cx);
  371. cy=XformHeightInPixelsToHimetric(hDCScreen, cy);
  372. ReleaseDC(NULL, hDCScreen);
  373. pMF->mm=MM_ANISOTROPIC;
  374. pMF->xExt=cx;
  375. pMF->yExt=cy;
  376. pMF->hMF=hMF;
  377. GlobalUnlock(hMem);
  378. DeleteObject(hFont);
  379. return hMem;
  380. }
  381. #endif // OBSOLETE
  382. /*
  383. * GetAssociatedExecutable
  384. *
  385. * Purpose: Finds the executable associated with the provided extension
  386. *
  387. * Parameters:
  388. * lpszExtension LPSTR points to the extension we're trying to find
  389. * an exe for. Does **NO** validation.
  390. *
  391. * lpszExecutable LPSTR points to where the exe name will be returned.
  392. * No validation here either - pass in 128 char buffer.
  393. *
  394. * Return:
  395. * BOOL TRUE if we found an exe, FALSE if we didn't.
  396. *
  397. */
  398. BOOL FAR PASCAL GetAssociatedExecutable(LPTSTR lpszExtension, LPTSTR lpszExecutable)
  399. {
  400. HKEY hKey;
  401. LONG dw;
  402. LRESULT lRet;
  403. TCHAR szValue[OLEUI_CCHKEYMAX];
  404. TCHAR szKey[OLEUI_CCHKEYMAX];
  405. LPTSTR lpszTemp, lpszExe;
  406. lRet = RegOpenKey(HKEY_CLASSES_ROOT, NULL, &hKey);
  407. if (ERROR_SUCCESS != lRet)
  408. return FALSE;
  409. dw = OLEUI_CCHPATHMAX_SIZE;
  410. lRet = RegQueryValue(hKey, lpszExtension, (LPTSTR)szValue, &dw); //ProgId
  411. if (ERROR_SUCCESS != lRet)
  412. {
  413. RegCloseKey(hKey);
  414. return FALSE;
  415. }
  416. // szValue now has ProgID
  417. lstrcpy(szKey, szValue);
  418. lstrcat(szKey, TEXT("\\Shell\\Open\\Command"));
  419. dw = OLEUI_CCHPATHMAX_SIZE;
  420. lRet = RegQueryValue(hKey, (LPTSTR)szKey, (LPTSTR)szValue, &dw);
  421. if (ERROR_SUCCESS != lRet)
  422. {
  423. RegCloseKey(hKey);
  424. return FALSE;
  425. }
  426. // szValue now has an executable name in it. Let's null-terminate
  427. // at the first post-executable space (so we don't have cmd line
  428. // args.
  429. lpszTemp = (LPTSTR)szValue;
  430. while ((TEXT('\0') != *lpszTemp) && (iswspace(*lpszTemp)))
  431. lpszTemp++; // Strip off leading spaces
  432. lpszExe = lpszTemp;
  433. while ((TEXT('\0') != *lpszTemp) && (!iswspace(*lpszTemp)))
  434. lpszTemp++; // Step through exe name
  435. *lpszTemp = TEXT('\0'); // null terminate at first space (or at end).
  436. lstrcpy(lpszExecutable, lpszExe);
  437. return TRUE;
  438. }
  439. /*
  440. * HIconAndSourceFromClass
  441. *
  442. * Purpose:
  443. * Given an object class name, finds an associated executable in the
  444. * registration database and extracts the first icon from that
  445. * executable. If none is available or the class has no associated
  446. * executable, this function returns NULL.
  447. *
  448. * Parameters:
  449. * rclsid pointer to clsid to look up.
  450. * pszSource LPSTR in which to place the source of the icon.
  451. * This is assumed to be OLEUI_CCHPATHMAX
  452. * puIcon UINT FAR * in which to store the index of the
  453. * icon in pszSource.
  454. *
  455. * Return Value:
  456. * HICON Handle to the extracted icon if there is a module
  457. * associated to pszClass. NULL on failure to either
  458. * find the executable or extract and icon.
  459. */
  460. HICON FAR PASCAL HIconAndSourceFromClass(REFCLSID rclsid, LPTSTR pszSource, UINT FAR *puIcon)
  461. {
  462. HICON hIcon;
  463. UINT IconIndex;
  464. if (NULL==rclsid || NULL==pszSource || IsEqualCLSID(rclsid,&CLSID_NULL))
  465. return NULL;
  466. if (!FIconFileFromClass(rclsid, pszSource, OLEUI_CCHPATHMAX_SIZE, &IconIndex))
  467. return NULL;
  468. hIcon=ExtractIcon(ghInst, pszSource, IconIndex);
  469. if ((HICON)32 > hIcon)
  470. hIcon=NULL;
  471. else
  472. *puIcon= IconIndex;
  473. return hIcon;
  474. }
  475. /*
  476. * PointerToNthField
  477. *
  478. * Purpose:
  479. * Returns a pointer to the beginning of the nth field.
  480. * Assumes null-terminated string.
  481. *
  482. * Parameters:
  483. * lpszString string to parse
  484. * nField field to return starting index of.
  485. * chDelimiter char that delimits fields
  486. *
  487. * Return Value:
  488. * LPSTR pointer to beginning of nField field.
  489. * NOTE: If the null terminator is found
  490. * Before we find the Nth field, then
  491. * we return a pointer to the null terminator -
  492. * calling app should be sure to check for
  493. * this case.
  494. *
  495. */
  496. LPTSTR FAR PASCAL PointerToNthField(LPTSTR lpszString, int nField, TCHAR chDelimiter)
  497. {
  498. LPTSTR lpField = lpszString;
  499. int cFieldFound = 1;
  500. if (1 ==nField)
  501. return lpszString;
  502. while (*lpField != TEXT('\0'))
  503. {
  504. if (*lpField++ == chDelimiter)
  505. {
  506. cFieldFound++;
  507. if (nField == cFieldFound)
  508. return lpField;
  509. }
  510. }
  511. return lpField;
  512. }
  513. /*
  514. * FIconFileFromClass
  515. *
  516. * Purpose:
  517. * Looks up the path to executable that contains the class default icon.
  518. *
  519. * Parameters:
  520. * rclsid pointer to CLSID to look up.
  521. * pszEXE LPSTR at which to store the server name
  522. * cch UINT size of pszEXE
  523. * lpIndex LPUINT to index of icon within executable
  524. *
  525. * Return Value:
  526. * BOOL TRUE if one or more characters were loaded into pszEXE.
  527. * FALSE otherwise.
  528. */
  529. BOOL FAR PASCAL FIconFileFromClass(REFCLSID rclsid, LPTSTR pszEXE, UINT cchBytes, UINT FAR *lpIndex)
  530. {
  531. LONG dw;
  532. LONG lRet;
  533. HKEY hKey;
  534. LPMALLOC lpIMalloc;
  535. HRESULT hrErr;
  536. LPTSTR lpBuffer;
  537. LPTSTR lpIndexString;
  538. UINT cBufferSize = 136;// room for 128 char path and icon's index
  539. TCHAR szKey[64];
  540. LPSTR pszClass;
  541. UINT cch=cchBytes / sizeof(TCHAR); // number of characters
  542. if (NULL==rclsid || NULL==pszEXE || 0==cch || IsEqualCLSID(rclsid,&CLSID_NULL))
  543. return FALSE;
  544. //Here, we use CoGetMalloc and alloc a buffer (maxpathlen + 8) to
  545. //pass to RegQueryValue. Then, we copy the exe to pszEXE and the
  546. //index to *lpIndex.
  547. hrErr = CoGetMalloc(MEMCTX_TASK, &lpIMalloc);
  548. if (NOERROR != hrErr)
  549. return FALSE;
  550. lpBuffer = (LPTSTR)lpIMalloc->lpVtbl->Alloc(lpIMalloc, cBufferSize);
  551. if (NULL == lpBuffer)
  552. {
  553. lpIMalloc->lpVtbl->Release(lpIMalloc);
  554. return FALSE;
  555. }
  556. if (CoIsOle1Class(rclsid))
  557. {
  558. LPOLESTR lpszProgID;
  559. // we've got an ole 1.0 class on our hands, so we look at
  560. // progID\protocol\stdfileedting\server to get the
  561. // name of the executable.
  562. ProgIDFromCLSID(rclsid, &lpszProgID);
  563. //Open up the class key
  564. #ifdef UNICODE
  565. lRet=RegOpenKey(HKEY_CLASSES_ROOT, lpszProgID, &hKey);
  566. #else
  567. {
  568. char szTemp[255];
  569. wcstombs(szTemp, lpszProgID, 255);
  570. lRet=RegOpenKey(HKEY_CLASSES_ROOT, szTemp, &hKey);
  571. }
  572. #endif
  573. if (ERROR_SUCCESS != lRet)
  574. {
  575. lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
  576. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  577. lpIMalloc->lpVtbl->Release(lpIMalloc);
  578. return FALSE;
  579. }
  580. dw=(LONG)cBufferSize;
  581. lRet = RegQueryValue(hKey, TEXT("Protocol\\StdFileEditing\\Server"), lpBuffer, &dw);
  582. if (ERROR_SUCCESS != lRet)
  583. {
  584. RegCloseKey(hKey);
  585. lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
  586. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  587. lpIMalloc->lpVtbl->Release(lpIMalloc);
  588. return FALSE;
  589. }
  590. // Use server and 0 as the icon index
  591. LSTRCPYN(pszEXE, lpBuffer, cch);
  592. *lpIndex = 0;
  593. RegCloseKey(hKey);
  594. lpIMalloc->lpVtbl->Free(lpIMalloc, lpszProgID);
  595. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  596. lpIMalloc->lpVtbl->Release(lpIMalloc);
  597. return TRUE;
  598. }
  599. /*
  600. * We have to go walking in the registration database under the
  601. * classname, so we first open the classname key and then check
  602. * under "\\DefaultIcon" to get the file that contains the icon.
  603. */
  604. StringFromCLSIDA(rclsid, &pszClass);
  605. lstrcpy(szKey, TEXT("CLSID\\"));
  606. lstrcat(szKey, pszClass);
  607. //Open up the class key
  608. lRet=RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hKey);
  609. if (ERROR_SUCCESS != lRet)
  610. {
  611. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  612. lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
  613. lpIMalloc->lpVtbl->Release(lpIMalloc);
  614. return FALSE;
  615. }
  616. //Get the executable path and icon index.
  617. dw=(LONG)cBufferSize;
  618. lRet=RegQueryValue(hKey, TEXT("DefaultIcon"), lpBuffer, &dw);
  619. if (ERROR_SUCCESS != lRet)
  620. {
  621. // no DefaultIcon key...try LocalServer
  622. dw=(LONG)cBufferSize;
  623. lRet=RegQueryValue(hKey, TEXT("LocalServer"), lpBuffer, &dw);
  624. if (ERROR_SUCCESS != lRet)
  625. {
  626. // no LocalServer entry either...they're outta luck.
  627. RegCloseKey(hKey);
  628. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  629. lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
  630. lpIMalloc->lpVtbl->Release(lpIMalloc);
  631. return FALSE;
  632. }
  633. // Use server from LocalServer or Server and 0 as the icon index
  634. LSTRCPYN(pszEXE, lpBuffer, cch);
  635. *lpIndex = 0;
  636. RegCloseKey(hKey);
  637. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  638. lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
  639. lpIMalloc->lpVtbl->Release(lpIMalloc);
  640. return TRUE;
  641. }
  642. RegCloseKey(hKey);
  643. // lpBuffer contains a string that looks like "<pathtoexe>,<iconindex>",
  644. // so we need to separate the path and the icon index.
  645. lpIndexString = PointerToNthField(lpBuffer, 2, TEXT(','));
  646. if (TEXT('\0') == *lpIndexString) // no icon index specified - use 0 as default.
  647. {
  648. *lpIndex = 0;
  649. }
  650. else
  651. {
  652. LPTSTR lpTemp;
  653. static TCHAR szTemp[16];
  654. lstrcpy((LPTSTR)szTemp, lpIndexString);
  655. // Put the icon index part into *pIconIndex
  656. #ifdef UNICODE
  657. {
  658. char szTEMP1[16];
  659. wcstombs(szTEMP1, szTemp, 16);
  660. *lpIndex = atoi((const char *)szTEMP1);
  661. }
  662. #else
  663. *lpIndex = atoi((const char *)szTemp);
  664. #endif
  665. // Null-terminate the exe part.
  666. #ifdef WIN32
  667. lpTemp = CharPrev(lpBuffer, lpIndexString);
  668. #else
  669. lpTemp = AnsiPrev(lpBuffer, lpIndexString);
  670. #endif
  671. *lpTemp = TEXT('\0');
  672. }
  673. if (!LSTRCPYN(pszEXE, lpBuffer, cch))
  674. {
  675. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  676. lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
  677. lpIMalloc->lpVtbl->Release(lpIMalloc);
  678. return FALSE;
  679. }
  680. // Free the memory we alloc'd and leave.
  681. lpIMalloc->lpVtbl->Free(lpIMalloc, lpBuffer);
  682. lpIMalloc->lpVtbl->Free(lpIMalloc, pszClass);
  683. lpIMalloc->lpVtbl->Release(lpIMalloc);
  684. return TRUE;
  685. }
  686. /*
  687. * OleStdIconLabelTextOut
  688. *
  689. * Purpose:
  690. * Replacement for DrawText to be used in the "Display as Icon" metafile.
  691. * Uses ExtTextOut to output a string center on (at most) two lines.
  692. * Uses a very simple word wrap algorithm to split the lines.
  693. *
  694. * Parameters: (same as for ExtTextOut, except for hFont)
  695. * hDC device context to draw into; if this is NULL, then we don't
  696. * ETO the text, we just return the index of the beginning
  697. * of the second line
  698. * hFont font to use
  699. * nXStart x-coordinate of starting position
  700. * nYStart y-coordinate of starting position
  701. * fuOptions rectangle type
  702. * lpRect rect far * containing rectangle to draw text in.
  703. * lpszString string to draw
  704. * cchString length of string (truncated if over OLEUI_CCHLABELMAX)
  705. * lpDX spacing between character cells
  706. *
  707. * Return Value:
  708. * UINT Index of beginning of last line (0 if there's only one
  709. * line of text).
  710. *
  711. */
  712. STDAPI_(UINT) OleStdIconLabelTextOut(HDC hDC,
  713. HFONT hFont,
  714. int nXStart,
  715. int nYStart,
  716. UINT fuOptions,
  717. RECT FAR * lpRect,
  718. LPTSTR lpszString,
  719. UINT cchString,
  720. int FAR * lpDX)
  721. {
  722. HDC hDCScreen;
  723. static TCHAR szTempBuff[OLEUI_CCHLABELMAX];
  724. int cxString, cyString, cxMaxString;
  725. int cxFirstLine, cyFirstLine, cxSecondLine;
  726. int index;
  727. int cch = cchString;
  728. TCHAR chKeep;
  729. LPTSTR lpszSecondLine;
  730. HFONT hFontT;
  731. BOOL fPrintText = TRUE;
  732. UINT iLastLineStart = 0;
  733. SIZE size;
  734. // Initialization stuff...
  735. if (NULL == hDC) // If we got NULL as the hDC, then we don't actually call ETO
  736. fPrintText = FALSE;
  737. // Make a copy of the string (NULL or non-NULL) that we're using
  738. if (NULL == lpszString)
  739. *szTempBuff = TEXT('\0');
  740. else
  741. LSTRCPYN(szTempBuff, lpszString, sizeof(szTempBuff)/sizeof(TCHAR));
  742. // set maximum width
  743. cxMaxString = lpRect->right - lpRect->left;
  744. // get screen DC to do text size calculations
  745. hDCScreen = GetDC(NULL);
  746. hFontT=SelectObject(hDCScreen, hFont);
  747. // get the extent of our label
  748. #ifdef WIN32
  749. // GetTextExtentPoint32 has fixed the off-by-one bug.
  750. GetTextExtentPoint32(hDCScreen, szTempBuff, cch, &size);
  751. #else
  752. GetTextExtentPoint(hDCScreen, szTempBuff, cch, &size);
  753. #endif
  754. cxString = size.cx;
  755. cyString = size.cy;
  756. // Select in the font we want to use
  757. if (fPrintText)
  758. SelectObject(hDC, hFont);
  759. // String is smaller than max string - just center, ETO, and return.
  760. if (cxString <= cxMaxString)
  761. {
  762. if (fPrintText)
  763. ExtTextOut(hDC,
  764. nXStart + (lpRect->right - cxString) / 2,
  765. nYStart,
  766. fuOptions,
  767. lpRect,
  768. szTempBuff,
  769. cch,
  770. NULL);
  771. iLastLineStart = 0; // only 1 line of text
  772. goto CleanupAndLeave;
  773. }
  774. // String is too long...we've got to word-wrap it.
  775. // Are there any spaces, slashes, tabs, or bangs in string?
  776. if (lstrlen(szTempBuff) != (int)
  777. #ifdef UNICODE
  778. wcscspn(szTempBuff, szSeparators)
  779. #else
  780. strcspn(szTempBuff, szSeparators)
  781. #endif
  782. )
  783. {
  784. // Yep, we've got spaces, so we'll try to find the largest
  785. // space-terminated string that will fit on the first line.
  786. index = cch;
  787. while (index >= 0)
  788. {
  789. TCHAR cchKeep;
  790. // scan the string backwards for spaces, slashes, tabs, or bangs
  791. while (!IS_SEPARATOR(szTempBuff[index]) )
  792. index--;
  793. if (index <= 0)
  794. break;
  795. cchKeep = szTempBuff[index]; // remember what char was there
  796. szTempBuff[index] = TEXT('\0'); // just for now
  797. #ifdef WIN32
  798. GetTextExtentPoint32(
  799. hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
  800. #else
  801. GetTextExtentPoint(
  802. hDCScreen, (LPTSTR)szTempBuff,lstrlen((LPTSTR)szTempBuff),&size);
  803. #endif
  804. cxFirstLine = size.cx;
  805. cyFirstLine = size.cy;
  806. szTempBuff[index] = cchKeep; // put the right char back
  807. if (cxFirstLine <= cxMaxString)
  808. {
  809. iLastLineStart = index + 1;
  810. if (!fPrintText)
  811. goto CleanupAndLeave;
  812. ExtTextOut(hDC,
  813. nXStart + (lpRect->right - cxFirstLine) / 2,
  814. nYStart,
  815. fuOptions,
  816. lpRect,
  817. (LPTSTR)szTempBuff,
  818. index + 1,
  819. lpDX);
  820. lpszSecondLine = (LPTSTR)szTempBuff;
  821. lpszSecondLine += (index + 1) ;
  822. GetTextExtentPoint(hDCScreen,
  823. lpszSecondLine,
  824. lstrlen(lpszSecondLine),
  825. &size);
  826. // If the second line is wider than the rectangle, we
  827. // just want to clip the text.
  828. cxSecondLine = min(size.cx, cxMaxString);
  829. ExtTextOut(hDC,
  830. nXStart + (lpRect->right - cxSecondLine) / 2,
  831. nYStart + cyFirstLine,
  832. fuOptions,
  833. lpRect,
  834. lpszSecondLine,
  835. lstrlen(lpszSecondLine),
  836. lpDX);
  837. goto CleanupAndLeave;
  838. } // end if
  839. index--;
  840. } // end while
  841. } // end if
  842. // Here, there are either no spaces in the string (strchr(szTempBuff, ' ')
  843. // returned NULL), or there spaces in the string, but they are
  844. // positioned so that the first space terminated string is still
  845. // longer than one line. So, we walk backwards from the end of the
  846. // string until we find the largest string that will fit on the first
  847. // line , and then we just clip the second line.
  848. cch = lstrlen((LPTSTR)szTempBuff);
  849. chKeep = szTempBuff[cch];
  850. szTempBuff[cch] = TEXT('\0');
  851. GetTextExtentPoint(hDCScreen, szTempBuff, lstrlen(szTempBuff),&size);
  852. cxFirstLine = size.cx;
  853. cyFirstLine = size.cy;
  854. while (cxFirstLine > cxMaxString)
  855. {
  856. // We allow 40 characters in the label, but the metafile is
  857. // only as wide as 10 W's (for aesthetics - 20 W's wide looked
  858. // dumb. This means that if we split a long string in half (in
  859. // terms of characters), then we could still be wider than the
  860. // metafile. So, if this is the case, we just step backwards
  861. // from the halfway point until we get something that will fit.
  862. // Since we just let ETO clip the second line
  863. szTempBuff[cch--] = chKeep;
  864. if (0 == cch)
  865. goto CleanupAndLeave;
  866. chKeep = szTempBuff[cch];
  867. szTempBuff[cch] = TEXT('\0');
  868. GetTextExtentPoint(
  869. hDCScreen, szTempBuff, lstrlen(szTempBuff), &size);
  870. cxFirstLine = size.cx;
  871. }
  872. iLastLineStart = cch;
  873. if (!fPrintText)
  874. goto CleanupAndLeave;
  875. ExtTextOut(hDC,
  876. nXStart + (lpRect->right - cxFirstLine) / 2,
  877. nYStart,
  878. fuOptions,
  879. lpRect,
  880. (LPTSTR)szTempBuff,
  881. lstrlen((LPTSTR)szTempBuff),
  882. lpDX);
  883. szTempBuff[cch] = chKeep;
  884. lpszSecondLine = szTempBuff;
  885. lpszSecondLine += cch ;
  886. GetTextExtentPoint(
  887. hDCScreen, (LPTSTR)lpszSecondLine, lstrlen(lpszSecondLine), &size);
  888. // If the second line is wider than the rectangle, we
  889. // just want to clip the text.
  890. cxSecondLine = min(size.cx, cxMaxString);
  891. ExtTextOut(hDC,
  892. nXStart + (lpRect->right - cxSecondLine) / 2,
  893. nYStart + cyFirstLine,
  894. fuOptions,
  895. lpRect,
  896. lpszSecondLine,
  897. lstrlen(lpszSecondLine),
  898. lpDX);
  899. CleanupAndLeave:
  900. SelectObject(hDCScreen, hFontT);
  901. ReleaseDC(NULL, hDCScreen);
  902. return iLastLineStart;
  903. }
  904.