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.

939 lines
26 KiB

  1. //
  2. // tsi.cpp
  3. //
  4. // CTextStoreImpl
  5. //
  6. #include "private.h"
  7. #include "tsi.h"
  8. #include "immxutil.h"
  9. #include "tsdo.h"
  10. #include "tsattrs.h"
  11. #include "ic.h"
  12. #include "rprop.h"
  13. #define TSI_TOKEN 0x01010101
  14. DBG_ID_INSTANCE(CTextStoreImpl);
  15. /* 012313d4-b1e7-476a-bf88-173a316572fb */
  16. extern const IID IID_PRIV_CTSI = { 0x012313d4, 0xb1e7, 0x476a, {0xbf, 0x88, 0x17, 0x3a, 0x31, 0x65, 0x72, 0xfb} };
  17. //+---------------------------------------------------------------------------
  18. //
  19. // ctor
  20. //
  21. //----------------------------------------------------------------------------
  22. CTextStoreImpl::CTextStoreImpl(CInputContext *pic)
  23. {
  24. Dbg_MemSetThisNameID(TEXT("CTextStoreImpl"));
  25. Assert(_fPendingWriteReq == FALSE);
  26. Assert(_dwlt == 0);
  27. _pic = pic;
  28. }
  29. //+---------------------------------------------------------------------------
  30. //
  31. // dtor
  32. //
  33. //----------------------------------------------------------------------------
  34. CTextStoreImpl::~CTextStoreImpl()
  35. {
  36. cicMemFree(_pch);
  37. }
  38. //+---------------------------------------------------------------------------
  39. //
  40. // AdviseSink
  41. //
  42. //----------------------------------------------------------------------------
  43. STDAPI CTextStoreImpl::AdviseSink(REFIID riid, IUnknown *punk, DWORD dwMask)
  44. {
  45. if (_ptss != NULL)
  46. {
  47. Assert(0); // cicero shouldn't do this
  48. return CONNECT_E_ADVISELIMIT;
  49. }
  50. if (FAILED(punk->QueryInterface(IID_ITextStoreACPSink, (void **)&_ptss)))
  51. return E_UNEXPECTED;
  52. return S_OK;
  53. }
  54. //+---------------------------------------------------------------------------
  55. //
  56. // UnadviseSink
  57. //
  58. //----------------------------------------------------------------------------
  59. STDAPI CTextStoreImpl::UnadviseSink(IUnknown *punk)
  60. {
  61. Assert(_ptss == punk); // we're dealing with cicero, this should always hold
  62. SafeReleaseClear(_ptss);
  63. return S_OK;
  64. }
  65. //+---------------------------------------------------------------------------
  66. //
  67. // GetSelection
  68. //
  69. //----------------------------------------------------------------------------
  70. STDAPI CTextStoreImpl::GetSelection(ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched)
  71. {
  72. if (pcFetched == NULL)
  73. return E_INVALIDARG;
  74. *pcFetched = 0;
  75. if (ulIndex > 1 && ulIndex != TS_DEFAULT_SELECTION)
  76. return E_INVALIDARG; // index too high
  77. if (ulCount == 0 || ulIndex == 1)
  78. return S_OK;
  79. if (pSelection == NULL)
  80. return E_INVALIDARG;
  81. pSelection[0] = _Sel;
  82. *pcFetched = 1;
  83. return S_OK;
  84. }
  85. //+---------------------------------------------------------------------------
  86. //
  87. // SetSelection
  88. //
  89. //----------------------------------------------------------------------------
  90. STDAPI CTextStoreImpl::SetSelection(ULONG ulCount, const TS_SELECTION_ACP *pSelection)
  91. {
  92. Assert(ulCount > 0); // should have been caught by caller
  93. Assert(pSelection != NULL); // should have been caught by caller
  94. Assert(pSelection[0].acpStart >= 0);
  95. Assert(pSelection[0].acpEnd >= pSelection[0].acpStart);
  96. if (ulCount > 1)
  97. return E_FAIL; // don't support disjoint sel
  98. if (pSelection[0].acpEnd > _cch)
  99. return TS_E_INVALIDPOS;
  100. _Sel = pSelection[0];
  101. return S_OK;
  102. }
  103. //+---------------------------------------------------------------------------
  104. //
  105. // GetText
  106. //
  107. //----------------------------------------------------------------------------
  108. STDAPI CTextStoreImpl::GetText(LONG acpStart, LONG acpEnd,
  109. WCHAR *pchPlain, ULONG cchPlainReq, ULONG *pcchPlainOut,
  110. TS_RUNINFO *prgRunInfo, ULONG ulRunInfoReq, ULONG *pulRunInfoOut,
  111. LONG *pacpNext)
  112. {
  113. ULONG cch;
  114. *pcchPlainOut = 0;
  115. *pulRunInfoOut = 0;
  116. *pacpNext = acpStart;
  117. if (acpStart < 0 || acpStart > _cch)
  118. return TS_E_INVALIDPOS;
  119. // get a count of acp chars requested
  120. cch = (acpEnd >= acpStart) ? acpEnd - acpStart : _cch - acpStart;
  121. // since we're plain text, we can also simply clip by the plaintext buffer len
  122. if (cchPlainReq > 0) // if they don't want plain text we won't clip!
  123. {
  124. cch = min(cch, cchPlainReq);
  125. }
  126. // check for eod
  127. if (acpStart + cch > (ULONG)_cch)
  128. {
  129. cch = _cch - acpStart;
  130. }
  131. if (ulRunInfoReq > 0 && cch > 0)
  132. {
  133. *pulRunInfoOut = 1;
  134. prgRunInfo[0].uCount = cch;
  135. prgRunInfo[0].type = TS_RT_PLAIN;
  136. }
  137. if (cchPlainReq > 0)
  138. {
  139. // we're a plain text buffer, so we always copy all the requested chars
  140. *pcchPlainOut = cch;
  141. memcpy(pchPlain, _pch + acpStart, cch*sizeof(WCHAR));
  142. }
  143. *pacpNext = acpStart + cch;
  144. return S_OK;
  145. }
  146. //+---------------------------------------------------------------------------
  147. //
  148. // SetText
  149. //
  150. //----------------------------------------------------------------------------
  151. STDAPI CTextStoreImpl::SetText(DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, ULONG cch, TS_TEXTCHANGE *pChange)
  152. {
  153. int iSizeRange;
  154. int cchAdjust;
  155. TS_STATUS tss;
  156. WCHAR *pch = NULL;
  157. // Since we know our only caller will be cicero, we can assert rather than
  158. // returning failure codes.
  159. Assert(acpStart >= 0);
  160. Assert(acpStart <= acpEnd);
  161. if (acpEnd > _cch)
  162. return TS_E_INVALIDPOS;
  163. if (_owner != NULL &&
  164. _owner->GetStatus(&tss) == S_OK &&
  165. (tss.dwDynamicFlags & TS_SD_READONLY))
  166. {
  167. return TS_E_READONLY;
  168. }
  169. //
  170. // Check mapped app property for TSATTRID_Text_ReadOnly.
  171. //
  172. CProperty *pProp;
  173. BOOL fReadOnly = FALSE;
  174. if (SUCCEEDED(_pic->GetMappedAppProperty(TSATTRID_Text_ReadOnly, &pProp)))
  175. {
  176. ITfRangeACP *range;
  177. if (SUCCEEDED(_pic->CreateRange(acpStart, acpEnd, &range)))
  178. {
  179. IEnumTfRanges *pEnumRanges;
  180. if (SUCCEEDED(pProp->EnumRanges(BACKDOOR_EDIT_COOKIE,
  181. &pEnumRanges,
  182. range)))
  183. {
  184. ITfRange *rangeTmp;
  185. while (pEnumRanges->Next(1, &rangeTmp, NULL) == S_OK)
  186. {
  187. VARIANT var;
  188. if (pProp->GetValue(BACKDOOR_EDIT_COOKIE, rangeTmp, &var) == S_OK)
  189. {
  190. if (var.lVal != 0)
  191. {
  192. fReadOnly = TRUE;
  193. break;
  194. }
  195. }
  196. rangeTmp->Release();
  197. }
  198. pEnumRanges->Release();
  199. }
  200. range->Release();
  201. }
  202. pProp->Release();
  203. }
  204. if (fReadOnly)
  205. {
  206. return TS_E_READONLY;
  207. }
  208. // this will all be rewritten for the gap buffer, so keep it simple for now.
  209. // delete the ranage, then insert the new text.
  210. iSizeRange = acpEnd - acpStart;
  211. cchAdjust = (LONG)cch - iSizeRange;
  212. if (cchAdjust > 0)
  213. {
  214. // if we need to alloc more memory, try now, to handle failure gracefully
  215. if ((pch = (_pch == NULL) ? (WCHAR *)cicMemAlloc((_cch + cchAdjust)*sizeof(WCHAR)) :
  216. (WCHAR *)cicMemReAlloc(_pch, (_cch + cchAdjust)*sizeof(WCHAR))) == NULL)
  217. {
  218. return E_OUTOFMEMORY;
  219. }
  220. // we're all set
  221. _pch = pch;
  222. }
  223. //
  224. // shift existing text to the right of the range
  225. //
  226. memmove(_pch + acpStart + cch, _pch + acpStart + iSizeRange, (_cch - iSizeRange - acpStart)*sizeof(WCHAR));
  227. //
  228. // now fill in the gap
  229. //
  230. if (pchText != NULL)
  231. {
  232. memcpy(_pch + acpStart, pchText, cch*sizeof(WCHAR));
  233. }
  234. //
  235. // update our buffer size
  236. //
  237. _cch += cchAdjust;
  238. Assert(_cch >= 0);
  239. // if we shrank, try to realloc a smaller buffer (otherwise we alloc'd above)
  240. if (cchAdjust < 0)
  241. {
  242. if (_cch == 0)
  243. {
  244. cicMemFree(_pch);
  245. _pch = NULL;
  246. }
  247. else if (pch = (WCHAR *)cicMemReAlloc(_pch, _cch*sizeof(WCHAR)))
  248. {
  249. _pch = pch;
  250. }
  251. }
  252. // handle the out params
  253. pChange->acpStart = acpStart;
  254. pChange->acpOldEnd = acpEnd;
  255. pChange->acpNewEnd = acpEnd + cchAdjust;
  256. //
  257. // update the selection
  258. //
  259. _Sel.acpStart = AdjustAnchor(acpStart, acpEnd, cch, _Sel.acpStart, FALSE);
  260. _Sel.acpEnd = AdjustAnchor(acpStart, acpEnd, cch, _Sel.acpEnd, TRUE);
  261. Assert(_Sel.acpStart >= 0);
  262. Assert(_Sel.acpStart <= _Sel.acpEnd);
  263. Assert(_Sel.acpEnd <= _cch);
  264. // never need to call OnTextChange because we have only one adaptor
  265. // and this class never calls SetText internally
  266. // do the OnDelta
  267. //_ptss->OnTextChange(acpStart, acpEnd, acpStart + cch);
  268. return S_OK;
  269. }
  270. //+---------------------------------------------------------------------------
  271. //
  272. // GetFormattedText
  273. //
  274. //----------------------------------------------------------------------------
  275. STDAPI CTextStoreImpl::GetFormattedText(LONG acpStart, LONG acpEnd, IDataObject **ppDataObject)
  276. {
  277. CTFDataObject *pcdo;
  278. Assert(acpStart >= 0 && acpEnd <= _cch);
  279. Assert(acpStart <= acpEnd);
  280. Assert(ppDataObject != NULL);
  281. *ppDataObject = NULL;
  282. pcdo = new CTFDataObject;
  283. if (pcdo == NULL)
  284. return E_OUTOFMEMORY;
  285. if (FAILED(pcdo->_SetData(&_pch[acpStart], acpEnd - acpStart)))
  286. {
  287. Assert(0);
  288. pcdo->Release();
  289. return E_FAIL;
  290. }
  291. return S_OK;
  292. }
  293. //+---------------------------------------------------------------------------
  294. //
  295. // GetEmbedded
  296. //
  297. //----------------------------------------------------------------------------
  298. STDAPI CTextStoreImpl::GetEmbedded(LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk)
  299. {
  300. return E_NOTIMPL;
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // InsertEmbedded
  305. //
  306. //----------------------------------------------------------------------------
  307. STDAPI CTextStoreImpl::InsertEmbedded(DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, TS_TEXTCHANGE *pChange)
  308. {
  309. ULONG cch;
  310. FORMATETC fe;
  311. STGMEDIUM sm;
  312. WCHAR *pch;
  313. HRESULT hr;
  314. Assert(acpStart <= acpEnd);
  315. Assert((dwFlags & ~TS_IE_CORRECTION) == 0);
  316. Assert(pDataObject != NULL);
  317. Assert(pChange != NULL);
  318. memset(pChange, 0, sizeof(*pChange));
  319. fe.cfFormat = CF_UNICODETEXT;
  320. fe.ptd = NULL;
  321. fe.dwAspect = DVASPECT_CONTENT;
  322. fe.lindex = -1;
  323. fe.tymed = TYMED_HGLOBAL;
  324. if (FAILED(pDataObject->GetData(&fe, &sm)))
  325. return TS_E_FORMAT;
  326. if (sm.hGlobal == NULL)
  327. return E_FAIL;
  328. pch = (WCHAR *)GlobalLock(sm.hGlobal);
  329. cch = wcslen(pch);
  330. hr = SetText(dwFlags, acpStart, acpEnd, pch, cch, pChange);
  331. GlobalUnlock(sm.hGlobal);
  332. ReleaseStgMedium(&sm);
  333. return hr;
  334. }
  335. //+---------------------------------------------------------------------------
  336. //
  337. // RequestLock
  338. //
  339. //----------------------------------------------------------------------------
  340. #define TS_LF_WRITE (TS_LF_READWRITE & ~TS_LF_READ)
  341. STDAPI CTextStoreImpl::RequestLock(DWORD dwLockFlags, HRESULT *phrSession)
  342. {
  343. Assert(phrSession != NULL); // caller should have caught this
  344. if (_dwlt != 0)
  345. {
  346. *phrSession = E_UNEXPECTED;
  347. // this is a reentrant call
  348. // only one case is legal
  349. if ((_dwlt & TS_LF_WRITE) ||
  350. !(dwLockFlags & TS_LF_WRITE) ||
  351. (dwLockFlags & TS_LF_SYNC))
  352. {
  353. Assert(0); // bogus reentrant lock req!
  354. return E_UNEXPECTED;
  355. }
  356. _fPendingWriteReq = TRUE;
  357. *phrSession = TS_S_ASYNC;
  358. return S_OK;
  359. }
  360. _dwlt = dwLockFlags;
  361. *phrSession = _ptss->OnLockGranted(dwLockFlags);
  362. if (_fPendingWriteReq)
  363. {
  364. _dwlt = TS_LF_READWRITE;
  365. _fPendingWriteReq = FALSE;
  366. if (_ptss != NULL) // might be NULL if we're disconnected during the OnLockGranted above
  367. {
  368. _ptss->OnLockGranted(TS_LF_READWRITE);
  369. }
  370. }
  371. _dwlt = 0;
  372. return S_OK;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // GetStatus
  377. //
  378. //----------------------------------------------------------------------------
  379. STDAPI CTextStoreImpl::GetStatus(TS_STATUS *pdcs)
  380. {
  381. HRESULT hr;
  382. if (_owner != NULL)
  383. {
  384. hr = _owner->GetStatus(pdcs);
  385. // only let the owner ctl certain bits
  386. if (hr == S_OK)
  387. {
  388. pdcs->dwDynamicFlags &= (TF_SD_READONLY | TF_SD_LOADING);
  389. pdcs->dwStaticFlags &= (TF_SS_TRANSITORY);
  390. }
  391. else
  392. {
  393. memset(pdcs, 0, sizeof(*pdcs));
  394. }
  395. }
  396. else
  397. {
  398. hr = S_OK;
  399. memset(pdcs, 0, sizeof(*pdcs));
  400. }
  401. return hr;
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // QueryInsert
  406. //
  407. //----------------------------------------------------------------------------
  408. STDAPI CTextStoreImpl::QueryInsert(LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, LONG *pacpResultEnd)
  409. {
  410. Assert(acpTestStart >= 0);
  411. Assert(acpTestStart <= acpTestEnd);
  412. Assert(acpTestEnd <= _cch);
  413. // default text store does not support overtype, and the selection is always replaced
  414. *pacpResultStart = acpTestStart;
  415. *pacpResultEnd = acpTestEnd;
  416. return S_OK;
  417. }
  418. //+---------------------------------------------------------------------------
  419. //
  420. // Unlock
  421. //
  422. //----------------------------------------------------------------------------
  423. STDAPI CTextStoreImpl::GetEndACP(LONG *pacp)
  424. {
  425. *pacp = _cch;
  426. return S_OK;
  427. }
  428. //+---------------------------------------------------------------------------
  429. //
  430. // GetACPFromPoint
  431. //
  432. //----------------------------------------------------------------------------
  433. STDAPI CTextStoreImpl::GetACPFromPoint(TsViewCookie vcView, const POINT *pt, DWORD dwFlags, LONG *pacp)
  434. {
  435. Assert(vcView == TSI_ACTIVE_VIEW_COOKIE); // default tsi only has a single view
  436. if (_owner == NULL)
  437. return E_FAIL; // who ever owns the ic hasn't bothered to give us a callback....
  438. return _owner->GetACPFromPoint(pt, dwFlags, pacp);
  439. }
  440. //+---------------------------------------------------------------------------
  441. //
  442. // GetScreenExt
  443. //
  444. //----------------------------------------------------------------------------
  445. STDAPI CTextStoreImpl::GetScreenExt(TsViewCookie vcView, RECT *prc)
  446. {
  447. Assert(vcView == TSI_ACTIVE_VIEW_COOKIE); // default tsi only has a single view
  448. if (_owner == NULL)
  449. return E_FAIL; // who ever owns the ic hasn't bothered to give us a callback....
  450. return _owner->GetScreenExt(prc);
  451. }
  452. //+---------------------------------------------------------------------------
  453. //
  454. // GetTextExt
  455. //
  456. //----------------------------------------------------------------------------
  457. STDAPI CTextStoreImpl::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped)
  458. {
  459. Assert(vcView == TSI_ACTIVE_VIEW_COOKIE); // default tsi only has a single view
  460. if (_owner == NULL)
  461. return E_FAIL; // who ever owns the ic hasn't bothered to give us a callback....
  462. return _owner->GetTextExt(acpStart, acpEnd, prc, pfClipped);
  463. }
  464. //+---------------------------------------------------------------------------
  465. //
  466. // GetWnd
  467. //
  468. //----------------------------------------------------------------------------
  469. STDAPI CTextStoreImpl::GetWnd(TsViewCookie vcView, HWND *phwnd)
  470. {
  471. Assert(vcView == TSI_ACTIVE_VIEW_COOKIE); // default tsi only has a single view
  472. Assert(phwnd != NULL); // should have caught this in the ic
  473. *phwnd = NULL;
  474. if (_owner == NULL)
  475. return E_FAIL; // who ever owns the ic hasn't bothered to give us a callback....
  476. return _owner->GetWnd(phwnd);
  477. }
  478. //+---------------------------------------------------------------------------
  479. //
  480. // _LoadAttr
  481. //
  482. //----------------------------------------------------------------------------
  483. HRESULT CTextStoreImpl::_LoadAttr(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
  484. {
  485. ULONG i;
  486. HRESULT hr;
  487. ClearAttrStore();
  488. if (dwFlags & TS_ATTR_FIND_WANT_VALUE)
  489. {
  490. if (_owner == NULL)
  491. return E_FAIL;
  492. }
  493. for (i=0; i<cFilterAttrs; i++)
  494. {
  495. VARIANT var;
  496. QuickVariantInit(&var);
  497. if (dwFlags & TS_ATTR_FIND_WANT_VALUE)
  498. {
  499. if (_owner->GetAttribute(paFilterAttrs[i], &var) != S_OK)
  500. {
  501. ClearAttrStore();
  502. return E_FAIL;
  503. }
  504. }
  505. else
  506. {
  507. // Issue: benwest: I think these should be init'd to VT_EMPTY if caller doesn't specify TS_ATTR_FIND_WANT_VALUE
  508. if (IsEqualGUID(paFilterAttrs[i], GUID_PROP_MODEBIAS))
  509. {
  510. var.vt = VT_I4;
  511. var.lVal = TF_INVALID_GUIDATOM;
  512. }
  513. else if (IsEqualGUID(paFilterAttrs[i], TSATTRID_Text_Orientation))
  514. {
  515. var.vt = VT_I4;
  516. var.lVal = 0;
  517. }
  518. else if (IsEqualGUID(paFilterAttrs[i], TSATTRID_Text_VerticalWriting))
  519. {
  520. var.vt = VT_BOOL;
  521. var.lVal = 0;
  522. }
  523. }
  524. if (var.vt != VT_EMPTY)
  525. {
  526. TSI_ATTRSTORE *pas = _rgAttrStore.Append(1);
  527. if (!pas)
  528. {
  529. hr = E_OUTOFMEMORY;
  530. goto Exit;
  531. }
  532. pas->attrid = paFilterAttrs[i];
  533. pas->var = var;
  534. }
  535. }
  536. hr = S_OK;
  537. Exit:
  538. return hr;
  539. }
  540. //+---------------------------------------------------------------------------
  541. //
  542. // RequestSupportedAttrs
  543. //
  544. //----------------------------------------------------------------------------
  545. STDAPI CTextStoreImpl::RequestSupportedAttrs(DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs)
  546. {
  547. // note the return value is technically a default value, but since we have a value for every location
  548. // this will never need to be used
  549. return _LoadAttr(dwFlags, cFilterAttrs, paFilterAttrs);
  550. }
  551. //+---------------------------------------------------------------------------
  552. //
  553. // RequestAttrsAtPosition
  554. //
  555. //----------------------------------------------------------------------------
  556. STDAPI CTextStoreImpl::RequestAttrsAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
  557. {
  558. return _LoadAttr(TS_ATTR_FIND_WANT_VALUE, cFilterAttrs, paFilterAttrs);
  559. }
  560. //+---------------------------------------------------------------------------
  561. //
  562. // RequestAttrsTransitioningAtPosition
  563. //
  564. //----------------------------------------------------------------------------
  565. STDAPI CTextStoreImpl::RequestAttrsTransitioningAtPosition(LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags)
  566. {
  567. ClearAttrStore();
  568. return S_OK;
  569. }
  570. //+---------------------------------------------------------------------------
  571. //
  572. // FindNextAttrTransition
  573. //
  574. //----------------------------------------------------------------------------
  575. STDAPI CTextStoreImpl::FindNextAttrTransition(LONG acpStart, LONG acpHaltPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset)
  576. {
  577. // our attrs never transition
  578. *pacpNext = acpStart;
  579. *pfFound = FALSE;
  580. plFoundOffset = 0;
  581. return S_OK;
  582. }
  583. //+---------------------------------------------------------------------------
  584. //
  585. // RetrieveRequestedAttrs
  586. //
  587. //----------------------------------------------------------------------------
  588. STDAPI CTextStoreImpl::RetrieveRequestedAttrs(ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched)
  589. {
  590. ULONG i = 0;
  591. while((i < ulCount) && ((int)i < _rgAttrStore.Count()))
  592. {
  593. TSI_ATTRSTORE *pas = _rgAttrStore.GetPtr(i);
  594. paAttrVals->idAttr = pas->attrid;
  595. paAttrVals->dwOverlapId = 0;
  596. QuickVariantInit(&paAttrVals->varValue);
  597. paAttrVals->varValue = pas->var;
  598. paAttrVals++;
  599. i++;
  600. }
  601. *pcFetched = i;
  602. ClearAttrStore();
  603. return S_OK;
  604. }
  605. //+---------------------------------------------------------------------------
  606. //
  607. // QueryService
  608. //
  609. //----------------------------------------------------------------------------
  610. STDAPI CTextStoreImpl::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  611. {
  612. if (ppv == NULL)
  613. return E_INVALIDARG;
  614. *ppv = NULL;
  615. if (!IsEqualGUID(guidService, GUID_SERVICE_TF) ||
  616. !IsEqualIID(riid, IID_PRIV_CTSI))
  617. {
  618. // SVC_E_NOSERVICE is proper return code for wrong service....
  619. // but it's not defined anywhere. So use E_NOINTERFACE for both
  620. // cases as trident is rumored to do
  621. return E_NOINTERFACE;
  622. }
  623. *ppv = this;
  624. AddRef();
  625. return S_OK;
  626. }
  627. //+---------------------------------------------------------------------------
  628. //
  629. // GetActiveView
  630. //
  631. //----------------------------------------------------------------------------
  632. STDAPI CTextStoreImpl::GetActiveView(TsViewCookie *pvcView)
  633. {
  634. // each CEditWnd has only a single view, so this can be constant.
  635. *pvcView = TSI_ACTIVE_VIEW_COOKIE;
  636. return S_OK;
  637. }
  638. //+---------------------------------------------------------------------------
  639. //
  640. // AdviseMouseSink
  641. //
  642. //----------------------------------------------------------------------------
  643. STDAPI CTextStoreImpl::AdviseMouseSink(ITfRangeACP *range, ITfMouseSink *pSink, DWORD *pdwCookie)
  644. {
  645. ITfMouseTrackerACP *pTracker;
  646. HRESULT hr;
  647. Assert(range != NULL);
  648. Assert(pSink != NULL);
  649. Assert(pdwCookie != NULL);
  650. *pdwCookie = 0;
  651. if (_owner == NULL)
  652. return E_FAIL;
  653. if (_owner->QueryInterface(IID_ITfMouseTrackerACP, (void **)&pTracker) != S_OK)
  654. return E_NOTIMPL;
  655. hr = pTracker->AdviseMouseSink(range, pSink, pdwCookie);
  656. pTracker->Release();
  657. return hr;
  658. }
  659. //+---------------------------------------------------------------------------
  660. //
  661. // UnadviseMouseSink
  662. //
  663. //----------------------------------------------------------------------------
  664. STDAPI CTextStoreImpl::UnadviseMouseSink(DWORD dwCookie)
  665. {
  666. ITfMouseTrackerACP *pTracker;
  667. HRESULT hr;
  668. if (_owner == NULL)
  669. return E_FAIL;
  670. if (_owner->QueryInterface(IID_ITfMouseTrackerACP, (void **)&pTracker) != S_OK)
  671. return E_NOTIMPL;
  672. hr = pTracker->UnadviseMouseSink(dwCookie);
  673. pTracker->Release();
  674. return hr;
  675. }
  676. //+---------------------------------------------------------------------------
  677. //
  678. // QueryInsertEmbedded
  679. //
  680. //----------------------------------------------------------------------------
  681. STDAPI CTextStoreImpl::QueryInsertEmbedded(const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable)
  682. {
  683. Assert(pfInsertable != NULL); // cicero should have caught this
  684. *pfInsertable = FALSE;
  685. // only accept unicode text
  686. if (pguidService == NULL &&
  687. pFormatEtc != NULL &&
  688. pFormatEtc->cfFormat == CF_UNICODETEXT &&
  689. pFormatEtc->dwAspect == DVASPECT_CONTENT &&
  690. pFormatEtc->lindex == -1 &&
  691. pFormatEtc->tymed == TYMED_HGLOBAL)
  692. {
  693. *pfInsertable = TRUE;
  694. }
  695. return S_OK;
  696. }
  697. //+---------------------------------------------------------------------------
  698. //
  699. // InsertTextAtSelection
  700. //
  701. //----------------------------------------------------------------------------
  702. STDAPI CTextStoreImpl::InsertTextAtSelection(DWORD dwFlags, const WCHAR *pchText,
  703. ULONG cch, LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
  704. {
  705. HRESULT hr;
  706. Assert((dwFlags & TS_IAS_QUERYONLY) || pchText != NULL); // caller should have already caught this
  707. Assert((dwFlags & TS_IAS_QUERYONLY) || cch > 0); // caller should have already caught this
  708. Assert(pacpStart != NULL && pacpEnd != NULL); // caller should have already caught this
  709. Assert((dwFlags & (TS_IAS_NOQUERY | TS_IAS_QUERYONLY)) != (TS_IAS_NOQUERY | TS_IAS_QUERYONLY)); // caller should have already caught this
  710. if (dwFlags & TS_IAS_QUERYONLY)
  711. goto Exit;
  712. *pacpStart = -1;
  713. *pacpEnd = -1;
  714. hr = SetText(0, _Sel.acpStart, _Sel.acpEnd, pchText, cch, pChange);
  715. if (hr != S_OK)
  716. return hr;
  717. Exit:
  718. // since this is cheap, always set the insert span even if caller sets TS_IAS_NOQUERY
  719. *pacpStart = _Sel.acpStart;
  720. *pacpEnd = _Sel.acpEnd;
  721. return S_OK;
  722. }
  723. //+---------------------------------------------------------------------------
  724. //
  725. // InsertEmbeddedAtSelection
  726. //
  727. //----------------------------------------------------------------------------
  728. STDAPI CTextStoreImpl::InsertEmbeddedAtSelection(DWORD dwFlags, IDataObject *pDataObject,
  729. LONG *pacpStart, LONG *pacpEnd, TS_TEXTCHANGE *pChange)
  730. {
  731. HRESULT hr;
  732. Assert((dwFlags & TS_IAS_QUERYONLY) || pDataObject != NULL); // caller should have already caught this
  733. Assert(pacpStart != NULL && pacpEnd != NULL); // caller should have already caught this
  734. Assert((dwFlags & (TS_IAS_NOQUERY | TS_IAS_QUERYONLY)) != (TS_IAS_NOQUERY | TS_IAS_QUERYONLY)); // caller should have already caught this
  735. if (dwFlags & TS_IAS_QUERYONLY)
  736. goto Exit;
  737. *pacpStart = -1;
  738. *pacpEnd = -1;
  739. hr = InsertEmbedded(0, _Sel.acpStart, _Sel.acpEnd, pDataObject, pChange);
  740. if (hr != S_OK)
  741. return hr;
  742. Exit:
  743. // since this is cheap, always set the insert span even if caller sets TS_IAS_QUERYONLY
  744. *pacpStart = _Sel.acpStart;
  745. *pacpEnd = _Sel.acpEnd;
  746. return S_OK;
  747. }