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.

2308 lines
71 KiB

  1. // DocWrapImpl.cpp : Implementation of CDocWrap
  2. #include "stdafx.h"
  3. #include "MSAAText.h"
  4. #include "DocWrap.h"
  5. #include <list_dl.h>
  6. #include "VersionInfo.h"
  7. #include <msctf.h>
  8. #include <msctfp.h>
  9. #define INITGUID
  10. #include <msctfx.h>
  11. #include <tStr.h>
  12. #include <fwd_macros.h> // currently in the DocModel\inc dir... adjust appropriately if porting...
  13. /*
  14. * IDoc - the variant of the ITextStoreACP we're using (ACP/Anchor)
  15. * ISink - the corresponding Sink interface (ACP/Anchor)
  16. *
  17. * ICicDoc - the Cicero doc interface, which extends IDoc
  18. * ICicSink - the Cicero sink interface, which extends ISink
  19. *
  20. * CDocWrap - the document wrapper class, implements ICicDoc (which includes IDoc)
  21. * CSinkWrap - the sink wrapper class, implements ICicSink (which includes ISink)
  22. *
  23. */
  24. class BasicDocTraitsAnchor
  25. {
  26. public:
  27. typedef struct ITextStoreAnchor IDoc;
  28. typedef struct ITextStoreAnchorSink ISink;
  29. typedef struct ITextStoreAnchor ICicDoc;
  30. typedef struct ITextStoreAnchorServices ICicSink;
  31. typedef class CDocWrapAnchor CDocWrap;
  32. typedef class CSinkWrapAnchor CSinkWrap;
  33. typedef struct ITextStoreAnchorEx IDocEx;
  34. typedef struct ITextStoreSinkAnchorEx ISinkEx;
  35. typedef IAnchor * PosType;
  36. };
  37. class BasicDocTraitsACP
  38. {
  39. public:
  40. typedef struct ITextStoreACP IDoc;
  41. typedef struct ITextStoreACPSink ISink;
  42. typedef struct ITextStoreACP ICicDoc;
  43. typedef struct ITextStoreACPServices ICicSink;
  44. typedef class CDocWrapACP CDocWrap;
  45. typedef class CSinkWrapACP CSinkWrap;
  46. typedef struct ITextStoreACPEx IDocEx;
  47. typedef struct ITextStoreACPSinkEx ISinkEx;
  48. typedef LONG PosType;
  49. };
  50. // DocWrapExcept contains exception wrapper classes for
  51. // some of the above interfaces...
  52. #include "DocWrapExcept.h"
  53. // Add the appropriate exception wrappers to the set of
  54. // doc traits.
  55. class DocTraitsAnchor: public BasicDocTraitsAnchor
  56. {
  57. public:
  58. typedef SEHWrapPtr_TextStoreAnchor IDocSEHWrap;
  59. };
  60. class DocTraitsACP: public BasicDocTraitsACP
  61. {
  62. public:
  63. typedef SEHWrapPtr_TextStoreACP IDocSEHWrap;
  64. };
  65. /////////////////////////////////////////////////////////////////
  66. // Create an instance of a local non-externally-createable class.
  67. // Just a wrapper for CComObject::CreateInstance, but also AddRef's so that
  68. // the returned object has a ref of 1.
  69. template< class C >
  70. HRESULT CreateLocalInstance( C ** p )
  71. {
  72. CComObject< C > * p2 = NULL;
  73. HRESULT hr = CComObject< C >::CreateInstance( & p2 );
  74. if( FAILED( hr ) )
  75. {
  76. TraceErrorHR( hr, TEXT("CreateLocalInstance") );
  77. return hr;
  78. }
  79. if( p2 == NULL || hr != S_OK )
  80. {
  81. TraceErrorHR( hr, TEXT("CreateLocalInstance returned NULL") );
  82. return E_UNEXPECTED;
  83. }
  84. p2->AddRef();
  85. *p = p2;
  86. return S_OK;
  87. }
  88. // Check hr and condition - return appropriate error if not S_OK and ! cond.
  89. #define CHECK_HR_RETURN( hr, cond ) /**/ \
  90. if( (hr) != S_OK ) \
  91. return FAILED( (hr) ) ? (hr) : E_UNEXPECTED; \
  92. if( (hr) == S_OK && ! ( cond ) ) \
  93. return E_UNEXPECTED;
  94. template < class T >
  95. inline
  96. void SafeReleaseClear( T * & ptr )
  97. {
  98. if( ptr )
  99. {
  100. ptr->Release();
  101. ptr = NULL;
  102. }
  103. }
  104. class CPrivateAddRef
  105. {
  106. public:
  107. CPrivateAddRef( long &rc ) : m_refcount( rc ) { m_refcount++; }
  108. ~CPrivateAddRef() { m_refcount--; }
  109. private:
  110. long &m_refcount;
  111. };
  112. class _declspec(uuid("{54D5D291-D8D7-4870-ADE1-331D86FD9430}")) IWrapMgr: public IUnknown
  113. {
  114. public:
  115. virtual void STDMETHODCALLTYPE SetDoc( IUnknown * pDoc ) = 0;
  116. virtual HRESULT STDMETHODCALLTYPE CreateWrappedDoc( IUnknown ** ppDoc ) = 0;
  117. };
  118. template < class DocTraits >
  119. class ATL_NO_VTABLE CWrapMgr :
  120. public CComObjectRootEx< CComSingleThreadModel >,
  121. public IWrapMgr
  122. {
  123. public:
  124. DECLARE_PROTECT_FINAL_CONSTRUCT()
  125. BEGIN_COM_MAP( CWrapMgr< DocTraits > )
  126. COM_INTERFACE_ENTRY( IWrapMgr )
  127. END_COM_MAP()
  128. private:
  129. // Ptr to the original document.
  130. // Each DocWrapper also has a copy of this ptr - but only we have a refcount on it.
  131. // DocTraits::IDoc * m_pDoc;
  132. DocTraits::IDocSEHWrap m_pDoc;
  133. // Used to remember who requested a sync lock...
  134. DocTraits::CDocWrap * m_pLockRequestedBy;
  135. BOOL m_fInSyncLockRequest;
  136. // Used to remember currently requested lock (ro vs rw)
  137. DWORD m_dwPendingLock;
  138. // Our sink - called by the doc
  139. DocTraits::CSinkWrap * m_pSinkWrap;
  140. // Current sink event mask - all client sink masks or'd together.
  141. DWORD m_dwSinkMask;
  142. BOOL m_fSinkActive;
  143. public:
  144. // List of DocWraps (one per client)
  145. List_dl< DocTraits::CDocWrap > m_DocWraps;
  146. LONG m_lIterationRefCount;
  147. //
  148. // Ctor, Dtor...
  149. //
  150. CWrapMgr()
  151. : m_pDoc( NULL ),
  152. m_pSinkWrap( NULL ),
  153. m_dwSinkMask( 0 ),
  154. m_fSinkActive( FALSE ),
  155. m_pLockRequestedBy( NULL ),
  156. m_fInSyncLockRequest( FALSE ),
  157. m_dwPendingLock( 0 ),
  158. m_lIterationRefCount( 0 )
  159. {
  160. // Done.
  161. TraceInfo( TEXT("WrapMgr ctor") );
  162. }
  163. ~CWrapMgr()
  164. {
  165. TraceInfo( TEXT("WrapMgr dtor") );
  166. AssertMsg( m_pDoc, TEXT("CWrapMgr::SetDoc never called?") );
  167. m_pDoc->Release();
  168. Assert( m_DocWraps.empty() );
  169. Assert( m_pSinkWrap == NULL );
  170. Assert( m_dwSinkMask == 0 );
  171. }
  172. //
  173. // IWrapMgr interface - used by the DocWrap holder to give us a doc and ask for wrappers for it...
  174. //
  175. void STDMETHODCALLTYPE SetDoc( IUnknown * pDoc )
  176. {
  177. _SetDoc( static_cast< DocTraits::IDoc * >( pDoc ) );
  178. }
  179. HRESULT STDMETHODCALLTYPE CreateWrappedDoc( IUnknown ** ppDoc )
  180. {
  181. return _CreateWrappedDoc( reinterpret_cast< DocTraits::IDoc ** >( ppDoc ) );
  182. }
  183. void RemoveDeadDocs()
  184. {
  185. for( Iter_dl < DocTraits::CDocWrap > i ( m_DocWraps ) ; ! i.AtEnd() ; )
  186. {
  187. Iter_dl < DocTraits::CDocWrap > dead = i;
  188. i++;
  189. if (dead->m_bUnadvised && m_lIterationRefCount == 0)
  190. m_DocWraps.remove( dead );
  191. }
  192. }
  193. //
  194. // Called by DocWrap, to tell us when it's been released, and to get us (the wrapper manager)
  195. // to handle a call that affects other wrappers on the same doc - advise/unadvise and lock calls.
  196. //
  197. void DocWrap_NotifyDisconnect( DocTraits::CDocWrap * pFrom )
  198. {
  199. // A DocWrap has been released by a client and is going away...
  200. // TODO - if using locks, check pFrom for lock, if it has it, release, broadcast relase.
  201. // - how can this scenario occur?
  202. // - doc is released in callback. Weird, but valid?
  203. }
  204. HRESULT DocWrap_HandleRequestLock( DocTraits::CDocWrap * pFrom, DWORD dwLockFlags, HRESULT * phrSession )
  205. {
  206. // Other clients may request a lock while it's being held by someone else, but the
  207. // current holder should not request a lock.
  208. // (This can happen when client1 is holding a lock, and issues an editing operation.
  209. // The wrapper broadcasts a OnTextChange event to other clients, and they may request locks.)
  210. AssertMsg( m_pLockRequestedBy != pFrom, TEXT("Lock owner re-request held lock? (Reentrancy?)") );
  211. if( dwLockFlags == 0 ||
  212. dwLockFlags & ~ ( TS_LF_SYNC | TS_LF_READ | TS_LF_READWRITE ) ) // check that only these bits present
  213. {
  214. AssertMsg( FALSE, TEXT("Bad lock flags") );
  215. return E_INVALIDARG;
  216. }
  217. if( dwLockFlags & TS_LF_SYNC )
  218. {
  219. // Can't process a SYNC call while someone else is holding the lock...
  220. if( m_pLockRequestedBy )
  221. {
  222. return E_FAIL;
  223. }
  224. // Sync lock - can just pass through - need to set up m_pLockRequestedBy so that the
  225. // sink can pass it onto the correct client.
  226. m_pLockRequestedBy = pFrom;
  227. m_fInSyncLockRequest = TRUE;
  228. HRESULT hr = m_pDoc->RequestLock( dwLockFlags, phrSession );
  229. m_fInSyncLockRequest = FALSE;
  230. m_pLockRequestedBy = NULL;
  231. return hr;
  232. } // sync lock
  233. else
  234. {
  235. // if async lock, update/upgrade the wrap's pending lock mask if necessary...
  236. // This test (which assumes that dwLockFlags != 0) upgrades to r/w if necessary.
  237. // TODO - should this update only be done conditionally if RequestLock succeeds?
  238. // (or no upgrade necessary?)
  239. Assert( dwLockFlags != 0 );
  240. if( pFrom->m_dwPendingLock != TS_LF_READWRITE )
  241. pFrom->m_dwPendingLock = dwLockFlags;
  242. if( m_pLockRequestedBy )
  243. {
  244. // someone else is currently holding the lock.
  245. // All we have to do is update the doc's PendingLock flags (see above) - they will
  246. // be picked up and handled by the loop in Handle_OnLockGranted when the current
  247. // lock holder returns.
  248. // Nothing else to do here.
  249. // But send it on the doc anyway if it's the same person
  250. if ( m_pLockRequestedBy == pFrom )
  251. {
  252. return m_pDoc->RequestLock( m_dwPendingLock, phrSession );
  253. }
  254. return S_OK;
  255. }
  256. else
  257. {
  258. // We don't have a lock yet.
  259. // Check our current request, if any, and if necessary, request a write,
  260. // even if we've already requested a read.
  261. // Update combined mask if necessary...
  262. DWORD dwNewLock = m_dwPendingLock;
  263. // Calculate required lock...
  264. if( dwNewLock != TS_LF_READWRITE )
  265. dwNewLock = dwLockFlags;
  266. HRESULT hr = E_FAIL;
  267. // Do we need to request a new lock/upgrade?
  268. if( dwNewLock != m_dwPendingLock )
  269. {
  270. // May get an immediate response even for an async request, so need to set this up
  271. // event if not a sync request...
  272. m_pLockRequestedBy = pFrom;
  273. DWORD OldPendingLock = m_dwPendingLock;
  274. m_dwPendingLock = dwNewLock;
  275. HRESULT hrOut = E_FAIL;
  276. hr = m_pDoc->RequestLock( m_dwPendingLock, & hrOut );
  277. m_pLockRequestedBy = NULL;
  278. if( hr != S_OK )
  279. {
  280. // After all that, the request failed...
  281. // Revert to previous pending lock...
  282. m_dwPendingLock = OldPendingLock;
  283. // fall out...
  284. }
  285. else
  286. {
  287. // Regardless of fail/success, copy the outgoing hr.
  288. // Clearing of the pending flags is done in OnLockgranted, not here.
  289. // Shouldn't get this for an async request...
  290. Assert( hrOut != TS_E_SYNCHRONOUS );
  291. *phrSession = hrOut;
  292. }
  293. }
  294. else
  295. {
  296. // Our existing pending lock covers this request - success.
  297. *phrSession = TS_S_ASYNC;
  298. hr = S_OK;
  299. }
  300. return hr;
  301. }
  302. } // async lock
  303. }
  304. HRESULT DocWrap_UpdateSubscription()
  305. {
  306. Assert( ( m_dwSinkMask & ~ TS_AS_ALL_SINKS ) == 0 );
  307. // If there are no active sinks, then SinkMask should be 0.
  308. Assert( m_fSinkActive || m_dwSinkMask == 0 );
  309. // Work out required mask - by or'ing masks of all doc's sinks...
  310. DWORD NewMask = 0;
  311. BOOL NewfSinkActive = FALSE;
  312. for( Iter_dl< DocTraits::CDocWrap > i ( m_DocWraps ) ; ! i.AtEnd() ; i++ )
  313. {
  314. if( i->m_Sink.m_pSink != NULL )
  315. {
  316. Assert( ( i->m_Sink.m_dwMask & ~ TS_AS_ALL_SINKS ) == 0 );
  317. NewMask |= i->m_Sink.m_dwMask;
  318. NewfSinkActive = TRUE;
  319. }
  320. }
  321. Assert( ( NewMask & ~ TS_AS_ALL_SINKS ) == 0 );
  322. // If there are no active sinks, then NewMask should be 0.
  323. Assert( NewfSinkActive || NewMask == 0 );
  324. // Tricky bit:
  325. // NewMask==0 does not mean that there's no sinks - some may have
  326. // dwMask == 0 to receive LockGranted calls.
  327. // So to check if the status has changed, we need to take whether
  328. // there are any active sinks (not just the masks) into account.
  329. if( NewfSinkActive == m_fSinkActive && NewMask == m_dwSinkMask )
  330. {
  331. // No change - nothing to do.
  332. return S_OK;
  333. }
  334. // Three possibilities:
  335. // (a) free to unregister,
  336. // (b) need to register
  337. // (c) need to update existing registration.
  338. // We handle (b) and (c) as the same case.
  339. if( ! NewfSinkActive )
  340. {
  341. // No sinks - can unregister...
  342. m_fSinkActive = FALSE;
  343. m_dwSinkMask = 0;
  344. if( ! m_pSinkWrap )
  345. {
  346. Assert( FALSE );
  347. // Odd - where did our sink wrap go - we didn't unregister it yet, so it should
  348. // still be around...
  349. // (Possible that server pre-emptively released us - so not an error.)
  350. }
  351. else
  352. {
  353. // Don't do anything else with m_pSinkWrap - the doc should release it.
  354. HRESULT hr = m_pDoc->UnadviseSink( static_cast< DocTraits::ICicSink * >( m_pSinkWrap ) );
  355. // shouldn't fail...
  356. Assert( hr == S_OK );
  357. // Doc should have released the sink (which would have called us back to NULL out
  358. // m_pSinkWrap...)
  359. Assert( m_pSinkWrap == NULL );
  360. }
  361. return S_OK;
  362. }
  363. else
  364. {
  365. // Update existing / add new...
  366. // If we already had an existing sink, there should be a sinkwrap...
  367. // (unless doc let it go prematurely...)
  368. Assert( ! m_fSinkActive || m_pSinkWrap );
  369. BOOL NeedRelease = FALSE;
  370. if( ! m_pSinkWrap )
  371. {
  372. HRESULT hr = CreateLocalInstance( & m_pSinkWrap );
  373. if( hr != S_OK )
  374. return hr;
  375. m_pSinkWrap->Init( this, & m_DocWraps );
  376. // After doing the Advise, release our ref on the sink, so that only
  377. // the doc holds a ref and controls its liftetime.
  378. // We still keep a pointer, but it's a "weak reference" - if the
  379. // sink goes away (because the doc releases its reference), the sink
  380. // notifies us so we can NULL-out the ptr. (see SinkWrap_NotifyDisconnect)
  381. NeedRelease = TRUE;
  382. }
  383. // Always try advising with the Cicero sink first - if that
  384. // doesn't work, fall back to the ITextStoreACP one.
  385. //
  386. // (Use of static_cast is necessary here to avoid ambiguity over
  387. // which IUnknown we convert to - the ICicSink one, or the
  388. // IServiceProvider one. We want the ICicSink one, to match the
  389. // IID passed in.)
  390. HRESULT hr = m_pDoc->AdviseSink( __uuidof( DocTraits::ICicSink ), static_cast< DocTraits::ICicSink * >( m_pSinkWrap ), NewMask );
  391. if( hr != S_OK )
  392. {
  393. hr = m_pDoc->AdviseSink( __uuidof( DocTraits::ISink ), static_cast< DocTraits::ISink * >( m_pSinkWrap ), NewMask );
  394. }
  395. if( NeedRelease )
  396. {
  397. m_pSinkWrap->Release();
  398. }
  399. if( hr == S_OK )
  400. {
  401. m_fSinkActive = TRUE;
  402. m_dwSinkMask = NewMask;
  403. }
  404. else
  405. {
  406. AssertMsg( FALSE, TEXT("AdviseSink failed") );
  407. }
  408. return hr;
  409. }
  410. }
  411. void DocWrap_NotifyRevoke()
  412. {
  413. // Send OnDisconnect to any SinkEx sinks,
  414. CPrivateAddRef MyAddRef(m_lIterationRefCount);
  415. for( Iter_dl< DocTraits::CDocWrap > i ( m_DocWraps ) ; ! i.AtEnd() ; i++ )
  416. {
  417. // Is this the SinkExt sink?
  418. if( i->m_Sink.m_iid == __uuidof( DocTraits::ISinkEx ) )
  419. {
  420. DocTraits::ISinkEx * pSink = static_cast< DocTraits::ISinkEx * >( i->m_Sink.m_pSink );
  421. if ( pSink )
  422. pSink->OnDisconnect();
  423. }
  424. }
  425. for( Iter_dl < DocTraits::CDocWrap > j ( m_DocWraps ) ; ! j.AtEnd() ; )
  426. {
  427. Iter_dl < DocTraits::CDocWrap > DocToDelete = j;
  428. j++;
  429. m_DocWraps.remove( DocToDelete );
  430. DocToDelete->Release();
  431. }
  432. }
  433. //
  434. // Called by SinkWrap to let us know when its been released...
  435. //
  436. void SinkWrap_NotifyDisconnect()
  437. {
  438. // The sink has been released by the application - it's now deleteing itself,
  439. // so we NULL-out our weak reference to it. (If we need another one in future,
  440. // we'll create a new one.)
  441. // Clear our sinks to reflect this...
  442. for( Iter_dl< DocTraits::CDocWrap > i ( m_DocWraps ) ; ! i.AtEnd() ; i++ )
  443. {
  444. i->m_Sink.ClearAndRelease();
  445. }
  446. m_pSinkWrap = NULL;
  447. }
  448. HRESULT SinkWrap_HandleOnLockGranted ( DWORD dwLockFlags )
  449. {
  450. // Is this servicing a sync or async request?
  451. Assert( ( dwLockFlags & ~ ( TS_LF_SYNC | TS_LF_READ | TS_LF_READWRITE ) ) == 0 );
  452. CPrivateAddRef MyAddRef(m_lIterationRefCount);
  453. if( m_fInSyncLockRequest )
  454. {
  455. // Sync lock - just pass it straight through to whoever requested it...
  456. Assert( dwLockFlags & TS_LF_SYNC );
  457. Assert( m_pLockRequestedBy && m_pLockRequestedBy->m_Sink.m_pSink );
  458. if( ! m_pLockRequestedBy || ! m_pLockRequestedBy->m_Sink.m_pSink )
  459. return E_UNEXPECTED;
  460. DocTraits::ISink * pSink = static_cast< DocTraits::ISink * > ( m_pLockRequestedBy->m_Sink.m_pSink );
  461. HRESULT hr = pSink->OnLockGranted( dwLockFlags );
  462. return hr;
  463. }
  464. else
  465. {
  466. // Async lock - hand it out to whoever wanted it...
  467. Assert( ! ( dwLockFlags & TS_LF_SYNC ) );
  468. // If we're waiting for a r/w lock, the lock granted should be r/w too...
  469. Assert( ! ( m_dwPendingLock & TS_LF_READWRITE ) || ( dwLockFlags & TS_LF_READWRITE ) );
  470. // Clear the pending lock, since we're now servicing them...
  471. m_dwPendingLock = 0;
  472. // Keep looking through the docs, servicing locks. We loop because some docs may
  473. // request locks while another holds the lock, so we have to come back an service them.
  474. // When we loop through all docs without seeing any locks, then we know all locks
  475. // have been serviced.
  476. //
  477. // If this is a read lock, then we can only service read locks now - we'll have to
  478. // ask for a separate write lock later if we need one.
  479. BOOL fNeedWriteLock = FALSE;
  480. for( ; ; )
  481. {
  482. BOOL fWorkDone = FALSE;
  483. // Forward to all clients who had requested a lock...
  484. for( Iter_dl< DocTraits::CDocWrap > i ( m_DocWraps ) ; ! i.AtEnd() ; i++ )
  485. {
  486. // Is the mask we've been granted sufficient for the client's request (if any)?
  487. DWORD ReqdLock = i->m_dwPendingLock;
  488. if( ReqdLock )
  489. {
  490. if( ( ReqdLock | dwLockFlags ) == dwLockFlags )
  491. {
  492. // tell the doc wrapper that it is in OnLockGranted and what kind of lock it has
  493. i->m_dwGrantedLock = ReqdLock;
  494. // Clear the mask...
  495. i->m_dwPendingLock = 0;
  496. DocTraits::ISink * pSink = static_cast< DocTraits::ISink * > ( i->m_Sink.m_pSink );
  497. // How about...
  498. // (a) also call Next before callback.
  499. // (b) store current value of iter in mgr - in doc's release, it can check, and bump if necessary;
  500. pSink->OnLockGranted( ReqdLock );
  501. // tell the doc wrapper that it is no longer in OnLockGranted
  502. i->m_dwGrantedLock = 0;
  503. fWorkDone = TRUE;
  504. }
  505. else
  506. {
  507. // This client wants a write lock, but we've only got a read lock...
  508. fNeedWriteLock = TRUE;
  509. }
  510. }
  511. }
  512. // If we didn't need to handle any lock requests the last time around the loop,
  513. // then our work is done. (If we did handle any lock requests, we should go back
  514. // and re-check all docs, in case one of them requested a lock while one of the
  515. // locks we serviced was holding it.)
  516. if( ! fWorkDone )
  517. break;
  518. }
  519. if( fNeedWriteLock )
  520. {
  521. // TODO - need to find a way to handle this. Can we call the doc's RequestLock again now?
  522. AssertMsg( FALSE, TEXT("Write lock requested while holding read lock - not implemented yet") );
  523. }
  524. // All done!
  525. return S_OK;
  526. }
  527. }
  528. private:
  529. //
  530. // Internal functions...
  531. //
  532. void _SetDoc( DocTraits::IDoc * pDoc )
  533. {
  534. AssertMsg( ! m_pDoc, TEXT("CWrapMgr::SetDoc should be called once when m_pDoc is NULL") );
  535. m_pDoc = pDoc;
  536. m_pDoc->AddRef();
  537. }
  538. HRESULT _CreateWrappedDoc( DocTraits::IDoc ** ppDoc )
  539. {
  540. *ppDoc = NULL;
  541. // Create a doc wrapper...
  542. DocTraits::CDocWrap * pCDocWrap;
  543. HRESULT hr = CreateLocalInstance( & pCDocWrap );
  544. CHECK_HR_RETURN( hr, pCDocWrap != NULL );
  545. pCDocWrap->Init( this, m_pDoc );
  546. // Add to our list...
  547. m_DocWraps.AddToHead( pCDocWrap );
  548. // And return it...
  549. *ppDoc = pCDocWrap;
  550. return S_OK;
  551. }
  552. };
  553. struct SinkInfo
  554. {
  555. IUnknown * m_pSink;
  556. IID m_iid;
  557. DWORD m_dwMask;
  558. IUnknown * m_pCanonicalUnk; // IUnknown used for identity comparisons
  559. void Validate()
  560. {
  561. #ifdef DEBUG
  562. if( m_pSink )
  563. {
  564. Assert( m_pCanonicalUnk != NULL );
  565. // Check that mask contains only valid bits
  566. Assert( ( m_dwMask & ~ TS_AS_ALL_SINKS ) == 0 );
  567. }
  568. else
  569. {
  570. Assert( m_pCanonicalUnk == NULL );
  571. Assert( m_dwMask == 0 );
  572. }
  573. #endif
  574. }
  575. SinkInfo()
  576. : m_pSink( NULL ),
  577. m_pCanonicalUnk( NULL ),
  578. m_dwMask( 0 )
  579. {
  580. Validate();
  581. // Done.
  582. }
  583. ~SinkInfo()
  584. {
  585. Validate();
  586. AssertMsg( m_pSink == NULL && m_pCanonicalUnk == NULL, TEXT("Sink not cleared" ) );
  587. }
  588. void Set( IUnknown * pSink, REFIID iid, DWORD dwMask, IUnknown * pCanonicalUnk )
  589. {
  590. Validate();
  591. AssertMsg( m_pSink == NULL, TEXT("Set() sink that's already in use" ) );
  592. m_pSink = pSink;
  593. m_pSink->AddRef();
  594. m_iid = iid;
  595. m_dwMask = dwMask;
  596. m_pCanonicalUnk = pCanonicalUnk;
  597. m_pCanonicalUnk->AddRef();
  598. Validate();
  599. }
  600. void UpdateMask( DWORD dwMask )
  601. {
  602. Validate();
  603. AssertMsg( m_pSink != NULL, TEXT("UpdateMask() on empty sink") );
  604. m_dwMask = dwMask;
  605. Validate();
  606. }
  607. void ClearAndRelease()
  608. {
  609. Validate();
  610. if( m_pSink )
  611. {
  612. m_pSink->Release();
  613. m_pSink = NULL;
  614. m_pCanonicalUnk->Release();
  615. m_pCanonicalUnk = NULL;
  616. m_dwMask = 0;
  617. }
  618. }
  619. };
  620. // Fwd. decl for the sink-wrap class, needed since we grant it frienship in the
  621. // DocWrap class...
  622. template< class DocTraits >
  623. class CSinkWrapBase;
  624. //
  625. // CDocWrapBase
  626. //
  627. // - Base from which Anchor and ACP document wrappers are derived.
  628. //
  629. // This class contains ACP/Anchor-neutral wrapping code - anything that is
  630. // ACP/Anchor-specific is handled in the derived ..ACP or ...Anchor class
  631. // instead.
  632. //
  633. // This class derives from the full Cicero doc interface (DocTraits::ICicDoc -
  634. // which is a typedef for ITfTextStore[Anchor]), which in turn includes the
  635. // ITextStoreACP doc interface. Currently the Cicero interface doesn't add any
  636. // additional methods.
  637. //
  638. // This class is also on a list of document wrappers - so we're derived from
  639. // Link_dl. (The list is managed by the wrapper manager.) The list will be a
  640. // list of derived classes, so the type of the link is of the derived class
  641. // (DocTraits::CDocWrap - which is a typedef for CDocWrapACP/Anchor), instead
  642. // of being based on this class.
  643. // (At the moment we don't actually use any of the derived-class functionality,
  644. // but may do so in future.)
  645. // {B5DCFDAF-FBAD-4ef6-A5F8-E7CC0833A3B1}
  646. static const GUID DOCWRAP_IMPLID = { 0xb5dcfdaf, 0xfbad, 0x4ef6, { 0xa5, 0xf8, 0xe7, 0xcc, 0x8, 0x33, 0xa3, 0xb1 } };
  647. template< class _DocTraits >
  648. class ATL_NO_VTABLE CDocWrapBase :
  649. public CComObjectRootEx< CComSingleThreadModel >,
  650. public Link_dl< _DocTraits::CDocWrap >,
  651. public _DocTraits::ICicDoc,
  652. public _DocTraits::IDocEx,
  653. public IClonableWrapper,
  654. public IInternalDocWrap,
  655. public ICoCreateLocally,
  656. public CVersionInfo,
  657. public IServiceProvider
  658. {
  659. public:
  660. // This typedef makes the DocTraits type visible in this and in the
  661. // Anchor/ACP-specific derived classes. (Otherwise, as a template
  662. // parameter in this class, it would not be available to them.)
  663. typedef _DocTraits DocTraits;
  664. DECLARE_PROTECT_FINAL_CONSTRUCT()
  665. BEGIN_COM_MAP( CDocWrapBase< DocTraits > )
  666. COM_INTERFACE_ENTRY( DocTraits::IDoc )
  667. COM_INTERFACE_ENTRY( DocTraits::ICicDoc )
  668. COM_INTERFACE_ENTRY( DocTraits::IDocEx )
  669. COM_INTERFACE_ENTRY( IClonableWrapper )
  670. COM_INTERFACE_ENTRY( IInternalDocWrap )
  671. COM_INTERFACE_ENTRY( ICoCreateLocally )
  672. COM_INTERFACE_ENTRY( IVersionInfo )
  673. COM_INTERFACE_ENTRY( IServiceProvider )
  674. END_COM_MAP()
  675. private:
  676. // WrapMgr uses the Link_dl base when adding this to its list.
  677. friend CWrapMgr< DocTraits >;
  678. // Used by WrapMgr to track what type of lock was requested.
  679. DWORD m_dwPendingLock;
  680. // Used by WrapMgr to track what type of lock granted.
  681. DWORD m_dwGrantedLock;
  682. // SinkWrapBase - and its derived Anchor/ACP-specific class - uses the list
  683. // and the members of SinkInfo when broadcasting
  684. friend CSinkWrapBase< DocTraits >;
  685. friend DocTraits::CSinkWrap;
  686. protected:
  687. // Each doc can have a corresponding sink:
  688. SinkInfo m_Sink;
  689. // Link back to the wrapper manager - so we can tell it when we're going
  690. // away. We also get it to handle calls which affect other wrappers on the
  691. // same document - especially sinks and locks.
  692. CWrapMgr< DocTraits > * m_pMgr;
  693. // Used by derived classes to forward calls to doc...
  694. // DocTraits::IDoc * m_pDoc;
  695. DocTraits::IDocSEHWrap m_pDoc;
  696. // TEMP BUGBUG - used to access the attribute extentions for the moment...
  697. DocTraits::IDocEx * m_pDocEx;
  698. bool m_bUnadvised;
  699. HRESULT STDMETHODCALLTYPE VerifyLock( DWORD dwLockFlags)
  700. {
  701. IMETHOD( VerifyLock );
  702. if ( m_dwGrantedLock )
  703. {
  704. // We have a lock, make sure it's the right kind
  705. if ( (dwLockFlags & TS_LF_READWRITE) == m_dwGrantedLock || (dwLockFlags & TS_LF_READWRITE) == TS_LF_READ )
  706. return S_OK;
  707. }
  708. TraceDebug( TEXT("Lock rejected") );
  709. return S_FALSE;
  710. }
  711. // This macro just forwards the call directly to the doc...
  712. #define DocWrap_FORWARD( fname, c, params ) /**/ \
  713. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params ) \
  714. {\
  715. IMETHOD( fname );\
  716. return m_pDoc-> fname AS_CALL( c, params ) ;\
  717. }
  718. // This macro just forwards the call directly to the doc after checking for the correct lock
  719. #define DocWrap_FORWARD_READLOCK( fname, c, params ) /**/ \
  720. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params ) \
  721. {\
  722. IMETHOD( fname );\
  723. if ( VerifyLock( TS_LF_READ ) == S_FALSE )\
  724. return TS_E_NOLOCK;\
  725. return m_pDoc-> fname AS_CALL( c, params ) ;\
  726. }
  727. #define DocWrap_FORWARDEXT( fname, c, params ) /**/ \
  728. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params ) \
  729. {\
  730. IMETHOD( fname );\
  731. if( ! m_pDocEx )\
  732. return E_NOTIMPL;\
  733. return m_pDocEx-> fname AS_CALL( c, params ) ;\
  734. }
  735. // This slightly more complicated one (!) forwards to the doc,
  736. // and if the call succeeds, then broadcasts to all sinks except the one
  737. // for this document.
  738. // So if one client does a SetText, that SetText goes through, and
  739. // all other clietns with callbacks for the TS_AS_TEXT_CHANGE event will
  740. // also get an OnTextChange event.
  741. #define DocWrap_FORWARD_AND_SINK( fname, c, params, mask, callsink ) /**/ \
  742. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params )\
  743. {\
  744. IMETHOD( fname );\
  745. Assert( m_pMgr );\
  746. if ( VerifyLock( TS_LF_READWRITE ) == S_FALSE )\
  747. return TS_E_NOLOCK;\
  748. m_pMgr->RemoveDeadDocs();\
  749. CPrivateAddRef MyAddRef(m_pMgr->m_lIterationRefCount);\
  750. HRESULT hr = m_pDoc-> fname AS_CALL( c, params );\
  751. if( hr != S_OK )\
  752. {\
  753. TraceDebugHR( hr, TEXT("failed") );\
  754. return hr;\
  755. }\
  756. for( Iter_dl < DocTraits::CDocWrap > i ( m_pMgr->m_DocWraps ) ; ! i.AtEnd() ; i++ )\
  757. {\
  758. DocTraits::ISink * pSink = static_cast< DocTraits::ISink * >( i->m_Sink.m_pSink );\
  759. DWORD dwMask = i->m_Sink.m_dwMask;\
  760. DocTraits::CDocWrap * pTheDoc = i;\
  761. if( pTheDoc != this && pSink && ( dwMask & mask ) )\
  762. {\
  763. callsink ;\
  764. }\
  765. }\
  766. return S_OK ;\
  767. }
  768. public:
  769. //
  770. // Ctor, Dtor, and initialization...
  771. //
  772. CDocWrapBase()
  773. : m_pDoc( NULL ),
  774. m_pMgr( NULL ),
  775. m_dwPendingLock( 0 ),
  776. m_dwGrantedLock( 0 ),
  777. m_pDocEx( NULL ),
  778. m_bUnadvised( false )
  779. {
  780. }
  781. ~CDocWrapBase()
  782. {
  783. AssertMsg( m_pMgr != NULL, TEXT("CDocWrapBase::Init never got called?") );
  784. // Clear up sink...
  785. if( m_Sink.m_pSink )
  786. {
  787. m_Sink.ClearAndRelease();
  788. // Manager will unadvise, if we were the last to go...
  789. m_pMgr->DocWrap_UpdateSubscription();
  790. }
  791. m_pMgr->DocWrap_NotifyDisconnect( static_cast< DocTraits::CDocWrap * >( this ) );
  792. m_pMgr->Release();
  793. if( m_pDocEx )
  794. m_pDocEx->Release();
  795. }
  796. void Init( CWrapMgr< DocTraits > * pMgr, DocTraits::IDoc * pDoc )
  797. {
  798. AssertMsg( m_pMgr == NULL, TEXT("CDocWrapBase::Init should only be called once when m_pMgr is NULL") );
  799. m_pMgr = pMgr;
  800. m_pMgr->AddRef();
  801. m_pDoc = pDoc;
  802. AddRef(); // Keep our own ref count so it dosn't go away until we remove from the list
  803. CVersionInfo::Add( DOCWRAP_IMPLID, 1, 0, L"Microsoft MSAA Wrapper 1.0", L"na", NULL);
  804. m_pDoc->QueryInterface( __uuidof( DocTraits::IDocEx ), (void **) & m_pDocEx );
  805. }
  806. //
  807. // Implementation of ACP/Anchor-neutral methods...
  808. // These ones require special handling...
  809. //
  810. HRESULT STDMETHODCALLTYPE AdviseSink( REFIID riid, IUnknown *punk, DWORD dwMask )
  811. {
  812. IMETHOD( AdviseSink );
  813. Assert( m_pMgr );
  814. if( punk == NULL )
  815. {
  816. return E_INVALIDARG;
  817. }
  818. // Accept the following sinks:
  819. // * Original ITextStoreACPSink,
  820. // * Cicero sink (ITextStoreACP + Cicero extentions)
  821. // * ITextStoreACPSinkEx sink (ITextStoreACP + OnDisconnect method)
  822. if( riid != __uuidof( DocTraits::ISink )
  823. && riid != __uuidof( DocTraits::ICicSink )
  824. && riid != __uuidof( DocTraits::ISinkEx ) )
  825. {
  826. return E_NOINTERFACE;
  827. }
  828. // check mask contains only valid bits
  829. if( dwMask & ~ ( TS_AS_ALL_SINKS ) )
  830. {
  831. return E_INVALIDARG;
  832. }
  833. // Get canonical unknown (for interface comparing...)
  834. IUnknown * pCanonicalUnk = NULL;
  835. HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk );
  836. if( hr != S_OK || pCanonicalUnk == NULL )
  837. {
  838. return E_FAIL;
  839. }
  840. // If this is first, set it...
  841. if( m_Sink.m_pSink == NULL )
  842. {
  843. // Allow the doc to work out the update cumulative mask and re-advise the doc if necessary...
  844. m_Sink.Set( punk, riid, dwMask, pCanonicalUnk );
  845. // Manager will scan through all sink masks, and re-Advise if necessary.
  846. hr = m_pMgr->DocWrap_UpdateSubscription();
  847. if( hr != S_OK )
  848. {
  849. // advising didn't work, or something else went wrong - revert back to empty sink...
  850. m_Sink.ClearAndRelease();
  851. }
  852. }
  853. else
  854. {
  855. // Not the first time - check if we're updating the existing mask...
  856. if( pCanonicalUnk != m_Sink.m_pCanonicalUnk )
  857. {
  858. // Attempt to register a different sink - error...
  859. hr = CONNECT_E_ADVISELIMIT;
  860. }
  861. else
  862. {
  863. // Remember the old mask - if the update doesn't work, revert back to this.
  864. DWORD OldMask = m_Sink.m_dwMask;
  865. m_Sink.UpdateMask( dwMask );
  866. // Manager will scan through all dwMasks, and re-Advise if necessary.
  867. hr = m_pMgr->DocWrap_UpdateSubscription();
  868. if( hr != S_OK )
  869. m_Sink.UpdateMask( OldMask );
  870. }
  871. }
  872. pCanonicalUnk->Release();
  873. return hr;
  874. }
  875. HRESULT STDMETHODCALLTYPE UnadviseSink( IUnknown *punk )
  876. {
  877. IMETHOD( UnadviseSink );
  878. Assert( m_pMgr );
  879. if( punk == NULL )
  880. {
  881. return E_POINTER;
  882. }
  883. // Get canonical unknown (for interface comparing...)
  884. IUnknown * pCanonicalUnk = NULL;
  885. HRESULT hr = punk->QueryInterface( IID_IUnknown, (void **) & pCanonicalUnk );
  886. if( hr != S_OK || pCanonicalUnk == NULL )
  887. {
  888. return E_FAIL;
  889. }
  890. if( pCanonicalUnk != m_Sink.m_pCanonicalUnk )
  891. {
  892. // Sink doesn't match!
  893. return E_INVALIDARG;
  894. }
  895. m_Sink.ClearAndRelease();
  896. // Manager will scan through all dwMasks, and re-Advise if necessary.
  897. hr = m_pMgr->DocWrap_UpdateSubscription();
  898. // Not much we can do if the update fails - but even if it does fail,
  899. // we want to disconnect this sink, and not fail the Unadvise.
  900. Assert( hr == S_OK );
  901. pCanonicalUnk->Release();
  902. m_bUnadvised = true;
  903. return S_OK; // NOT hr, since this should always succeed.
  904. }
  905. HRESULT STDMETHODCALLTYPE RequestLock( DWORD dwLockFlags, HRESULT * phrSession )
  906. {
  907. IMETHOD( RequestLock );
  908. Assert( m_pMgr );
  909. // The cast here is safe, since we'll only be used as a derived class
  910. DocTraits::CDocWrap * pThisAsDerived = static_cast< DocTraits::CDocWrap * >( this );
  911. return m_pMgr->DocWrap_HandleRequestLock( pThisAsDerived, dwLockFlags, phrSession );
  912. }
  913. //
  914. // These Anchor/ACP-neutral methods can just be forwarded directly to the real doc...
  915. //
  916. DocWrap_FORWARD( GetStatus, 1, ( TS_STATUS *, pdcs ) )
  917. DocWrap_FORWARD_READLOCK( QueryInsert, 5, ( DocTraits::PosType, InsertStart,
  918. DocTraits::PosType, InsertEnd,
  919. ULONG, cch,
  920. DocTraits::PosType *, ppaInsertStart,
  921. DocTraits::PosType *, ppaInsertEnd ) )
  922. DocWrap_FORWARD_READLOCK( QueryInsertEmbedded, 3, ( const GUID *, pguidService,
  923. const FORMATETC *, pFormatEtc,
  924. BOOL *, pfInsertable ) )
  925. DocWrap_FORWARD( GetScreenExt, 2, ( TsViewCookie, vcView,
  926. RECT *, prc ) )
  927. DocWrap_FORWARD( GetWnd, 2, ( TsViewCookie, vcView,
  928. HWND *, phwnd ) )
  929. DocWrap_FORWARD_READLOCK( GetFormattedText, 3, ( DocTraits::PosType, Start,
  930. DocTraits::PosType, End,
  931. IDataObject **, ppDataObject ) )
  932. DocWrap_FORWARD_READLOCK( GetTextExt, 5, ( TsViewCookie, vcView,
  933. DocTraits::PosType, Start,
  934. DocTraits::PosType, End,
  935. RECT *, prc,
  936. BOOL *, pfClipped ) )
  937. DocWrap_FORWARDEXT( ScrollToRect, 4, ( DocTraits::PosType, Start,
  938. DocTraits::PosType, End,
  939. RECT, rc,
  940. DWORD, dwPosition ) )
  941. DocWrap_FORWARD( GetActiveView, 1, ( TsViewCookie *, pvcView ) )
  942. // IClonableWrapper
  943. HRESULT STDMETHODCALLTYPE CloneNewWrapper( REFIID riid, void ** ppv )
  944. {
  945. IMETHOD( CloneNewWrapper );
  946. // Just call through to CWrapMgr's CreateWrappedDoc...
  947. Assert( m_pMgr );
  948. IUnknown * punk;
  949. HRESULT hr = m_pMgr->CreateWrappedDoc( & punk );
  950. if( hr != S_OK )
  951. return hr;
  952. hr = punk->QueryInterface( riid, ppv );
  953. punk->Release();
  954. return hr;
  955. }
  956. // IInternalDocWrap
  957. HRESULT STDMETHODCALLTYPE NotifyRevoke()
  958. {
  959. // Just pass on to the CWrapMgr...
  960. Assert( m_pMgr );
  961. m_pMgr->DocWrap_NotifyRevoke();
  962. return S_OK;
  963. }
  964. // ICoCreateLocally
  965. #include <Rpcdce.h>
  966. HRESULT STDMETHODCALLTYPE CoCreateLocally (
  967. REFCLSID rclsid,
  968. DWORD dwClsContext,
  969. REFIID riid,
  970. IUnknown ** punk,
  971. REFIID riidParam,
  972. IUnknown * punkParam,
  973. VARIANT varParam
  974. )
  975. {
  976. IMETHOD( CoCreateLocally );
  977. LPCTSTR pPrivs = NULL; //Pointer to handle to privilege information
  978. HRESULT hrSec = CoQueryClientBlanket( 0, 0, 0, 0, 0, (void **)&pPrivs, 0 );
  979. if ( hrSec != S_OK )
  980. return hrSec;
  981. TSTR strUser(128);
  982. DWORD nSize = strUser.left();
  983. if ( !GetUserName( strUser.ptr(), &nSize ) )
  984. return E_ACCESSDENIED;
  985. strUser.advance( nSize - 1 );
  986. TSTR strClientUser( pPrivs );
  987. const int nSlashPos = strClientUser.find( TEXT("\\") );
  988. if ( nSlashPos > 0 )
  989. strClientUser = strClientUser.substr( nSlashPos + 1, strClientUser.size() - nSlashPos );
  990. TraceDebug( TSTR() << TEXT("Current user = ") << strUser << TEXT(", Client user = ") << strClientUser );
  991. if ( strClientUser.compare( strUser ) != 0 )
  992. if ( strClientUser.compare( TEXT("SYSTEM") ) != 0 )
  993. return E_ACCESSDENIED;
  994. HRESULT hr = CoCreateInstance(rclsid, NULL, dwClsContext, riid, (void **)punk);
  995. if (hr != S_OK)
  996. return hr;
  997. CComPtr<ICoCreatedLocally> pICoCreatedLocally;
  998. hr = (*punk)->QueryInterface(IID_ICoCreatedLocally, (void **)&pICoCreatedLocally);
  999. if (hr != S_OK)
  1000. return hr;
  1001. hr = pICoCreatedLocally->LocalInit(m_pDoc, riidParam, punkParam, varParam);
  1002. if (hr != S_OK)
  1003. return hr;
  1004. return S_OK;
  1005. }
  1006. //
  1007. // IServiceProvider - Cicero uses this to 'drill through' to the original anchor to pull out
  1008. // internal information. Just pass it through...
  1009. //
  1010. HRESULT STDMETHODCALLTYPE QueryService( REFGUID guidService, REFIID riid, void **ppvObject )
  1011. {
  1012. IMETHOD( QueryService );
  1013. *ppvObject = NULL;
  1014. CComPtr<IServiceProvider> pISP;
  1015. HRESULT hr = m_pDoc->QueryInterface( IID_IServiceProvider, (void **) & pISP );
  1016. if( hr != S_OK || pISP == NULL )
  1017. return E_FAIL;
  1018. hr = pISP->QueryService( guidService, riid, ppvObject );
  1019. return hr;
  1020. }
  1021. };
  1022. //
  1023. // CTextStoreWrapACP - ACP version of ITextStoreACP wrapper...
  1024. //
  1025. class ATL_NO_VTABLE CDocWrapACP :
  1026. public CDocWrapBase< DocTraitsACP >
  1027. {
  1028. public:
  1029. // ITextStoreACP
  1030. DocWrap_FORWARD_READLOCK( GetSelection, 4, ( ULONG, ulIndex, ULONG, ulCount, TS_SELECTION_ACP *, pSelection, ULONG *, pcFetched ) )
  1031. DocWrap_FORWARD_READLOCK( GetText, 9, ( LONG, acpStart,
  1032. LONG, acpEnd,
  1033. WCHAR *, pchPlain,
  1034. ULONG, cchPlainReq,
  1035. ULONG *, pcchPlainRet,
  1036. TS_RUNINFO *, prgRunInfo,
  1037. ULONG, cRunInfoReq,
  1038. ULONG *, pcRunInfoRet,
  1039. LONG *, pacpNext ) )
  1040. DocWrap_FORWARD_READLOCK( GetEmbedded, 4, ( LONG, Pos, REFGUID, rguidService, REFIID, riid, IUnknown **, ppunk ) )
  1041. DocWrap_FORWARD_READLOCK( GetEndACP, 1, ( LONG *, pacp ) )
  1042. DocWrap_FORWARD_READLOCK( GetACPFromPoint, 4, ( TsViewCookie, vcView, const POINT *, ptScreen, DWORD, dwFlags, LONG *, pacp ) )
  1043. DocWrap_FORWARD( RequestSupportedAttrs, 3, ( DWORD, dwFlags,
  1044. ULONG, cFilterAttrs,
  1045. const TS_ATTRID *, paFilterAttrs ) )
  1046. DocWrap_FORWARD_READLOCK( RequestAttrsAtPosition, 4, ( DocTraits::PosType, Pos,
  1047. ULONG, cFilterAttrs,
  1048. const TS_ATTRID *, paFilterAttrs,
  1049. DWORD, dwFlags ) )
  1050. DocWrap_FORWARD_READLOCK( RequestAttrsTransitioningAtPosition,
  1051. 4, ( DocTraits::PosType, Pos,
  1052. ULONG, cFilterAttrs,
  1053. const TS_ATTRID *, paFilterAttrs,
  1054. DWORD, dwFlags ) )
  1055. DocWrap_FORWARD_READLOCK( FindNextAttrTransition, 8, ( LONG, acpStart, LONG, acpEnd, ULONG, cFilterAttrs, const TS_ATTRID *, paFilterAttrs, DWORD, dwFlags, LONG *, pacpNext, BOOL *, pfFound, LONG *, plFoundOffset ) )
  1056. DocWrap_FORWARD( RetrieveRequestedAttrs, 3, ( ULONG, ulCount,
  1057. TS_ATTRVAL *, paAttrVals,
  1058. ULONG *, pcFetched ) )
  1059. DocWrap_FORWARD_AND_SINK( SetSelection, 2, ( ULONG, ulCount, const TS_SELECTION_ACP *, pSelection ),
  1060. TS_AS_SEL_CHANGE, pSink->OnSelectionChange() )
  1061. DocWrap_FORWARD_AND_SINK( SetText, 6, ( DWORD, dwFlags, LONG, acpStart, LONG, acpEnd, const WCHAR *, pchText, ULONG, cch, TS_TEXTCHANGE *, pChange ),
  1062. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, pChange ) )
  1063. DocWrap_FORWARD_AND_SINK( InsertEmbedded, 5, ( DWORD, dwFlags, LONG, acpStart, LONG, acpEnd, IDataObject *, pDataObject, TS_TEXTCHANGE *, pChange ),
  1064. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, pChange ) )
  1065. DocWrap_FORWARD_AND_SINK( InsertTextAtSelection, 6, ( DWORD, dwFlags, const WCHAR *, pchText, ULONG, cch, LONG *, pacpStart, LONG *, pacpEnd, TS_TEXTCHANGE *, pChange),
  1066. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, pChange ) )
  1067. DocWrap_FORWARD_AND_SINK( InsertEmbeddedAtSelection, 5, ( DWORD, dwFlags, IDataObject *, pDataObject, LONG *, pacpStart, LONG *, pacpEnd, TS_TEXTCHANGE *, pChange),
  1068. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, pChange ) )
  1069. };
  1070. //
  1071. // CTextStoreWrapAnchor - Anchor version of ITextStoreACP wrapper
  1072. //
  1073. class ATL_NO_VTABLE CDocWrapAnchor :
  1074. public CDocWrapBase< DocTraitsAnchor >
  1075. {
  1076. /*
  1077. // Used when generating OnTextChange events in response to InsertEmbedded.
  1078. // See forwarding macro for InsertEmbedded below...
  1079. void ProcessInsertEmbeddedOnTextChange( DocTraits::ISink * pSink, DWORD dwFlags, IAnchor * paPos )
  1080. {
  1081. // Want to send a TextChange with anchors before and after the insert position -
  1082. // we have the before position - clone and move it to get the after position.
  1083. IAnchor * pAnchorAfter = NULL;
  1084. HRESULT hr = paPos->Clone( & pAnchorAfter );
  1085. if( hr != S_OK || pAnchorAfter == NULL )
  1086. {
  1087. TraceInteropHR( hr, TEXT("IAnchor::Clone failed") );
  1088. return;
  1089. }
  1090. LONG cchShifted = 0;
  1091. hr = pAnchorAfter->Shift( 1, & cchShifted, NULL );
  1092. if( hr != S_OK || cchShifted != 1 )
  1093. {
  1094. TraceInteropHR( hr, TEXT("IAnchor::Shift failed?") );
  1095. return;
  1096. }
  1097. pSink->OnTextChange( dwFlags, paPos, pAnchorAfter );
  1098. pAnchorAfter->Release();
  1099. }
  1100. */
  1101. public:
  1102. CDocWrapAnchor() : m_cMaxAttrs(0),
  1103. m_cAttrsTAP(0),
  1104. m_iAttrsTAP(0),
  1105. m_cAttrsTAPSize(0),
  1106. m_paAttrsTAP(NULL),
  1107. m_paAttrsSupported(NULL)
  1108. {
  1109. }
  1110. ~CDocWrapAnchor()
  1111. {
  1112. ResetAttrs();
  1113. if ( m_paAttrsTAP )
  1114. {
  1115. delete [] m_paAttrsTAP;
  1116. m_paAttrsTAP = NULL;
  1117. }
  1118. if ( m_paAttrsSupported )
  1119. {
  1120. delete [] m_paAttrsSupported;
  1121. m_paAttrsSupported = NULL;
  1122. }
  1123. }
  1124. // ITextStoreAnchor
  1125. DocWrap_FORWARD_READLOCK( GetSelection, 4, ( ULONG, ulIndex, ULONG, ulCount, TS_SELECTION_ANCHOR *, pSelection, ULONG *, pcFetched ) )
  1126. DocWrap_FORWARD_READLOCK( GetText, 7, ( DWORD, dwFlags, IAnchor *, paStart, IAnchor *, paEnd, WCHAR *, pchText, ULONG, cchReq, ULONG *, pcch, BOOL, fUpdateAnchor ) )
  1127. DocWrap_FORWARD_READLOCK( GetEmbedded, 5, ( DWORD, dwFlags,
  1128. IAnchor *, Pos,
  1129. REFGUID, rguidService,
  1130. REFIID, riid,
  1131. IUnknown **, ppunk ) )
  1132. DocWrap_FORWARD_READLOCK( GetStart, 1, ( IAnchor **, ppaStart ) )
  1133. DocWrap_FORWARD_READLOCK( GetEnd, 1, ( IAnchor **, ppaEnd ) )
  1134. DocWrap_FORWARD_READLOCK( GetAnchorFromPoint, 4, ( TsViewCookie, vcView, const POINT *, ptScreen, DWORD, dwFlags, IAnchor **, ppaSite ) )
  1135. // DocWrap_FORWARD( RequestSupportedAttrs, 3, ( DWORD, dwFlags,
  1136. // ULONG, cFilterAttrs,
  1137. // const TS_ATTRID *, paFilterAttrs ) )
  1138. // DocWrap_FORWARD_READLOCK( RequestAttrsAtPosition, 4, ( DocTraits::PosType, Pos,
  1139. // ULONG, cFilterAttrs,
  1140. // const TS_ATTRID *, paFilterAttrs,
  1141. // DWORD, dwFlags ) )
  1142. // DocWrap_FORWARD_READLOCK( RequestAttrsTransitioningAtPosition,
  1143. // 4, ( DocTraits::PosType, Pos,
  1144. // ULONG, cFilterAttrs,
  1145. // const TS_ATTRID *, paFilterAttrs,
  1146. // DWORD, dwFlags ) )
  1147. // DocWrap_FORWARD_READLOCK( FindNextAttrTransition, 7, ( IAnchor *, paStart, IAnchor *, paEnd, ULONG, cFilterAttrs, const TS_ATTRID *, paFilterAttrs, DWORD, dwFlags, BOOL *, pfFound, LONG *, plFoundOffset ) )
  1148. DocWrap_FORWARD_AND_SINK( SetSelection, 2, ( ULONG, ulCount, const TS_SELECTION_ANCHOR *, pSelection ),
  1149. TS_AS_SEL_CHANGE, pSink->OnSelectionChange() )
  1150. DocWrap_FORWARD_AND_SINK( SetText, 5, ( DWORD, dwFlags, IAnchor *, paStart, IAnchor *, paEnd, const WCHAR *, pchText, ULONG, cch ),
  1151. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, paStart, paEnd ) )
  1152. DocWrap_FORWARD_AND_SINK( InsertEmbedded, 4, ( DWORD, dwFlags, IAnchor *, paStart, IAnchor *, paEnd, IDataObject *, pDataObject ),
  1153. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, paStart, paEnd ) )
  1154. DocWrap_FORWARD_AND_SINK( InsertTextAtSelection, 5, ( DWORD, dwFlags, const WCHAR *, pchText, ULONG, cch, IAnchor **, ppaStart, IAnchor **, ppaEnd ),
  1155. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, *ppaStart, *ppaEnd ) )
  1156. DocWrap_FORWARD_AND_SINK( InsertEmbeddedAtSelection, 4, ( DWORD, dwFlags, IDataObject *, pDataObject, IAnchor **, ppaStart, IAnchor **, ppaEnd ),
  1157. TS_AS_TEXT_CHANGE, pSink->OnTextChange( dwFlags, *ppaStart, *ppaEnd ) )
  1158. HRESULT STDMETHODCALLTYPE RequestSupportedAttrs ( DWORD dwFlags,
  1159. ULONG cFilterAttrs,
  1160. const TS_ATTRID * paFilterAttrs )
  1161. {
  1162. IMETHOD( RequestSupportedAttrs );
  1163. ResetAttrs();
  1164. return m_pDoc->RequestSupportedAttrs( dwFlags, cFilterAttrs, paFilterAttrs ) ;
  1165. }
  1166. HRESULT STDMETHODCALLTYPE RequestAttrsAtPosition ( DocTraits::PosType Pos,
  1167. ULONG cFilterAttrs,
  1168. const TS_ATTRID * paFilterAttrs,
  1169. DWORD dwFlags )
  1170. {
  1171. IMETHOD( RequestAttrsAtPosition );
  1172. if ( VerifyLock( TS_LF_READ ) == S_FALSE )
  1173. return TS_E_NOLOCK;
  1174. ResetAttrs();
  1175. return m_pDoc->RequestAttrsAtPosition( Pos, cFilterAttrs, paFilterAttrs, dwFlags ) ;
  1176. }
  1177. HRESULT STDMETHODCALLTYPE RequestAttrsTransitioningAtPosition ( IAnchor * paStart,
  1178. ULONG cFilterAttrs,
  1179. const TS_ATTRID * paFilterAttrs,
  1180. DWORD dwFlags )
  1181. {
  1182. IMETHOD( RequestAttrsTransitioningAtPosition );
  1183. if ( VerifyLock( TS_LF_READ ) == S_FALSE )
  1184. return TS_E_NOLOCK;
  1185. ResetAttrs();
  1186. // call through to the doc
  1187. HRESULT hr = m_pDoc->RequestAttrsTransitioningAtPosition( paStart, cFilterAttrs, paFilterAttrs, dwFlags );
  1188. if ( hr != E_NOTIMPL )
  1189. return hr;
  1190. // if the server does not support this do it ourselves
  1191. // make sure there is really something to do
  1192. if ( paStart == NULL )
  1193. return S_OK;
  1194. // make sure we can hold the attributes we find
  1195. hr = AllocateAttrs( cFilterAttrs );
  1196. if ( FAILED(hr) )
  1197. return hr;
  1198. ULONG cAlloAttrs = cFilterAttrs ? cFilterAttrs : m_cMaxAttrs;
  1199. TS_ATTRVAL * paCurrent = reinterpret_cast<TS_ATTRVAL *>( alloca( sizeof( TS_ATTRVAL ) * cAlloAttrs ) );
  1200. if ( !paCurrent )
  1201. return E_OUTOFMEMORY;
  1202. hr = GetAttr ( paStart, cFilterAttrs, paFilterAttrs, dwFlags, paCurrent);
  1203. if ( FAILED(hr) )
  1204. return hr;
  1205. LONG cchShifted;
  1206. ULONG iAttrs = 0;
  1207. TS_ATTRVAL * paComp = NULL;
  1208. CComPtr <IAnchor> paPos;
  1209. paStart->Clone( &paPos );
  1210. hr = paPos->Shift( 0, -1, &cchShifted, NULL ); // TODO fix hidden text
  1211. if ( SUCCEEDED(hr) && cchShifted == -1 )
  1212. {
  1213. paComp = reinterpret_cast<TS_ATTRVAL *>( alloca( sizeof( TS_ATTRVAL ) * cAlloAttrs ) );
  1214. if ( !paComp )
  1215. return E_OUTOFMEMORY;
  1216. hr = GetAttr ( paPos, cFilterAttrs, paFilterAttrs, dwFlags, paComp);
  1217. if ( FAILED(hr) )
  1218. return hr;
  1219. if ( dwFlags & TS_ATTR_FIND_WANT_END )
  1220. CompareAttrs ( paCurrent, paComp, cAlloAttrs, iAttrs, TRUE );
  1221. else
  1222. CompareAttrs ( paComp, paCurrent, cAlloAttrs, iAttrs, TRUE );
  1223. }
  1224. if ( !( dwFlags & TS_ATTR_FIND_WANT_VALUE ) )
  1225. {
  1226. for ( int i= 0; i < cFilterAttrs; i++ )
  1227. {
  1228. VariantClear( &m_paAttrsTAP[i].varValue );
  1229. }
  1230. }
  1231. m_cAttrsTAP = iAttrs;
  1232. return S_OK;
  1233. }
  1234. HRESULT STDMETHODCALLTYPE FindNextAttrTransition ( IAnchor * paStart,
  1235. IAnchor * paEnd,
  1236. ULONG cFilterAttrs,
  1237. const TS_ATTRID * paFilterAttrs,
  1238. DWORD dwFlags,
  1239. BOOL * pfFound,
  1240. LONG * plFoundOffset )
  1241. {
  1242. IMETHOD( FindNextAttrTransition );
  1243. if ( VerifyLock( TS_LF_READ ) == S_FALSE )
  1244. return TS_E_NOLOCK;
  1245. HRESULT hr = m_pDoc->FindNextAttrTransition( paStart, paEnd, cFilterAttrs, paFilterAttrs, dwFlags, pfFound, plFoundOffset );
  1246. if ( hr != E_NOTIMPL )
  1247. return hr;
  1248. *pfFound = FALSE;
  1249. *plFoundOffset = 0;
  1250. // if the server does not support this do it ourselves
  1251. // make sure there is really something to do
  1252. if ( paStart == NULL )
  1253. return S_OK;
  1254. // make sure we can hold the attributes we find
  1255. hr = AllocateAttrs( cFilterAttrs );
  1256. if ( FAILED(hr) )
  1257. {
  1258. TraceDebugHR( hr, TEXT("AllocateAttrs failed ") );
  1259. return hr;
  1260. }
  1261. ULONG cAlloAttrs = cFilterAttrs ? cFilterAttrs : m_cMaxAttrs;
  1262. TS_ATTRVAL * paCurrent = reinterpret_cast<TS_ATTRVAL *>( alloca( sizeof( TS_ATTRVAL ) * cAlloAttrs ) );
  1263. TS_ATTRVAL * paNext = reinterpret_cast<TS_ATTRVAL *>( alloca( sizeof( TS_ATTRVAL ) * cAlloAttrs ) );
  1264. if ( !paCurrent || !paNext )
  1265. return E_OUTOFMEMORY;
  1266. hr = GetAttr ( paStart, cFilterAttrs, paFilterAttrs, dwFlags, paCurrent);
  1267. if ( FAILED(hr) )
  1268. {
  1269. TraceDebugHR( hr, TEXT("Current GetAttr failed ") );
  1270. return hr;
  1271. }
  1272. LONG cchShifted;
  1273. ULONG iAttrs = 0;
  1274. BOOL fDone = TRUE;
  1275. const LONG cchShift = ( dwFlags & TS_ATTR_FIND_BACKWARDS ) ? -1 : 1;
  1276. CComPtr <IAnchor> paPos, paEndOfDoc;
  1277. hr = paStart->Clone( &paPos );
  1278. if ( FAILED(hr) )
  1279. {
  1280. TraceDebugHR( hr, TEXT("Clone failed ") );
  1281. return hr;
  1282. }
  1283. if ( paEnd == NULL )
  1284. {
  1285. if ( dwFlags & TS_ATTR_FIND_BACKWARDS )
  1286. {
  1287. m_pDoc->GetStart( &paEndOfDoc );
  1288. }
  1289. else
  1290. {
  1291. BOOL fRegion = FALSE;
  1292. hr = paStart->Clone( &paEndOfDoc );
  1293. while ( fRegion )
  1294. {
  1295. paEndOfDoc->Shift( 0, LONG_MAX, &cchShifted, NULL );
  1296. paEndOfDoc->ShiftRegion( 0, TS_SD_FORWARD, &fRegion );
  1297. }
  1298. }
  1299. }
  1300. while ( iAttrs == 0 )
  1301. {
  1302. hr = paPos->Shift( 0, cchShift, &cchShifted, NULL ); // TODO fix hidden text
  1303. if ( SUCCEEDED(hr) && cchShifted == cchShift )
  1304. {
  1305. *plFoundOffset += 1;
  1306. hr = paPos->IsEqual( paEnd ? paEnd : paEndOfDoc, &fDone );
  1307. if ( FAILED(hr) )
  1308. {
  1309. TraceDebugHR( hr, TEXT("IsEqual failed ") );
  1310. return hr;
  1311. }
  1312. if ( fDone )
  1313. break;
  1314. hr = GetAttr ( paPos, cFilterAttrs, paFilterAttrs, dwFlags, paNext);
  1315. if ( FAILED(hr) )
  1316. {
  1317. TraceDebugHR( hr, TEXT("Next GetAttr failed ") );
  1318. return hr;
  1319. }
  1320. CompareAttrs ( paCurrent, paNext, cFilterAttrs, iAttrs, FALSE );
  1321. if ( iAttrs )
  1322. {
  1323. *pfFound = TRUE;
  1324. }
  1325. }
  1326. else
  1327. {
  1328. TraceDebugHR( hr, TEXT("Shift failed ") );
  1329. return hr;
  1330. }
  1331. }
  1332. return S_OK;
  1333. }
  1334. HRESULT STDMETHODCALLTYPE RetrieveRequestedAttrs ( ULONG ulCount,
  1335. TS_ATTRVAL * paAttrVals,
  1336. ULONG * pcFetched )
  1337. {
  1338. // if there is no outstanding requests we satisfy then call through to the doc
  1339. if ( m_cAttrsTAP == 0 )
  1340. return m_pDoc->RetrieveRequestedAttrs( ulCount, paAttrVals, pcFetched );
  1341. if ( ( m_cAttrsTAP - m_iAttrsTAP ) < ulCount )
  1342. *pcFetched = m_cAttrsTAP - m_iAttrsTAP;
  1343. else
  1344. *pcFetched = ulCount;
  1345. memcpy(paAttrVals, &m_paAttrsTAP[m_iAttrsTAP], *pcFetched * sizeof(TS_ATTRVAL));
  1346. memset(&m_paAttrsTAP[m_iAttrsTAP], 0, *pcFetched * sizeof(TS_ATTRVAL));
  1347. m_iAttrsTAP += *pcFetched;
  1348. if ( m_iAttrsTAP == m_cAttrsTAP )
  1349. ResetAttrs();
  1350. return S_OK;
  1351. }
  1352. private:
  1353. ULONG m_cMaxAttrs;
  1354. ULONG m_iAttrsTAP;
  1355. ULONG m_cAttrsTAP;
  1356. ULONG m_cAttrsTAPSize;
  1357. TS_ATTRVAL * m_paAttrsTAP;
  1358. TS_ATTRID * m_paAttrsSupported;
  1359. private:
  1360. HRESULT STDMETHODCALLTYPE CompareAttrs ( TS_ATTRVAL * paAttr1,
  1361. TS_ATTRVAL * paAttr2,
  1362. ULONG cAttrs,
  1363. ULONG &iAttrs,
  1364. BOOL fCopy)
  1365. {
  1366. cAttrs = cAttrs ? cAttrs : m_cMaxAttrs;
  1367. for ( int i = 0; i < cAttrs; i++ )
  1368. {
  1369. for ( int j = 0; j < cAttrs; j++ )
  1370. {
  1371. if ( paAttr1[i].idAttr == paAttr2[j].idAttr )
  1372. {
  1373. if ( CComVariant( paAttr1[i].varValue ) != CComVariant( paAttr2[j].varValue ) )
  1374. {
  1375. if ( fCopy )
  1376. {
  1377. char * cBuf = ( char * )&m_paAttrsTAP[iAttrs];
  1378. memcpy( cBuf, ( char * )&paAttr2[j], sizeof(TS_ATTRVAL) );
  1379. }
  1380. iAttrs++;
  1381. }
  1382. break;
  1383. }
  1384. }
  1385. }
  1386. return S_OK;
  1387. }
  1388. HRESULT STDMETHODCALLTYPE GetAttr ( IAnchor * paStart,
  1389. ULONG cFilterAttrs,
  1390. const TS_ATTRID * paFilterAttrs,
  1391. DWORD dwFlags,
  1392. TS_ATTRVAL * paAttrVals)
  1393. {
  1394. ULONG cFetched;
  1395. HRESULT hr;
  1396. ULONG cAlloAttrs = cFilterAttrs ? cFilterAttrs : m_cMaxAttrs;
  1397. const TS_ATTRID * paActualFilterAttrs = paFilterAttrs ? paFilterAttrs : m_paAttrsSupported;
  1398. hr = m_pDoc->RequestAttrsAtPosition( paStart, cAlloAttrs, paActualFilterAttrs, 0 );
  1399. if ( FAILED(hr) )
  1400. return hr;
  1401. hr = m_pDoc->RetrieveRequestedAttrs( cAlloAttrs, paAttrVals, &cFetched );
  1402. if ( FAILED(hr) )
  1403. return hr;
  1404. return S_OK;
  1405. }
  1406. HRESULT STDMETHODCALLTYPE AllocateAttrs ( ULONG cFilterAttrs )
  1407. {
  1408. if ( cFilterAttrs == 0 && m_cMaxAttrs == 0 )
  1409. {
  1410. const LONG cAttrs = 512;
  1411. HRESULT hr = m_pDoc->RequestSupportedAttrs( 0, 0, NULL );
  1412. if ( FAILED(hr) )
  1413. return hr;
  1414. TS_ATTRVAL * paSupported = new TS_ATTRVAL[ cAttrs ];
  1415. if ( !paSupported )
  1416. return E_OUTOFMEMORY;
  1417. hr = m_pDoc->RetrieveRequestedAttrs( cAttrs, paSupported, &m_cMaxAttrs );
  1418. if ( SUCCEEDED(hr) )
  1419. {
  1420. m_paAttrsSupported = new TS_ATTRID[ m_cMaxAttrs ];
  1421. if ( m_paAttrsSupported )
  1422. {
  1423. for ( int i = 0; i < m_cMaxAttrs; i++ )
  1424. {
  1425. m_paAttrsSupported[i] = paSupported[i].idAttr;
  1426. }
  1427. }
  1428. }
  1429. delete [] paSupported;
  1430. if ( FAILED(hr) )
  1431. return hr;
  1432. if ( !m_paAttrsSupported )
  1433. return E_OUTOFMEMORY;
  1434. }
  1435. ULONG cAlloAttrs = cFilterAttrs ? cFilterAttrs : m_cMaxAttrs;
  1436. if ( m_cAttrsTAPSize < cAlloAttrs )
  1437. {
  1438. if ( m_paAttrsTAP )
  1439. delete [] m_paAttrsTAP;
  1440. m_paAttrsTAP = new TS_ATTRVAL[ cAlloAttrs ];
  1441. if ( !m_paAttrsTAP )
  1442. {
  1443. m_cAttrsTAPSize = 0;
  1444. return E_OUTOFMEMORY;
  1445. }
  1446. m_cAttrsTAPSize = cAlloAttrs;
  1447. }
  1448. return S_OK;
  1449. }
  1450. void ResetAttrs()
  1451. {
  1452. m_cAttrsTAP = 0;
  1453. m_iAttrsTAP = 0;
  1454. }
  1455. };
  1456. /* 12e53b1b-7d7f-40bd-8f88-4603ee40cf58 */
  1457. const IID IID_PRIV_CINPUTCONTEXT = { 0x12e53b1b, 0x7d7f, 0x40bd, {0x8f, 0x88, 0x46, 0x03, 0xee, 0x40, 0xcf, 0x58} };
  1458. /* aabf7f9a-4487-4b2e-8164-e54c5fe19204 */
  1459. const GUID GUID_SERVICE_CTF = { 0xaabf7f9a, 0x4487, 0x4b2e, {0x81, 0x64, 0xe5, 0x4c, 0x5f, 0xe1, 0x92, 0x04} };
  1460. //
  1461. // CDocSinkWrapBase
  1462. //
  1463. // - Base from which Anchor and ACP sink wrappers are derived.
  1464. //
  1465. // This class contains ACP/Anchor-neutral wrapping code - anything that is
  1466. // ACP/Anchor-specific is handled in the derived ..ACP or ...Anchor class
  1467. // instead.
  1468. //
  1469. // Since this class is the sink for the wrapper, it derives from the full Cicero
  1470. // sink (DocTraits::ICicSink - which is a typedef for ITfTextStoreSink[Anchor]),
  1471. // and that in turn includes the ITextStoreACP sink.
  1472. //
  1473. template < class _DocTraits >
  1474. class ATL_NO_VTABLE CSinkWrapBase :
  1475. public CComObjectRootEx<CComSingleThreadModel>,
  1476. public _DocTraits::ISink,
  1477. public _DocTraits::ICicSink,
  1478. public IServiceProvider
  1479. {
  1480. public:
  1481. // This typedef makes the DocTraits type visible in this and in the
  1482. // Anchor/ACP-specific derived classes. (Otherwise, as a template
  1483. // parameter in this class, it would not be available to them.)
  1484. typedef _DocTraits DocTraits;
  1485. DECLARE_PROTECT_FINAL_CONSTRUCT()
  1486. BEGIN_COM_MAP( CSinkWrapBase<DocTraits> )
  1487. COM_INTERFACE_ENTRY( DocTraits::ISink )
  1488. COM_INTERFACE_ENTRY( DocTraits::ICicSink )
  1489. COM_INTERFACE_ENTRY( IServiceProvider )
  1490. END_COM_MAP()
  1491. /*
  1492. static HRESULT InternalQueryInterface( void* pThis, const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject )
  1493. {
  1494. // Hack for cicero - they expect to be able to QI for IID_PRIV_CINPUTCONTEXT and get
  1495. // a ptr to one of ther internal class types (ick!)
  1496. // This breaks COM identity, but hey, it's a private IID, and is only ever used
  1497. // locally.
  1498. // We can't do that sort of goo using the interface map (above), so have to hijack InternalQI instead.
  1499. if( iid == IID_PRIV_CINPUTCONTEXT )
  1500. {
  1501. CSinkWrapBase<DocTraits> * pTHIS = (CSinkWrapBase<DocTraits> *)pThis;
  1502. // Look for the cicero sink...
  1503. // recognize it by the iid - it will have reg'd with a ITf (not TextStore) IID...
  1504. for( Iter_dl< DocTraits::CDocWrap > i ( pTHIS->m_pMgr->m_DocWraps ) ; ! i.AtEnd(); i++ )
  1505. {
  1506. if( i->m_Sink.m_pSink && i->m_Sink.m_iid == __uuidof( DocTraits::ICicSink ) )
  1507. {
  1508. return i->m_Sink.m_pSink->QueryInterface( iid, ppvObject );
  1509. }
  1510. }
  1511. return E_NOINTERFACE;
  1512. }
  1513. return CComObjectRootEx<CComSingleThreadModel>::InternalQueryInterface( pThis, pEntries, iid, ppvObject );
  1514. }
  1515. */
  1516. protected:
  1517. // Protected stuff - used in this class, and by the ACP/Anchor-specific
  1518. // derived classes.
  1519. // Link back to the wrap manager. Used to tell it when we are going
  1520. // away...
  1521. CWrapMgr< DocTraits > * m_pMgr;
  1522. // Ptr to the manager's list of docs (which contain sinks)...
  1523. List_dl< DocTraits::CDocWrap > * m_pDocs;
  1524. // This macro forwards a call by iterating all the sinks in the manager,
  1525. // and forwarding if their mask has the right bit set.
  1526. // Note - this CANNOT be used for OnLockGranted.
  1527. #define CSinkWrap_FORWARD( mask, fname, c, params ) /**/ \
  1528. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params )\
  1529. {\
  1530. IMETHOD( fname );\
  1531. Assert( m_pMgr && m_pDocs );\
  1532. m_pMgr->RemoveDeadDocs();\
  1533. CPrivateAddRef MyAddRef(m_pMgr->m_lIterationRefCount);\
  1534. for( Iter_dl < DocTraits::CDocWrap > i ( *m_pDocs ) ; ! i.AtEnd() ; i++ )\
  1535. {\
  1536. DocTraits::ISink * pSink = static_cast< DocTraits::ISink * >( i->m_Sink.m_pSink );\
  1537. DWORD dwMask = i->m_Sink.m_dwMask;\
  1538. if( pSink && ( mask == 0 || ( dwMask & mask ) ) )\
  1539. {\
  1540. pSink-> fname AS_CALL( c, params );\
  1541. }\
  1542. }\
  1543. return S_OK ;\
  1544. }
  1545. // This macro forwards Cicero's TextStoreSink calls - they're not really sinks since
  1546. // the return values are significant - true broadcast is not supported; only the
  1547. // first sink in the manager which supports the interface is used - and its
  1548. // return value gets returned.
  1549. #define CSinkWrap_FORWARD_CICERO( fname, c, params ) /**/ \
  1550. HRESULT STDMETHODCALLTYPE fname AS_DECL( c, params )\
  1551. {\
  1552. IMETHOD( fname );\
  1553. Assert( m_pMgr && m_pDocs );\
  1554. for( Iter_dl < DocTraits::CDocWrap > i ( *m_pDocs ) ; ! i.AtEnd() ; i++ )\
  1555. {\
  1556. if ( i->m_Sink.m_pSink )\
  1557. {\
  1558. CComPtr< DocTraits::ICicSink > pTheSink;\
  1559. HRESULT hr = i->m_Sink.m_pSink->QueryInterface( __uuidof(DocTraits::ICicSink), (void **)&pTheSink );\
  1560. if( hr == S_OK )\
  1561. {\
  1562. return pTheSink-> fname AS_CALL( c, params );\
  1563. }\
  1564. }\
  1565. }\
  1566. return E_FAIL ;\
  1567. }
  1568. public:
  1569. //
  1570. // Ctor, Dtor and initialization...
  1571. //
  1572. CSinkWrapBase()
  1573. : m_pMgr( NULL ),
  1574. m_pDocs( NULL )
  1575. {
  1576. }
  1577. ~CSinkWrapBase()
  1578. {
  1579. AssertMsg( m_pMgr != NULL && m_pDocs != NULL, TEXT("CSinkWrapBase::Init never got called?") );
  1580. m_pMgr->SinkWrap_NotifyDisconnect();
  1581. m_pMgr->Release();
  1582. }
  1583. void Init( CWrapMgr< DocTraits > * pMgr, List_dl< DocTraits::CDocWrap > * pDocs )
  1584. {
  1585. AssertMsg( m_pMgr == NULL && m_pDocs == NULL, TEXT("CSinkWrapBase::Init should only be called once when m_pMgr is NULL") );
  1586. m_pMgr = pMgr;
  1587. m_pMgr->AddRef();
  1588. m_pDocs = pDocs;
  1589. }
  1590. //
  1591. // IServiceProvider - Cicero uses this to 'drill through' to the original anchor to pull out
  1592. // internal information. Just pass it through...
  1593. //
  1594. HRESULT STDMETHODCALLTYPE QueryService( REFGUID guidService, REFIID riid, void **ppvObject )
  1595. {
  1596. IMETHOD( QueryService );
  1597. // Find the cicero sink...
  1598. DocTraits::ICicSink * pTheSink = NULL;
  1599. // Look for the cicero sink...
  1600. // The cicero sink supports the Services interfaces and other don't
  1601. for( Iter_dl< DocTraits::CDocWrap > i ( m_pMgr->m_DocWraps ) ; ! i.AtEnd(); i++ )
  1602. {
  1603. if ( i->m_Sink.m_pSink )
  1604. {
  1605. if( i->m_Sink.m_pSink->QueryInterface( __uuidof(DocTraits::ICicSink), (void **)&pTheSink ) == S_OK )
  1606. {
  1607. break;
  1608. }
  1609. }
  1610. }
  1611. if( pTheSink == NULL )
  1612. return E_FAIL;
  1613. CComPtr<IServiceProvider> pISP;
  1614. HRESULT hr = pTheSink->QueryInterface( IID_IServiceProvider, (void **) & pISP );
  1615. if( hr != S_OK || pISP == NULL )
  1616. return E_FAIL;
  1617. hr = pISP->QueryService( guidService, riid, ppvObject );
  1618. return hr;
  1619. }
  1620. //
  1621. // ACP/Anchor-neutral sinks - just broadcast these...
  1622. //
  1623. CSinkWrap_FORWARD( TS_AS_SEL_CHANGE, OnSelectionChange, 0, () )
  1624. CSinkWrap_FORWARD( TS_AS_LAYOUT_CHANGE, OnLayoutChange, 2, ( TsLayoutCode, lcode, TsViewCookie, vcView ) )
  1625. CSinkWrap_FORWARD( 0, OnStatusChange, 1, ( DWORD, dwFlags ) )
  1626. CSinkWrap_FORWARD( 0, OnStartEditTransaction,0, () )
  1627. CSinkWrap_FORWARD( 0, OnEndEditTransaction, 0, () )
  1628. //
  1629. // Special case for OnLockGranted...
  1630. // Handle single-client sync requests, and multiple queued async requests...
  1631. //
  1632. HRESULT STDMETHODCALLTYPE OnLockGranted ( DWORD dwLockFlags )
  1633. {
  1634. IMETHOD( OnLockGranted );
  1635. Assert( m_pMgr );
  1636. return m_pMgr->SinkWrap_HandleOnLockGranted( dwLockFlags );
  1637. }
  1638. };
  1639. //
  1640. // CSinkWrapACP
  1641. //
  1642. // - ACP sink wrapper
  1643. //
  1644. // Derived from the CSinkWrapBase, this adds ACP-specific methods; including
  1645. // those from both ITextStoreACP and the cicero-specific ITfTextStoreSink
  1646. // interfaces.
  1647. //
  1648. class ATL_NO_VTABLE CSinkWrapACP :
  1649. public CSinkWrapBase< DocTraitsACP >
  1650. {
  1651. public:
  1652. //
  1653. // ITextStoreACPSink ACP/Anchor-specific methods - broadcast to all interested sinks...
  1654. // (See CSinkWrapBase for the forwarding macro.)
  1655. //
  1656. CSinkWrap_FORWARD( TS_AS_TEXT_CHANGE, OnTextChange, 2, ( DWORD, dwFlags, const TS_TEXTCHANGE *, pChange ) )
  1657. CSinkWrap_FORWARD( 0, OnAttrsChange, 4, ( LONG, acpStart, LONG, acpEnd, ULONG, cAttrs, const TS_ATTRID *, paAttrs ) )
  1658. //
  1659. // Cicero-specific sink methods - forward these to the first available sink that implements the cicero interface...
  1660. // (See CSinkWrapBase for the forwarding macro.)
  1661. //
  1662. CSinkWrap_FORWARD_CICERO( Serialize, 4, (ITfProperty *, pProp, ITfRange *, pRange, TF_PERSISTENT_PROPERTY_HEADER_ACP *, pHdr, IStream *, pStream) )
  1663. CSinkWrap_FORWARD_CICERO( Unserialize, 4, (ITfProperty *, pProp, const TF_PERSISTENT_PROPERTY_HEADER_ACP *, pHdr, IStream *, pStream, ITfPersistentPropertyLoaderACP *, pLoader) )
  1664. CSinkWrap_FORWARD_CICERO( ForceLoadProperty,1, (ITfProperty *, pProp) )
  1665. CSinkWrap_FORWARD_CICERO( CreateRange, 3, (LONG, acpStart, LONG, acpEnd, ITfRangeACP **, ppRange) )
  1666. };
  1667. //
  1668. // CSinkWrapAnchor
  1669. //
  1670. // - Anchor sink wrapper
  1671. //
  1672. // Derived from the CSinkWrapBase, this adds Anchor-specific methods; including
  1673. // those from both ITextStoreACP and the cicero-specific ITfTextStoreSink
  1674. // interfaces.
  1675. //
  1676. class ATL_NO_VTABLE CSinkWrapAnchor :
  1677. public CSinkWrapBase< DocTraitsAnchor >
  1678. {
  1679. public:
  1680. //
  1681. // ITextStoreACPSink ACP/Anchor-specific methods - broadcast to all interested sinks...
  1682. // (See CSinkWrapBase for the forwarding macro.)
  1683. //
  1684. CSinkWrap_FORWARD( TS_AS_TEXT_CHANGE, OnTextChange, 3, ( DWORD, dwFlags, IAnchor *, paStart, IAnchor *, paEnd ) )
  1685. CSinkWrap_FORWARD( 0, OnAttrsChange, 4, ( IAnchor *, paStart, IAnchor *, paEnd, ULONG, cAttrs, const TS_ATTRID *, paAttrs ) )
  1686. //
  1687. // Cicero-specific sink methods - forward these to the first available sink that implements the cicero interface...
  1688. // (See CSinkWrapBase for the forwarding macro.)
  1689. //
  1690. CSinkWrap_FORWARD_CICERO( Serialize, 4, (ITfProperty *, pProp, ITfRange *, pRange, TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *, pHdr, IStream *, pStream) )
  1691. CSinkWrap_FORWARD_CICERO( Unserialize, 4, (ITfProperty *, pProp, const TF_PERSISTENT_PROPERTY_HEADER_ANCHOR *, pHdr, IStream *, pStream, ITfPersistentPropertyLoaderAnchor *, pLoader) )
  1692. CSinkWrap_FORWARD_CICERO( ForceLoadProperty,1, (ITfProperty *, pProp) )
  1693. CSinkWrap_FORWARD_CICERO( CreateRange, 3, (IAnchor *, paStart, IAnchor *, paEnd, ITfRangeAnchor **, ppRange) )
  1694. };
  1695. CDocWrap::CDocWrap()
  1696. : m_punkDoc( NULL ),
  1697. m_pWrapMgr( NULL )
  1698. {
  1699. IMETHOD( CDocWrap );
  1700. // Done.
  1701. }
  1702. CDocWrap::~CDocWrap()
  1703. {
  1704. IMETHOD( ~CDocWrap );
  1705. _Clear();
  1706. }
  1707. HRESULT STDMETHODCALLTYPE CDocWrap::SetDoc( REFIID riid, IUnknown * pDocIn )
  1708. {
  1709. IMETHOD( SetDoc );
  1710. _Clear();
  1711. if( pDocIn == NULL )
  1712. {
  1713. TraceInfo( TEXT("CDocWrapp::SetDoc( NULL ) - doc cleared") );
  1714. return S_OK;
  1715. }
  1716. HRESULT hr;
  1717. if( riid == IID_ITextStoreACP || riid == IID_ITfTextStoreACP )
  1718. {
  1719. CWrapMgr< DocTraitsACP > * pWrapMgrACP;
  1720. hr = CreateLocalInstance( & pWrapMgrACP );
  1721. m_pWrapMgr = pWrapMgrACP;
  1722. }
  1723. else if( riid == IID_ITextStoreAnchor || riid == IID_ITfTextStoreAnchor )
  1724. {
  1725. CWrapMgr< DocTraitsAnchor > * pWrapMgrAnchor;
  1726. hr = CreateLocalInstance( & pWrapMgrAnchor );
  1727. m_pWrapMgr = pWrapMgrAnchor;
  1728. }
  1729. else
  1730. {
  1731. TraceParam( TEXT("CDocWrapp::SetDoc - given unknown IID") );
  1732. return E_NOINTERFACE;
  1733. }
  1734. CHECK_HR_RETURN( hr, m_pWrapMgr != NULL );
  1735. if( hr != S_OK )
  1736. {
  1737. TraceErrorHR( hr, TEXT("Couldn't create CWrapMgr") );
  1738. return FAILED( (hr) ) ? (hr) : E_UNEXPECTED;
  1739. }
  1740. if( hr == S_OK && ! m_pWrapMgr )
  1741. {
  1742. TraceErrorHR( hr, TEXT("Couldn't create CWrapMgr") );
  1743. return E_UNEXPECTED;
  1744. }
  1745. m_pWrapMgr->SetDoc( pDocIn );
  1746. m_iid = riid;
  1747. m_punkDoc = pDocIn;
  1748. m_punkDoc->AddRef();
  1749. TraceInfo( TEXT("CDocWrap::SetDoc - new doc set.") );
  1750. return S_OK;
  1751. }
  1752. HRESULT STDMETHODCALLTYPE CDocWrap::GetWrappedDoc( REFIID riid, IUnknown ** pWrappedDocOut )
  1753. {
  1754. IMETHOD( GetWrappedDoc );
  1755. if( ! m_punkDoc || ! m_pWrapMgr )
  1756. {
  1757. TraceParam( TEXT("GetWrappedDoc called without prior successful call to SetDoc") );
  1758. return E_FAIL;
  1759. }
  1760. if( ! pWrappedDocOut )
  1761. {
  1762. TraceParam( TEXT("GetWrappedDoc called without NULL pWrappedDocOut param") );
  1763. return E_POINTER;
  1764. }
  1765. // Check that requested iid matches...
  1766. // We allow Doc/ITf mixes, provided the interfaces match ACP/Anchor-wise.
  1767. if( m_iid == IID_ITextStoreAnchor || m_iid == IID_ITfTextStoreAnchor )
  1768. {
  1769. if( riid != IID_ITextStoreAnchor && riid != IID_ITfTextStoreAnchor )
  1770. {
  1771. TraceParam( TEXT("Interface requested by GetWrappedDoc doesn't match that suplied by SetDoc") );
  1772. return E_NOINTERFACE;
  1773. }
  1774. }
  1775. else
  1776. {
  1777. if( riid != IID_ITextStoreACP && riid != IID_ITfTextStoreACP )
  1778. {
  1779. TraceParam( TEXT("Interface requested by GetWrappedDoc doesn't match that suplied by SetDoc") );
  1780. return E_NOINTERFACE;
  1781. }
  1782. }
  1783. TraceInfo( TEXT("GetWrappedDoc succeeded") );
  1784. return m_pWrapMgr->CreateWrappedDoc( pWrappedDocOut );
  1785. }
  1786. void CDocWrap::_Clear()
  1787. {
  1788. SafeReleaseClear( m_pWrapMgr );
  1789. SafeReleaseClear( m_punkDoc );
  1790. }