Reactos
at master 989 lines 26 kB view raw
1/* 2 * PROJECT: ReactOS CTF 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: ITfContext implementation 5 * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers 6 * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 */ 8 9#include "precomp.h" 10 11#include <wine/debug.h> 12WINE_DEFAULT_DEBUG_CHANNEL(msctf); 13 14//////////////////////////////////////////////////////////////////////////// 15 16class CContext 17 : public ITfContext 18 , public ITfSource 19 // , public ITfContextComposition 20 , public ITfContextOwnerCompositionServices 21 // , public ITfContextOwnerServices 22 , public ITfInsertAtSelection 23 // , public ITfMouseTracker 24 // , public ITfQueryEmbedded 25 , public ITfSourceSingle 26 , public ITextStoreACPSink 27 , public ITextStoreACPServices 28{ 29public: 30 CContext(); 31 virtual ~CContext(); 32 33 static HRESULT CreateInstance( 34 TfClientId tidOwner, 35 IUnknown *punk, 36 ITfDocumentMgr *mgr, 37 ITfContext **ppOut, 38 TfEditCookie *pecTextStore); 39 HRESULT Initialize(ITfDocumentMgr *manager); 40 HRESULT Uninitialize(); 41 42 // ** IUnknown methods ** 43 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override; 44 STDMETHODIMP_(ULONG) AddRef() override; 45 STDMETHODIMP_(ULONG) Release() override; 46 47 // ** ITfContext methods ** 48 STDMETHODIMP RequestEditSession( 49 _In_ TfClientId tid, 50 _In_ ITfEditSession *pes, 51 _In_ DWORD dwFlags, 52 _Out_ HRESULT *phrSession) override; 53 STDMETHODIMP InWriteSession( 54 _In_ TfClientId tid, 55 _Out_ BOOL *pfWriteSession) override; 56 STDMETHODIMP GetSelection( 57 _In_ TfEditCookie ec, 58 _In_ ULONG ulIndex, 59 _In_ ULONG ulCount, 60 _Out_ TF_SELECTION *pSelection, 61 _Out_ ULONG *pcFetched) override; 62 STDMETHODIMP SetSelection( 63 _In_ TfEditCookie ec, 64 _In_ ULONG ulCount, 65 _In_ const TF_SELECTION *pSelection) override; 66 STDMETHODIMP GetStart( 67 _In_ TfEditCookie ec, 68 _Out_ ITfRange **ppStart) override; 69 STDMETHODIMP GetEnd( 70 _In_ TfEditCookie ec, 71 _Out_ ITfRange **ppEnd) override; 72 STDMETHODIMP GetActiveView(_Out_ ITfContextView **ppView) override; 73 STDMETHODIMP EnumViews(_Out_ IEnumTfContextViews **ppEnum) override; 74 STDMETHODIMP GetStatus(_Out_ TF_STATUS *pdcs) override; 75 STDMETHODIMP GetProperty( 76 _In_ REFGUID guidProp, 77 _Out_ ITfProperty **ppProp) override; 78 STDMETHODIMP GetAppProperty( 79 _In_ REFGUID guidProp, 80 _Out_ ITfReadOnlyProperty **ppProp) override; 81 STDMETHODIMP TrackProperties( 82 _In_ const GUID **prgProp, 83 _In_ ULONG cProp, 84 _In_ const GUID **prgAppProp, 85 _In_ ULONG cAppProp, 86 _Out_ ITfReadOnlyProperty **ppProperty) override; 87 STDMETHODIMP EnumProperties(_Out_ IEnumTfProperties **ppEnum) override; 88 STDMETHODIMP GetDocumentMgr(_Out_ ITfDocumentMgr **ppDm) override; 89 STDMETHODIMP CreateRangeBackup( 90 _In_ TfEditCookie ec, 91 _In_ ITfRange *pRange, 92 _Out_ ITfRangeBackup **ppBackup) override; 93 94 // ** ITfSource methods ** 95 STDMETHODIMP AdviseSink( 96 _In_ REFIID riid, 97 _In_ IUnknown *punk, 98 _Out_ DWORD *pdwCookie) override; 99 STDMETHODIMP UnadviseSink(_In_ DWORD dwCookie) override; 100 101 // ** ITfContextOwnerCompositionServices methods ** 102 STDMETHODIMP StartComposition( 103 _In_ TfEditCookie ecWrite, 104 _In_ ITfRange *pCompositionRange, 105 _In_ ITfCompositionSink *pSink, 106 _Out_ ITfComposition **ppComposition) override; 107 STDMETHODIMP EnumCompositions(_Out_ IEnumITfCompositionView **ppEnum) override; 108 STDMETHODIMP FindComposition( 109 _In_ TfEditCookie ecRead, 110 _In_ ITfRange *pTestRange, 111 _Out_ IEnumITfCompositionView **ppEnum) override; 112 STDMETHODIMP TakeOwnership( 113 _In_ TfEditCookie ecWrite, 114 _In_ ITfCompositionView *pComposition, 115 _In_ ITfCompositionSink *pSink, 116 _Out_ ITfComposition **ppComposition) override; 117 STDMETHODIMP TerminateComposition(_In_ ITfCompositionView *pComposition) override; 118 119 // ** ITfInsertAtSelection methods ** 120 STDMETHODIMP InsertTextAtSelection( 121 _In_ TfEditCookie ec, 122 _In_ DWORD dwFlags, 123 _In_ const WCHAR *pchText, 124 _In_ LONG cch, 125 _Out_ ITfRange **ppRange) override; 126 STDMETHODIMP InsertEmbeddedAtSelection( 127 _In_ TfEditCookie ec, 128 _In_ DWORD dwFlags, 129 _In_ IDataObject *pDataObject, 130 _Out_ ITfRange **ppRange) override; 131 132 // ** ITfSourceSingle methods ** 133 STDMETHODIMP AdviseSingleSink( 134 _In_ TfClientId tid, 135 _In_ REFIID riid, 136 _In_ IUnknown *punk) override; 137 STDMETHODIMP UnadviseSingleSink( 138 _In_ TfClientId tid, 139 _In_ REFIID riid) override; 140 141 // ** ITextStoreACPSink methods ** 142 STDMETHODIMP OnTextChange( 143 _In_ DWORD dwFlags, 144 _In_ const TS_TEXTCHANGE *pChange) override; 145 STDMETHODIMP OnSelectionChange() override; 146 STDMETHODIMP OnLayoutChange( 147 _In_ TsLayoutCode lcode, 148 _In_ TsViewCookie vcView) override; 149 STDMETHODIMP OnStatusChange(_In_ DWORD dwFlags) override; 150 STDMETHODIMP OnAttrsChange( 151 _In_ LONG acpStart, 152 _In_ LONG acpEnd, 153 _In_ ULONG cAttrs, 154 _In_ const TS_ATTRID *paAttrs) override; 155 STDMETHODIMP OnLockGranted(_In_ DWORD dwLockFlags) override; 156 STDMETHODIMP OnStartEditTransaction() override; 157 STDMETHODIMP OnEndEditTransaction() override; 158 159 // ** ITextStoreACPServices methods ** 160 STDMETHODIMP Serialize( 161 _In_ ITfProperty *prop, 162 _In_ ITfRange *range, 163 _Out_ TF_PERSISTENT_PROPERTY_HEADER_ACP *header, 164 _In_ IStream *stream) override; 165 STDMETHODIMP Unserialize( 166 _In_ ITfProperty *prop, 167 _In_ const TF_PERSISTENT_PROPERTY_HEADER_ACP *header, 168 _In_ IStream *stream, 169 _In_ ITfPersistentPropertyLoaderACP *loader) override; 170 STDMETHODIMP ForceLoadProperty(_In_ ITfProperty *prop) override; 171 STDMETHODIMP CreateRange( 172 _In_ LONG start, 173 _In_ LONG end, 174 _Out_ ITfRangeACP **range) override; 175 176protected: 177 LONG m_cRefs; 178 BOOL m_connected; 179 180 // Aggregation 181 ITfCompartmentMgr *m_CompartmentMgr; 182 183 TfClientId m_tidOwner; 184 TfEditCookie m_defaultCookie; 185 TS_STATUS m_documentStatus; 186 ITfDocumentMgr *m_manager; 187 188 ITextStoreACP *m_pITextStoreACP; 189 ITfContextOwnerCompositionSink *m_pITfContextOwnerCompositionSink; 190 ITfEditSession *m_currentEditSession; 191 192 // kept as separate lists to reduce unnecessary iterations 193 struct list m_pContextKeyEventSink; 194 struct list m_pEditTransactionSink; 195 struct list m_pStatusSink; 196 struct list m_pTextEditSink; 197 struct list m_pTextLayoutSink; 198}; 199 200//////////////////////////////////////////////////////////////////////////// 201 202typedef struct tagEditCookie 203{ 204 DWORD lockType; 205 CContext *pOwningContext; 206} EditCookie; 207 208//////////////////////////////////////////////////////////////////////////// 209 210CContext::CContext() 211 : m_cRefs(1) 212 , m_connected(FALSE) 213 , m_CompartmentMgr(NULL) 214 , m_manager(NULL) 215 , m_pITextStoreACP(NULL) 216 , m_pITfContextOwnerCompositionSink(NULL) 217 , m_currentEditSession(NULL) 218{ 219 list_init(&m_pContextKeyEventSink); 220 list_init(&m_pEditTransactionSink); 221 list_init(&m_pStatusSink); 222 list_init(&m_pTextEditSink); 223 list_init(&m_pTextLayoutSink); 224} 225 226CContext::~CContext() 227{ 228 EditCookie *cookie; 229 TRACE("destroying %p\n", this); 230 231 if (m_pITextStoreACP) 232 m_pITextStoreACP->Release(); 233 234 if (m_pITfContextOwnerCompositionSink) 235 m_pITfContextOwnerCompositionSink->Release(); 236 237 if (m_defaultCookie) 238 { 239 cookie = (EditCookie *)remove_Cookie(m_defaultCookie); 240 cicMemFree(cookie); 241 m_defaultCookie = 0; 242 } 243 244 free_sinks(&m_pContextKeyEventSink); 245 free_sinks(&m_pEditTransactionSink); 246 free_sinks(&m_pStatusSink); 247 free_sinks(&m_pTextEditSink); 248 free_sinks(&m_pTextLayoutSink); 249 250 if (m_CompartmentMgr) 251 m_CompartmentMgr->Release(); 252} 253 254STDMETHODIMP CContext::QueryInterface(REFIID riid, void **ppvObj) 255{ 256 *ppvObj = NULL; 257 258 IUnknown *pUnk = NULL; 259 if (riid == IID_IUnknown || riid == IID_ITfContext) 260 pUnk = static_cast<ITfContext *>(this); 261 else if (riid == IID_ITfSource) 262 pUnk = static_cast<ITfSource *>(this); 263 else if (riid == IID_ITfContextOwnerCompositionServices) 264 pUnk = static_cast<ITfContextOwnerCompositionServices *>(this); 265 else if (riid == IID_ITfInsertAtSelection) 266 pUnk = static_cast<ITfInsertAtSelection *>(this); 267 else if (riid == IID_ITfCompartmentMgr) 268 pUnk = m_CompartmentMgr; 269 else if (riid == IID_ITfSourceSingle) 270 pUnk = static_cast<ITfSourceSingle *>(this); 271 else if (riid == IID_ITextStoreACPSink) 272 pUnk = static_cast<ITextStoreACPSink *>(this); 273 else if (riid == IID_ITextStoreACPServices) 274 pUnk = static_cast<ITextStoreACPServices *>(this); 275 276 if (pUnk) 277 { 278 pUnk->AddRef(); 279 *ppvObj = pUnk; 280 return S_OK; 281 } 282 283 WARN("unsupported interface: %s\n", debugstr_guid(&riid)); 284 return E_NOINTERFACE; 285} 286 287STDMETHODIMP_(ULONG) CContext::AddRef() 288{ 289 return ::InterlockedIncrement(&m_cRefs); 290} 291 292STDMETHODIMP_(ULONG) CContext::Release() 293{ 294 ULONG ret = ::InterlockedDecrement(&m_cRefs); 295 if (!ret) 296 delete this; 297 return ret; 298} 299 300STDMETHODIMP CContext::RequestEditSession( 301 _In_ TfClientId tid, 302 _In_ ITfEditSession *pes, 303 _In_ DWORD dwFlags, 304 _Out_ HRESULT *phrSession) 305{ 306 HRESULT hr; 307 DWORD dwLockFlags = 0x0; 308 309 TRACE("(%p) %i %p %x %p\n", this, tid, pes, dwFlags, phrSession); 310 311 if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE)) 312 { 313 *phrSession = E_FAIL; 314 return E_INVALIDARG; 315 } 316 317 if (!m_pITextStoreACP) 318 { 319 FIXME("No ITextStoreACP available\n"); 320 *phrSession = E_FAIL; 321 return E_FAIL; 322 } 323 324 if (!(dwFlags & TF_ES_ASYNC)) 325 dwLockFlags |= TS_LF_SYNC; 326 327 if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) 328 dwLockFlags |= TS_LF_READWRITE; 329 else if (dwFlags & TF_ES_READ) 330 dwLockFlags |= TS_LF_READ; 331 332 if (!m_documentStatus.dwDynamicFlags) 333 m_pITextStoreACP->GetStatus(&m_documentStatus); 334 335 if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && 336 (m_documentStatus.dwDynamicFlags & TS_SD_READONLY)) 337 { 338 *phrSession = TS_E_READONLY; 339 return S_OK; 340 } 341 342 hr = pes->QueryInterface(IID_ITfEditSession, (LPVOID *)&m_currentEditSession); 343 if (FAILED(hr)) 344 { 345 *phrSession = E_FAIL; 346 return E_INVALIDARG; 347 } 348 349 return m_pITextStoreACP->RequestLock(dwLockFlags, phrSession); 350} 351 352STDMETHODIMP CContext::InWriteSession( 353 _In_ TfClientId tid, 354 _Out_ BOOL *pfWriteSession) 355{ 356 FIXME("STUB:(%p)\n", this); 357 return E_NOTIMPL; 358} 359 360STDMETHODIMP CContext::GetSelection( 361 _In_ TfEditCookie ec, 362 _In_ ULONG ulIndex, 363 _In_ ULONG ulCount, 364 _Out_ TF_SELECTION *pSelection, 365 _Out_ ULONG *pcFetched) 366{ 367 ULONG count, i; 368 ULONG totalFetched = 0; 369 HRESULT hr = S_OK; 370 371 if (!pSelection || !pcFetched) 372 return E_INVALIDARG; 373 374 *pcFetched = 0; 375 376 if (!m_connected) 377 return TF_E_DISCONNECTED; 378 379 if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE) 380 return TF_E_NOLOCK; 381 382 if (!m_pITextStoreACP) 383 { 384 FIXME("Context does not have a ITextStoreACP\n"); 385 return E_NOTIMPL; 386 } 387 388 count = (ulIndex == (ULONG)TF_DEFAULT_SELECTION) ? 1 : ulCount; 389 390 for (i = 0; i < count; i++) 391 { 392 DWORD fetched; 393 TS_SELECTION_ACP acps; 394 395 hr = m_pITextStoreACP->GetSelection(ulIndex + i, 1, &acps, &fetched); 396 if (hr == TS_E_NOLOCK) 397 return TF_E_NOLOCK; 398 else if (FAILED(hr)) 399 break; 400 401 pSelection[totalFetched].style.ase = (TfActiveSelEnd)acps.style.ase; 402 pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar; 403 Range_Constructor(this, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range); 404 totalFetched++; 405 } 406 407 *pcFetched = totalFetched; 408 return hr; 409} 410 411STDMETHODIMP 412CContext::SetSelection( 413 _In_ TfEditCookie ec, 414 _In_ ULONG ulCount, 415 _In_ const TF_SELECTION *pSelection) 416{ 417 TS_SELECTION_ACP *acp; 418 ULONG i; 419 HRESULT hr; 420 421 TRACE("(%p) %i %i %p\n", this, ec, ulCount, pSelection); 422 423 if (!m_pITextStoreACP) 424 { 425 FIXME("Context does not have a ITextStoreACP\n"); 426 return E_NOTIMPL; 427 } 428 429 if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE) 430 return TF_E_NOLOCK; 431 432 acp = (TS_SELECTION_ACP *)cicMemAlloc(sizeof(TS_SELECTION_ACP) * ulCount); 433 if (!acp) 434 return E_OUTOFMEMORY; 435 436 for (i = 0; i < ulCount; i++) 437 { 438 if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i]))) 439 { 440 TRACE("Selection Conversion Failed\n"); 441 cicMemFree(acp); 442 return E_FAIL; 443 } 444 } 445 446 hr = m_pITextStoreACP->SetSelection(ulCount, acp); 447 448 cicMemFree(acp); 449 450 return hr; 451} 452 453STDMETHODIMP 454CContext::GetStart( 455 _In_ TfEditCookie ec, 456 _Out_ ITfRange **ppStart) 457{ 458 TRACE("(%p) %i %p\n", this, ec, ppStart); 459 460 if (!ppStart) 461 return E_INVALIDARG; 462 463 *ppStart = NULL; 464 465 if (!m_connected) 466 return TF_E_DISCONNECTED; 467 468 if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE) 469 return TF_E_NOLOCK; 470 471 return Range_Constructor(this, 0, 0, ppStart); 472} 473 474STDMETHODIMP 475CContext::GetEnd( 476 _In_ TfEditCookie ec, 477 _Out_ ITfRange **ppEnd) 478{ 479 LONG end; 480 481 TRACE("(%p) %i %p\n", this, ec, ppEnd); 482 483 if (!ppEnd) 484 return E_INVALIDARG; 485 486 *ppEnd = NULL; 487 488 if (!m_connected) 489 return TF_E_DISCONNECTED; 490 491 if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE) 492 return TF_E_NOLOCK; 493 494 if (!m_pITextStoreACP) 495 { 496 FIXME("Context does not have a ITextStoreACP\n"); 497 return E_NOTIMPL; 498 } 499 500 m_pITextStoreACP->GetEndACP(&end); 501 502 return Range_Constructor(this, end, end, ppEnd); 503} 504 505STDMETHODIMP CContext::GetActiveView(_Out_ ITfContextView **ppView) 506{ 507 FIXME("STUB:(%p)\n", this); 508 return E_NOTIMPL; 509} 510 511STDMETHODIMP CContext::EnumViews(_Out_ IEnumTfContextViews **ppEnum) 512{ 513 FIXME("STUB:(%p)\n", this); 514 return E_NOTIMPL; 515} 516 517STDMETHODIMP CContext::GetStatus(_Out_ TF_STATUS *pdcs) 518{ 519 TRACE("(%p) %p\n", this, pdcs); 520 521 if (!m_connected) 522 return TF_E_DISCONNECTED; 523 524 if (!pdcs) 525 return E_INVALIDARG; 526 527 if (!m_pITextStoreACP) 528 { 529 FIXME("Context does not have a ITextStoreACP\n"); 530 return E_NOTIMPL; 531 } 532 533 m_pITextStoreACP->GetStatus(&m_documentStatus); 534 535 *pdcs = m_documentStatus; 536 537 return S_OK; 538} 539 540STDMETHODIMP CContext::GetProperty( 541 _In_ REFGUID guidProp, 542 _Out_ ITfProperty **ppProp) 543{ 544 FIXME("STUB:(%p)\n", this); 545 return E_NOTIMPL; 546} 547 548STDMETHODIMP CContext::GetAppProperty( 549 _In_ REFGUID guidProp, 550 _Out_ ITfReadOnlyProperty **ppProp) 551{ 552 FIXME("STUB:(%p)\n", this); 553 return E_NOTIMPL; 554} 555 556STDMETHODIMP CContext::TrackProperties( 557 _In_ const GUID **prgProp, 558 _In_ ULONG cProp, 559 _In_ const GUID **prgAppProp, 560 _In_ ULONG cAppProp, 561 _Out_ ITfReadOnlyProperty **ppProperty) 562{ 563 FIXME("STUB:(%p)\n", this); 564 return E_NOTIMPL; 565} 566 567STDMETHODIMP CContext::EnumProperties(_Out_ IEnumTfProperties **ppEnum) 568{ 569 FIXME("STUB:(%p)\n", this); 570 return E_NOTIMPL; 571} 572 573STDMETHODIMP CContext::GetDocumentMgr(_Out_ ITfDocumentMgr **ppDm) 574{ 575 TRACE("(%p) %p\n", this, ppDm); 576 577 if (!ppDm) 578 return E_INVALIDARG; 579 580 *ppDm = m_manager; 581 if (!m_manager) 582 return S_FALSE; 583 584 m_manager->AddRef(); 585 return S_OK; 586} 587 588STDMETHODIMP CContext::CreateRangeBackup( 589 _In_ TfEditCookie ec, 590 _In_ ITfRange *pRange, 591 _Out_ ITfRangeBackup **ppBackup) 592{ 593 FIXME("STUB:(%p)\n", this); 594 return E_NOTIMPL; 595} 596 597STDMETHODIMP CContext::AdviseSink( 598 _In_ REFIID riid, 599 _In_ IUnknown *punk, 600 _Out_ DWORD *pdwCookie) 601{ 602 TRACE("(%p) %s %p %p\n", this, debugstr_guid(&riid), punk, pdwCookie); 603 604 if (cicIsNullPtr(&riid) || !punk || !pdwCookie) 605 return E_INVALIDARG; 606 607 if (riid == IID_ITfTextEditSink) 608 return advise_sink(&m_pTextEditSink, IID_ITfTextEditSink, COOKIE_MAGIC_CONTEXTSINK, punk, pdwCookie); 609 610 FIXME("(%p) Unhandled Sink: %s\n", this, debugstr_guid(&riid)); 611 return E_NOTIMPL; 612} 613 614STDMETHODIMP CContext::UnadviseSink(_In_ DWORD dwCookie) 615{ 616 TRACE("(%p) %x\n", this, dwCookie); 617 618 if (get_Cookie_magic(dwCookie) != COOKIE_MAGIC_CONTEXTSINK) 619 return E_INVALIDARG; 620 621 return unadvise_sink(dwCookie); 622} 623 624STDMETHODIMP CContext::StartComposition( 625 _In_ TfEditCookie ecWrite, 626 _In_ ITfRange *pCompositionRange, 627 _In_ ITfCompositionSink *pSink, 628 _Out_ ITfComposition **ppComposition) 629{ 630 FIXME("STUB:(%p) %#x %p %p %p\n", this, ecWrite, pCompositionRange, pSink, ppComposition); 631 return E_NOTIMPL; 632} 633 634STDMETHODIMP CContext::EnumCompositions(_Out_ IEnumITfCompositionView **ppEnum) 635{ 636 FIXME("STUB:(%p) %p\n", this, ppEnum); 637 return E_NOTIMPL; 638} 639 640STDMETHODIMP CContext::FindComposition( 641 _In_ TfEditCookie ecRead, 642 _In_ ITfRange *pTestRange, 643 _Out_ IEnumITfCompositionView **ppEnum) 644{ 645 FIXME("STUB:(%p) %#x %p %p\n", this, ecRead, pTestRange, ppEnum); 646 return E_NOTIMPL; 647} 648 649STDMETHODIMP CContext::TakeOwnership( 650 _In_ TfEditCookie ecWrite, 651 _In_ ITfCompositionView *pComposition, 652 _In_ ITfCompositionSink *pSink, 653 _Out_ ITfComposition **ppComposition) 654{ 655 FIXME("STUB:(%p) %#x %p %p %p\n", this, ecWrite, pComposition, pSink, ppComposition); 656 return E_NOTIMPL; 657} 658 659STDMETHODIMP CContext::TerminateComposition(_In_ ITfCompositionView *pComposition) 660{ 661 FIXME("STUB:(%p) %p\n", this, pComposition); 662 return E_NOTIMPL; 663} 664 665STDMETHODIMP CContext::InsertTextAtSelection( 666 _In_ TfEditCookie ec, 667 _In_ DWORD dwFlags, 668 _In_ const WCHAR *pchText, 669 _In_ LONG cch, 670 _Out_ ITfRange **ppRange) 671{ 672 EditCookie *cookie; 673 LONG acpStart, acpEnd; 674 TS_TEXTCHANGE change; 675 HRESULT hr; 676 677 TRACE("(%p) %i %x %s %p\n", this, ec, dwFlags, debugstr_wn(pchText,cch), ppRange); 678 679 if (!m_connected) 680 return TF_E_DISCONNECTED; 681 682 if (get_Cookie_magic(ec) != COOKIE_MAGIC_EDITCOOKIE) 683 return TF_E_NOLOCK; 684 685 cookie = (EditCookie *)get_Cookie_data(ec); 686 687 if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE) 688 return TS_E_READONLY; 689 690 if (!m_pITextStoreACP) 691 { 692 FIXME("Context does not have a ITextStoreACP\n"); 693 return E_NOTIMPL; 694 } 695 696 hr = m_pITextStoreACP->InsertTextAtSelection(dwFlags, pchText, cch, &acpStart, &acpEnd, &change); 697 if (SUCCEEDED(hr)) 698 Range_Constructor(this, change.acpStart, change.acpNewEnd, ppRange); 699 700 return hr; 701} 702 703STDMETHODIMP CContext::InsertEmbeddedAtSelection( 704 _In_ TfEditCookie ec, 705 _In_ DWORD dwFlags, 706 _In_ IDataObject *pDataObject, 707 _Out_ ITfRange **ppRange) 708{ 709 FIXME("STUB:(%p)\n", this); 710 return E_NOTIMPL; 711} 712 713STDMETHODIMP CContext::AdviseSingleSink( 714 _In_ TfClientId tid, 715 _In_ REFIID riid, 716 _In_ IUnknown *punk) 717{ 718 FIXME("STUB:(%p) %i %s %p\n", this, tid, debugstr_guid(&riid), punk); 719 return E_NOTIMPL; 720} 721 722STDMETHODIMP CContext::UnadviseSingleSink( 723 _In_ TfClientId tid, 724 _In_ REFIID riid) 725{ 726 FIXME("STUB:(%p) %i %s\n", this, tid, debugstr_guid(&riid)); 727 return E_NOTIMPL; 728} 729 730STDMETHODIMP CContext::OnTextChange( 731 _In_ DWORD dwFlags, 732 _In_ const TS_TEXTCHANGE *pChange) 733{ 734 FIXME("STUB:(%p)\n", this); 735 return S_OK; 736} 737 738STDMETHODIMP CContext::OnSelectionChange() 739{ 740 FIXME("STUB:(%p)\n", this); 741 return S_OK; 742} 743 744STDMETHODIMP CContext::OnLayoutChange( 745 _In_ TsLayoutCode lcode, 746 _In_ TsViewCookie vcView) 747{ 748 FIXME("STUB:(%p)\n", this); 749 return S_OK; 750} 751 752STDMETHODIMP CContext::OnStatusChange(_In_ DWORD dwFlags) 753{ 754 HRESULT hr, hrSession; 755 756 TRACE("(%p) %x\n", this, dwFlags); 757 758 if (!m_pITextStoreACP) 759 { 760 FIXME("Context does not have a ITextStoreACP\n"); 761 return E_NOTIMPL; 762 } 763 764 hr = m_pITextStoreACP->RequestLock(TS_LF_READ, &hrSession); 765 766 if(SUCCEEDED(hr) && SUCCEEDED(hrSession)) 767 m_documentStatus.dwDynamicFlags = dwFlags; 768 769 return S_OK; 770} 771 772STDMETHODIMP CContext::OnAttrsChange( 773 _In_ LONG acpStart, 774 _In_ LONG acpEnd, 775 _In_ ULONG cAttrs, 776 _In_ const TS_ATTRID *paAttrs) 777{ 778 FIXME("STUB:(%p)\n", this); 779 return E_NOTIMPL; 780} 781 782STDMETHODIMP CContext::OnLockGranted(_In_ DWORD dwLockFlags) 783{ 784 HRESULT hr; 785 EditCookie *cookie, *sinkcookie; 786 TfEditCookie ec; 787 struct list *cursor; 788 789 TRACE("(%p) %x\n", this, dwLockFlags); 790 791 if (!m_currentEditSession) 792 { 793 FIXME("OnLockGranted called for something other than an EditSession\n"); 794 return S_OK; 795 } 796 797 cookie = (EditCookie *)cicMemAlloc(sizeof(EditCookie)); 798 if (!cookie) 799 return E_OUTOFMEMORY; 800 801 sinkcookie = (EditCookie *)cicMemAlloc(sizeof(EditCookie)); 802 if (!sinkcookie) 803 { 804 cicMemFree(cookie); 805 return E_OUTOFMEMORY; 806 } 807 808 cookie->lockType = dwLockFlags; 809 cookie->pOwningContext = this; 810 ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie); 811 812 hr = m_currentEditSession->DoEditSession(ec); 813 814 if ((dwLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) 815 { 816 ITfTextEditSink *sink; 817 TfEditCookie sc; 818 819 sinkcookie->lockType = TS_LF_READ; 820 sinkcookie->pOwningContext = this; 821 sc = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, sinkcookie); 822 823 /*TODO: implement ITfEditRecord */ 824 SINK_FOR_EACH(cursor, &m_pTextEditSink, ITfTextEditSink, sink) 825 { 826 sink->OnEndEdit(static_cast<ITfContext *>(this), sc, NULL); 827 } 828 sinkcookie = (EditCookie *)remove_Cookie(sc); 829 } 830 cicMemFree(sinkcookie); 831 832 m_currentEditSession->Release(); 833 m_currentEditSession = NULL; 834 835 /* Edit Cookie is only valid during the edit session */ 836 cookie = (EditCookie *)remove_Cookie(ec); 837 cicMemFree(cookie); 838 839 return hr; 840} 841 842STDMETHODIMP CContext::OnStartEditTransaction() 843{ 844 FIXME("STUB:(%p)\n", this); 845 return E_NOTIMPL; 846} 847 848STDMETHODIMP CContext::OnEndEditTransaction() 849{ 850 FIXME("STUB:(%p)\n", this); 851 return E_NOTIMPL; 852} 853 854STDMETHODIMP CContext::Serialize( 855 _In_ ITfProperty *prop, 856 _In_ ITfRange *range, 857 _Out_ TF_PERSISTENT_PROPERTY_HEADER_ACP *header, 858 _In_ IStream *stream) 859{ 860 FIXME("stub: %p %p %p %p %p\n", this, prop, range, header, stream); 861 return E_NOTIMPL; 862} 863 864STDMETHODIMP CContext::Unserialize( 865 _In_ ITfProperty *prop, 866 _In_ const TF_PERSISTENT_PROPERTY_HEADER_ACP *header, 867 _In_ IStream *stream, 868 _In_ ITfPersistentPropertyLoaderACP *loader) 869{ 870 FIXME("stub: %p %p %p %p %p\n", this, prop, header, stream, loader); 871 return E_NOTIMPL; 872} 873 874STDMETHODIMP CContext::ForceLoadProperty(_In_ ITfProperty *prop) 875{ 876 FIXME("stub: %p %p\n", this, prop); 877 return E_NOTIMPL; 878} 879 880STDMETHODIMP CContext::CreateRange( 881 _In_ LONG start, 882 _In_ LONG end, 883 _Out_ ITfRangeACP **range) 884{ 885 FIXME("stub: %p %d %d %p\n", this, start, end, range); 886 return S_OK; 887} 888 889HRESULT CContext::CreateInstance( 890 TfClientId tidOwner, 891 IUnknown *punk, 892 ITfDocumentMgr *mgr, 893 ITfContext **ppOut, 894 TfEditCookie *pecTextStore) 895{ 896 CContext *This = new(cicNoThrow) CContext(); 897 if (!This) 898 return E_OUTOFMEMORY; 899 900 EditCookie *cookie = (EditCookie *)cicMemAlloc(sizeof(EditCookie)); 901 if (!cookie) 902 { 903 delete This; 904 return E_OUTOFMEMORY; 905 } 906 907 TRACE("(%p) %x %p %p %p\n", This, tidOwner, punk, ppOut, pecTextStore); 908 909 This->m_tidOwner = tidOwner; 910 This->m_manager = mgr; 911 912 CompartmentMgr_Constructor(static_cast<ITfContext *>(This), IID_IUnknown, (IUnknown **)&This->m_CompartmentMgr); 913 914 cookie->lockType = TF_ES_READ; 915 cookie->pOwningContext = This; 916 917 if (punk) 918 { 919 punk->QueryInterface(IID_ITextStoreACP, (LPVOID*)&This->m_pITextStoreACP); 920 punk->QueryInterface(IID_ITfContextOwnerCompositionSink, (LPVOID*)&This->m_pITfContextOwnerCompositionSink); 921 922 if (!This->m_pITextStoreACP && !This->m_pITfContextOwnerCompositionSink) 923 FIXME("Unhandled pUnk\n"); 924 } 925 926 This->m_defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie); 927 *pecTextStore = This->m_defaultCookie; 928 929 list_init(&This->m_pContextKeyEventSink); 930 list_init(&This->m_pEditTransactionSink); 931 list_init(&This->m_pStatusSink); 932 list_init(&This->m_pTextEditSink); 933 list_init(&This->m_pTextLayoutSink); 934 935 *ppOut = static_cast<ITfContext *>(This); 936 TRACE("returning %p\n", *ppOut); 937 938 return S_OK; 939} 940 941HRESULT CContext::Initialize(ITfDocumentMgr *manager) 942{ 943 if (m_pITextStoreACP) 944 { 945 m_pITextStoreACP->AdviseSink(IID_ITextStoreACPSink, 946 static_cast<ITextStoreACPSink *>(this), 947 TS_AS_ALL_SINKS); 948 } 949 m_connected = TRUE; 950 m_manager = manager; 951 return S_OK; 952} 953 954HRESULT CContext::Uninitialize() 955{ 956 if (m_pITextStoreACP) 957 m_pITextStoreACP->UnadviseSink(static_cast<ITextStoreACPSink *>(this)); 958 m_connected = FALSE; 959 m_manager = NULL; 960 return S_OK; 961} 962 963//////////////////////////////////////////////////////////////////////////// 964 965EXTERN_C 966HRESULT 967Context_Constructor( 968 TfClientId tidOwner, 969 IUnknown *punk, 970 ITfDocumentMgr *mgr, 971 ITfContext **ppOut, 972 TfEditCookie *pecTextStore) 973{ 974 return CContext::CreateInstance(tidOwner, punk, mgr, ppOut, pecTextStore); 975} 976 977EXTERN_C 978HRESULT Context_Initialize(ITfContext *iface, ITfDocumentMgr *manager) 979{ 980 CContext *This = static_cast<CContext *>(iface); 981 return This->Initialize(manager); 982} 983 984EXTERN_C 985HRESULT Context_Uninitialize(ITfContext *iface) 986{ 987 CContext *This = static_cast<CContext *>(iface); 988 return This->Uninitialize(); 989}