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.

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