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.

1410 lines
33 KiB

  1. /*
  2. * UTIL.C
  3. *
  4. * Purpose:
  5. * Implementation of various useful utility functions
  6. *
  7. * Author:
  8. * alexgo (4/25/95)
  9. */
  10. #include "_common.h"
  11. #include "_rtfconv.h"
  12. ASSERTDATA
  13. // Author revision color table
  14. const COLORREF rgcrRevisions[] =
  15. {
  16. RGB(0, 0, 255),
  17. RGB(0, 128, 0),
  18. RGB(255, 0, 0),
  19. RGB(0, 128, 128),
  20. RGB(128, 0, 128),
  21. RGB(0, 0, 128),
  22. RGB(128, 0, 0),
  23. RGB(255, 0, 255)
  24. };
  25. #if REVMASK != 7
  26. #pragma message ("WARNING, Revision mask not equal to table!");
  27. #endif
  28. /*
  29. * DuplicateHGlobal
  30. *
  31. * Purpose:
  32. * duplicates the passed in hglobal
  33. */
  34. HGLOBAL DuplicateHGlobal( HGLOBAL hglobal )
  35. {
  36. TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "DuplicateHGlobal");
  37. UINT flags;
  38. DWORD size;
  39. HGLOBAL hNew;
  40. BYTE * pSrc;
  41. BYTE * pDest;
  42. if( hglobal == NULL )
  43. {
  44. return NULL;
  45. }
  46. flags = GlobalFlags(hglobal);
  47. size = GlobalSize(hglobal);
  48. hNew = GlobalAlloc(flags, size);
  49. if( hNew )
  50. {
  51. pDest = (BYTE *)GlobalLock(hNew);
  52. pSrc = (BYTE *)GlobalLock(hglobal);
  53. if( pDest == NULL || pSrc == NULL )
  54. {
  55. GlobalUnlock(hNew);
  56. GlobalUnlock(hglobal);
  57. GlobalFree(hNew);
  58. return NULL;
  59. }
  60. memcpy(pDest, pSrc, size);
  61. GlobalUnlock(hNew);
  62. GlobalUnlock(hglobal);
  63. }
  64. return hNew;
  65. }
  66. /*
  67. * CountMatchingBits (*pA, *pB, n)
  68. *
  69. * @mfunc
  70. * Count matching bit fields
  71. *
  72. * @comm
  73. * This is used to help decide how good the match is between
  74. * code page bit fields. Mainly for KB/font switching support.
  75. *
  76. * Author:
  77. * Jon Matousek
  78. */
  79. INT CountMatchingBits(
  80. const DWORD *pA, //@parm Array A to be matched
  81. const DWORD *pB, //@parm Array B to be matched
  82. INT n) //@parm # DWORDs to be matched
  83. {
  84. TRACEBEGIN(TRCSUBSYSUTIL, TRCSCOPEINTERN, "CountMatchingBits");
  85. //0 1 2 3 4 5 6 7 8 9 A B C D E F
  86. static INT bitCount[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
  87. INT c = 0; // Bit count to return
  88. DWORD matchBits; // Next DWORD match
  89. while(n--)
  90. {
  91. //matchBits = ~(*pA++ ^ *pB++); // 1 and 0's
  92. matchBits = *pA++ & *pB++; // 1 only
  93. for( ; matchBits; matchBits >>= 4) // Early out
  94. c += bitCount[matchBits & 15];
  95. }
  96. return c;
  97. }
  98. //
  99. // Object Stabilization classes
  100. //
  101. //+-------------------------------------------------------------------------
  102. //
  103. // Member: CSafeRefCount::CSafeRefCount
  104. //
  105. // Synopsis: constructor for the safe ref count class
  106. //
  107. // Effects:
  108. //
  109. // Arguments: none
  110. //
  111. // Requires:
  112. //
  113. // Returns: none
  114. //
  115. // Signals:
  116. //
  117. // Modifies:
  118. //
  119. // Derivation:
  120. //
  121. // Algorithm:
  122. //
  123. // History: dd-mmm-yy Author Comment
  124. // 28-Jul-94 alexgo author
  125. //
  126. // Notes:
  127. //
  128. //--------------------------------------------------------------------------
  129. CSafeRefCount::CSafeRefCount()
  130. {
  131. m_cRefs = 0;
  132. m_cNest = 0;
  133. m_fInDelete = FALSE;
  134. m_fForceZombie = FALSE;
  135. }
  136. //+-------------------------------------------------------------------------
  137. //
  138. // Member: CSafeRefCount::CSafeRefCount (virtual)
  139. //
  140. // Synopsis:
  141. //
  142. // Effects:
  143. //
  144. // Arguments:
  145. //
  146. // Requires:
  147. //
  148. // Returns:
  149. //
  150. // Signals:
  151. //
  152. // Modifies:
  153. //
  154. // Derivation:
  155. //
  156. // Algorithm:
  157. //
  158. // History: dd-mmm-yy Author Comment
  159. // 28-Jul-94 alexgo author
  160. //
  161. // Notes:
  162. //
  163. //--------------------------------------------------------------------------
  164. CSafeRefCount::~CSafeRefCount()
  165. {
  166. Assert(m_cRefs == 0 && m_cNest == 0 && m_fInDelete == TRUE);
  167. }
  168. //+-------------------------------------------------------------------------
  169. //
  170. // Member: CSafeRefCount::SafeAddRef
  171. //
  172. // Synopsis: increments the reference count on the object
  173. //
  174. // Effects:
  175. //
  176. // Arguments: none
  177. //
  178. // Requires:
  179. //
  180. // Returns: ULONG -- the reference count after the increment
  181. //
  182. // Signals:
  183. //
  184. // Modifies:
  185. //
  186. // Derivation:
  187. //
  188. // Algorithm: increments the reference count.
  189. //
  190. // History: dd-mmm-yy Author Comment
  191. // 28-Jul-94 alexgo author
  192. //
  193. // Notes:
  194. //
  195. //--------------------------------------------------------------------------
  196. ULONG CSafeRefCount::SafeAddRef()
  197. {
  198. m_cRefs++;
  199. //AssertSz(m_fInDelete == FALSE, "AddRef called on deleted object!");
  200. // this *could* be really bad. If we are deleting the object,
  201. // it means that during the destructor, somebody made an outgoing
  202. // call eventually ended up with another addref to ourselves
  203. // (even though all pointers to us had been 'Released').
  204. //
  205. // this is usually caused by code like the following:
  206. // m_pFoo->Release();
  207. // m_pFoo = NULL;
  208. //
  209. // If the the Release may cause Foo to be deleted, which may cause
  210. // the object to get re-entered during Foo's destructor. However,
  211. // 'this' object has not yet set m_pFoo to NULL, so it may
  212. // try to continue to use m_pFoo.
  213. //
  214. // However, the May '94 aggregation rules REQUIRE this behaviour
  215. // In your destructor, you have to addref the outer unknown before
  216. // releasing cached interface pointers on your aggregatee. We
  217. // can't put an assert here because we do this all the time now.
  218. //
  219. return m_cRefs;
  220. }
  221. //+-------------------------------------------------------------------------
  222. //
  223. // Member: CSafeRefCount::SafeRelease
  224. //
  225. // Synopsis: decrements the reference count on the object
  226. //
  227. // Effects: May delete the object!
  228. //
  229. // Arguments:
  230. //
  231. // Requires:
  232. //
  233. // Returns: ULONG -- the reference count after decrement
  234. //
  235. // Signals:
  236. //
  237. // Modifies:
  238. //
  239. // Derivation:
  240. //
  241. // Algorithm: decrements the reference count. If the reference count
  242. // is zero AND the nest count is zero AND we are not currently
  243. // trying to delete our object, then it is safe to delete.
  244. //
  245. // History: dd-mmm-yy Author Comment
  246. // 28-Jul-94 alexgo author
  247. //
  248. // Notes:
  249. //
  250. //--------------------------------------------------------------------------
  251. ULONG CSafeRefCount::SafeRelease()
  252. {
  253. ULONG cRefs;
  254. if( m_cRefs > 0 )
  255. {
  256. cRefs = --m_cRefs;
  257. if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )
  258. {
  259. m_fInDelete = TRUE;
  260. delete this;
  261. }
  262. }
  263. else
  264. {
  265. // somebody is releasing a non-addrefed pointer!!
  266. AssertSz(0, "Release called on a non-addref'ed pointer!\n");
  267. cRefs = 0;
  268. }
  269. return cRefs;
  270. }
  271. //+-------------------------------------------------------------------------
  272. //
  273. // Member: CSafeRefCount::IncrementNestCount
  274. //
  275. // Synopsis: increments the nesting count of the object
  276. //
  277. // Effects:
  278. //
  279. // Arguments: none
  280. //
  281. // Requires:
  282. //
  283. // Returns: ULONG; the nesting count after increment
  284. //
  285. // Signals:
  286. //
  287. // Modifies:
  288. //
  289. // Derivation:
  290. //
  291. // Algorithm:
  292. //
  293. // History: dd-mmm-yy Author Comment
  294. // 28-Jul-94 alexgo author
  295. //
  296. // Notes: The nesting count is the count of how many times an
  297. // an object has been re-entered. For example, suppose
  298. // somebody calls pFoo->Bar1(), which makes some calls that
  299. // eventually call pFoo->Bar2();. On entrace to Bar2, the
  300. // nest count of the object should be 2 (since the invocation
  301. // of Bar1 is still on the stack above us).
  302. //
  303. // It is important to keep track of the nest count so we do
  304. // not accidentally delete ourselves during a nested invocation.
  305. // If we did, then when the stack unwinds to the original
  306. // top level call, it could try to access a non-existent member
  307. // variable and crash.
  308. //
  309. //--------------------------------------------------------------------------
  310. ULONG CSafeRefCount::IncrementNestCount()
  311. {
  312. #ifdef DEBUG
  313. if( m_fInDelete )
  314. {
  315. TRACEWARNSZ("WARNING: CSafeRefCount, object "
  316. "re-entered during delete!\n");
  317. }
  318. #endif
  319. m_cNest++;
  320. return m_cNest;
  321. }
  322. //+-------------------------------------------------------------------------
  323. //
  324. // Member: CSafeRefCount::DecrementNestCount
  325. //
  326. // Synopsis: decrements the nesting count and deletes the object
  327. // (if necessary)
  328. //
  329. // Effects: may delete 'this' object!
  330. //
  331. // Arguments: none
  332. //
  333. // Requires:
  334. //
  335. // Returns: ULONG, the nesting count after decrement
  336. //
  337. // Signals:
  338. //
  339. // Modifies:
  340. //
  341. // Derivation:
  342. //
  343. // Algorithm: decrements the nesting count. If the nesting count is zero
  344. // AND the reference count is zero AND we are not currently
  345. // trying to delete ourselves, then delete 'this' object
  346. //
  347. // History: dd-mmm-yy Author Comment
  348. // 28-Jul-94 alexgo author
  349. //
  350. // Notes:
  351. //
  352. //--------------------------------------------------------------------------
  353. ULONG CSafeRefCount::DecrementNestCount()
  354. {
  355. ULONG cNest;
  356. if( m_cNest > 0 )
  357. {
  358. cNest = --m_cNest;
  359. if( m_cRefs == 0 && m_cNest == 0 && m_fInDelete == FALSE )
  360. {
  361. m_fInDelete = TRUE;
  362. delete this;
  363. }
  364. }
  365. else
  366. {
  367. // somebody forget to increment the nest count!!
  368. AssertSz(0, "Unbalanced nest count!!");
  369. cNest = 0;
  370. }
  371. return cNest;
  372. }
  373. //+-------------------------------------------------------------------------
  374. //
  375. // Member: CSafeRefCount::IsZombie
  376. //
  377. // Synopsis: determines whether or not the object is in a zombie state
  378. // (i.e. all references gone, but we are still on the stack
  379. // somewhere).
  380. //
  381. // Effects:
  382. //
  383. // Arguments: none
  384. //
  385. // Requires:
  386. //
  387. // Returns: TRUE if in a zombie state
  388. // FALSE otherwise
  389. //
  390. // Signals:
  391. //
  392. // Modifies:
  393. //
  394. // Derivation:
  395. //
  396. // Algorithm: If we are in the middle of a delete, or if the ref count
  397. // is zero and the nest count is greater than zero, then we
  398. // are a zombie
  399. //
  400. // History: dd-mmm-yy Author Comment
  401. // 28-Jul-94 alexgo author
  402. //
  403. // Notes:
  404. //
  405. //--------------------------------------------------------------------------
  406. BOOL CSafeRefCount::IsZombie()
  407. {
  408. BOOL fIsZombie;
  409. if( (m_cRefs == 0 && m_cNest > 0) || m_fInDelete == TRUE
  410. || m_fForceZombie == TRUE)
  411. {
  412. fIsZombie = TRUE;
  413. }
  414. else
  415. {
  416. fIsZombie = FALSE;
  417. }
  418. return fIsZombie;
  419. }
  420. //+-------------------------------------------------------------------------
  421. //
  422. // Member: CSafeRefCount::Zombie
  423. //
  424. // Synopsis: Forces the object into a zombie state. This is called
  425. // when the object is still around but shouldn't be. It
  426. // flags us so we behave safely while we are in this state.
  427. //
  428. // Effects:
  429. //
  430. // Arguments: none
  431. //
  432. // Requires:
  433. //
  434. // Returns: none
  435. //
  436. // Signals:
  437. //
  438. // Modifies:
  439. //
  440. // Derivation:
  441. //
  442. // Algorithm:
  443. //
  444. // History:
  445. //
  446. // Notes:
  447. //
  448. //--------------------------------------------------------------------------
  449. VOID CSafeRefCount::Zombie()
  450. {
  451. m_fForceZombie = TRUE;
  452. }
  453. /* OleStdSwitchDisplayAspect
  454. **
  455. ** @mfunc
  456. ** Switch the currently cached display aspect between DVASPECT_ICON
  457. ** and DVASPECT_CONTENT.
  458. **
  459. ** NOTE: when setting up icon aspect, any currently cached content
  460. ** cache is discarded and any advise connections for content aspect
  461. ** are broken.
  462. **
  463. ** @rdesc
  464. ** S_OK -- new display aspect setup successfully
  465. ** E_INVALIDARG -- IOleCache interface is NOT supported (this is
  466. ** required).
  467. ** <other SCODE> -- any SCODE that can be returned by
  468. ** IOleCache::Cache method.
  469. ** NOTE: if an error occurs then the current display aspect and
  470. ** cache contents unchanged.
  471. */
  472. HRESULT OleStdSwitchDisplayAspect(
  473. LPOLEOBJECT lpOleObj,
  474. LPDWORD lpdwCurAspect,
  475. DWORD dwNewAspect,
  476. HGLOBAL hMetaPict,
  477. BOOL fDeleteOldAspect,
  478. BOOL fSetupViewAdvise,
  479. LPADVISESINK lpAdviseSink,
  480. BOOL FAR* lpfMustUpdate)
  481. {
  482. #ifndef PEGASUS
  483. LPOLECACHE lpOleCache = NULL;
  484. LPVIEWOBJECT lpViewObj = NULL;
  485. LPENUMSTATDATA lpEnumStatData = NULL;
  486. STATDATA StatData;
  487. FORMATETC FmtEtc;
  488. STGMEDIUM Medium;
  489. DWORD dwAdvf;
  490. DWORD dwNewConnection;
  491. DWORD dwOldAspect = *lpdwCurAspect;
  492. HRESULT hrErr;
  493. if (lpfMustUpdate)
  494. *lpfMustUpdate = FALSE;
  495. if (hrErr =
  496. lpOleObj->QueryInterface(IID_IOleCache, (void**)&lpOleCache))
  497. {
  498. return hrErr;
  499. }
  500. // Setup new cache with the new aspect
  501. FmtEtc.cfFormat = 0; // whatever is needed to draw
  502. FmtEtc.ptd = NULL;
  503. FmtEtc.dwAspect = dwNewAspect;
  504. FmtEtc.lindex = -1;
  505. FmtEtc.tymed = TYMED_NULL;
  506. /* NOTE: if we are setting up Icon aspect with a custom icon
  507. ** then we do not want DataAdvise notifications to ever change
  508. ** the contents of the data cache. thus we set up a NODATA
  509. ** advise connection. otherwise we set up a standard DataAdvise
  510. ** connection.
  511. */
  512. if (dwNewAspect == DVASPECT_ICON && hMetaPict)
  513. dwAdvf = ADVF_NODATA;
  514. else
  515. dwAdvf = ADVF_PRIMEFIRST;
  516. hrErr = lpOleCache->Cache(
  517. (LPFORMATETC)&FmtEtc,
  518. dwAdvf,
  519. (LPDWORD)&dwNewConnection
  520. );
  521. if (! SUCCEEDED(hrErr)) {
  522. lpOleCache->Release();
  523. return hrErr;
  524. }
  525. *lpdwCurAspect = dwNewAspect;
  526. /* NOTE: if we are setting up Icon aspect with a custom icon,
  527. ** then stuff the icon into the cache. otherwise the cache must
  528. ** be forced to be updated. set the *lpfMustUpdate flag to tell
  529. ** caller to force the object to Run so that the cache will be
  530. ** updated.
  531. */
  532. if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
  533. FmtEtc.cfFormat = CF_METAFILEPICT;
  534. FmtEtc.ptd = NULL;
  535. FmtEtc.dwAspect = DVASPECT_ICON;
  536. FmtEtc.lindex = -1;
  537. FmtEtc.tymed = TYMED_MFPICT;
  538. Medium.tymed = TYMED_MFPICT;
  539. Medium.hGlobal = hMetaPict;
  540. Medium.pUnkForRelease = NULL;
  541. hrErr = lpOleCache->SetData(
  542. (LPFORMATETC)&FmtEtc,
  543. (LPSTGMEDIUM)&Medium,
  544. FALSE /* fRelease */
  545. );
  546. } else {
  547. if (lpfMustUpdate)
  548. *lpfMustUpdate = TRUE;
  549. }
  550. if (fSetupViewAdvise && lpAdviseSink) {
  551. /* NOTE: re-establish the ViewAdvise connection */
  552. lpOleObj->QueryInterface(IID_IViewObject, (void**)&lpViewObj);
  553. if (lpViewObj) {
  554. lpViewObj->SetAdvise(
  555. dwNewAspect,
  556. 0,
  557. lpAdviseSink
  558. );
  559. lpViewObj->Release();
  560. }
  561. }
  562. /* NOTE: remove any existing caches that are set up for the old
  563. ** display aspect. It WOULD be possible to retain the caches set
  564. ** up for the old aspect, but this would increase the storage
  565. ** space required for the object and possibly require additional
  566. ** overhead to maintain the unused cachaes. For these reasons the
  567. ** strategy to delete the previous caches is prefered. if it is a
  568. ** requirement to quickly switch between Icon and Content
  569. ** display, then it would be better to keep both aspect caches.
  570. */
  571. if (fDeleteOldAspect) {
  572. hrErr = lpOleCache->EnumCache(
  573. (LPENUMSTATDATA FAR*)&lpEnumStatData
  574. );
  575. while(hrErr == NOERROR) {
  576. hrErr = lpEnumStatData->Next(
  577. 1,
  578. (LPSTATDATA)&StatData,
  579. NULL
  580. );
  581. if (hrErr != NOERROR)
  582. break; // DONE! no more caches.
  583. if (StatData.formatetc.dwAspect == dwOldAspect) {
  584. // Remove previous cache with old aspect
  585. lpOleCache->Uncache(StatData.dwConnection);
  586. }
  587. }
  588. if (lpEnumStatData)
  589. lpEnumStatData->Release();
  590. }
  591. if (lpOleCache)
  592. lpOleCache->Release();
  593. #endif
  594. return NOERROR;
  595. }
  596. /*
  597. * ObjectReadSiteFlags
  598. *
  599. * @mfunc
  600. * Read the dwFlags, dwUser, & dvaspect bytes from a container
  601. * specific stream.
  602. *
  603. * Arguments:
  604. * preobj The REOBJ in which to copy the flags.
  605. *
  606. * @rdesc
  607. * HRESULT
  608. */
  609. HRESULT ObjectReadSiteFlags(REOBJECT * preobj)
  610. {
  611. HRESULT hr = NOERROR;
  612. #ifndef PEGASUS
  613. LPSTREAM pstm = NULL;
  614. OLECHAR StreamName[] = OLESTR("RichEditFlags");
  615. // Make sure we have a storage to read from
  616. if (!preobj->pstg)
  617. return E_INVALIDARG;
  618. // Open the stream
  619. if (hr = preobj->pstg->OpenStream(StreamName, 0, STGM_READ |
  620. STGM_SHARE_EXCLUSIVE, 0, &pstm))
  621. {
  622. goto Cleanup;
  623. }
  624. if ((hr = pstm->Read(&preobj->dwFlags,
  625. sizeof(preobj->dwFlags), NULL)) ||
  626. (hr = pstm->Read(&preobj->dwUser,
  627. sizeof(preobj->dwUser), NULL)) ||
  628. (hr = pstm->Read(&preobj->dvaspect,
  629. sizeof(preobj->dvaspect), NULL)))
  630. {
  631. goto Cleanup;
  632. }
  633. Cleanup:
  634. if (pstm)
  635. pstm->Release();
  636. #endif
  637. return hr;
  638. }
  639. //Used for EnumMetafileCheckIcon & FIsIconMetafilePict
  640. typedef struct _walkmetafile
  641. {
  642. BOOL fAND;
  643. BOOL fPastIcon;
  644. BOOL fHasIcon;
  645. } WALKMETAFILE;
  646. static CHAR szIconOnly[] = "IconOnly";
  647. /*
  648. * EnumMetafileCheckIcon
  649. *
  650. * @mfunc
  651. * Stripped down version of EnumMetafileExtractIcon and
  652. * EnumMetafileExtractIconSource from the OLE2UI library.
  653. *
  654. * EnumMetaFile callback function that walks a metafile looking for
  655. * StretchBlt (3.1) and BitBlt (3.0) records. We expect to see two
  656. * of them, the first being the AND mask and the second being the XOR
  657. * data.
  658. *
  659. * Once we find the icon, we confirm this find by looking for the "IconOnly"
  660. * comment block found in standard OLE iconic metafiles.
  661. *
  662. * Arguments:
  663. * hDC HDC into which the metafile should be played.
  664. * phTable HANDLETABLE FAR * providing handles selected into the DC.
  665. * pMFR METARECORD FAR * giving the enumerated record.
  666. * pIE LPICONEXTRACT providing the destination buffer and length.
  667. *
  668. * @rdesc
  669. * int 0 to stop enumeration, 1 to continue.
  670. */
  671. int CALLBACK EnumMetafileCheckIcon(HDC hdc, HANDLETABLE *phTable,
  672. METARECORD *pMFR, int cObj,
  673. LPARAM lparam)
  674. {
  675. #ifndef PEGASUS
  676. WALKMETAFILE * pwmf = (WALKMETAFILE *) lparam;
  677. switch (pMFR->rdFunction)
  678. {
  679. case META_DIBBITBLT: // Win30
  680. case META_DIBSTRETCHBLT: // Win31
  681. // If this is the first pass (pIE->fAND==TRUE) then save the memory
  682. // of the AND bits for the next pass.
  683. if (pwmf->fAND)
  684. pwmf->fAND = FALSE;
  685. else
  686. pwmf->fPastIcon = TRUE;
  687. break;
  688. case META_ESCAPE:
  689. if (pwmf->fPastIcon &&
  690. pMFR->rdParm[0] == MFCOMMENT &&
  691. !lstrcmpiA(szIconOnly, (LPSTR)&pMFR->rdParm[2]))
  692. {
  693. pwmf->fHasIcon = TRUE;
  694. return 0;
  695. }
  696. break;
  697. }
  698. #endif
  699. return 1;
  700. }
  701. /*
  702. * FIsIconMetafilePict
  703. *
  704. * @mfunc
  705. * Detect whether the metafile contains an iconic presentation. We do this
  706. * by getting a screen DC and walking the metafile records until we find
  707. * the landmarks denoting an icon.
  708. *
  709. * Arguments:
  710. * hmfp The metafile to test
  711. *
  712. * @rdesc
  713. * BOOL TRUE if the metafile contains an iconic view
  714. */
  715. BOOL FIsIconMetafilePict(HGLOBAL hmfp)
  716. {
  717. #ifndef PEGASUS
  718. LPMETAFILEPICT pmfp;
  719. WALKMETAFILE wmf = { 0 };
  720. HDC hdc;
  721. wmf.fAND = TRUE;
  722. if (!hmfp || !(pmfp = (LPMETAFILEPICT)GlobalLock(hmfp)))
  723. goto CleanUp;
  724. // We get information back in the ICONEXTRACT structure.
  725. hdc = GetDC(NULL);
  726. EnumMetaFile(hdc, pmfp->hMF, EnumMetafileCheckIcon, (LPARAM) &wmf);
  727. ReleaseDC(NULL, hdc);
  728. GlobalUnlock(hmfp);
  729. CleanUp:
  730. return wmf.fHasIcon;
  731. #else
  732. return TRUE;
  733. #endif
  734. }
  735. /*
  736. * AllocObjectDescriptor
  737. *
  738. * Purpose:
  739. * Allocated and fills an OBJECTDESCRIPTOR structure.
  740. *
  741. * Parameters:
  742. * clsID CLSID to store.
  743. * dwAspect DWORD with the display aspect
  744. * pszl LPSIZEL (optional) if the object is being scaled in
  745. * its container, then the container should pass the
  746. * extents that it is using to display the object.
  747. * ptl POINTL from upper-left corner of object where
  748. * mouse went down for use with Drag & Drop.
  749. * dwMisc DWORD containing MiscStatus flags
  750. * pszName LPTSTR naming the object to copy
  751. * pszSrc LPTSTR identifying the source of the object.
  752. *
  753. * Return Value:
  754. * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
  755. */
  756. /*
  757. * AllocObjectDescriptor
  758. *
  759. * Purpose:
  760. * Allocated and fills an OBJECTDESCRIPTOR structure.
  761. *
  762. * Parameters:
  763. * clsID CLSID to store.
  764. * dwAspect DWORD with the display aspect
  765. * pszl LPSIZEL (optional) if the object is being scaled in
  766. * its container, then the container should pass the
  767. * extents that it is using to display the object.
  768. * ptl POINTL from upper-left corner of object where
  769. * mouse went down for use with Drag & Drop.
  770. * dwMisc DWORD containing MiscStatus flags
  771. * pszName LPTSTR naming the object to copy
  772. * pszSrc LPTSTR identifying the source of the object.
  773. *
  774. * Return Value:
  775. * HBGLOBAL Handle to OBJECTDESCRIPTOR structure.
  776. */
  777. static HGLOBAL AllocObjectDescriptor(
  778. CLSID clsID,
  779. DWORD dwAspect,
  780. SIZEL szl,
  781. POINTL ptl,
  782. DWORD dwMisc,
  783. LPTSTR pszName,
  784. LPTSTR pszSrc)
  785. {
  786. #ifndef PEGASUS
  787. HGLOBAL hMem=NULL;
  788. LPOBJECTDESCRIPTOR pOD;
  789. DWORD cb, cbStruct;
  790. DWORD cchName, cchSrc;
  791. cchName=wcslen(pszName)+1;
  792. if (NULL!=pszSrc)
  793. cchSrc=wcslen(pszSrc)+1;
  794. else
  795. {
  796. cchSrc=cchName;
  797. pszSrc=pszName;
  798. }
  799. /*
  800. * Note: CFSTR_OBJECTDESCRIPTOR is an ANSI structure.
  801. * That means strings in it must be ANSI. OLE will do
  802. * internal conversions back to Unicode as necessary,
  803. * but we have to put ANSI strings in it ourselves.
  804. */
  805. cbStruct=sizeof(OBJECTDESCRIPTOR);
  806. cb=cbStruct+(sizeof(WCHAR)*(cchName+cchSrc)); //HACK
  807. hMem=GlobalAlloc(GHND, cb);
  808. if (NULL==hMem)
  809. return NULL;
  810. pOD=(LPOBJECTDESCRIPTOR)GlobalLock(hMem);
  811. pOD->cbSize=cb;
  812. pOD->clsid=clsID;
  813. pOD->dwDrawAspect=dwAspect;
  814. pOD->sizel=szl;
  815. pOD->pointl=ptl;
  816. pOD->dwStatus=dwMisc;
  817. if (pszName)
  818. {
  819. pOD->dwFullUserTypeName=cbStruct;
  820. wcscpy((LPTSTR)((LPBYTE)pOD+pOD->dwFullUserTypeName)
  821. , pszName);
  822. }
  823. else
  824. pOD->dwFullUserTypeName=0; //No string
  825. if (pszSrc)
  826. {
  827. pOD->dwSrcOfCopy=cbStruct+(cchName*sizeof(WCHAR));
  828. wcscpy((LPTSTR)((LPBYTE)pOD+pOD->dwSrcOfCopy), pszSrc);
  829. }
  830. else
  831. pOD->dwSrcOfCopy=0; //No string
  832. GlobalUnlock(hMem);
  833. return hMem;
  834. #else
  835. return NULL;
  836. #endif
  837. }
  838. HGLOBAL OleGetObjectDescriptorDataFromOleObject(
  839. LPOLEOBJECT pObj,
  840. DWORD dwAspect,
  841. POINTL ptl,
  842. LPSIZEL pszl
  843. )
  844. {
  845. #ifndef PEGASUS
  846. CLSID clsID;
  847. LPTSTR pszName=NULL;
  848. LPTSTR pszSrc=NULL;
  849. BOOL fLink=FALSE;
  850. IOleLink *pLink;
  851. TCHAR szName[512];
  852. DWORD dwMisc=0;
  853. SIZEL szl = {0,0};
  854. HGLOBAL hMem;
  855. HRESULT hr;
  856. if (SUCCEEDED(pObj->QueryInterface(IID_IOleLink
  857. , (void **)&pLink)))
  858. fLink=TRUE;
  859. if (FAILED(pObj->GetUserClassID(&clsID)))
  860. ZeroMemory(&clsID, sizeof(CLSID));
  861. //Get user string, expand to "Linked %s" if this is link
  862. pObj->GetUserType(USERCLASSTYPE_FULL, &pszName);
  863. if (fLink && NULL!=pszName)
  864. {
  865. // NB!! we do these two lines of code below instead
  866. // wcscat because we don't use wcscat anywhere else
  867. // in the product at the moment. The string "Linked "
  868. // should never change either.
  869. wcscpy(szName, TEXT("Linked "));
  870. wcscpy(&(szName[7]), pszName);
  871. }
  872. else if (pszName)
  873. wcscpy(szName, pszName);
  874. else
  875. szName[0] = 0;
  876. CoTaskMemFree(pszName);
  877. /*
  878. * Get the source name of this object using either the
  879. * link display name (for link) or a moniker display
  880. * name.
  881. */
  882. if (fLink)
  883. {
  884. hr=pLink->GetSourceDisplayName(&pszSrc);
  885. }
  886. else
  887. {
  888. IMoniker *pmk;
  889. hr=pObj->GetMoniker(OLEGETMONIKER_TEMPFORUSER
  890. , OLEWHICHMK_OBJFULL, &pmk);
  891. if (SUCCEEDED(hr))
  892. {
  893. IBindCtx *pbc;
  894. CreateBindCtx(0, &pbc);
  895. pmk->GetDisplayName(pbc, NULL, &pszSrc);
  896. pbc->Release();
  897. pmk->Release();
  898. }
  899. }
  900. if (fLink)
  901. pLink->Release();
  902. //Get MiscStatus bits
  903. hr=pObj->GetMiscStatus(dwAspect, &dwMisc);
  904. if (pszl)
  905. {
  906. szl.cx = pszl->cx;
  907. szl.cy = pszl->cy;
  908. }
  909. //Get OBJECTDESCRIPTOR
  910. hMem=AllocObjectDescriptor(clsID, dwAspect, szl, ptl, dwMisc, szName, pszSrc);
  911. CoTaskMemFree(pszSrc);
  912. return hMem;
  913. #else
  914. return NULL;
  915. #endif
  916. }
  917. /*
  918. * OleStdGetMetafilePictFromOleObject()
  919. *
  920. * @mfunc:
  921. * Generate a MetafilePict from the OLE object.
  922. * Parameters:
  923. * lpOleObj LPOLEOBJECT pointer to OLE Object
  924. * dwDrawAspect DWORD Display Aspect of object
  925. * lpSizelHim SIZEL (optional) If the object is being scaled in its
  926. * container, then the container should pass the extents
  927. * that it is using to display the object.
  928. * May be NULL if the object is NOT being scaled. in this
  929. * case, IViewObject2::GetExtent will be called to get the
  930. * extents from the object.
  931. * ptd TARGETDEVICE FAR* (optional) target device to render
  932. * metafile for. May be NULL.
  933. *
  934. * @rdesc
  935. * HANDLE -- handle of allocated METAFILEPICT
  936. */
  937. HANDLE OleStdGetMetafilePictFromOleObject(
  938. LPOLEOBJECT lpOleObj,
  939. DWORD dwDrawAspect,
  940. LPSIZEL lpSizelHim,
  941. DVTARGETDEVICE FAR* ptd
  942. )
  943. {
  944. #ifndef PEGASUS
  945. LPVIEWOBJECT2 lpViewObj2 = NULL;
  946. HDC hDC;
  947. HMETAFILE hmf;
  948. HANDLE hMetaPict;
  949. LPMETAFILEPICT lpPict;
  950. RECT rcHim;
  951. RECTL rclHim;
  952. SIZEL sizelHim;
  953. HRESULT hrErr;
  954. SIZE size;
  955. POINT point;
  956. LPOLECACHE polecache = NULL;
  957. LPDATAOBJECT pdataobj = NULL;
  958. FORMATETC fetc;
  959. STGMEDIUM med;
  960. // First try the easy way,
  961. // pull out the cache's version of things.
  962. ZeroMemory(&fetc, sizeof(FORMATETC));
  963. fetc.dwAspect = dwDrawAspect;
  964. fetc.cfFormat = CF_METAFILEPICT;
  965. fetc.lindex = -1;
  966. fetc.tymed = TYMED_MFPICT;
  967. ZeroMemory(&med, sizeof(STGMEDIUM));
  968. hMetaPict = NULL;
  969. if (!lpOleObj->QueryInterface(IID_IOleCache, (void **)&polecache) &&
  970. !polecache->QueryInterface(IID_IDataObject, (void **)&pdataobj) &&
  971. !pdataobj->GetData(&fetc, &med))
  972. {
  973. hMetaPict = OleDuplicateData(med.hGlobal, CF_METAFILEPICT, 0);
  974. ReleaseStgMedium(&med);
  975. }
  976. if (pdataobj)
  977. {
  978. pdataobj->Release();
  979. }
  980. if (polecache)
  981. {
  982. polecache->Release();
  983. }
  984. // If all this failed, fall back to the hard way and draw the object
  985. // into a metafile.
  986. if (hMetaPict)
  987. return hMetaPict;
  988. if (lpOleObj->QueryInterface(IID_IViewObject2, (void **)&lpViewObj2))
  989. return NULL;
  990. // Get SIZEL
  991. if (lpSizelHim) {
  992. // Use extents passed by the caller
  993. sizelHim = *lpSizelHim;
  994. } else {
  995. // Get the current extents from the object
  996. hrErr = lpViewObj2->GetExtent(
  997. dwDrawAspect,
  998. -1, /*lindex*/
  999. ptd, /*ptd*/
  1000. (LPSIZEL)&sizelHim);
  1001. if (hrErr != NOERROR)
  1002. sizelHim.cx = sizelHim.cy = 0;
  1003. }
  1004. hDC = CreateMetaFileA(NULL);
  1005. rclHim.left = 0;
  1006. rclHim.top = 0;
  1007. rclHim.right = sizelHim.cx;
  1008. rclHim.bottom = sizelHim.cy;
  1009. rcHim.left = (int)rclHim.left;
  1010. rcHim.top = (int)rclHim.top;
  1011. rcHim.right = (int)rclHim.right;
  1012. rcHim.bottom = (int)rclHim.bottom;
  1013. SetWindowOrgEx(hDC, rcHim.left, rcHim.top, &point);
  1014. SetWindowExtEx(hDC, rcHim.right-rcHim.left, rcHim.bottom-rcHim.top,&size);
  1015. hrErr = lpViewObj2->Draw(
  1016. dwDrawAspect,
  1017. -1,
  1018. NULL,
  1019. ptd,
  1020. NULL,
  1021. hDC,
  1022. (LPRECTL)&rclHim,
  1023. (LPRECTL)&rclHim,
  1024. NULL,
  1025. 0
  1026. );
  1027. lpViewObj2->Release();
  1028. hmf = CloseMetaFile(hDC);
  1029. if (hrErr != NOERROR) {
  1030. TRACEERRORHR(hrErr);
  1031. hMetaPict = NULL;
  1032. }
  1033. else
  1034. {
  1035. hMetaPict = GlobalAlloc(GHND|GMEM_SHARE, sizeof(METAFILEPICT));
  1036. if (hMetaPict && (lpPict = (LPMETAFILEPICT)GlobalLock(hMetaPict))){
  1037. lpPict->hMF = hmf;
  1038. lpPict->xExt = (int)sizelHim.cx ;
  1039. lpPict->yExt = (int)sizelHim.cy ;
  1040. lpPict->mm = MM_ANISOTROPIC;
  1041. GlobalUnlock(hMetaPict);
  1042. }
  1043. }
  1044. if (!hMetaPict)
  1045. DeleteMetaFile(hmf);
  1046. return hMetaPict;
  1047. #else
  1048. return NULL;
  1049. #endif
  1050. }
  1051. /*
  1052. * OleUIDrawShading
  1053. *
  1054. * Purpose:
  1055. * Shade the object when it is in in-place editing. Borders are drawn
  1056. * on the Object rectangle. The right and bottom edge of the rectangle
  1057. * are excluded in the drawing.
  1058. *
  1059. * Parameters:
  1060. * lpRect Dimensions of Container Object
  1061. * hdc HDC for drawing
  1062. *
  1063. * Return Value: null
  1064. *
  1065. */
  1066. void OleUIDrawShading(LPRECT lpRect, HDC hdc)
  1067. {
  1068. #ifndef PEGASUS
  1069. HBRUSH hbr;
  1070. HBRUSH hbrOld;
  1071. HBITMAP hbm;
  1072. RECT rc;
  1073. WORD wHatchBmp[] = {0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88};
  1074. COLORREF cvText;
  1075. COLORREF cvBk;
  1076. hbm = CreateBitmap(8, 8, 1, 1, wHatchBmp);
  1077. hbr = CreatePatternBrush(hbm);
  1078. hbrOld = (HBRUSH)SelectObject(hdc, hbr);
  1079. rc = *lpRect;
  1080. cvText = SetTextColor(hdc, RGB(255, 255, 255));
  1081. cvBk = SetBkColor(hdc, RGB(0, 0, 0));
  1082. PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
  1083. 0x00A000C9L /* DPa */ );
  1084. SetTextColor(hdc, cvText);
  1085. SetBkColor(hdc, cvBk);
  1086. SelectObject(hdc, hbrOld);
  1087. DeleteObject(hbr);
  1088. DeleteObject(hbm);
  1089. #endif
  1090. }
  1091. /*
  1092. * OleSaveSiteFlags
  1093. *
  1094. * Purpose:
  1095. * Save the dwFlags and dwUser bytes into a container specific stream
  1096. *
  1097. * Arguments:
  1098. * pstg The storage to save to
  1099. * pobsite The site from where to copy the flags
  1100. *
  1101. * Returns:
  1102. * None.
  1103. */
  1104. VOID OleSaveSiteFlags(LPSTORAGE pstg, DWORD dwFlags, DWORD dwUser, DWORD dvAspect)
  1105. {
  1106. #ifndef PEGASUS
  1107. HRESULT hr;
  1108. LPSTREAM pstm = NULL;
  1109. static const OLECHAR szSiteFlagsStm[] = OLESTR("RichEditFlags");
  1110. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "OleSaveSiteFlags");
  1111. // Create/overwrite the stream
  1112. AssertSz(pstg, "Invalid storage");
  1113. if (hr = pstg->CreateStream(szSiteFlagsStm, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
  1114. 0, 0, &pstm))
  1115. {
  1116. TraceError("OleSaveSiteFlags", GetScode(hr));
  1117. goto Cleanup;
  1118. }
  1119. //$ FUTURE: Put a version stamp
  1120. // Write out the values
  1121. //$ BUG: byte order
  1122. if ((hr = pstm->Write(&dwFlags, sizeof(dwFlags), NULL)) ||
  1123. (hr = pstm->Write(&dwUser, sizeof(dwUser), NULL)) ||
  1124. (hr = pstm->Write(&dvAspect, sizeof(dvAspect), NULL)))
  1125. {
  1126. TraceError("OleSaveSiteFlags", GetScode(hr));
  1127. //$ FUTURE: Wipe the data to make this operation all or nothing
  1128. goto Cleanup;
  1129. }
  1130. Cleanup:
  1131. if (pstm)
  1132. pstm->Release();
  1133. #endif
  1134. }
  1135. /*
  1136. * AppendString ( szInput, szAppendStr, dBuffSize, dByteUsed )
  1137. *
  1138. * Purpose:
  1139. * Append new string to original string. Check for size of buffer
  1140. * and re-allocate a large buffer is necessary
  1141. *
  1142. * Arguments:
  1143. * szInput Original String
  1144. * szAppendStr String to be appended to szInput
  1145. * dBuffSize Byte size of the buffer for szInput
  1146. * dByteUsed Byte used in the buffer for szInput
  1147. *
  1148. * Returns:
  1149. * INT The error code
  1150. */
  1151. INT AppendString(
  1152. BYTE ** szInput,
  1153. BYTE * szAppendStr,
  1154. int * dBuffSize,
  1155. int * dByteUsed)
  1156. {
  1157. BYTE *pch;
  1158. int cchAppendStr;
  1159. pch = *szInput;
  1160. // check if we have enough space to append the new string
  1161. cchAppendStr = strlen( (char *)szAppendStr );
  1162. if ( cchAppendStr + *dByteUsed >= *dBuffSize )
  1163. {
  1164. // re-alloc a bigger buffer
  1165. int cchNewSize = *dBuffSize + cchAppendStr + 32;
  1166. pch = (BYTE *)PvReAlloc( *szInput, cchNewSize );
  1167. if ( !pch )
  1168. {
  1169. return ( ecNoMemory );
  1170. }
  1171. *dBuffSize = cchNewSize;
  1172. *szInput = pch;
  1173. }
  1174. pch += *dByteUsed;
  1175. *dByteUsed += cchAppendStr;
  1176. while (*pch++ = *szAppendStr++);
  1177. return ecNoError;
  1178. }
  1179. /*
  1180. * CTempBuf::Init
  1181. *
  1182. * @mfunc Set object to its initial state using the stack buffer
  1183. *
  1184. */
  1185. void CTempBuf::Init()
  1186. {
  1187. _pv = (void *) &_chBuf[0];
  1188. _cb = MAX_STACK_BUF;
  1189. }
  1190. /*
  1191. * CTempBuf::FreeBuf
  1192. *
  1193. * @mfunc Free an allocated buffer if there is one
  1194. *
  1195. */
  1196. void CTempBuf::FreeBuf()
  1197. {
  1198. if (_pv != &_chBuf[0])
  1199. {
  1200. delete _pv;
  1201. }
  1202. }
  1203. /*
  1204. * CTempBuf::GetBuf
  1205. *
  1206. * @mfunc Get a buffer for temporary use
  1207. *
  1208. * @rdesc Pointer to buffer if one could be allocated otherwise NULL.
  1209. *
  1210. *
  1211. */
  1212. void *CTempBuf::GetBuf(
  1213. LONG cb) //@parm Size of buffer needed in bytes
  1214. {
  1215. if (_cb >= cb)
  1216. {
  1217. // Currently allocated buffer is big enough so use it
  1218. return _pv;
  1219. }
  1220. // Free our current buffer
  1221. FreeBuf();
  1222. // Allocate a new buffer if we can
  1223. _pv = new BYTE[cb];
  1224. if (NULL == _pv)
  1225. {
  1226. // Could not allocate a buffer so reset to our initial state and
  1227. // return NULL.
  1228. Init();
  1229. return NULL;
  1230. }
  1231. // Store the size of our new buffer.
  1232. _cb = cb;
  1233. // Returnt he pointer to the buffer.
  1234. return _pv;
  1235. }