Reactos
at master 526 lines 12 kB view raw
1/* 2 * PROJECT: ReactOS msctfime.ime 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: The sinks of msctfime.ime 5 * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 6 */ 7 8#include "msctfime.h" 9 10WINE_DEFAULT_DEBUG_CHANNEL(msctfime); 11 12/// @implemented 13CCompartmentEventSink::CCompartmentEventSink(FN_EVENTSINK fnEventSink, LPVOID pUserData) 14 : m_array() 15 , m_cRefs(1) 16 , m_fnEventSink(fnEventSink) 17 , m_pUserData(pUserData) 18{ 19} 20 21/// @implemented 22CCompartmentEventSink::~CCompartmentEventSink() 23{ 24} 25 26/// @implemented 27STDMETHODIMP CCompartmentEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj) 28{ 29 static const QITAB c_tab[] = 30 { 31 QITABENT(CCompartmentEventSink, ITfCompartmentEventSink), 32 { NULL } 33 }; 34 return ::QISearch(this, c_tab, riid, ppvObj); 35} 36 37/// @implemented 38STDMETHODIMP_(ULONG) CCompartmentEventSink::AddRef() 39{ 40 return ::InterlockedIncrement(&m_cRefs); 41} 42 43/// @implemented 44STDMETHODIMP_(ULONG) CCompartmentEventSink::Release() 45{ 46 if (::InterlockedDecrement(&m_cRefs) == 0) 47 { 48 delete this; 49 return 0; 50 } 51 return m_cRefs; 52} 53 54/// @implemented 55STDMETHODIMP CCompartmentEventSink::OnChange(REFGUID rguid) 56{ 57 return m_fnEventSink(m_pUserData, rguid); 58} 59 60/// @implemented 61HRESULT 62CCompartmentEventSink::_Advise(IUnknown *pUnknown, REFGUID rguid, BOOL bThread) 63{ 64 CESMAP *pCesMap = m_array.Append(1); 65 if (!pCesMap) 66 return E_OUTOFMEMORY; 67 68 ITfSource *pSource = NULL; 69 70 HRESULT hr = GetCompartment(pUnknown, rguid, &pCesMap->m_pComp, bThread); 71 if (FAILED(hr)) 72 { 73 hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource); 74 if (FAILED(hr)) 75 { 76 hr = pSource->AdviseSink(IID_ITfCompartmentEventSink, this, &pCesMap->m_dwCookie); 77 if (FAILED(hr)) 78 { 79 if (pCesMap->m_pComp) 80 { 81 pCesMap->m_pComp->Release(); 82 pCesMap->m_pComp = NULL; 83 } 84 m_array.Remove(m_array.size() - 1, 1); 85 } 86 else 87 { 88 hr = S_OK; 89 } 90 } 91 } 92 93 if (pSource) 94 pSource->Release(); 95 96 return hr; 97} 98 99/// @implemented 100HRESULT CCompartmentEventSink::_Unadvise() 101{ 102 CESMAP *pCesMap = m_array.data(); 103 size_t cItems = m_array.size(); 104 if (!cItems) 105 return S_OK; 106 107 do 108 { 109 ITfSource *pSource = NULL; 110 HRESULT hr = pCesMap->m_pComp->QueryInterface(IID_ITfSource, (void **)&pSource); 111 if (SUCCEEDED(hr)) 112 pSource->UnadviseSink(pCesMap->m_dwCookie); 113 114 if (pCesMap->m_pComp) 115 { 116 pCesMap->m_pComp->Release(); 117 pCesMap->m_pComp = NULL; 118 } 119 120 if (pSource) 121 pSource->Release(); 122 123 ++pCesMap; 124 --cItems; 125 } while (cItems); 126 127 return S_OK; 128} 129 130/***********************************************************************/ 131 132/// @implemented 133CTextEventSink::CTextEventSink(FN_ENDEDIT fnEndEdit, LPVOID pCallbackPV) 134{ 135 m_cRefs = 1; 136 m_pUnknown = NULL; 137 m_dwEditSinkCookie = (DWORD)-1; 138 m_dwLayoutSinkCookie = (DWORD)-1; 139 m_fnLayoutChange = NULL; 140 m_fnEndEdit = fnEndEdit; 141 m_pCallbackPV = pCallbackPV; 142} 143 144/// @implemented 145CTextEventSink::~CTextEventSink() 146{ 147} 148 149/// @implemented 150STDMETHODIMP CTextEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj) 151{ 152 static const QITAB c_tab[] = 153 { 154 QITABENT(CTextEventSink, ITfTextEditSink), 155 QITABENT(CTextEventSink, ITfTextLayoutSink), 156 { NULL } 157 }; 158 return ::QISearch(this, c_tab, riid, ppvObj); 159} 160 161/// @implemented 162STDMETHODIMP_(ULONG) CTextEventSink::AddRef() 163{ 164 return ::InterlockedIncrement(&m_cRefs); 165} 166 167/// @implemented 168STDMETHODIMP_(ULONG) CTextEventSink::Release() 169{ 170 if (::InterlockedDecrement(&m_cRefs) == 0) 171 { 172 delete this; 173 return 0; 174 } 175 return m_cRefs; 176} 177 178struct TEXT_EVENT_SINK_END_EDIT 179{ 180 TfEditCookie m_ecReadOnly; 181 ITfEditRecord *m_pEditRecord; 182 ITfContext *m_pContext; 183}; 184 185/// @implemented 186STDMETHODIMP CTextEventSink::OnEndEdit( 187 ITfContext *pic, 188 TfEditCookie ecReadOnly, 189 ITfEditRecord *pEditRecord) 190{ 191 TEXT_EVENT_SINK_END_EDIT Data = { ecReadOnly, pEditRecord, pic }; 192 return m_fnEndEdit(1, m_pCallbackPV, (LPVOID)&Data); 193} 194 195/// @implemented 196STDMETHODIMP CTextEventSink::OnLayoutChange( 197 ITfContext *pContext, 198 TfLayoutCode lcode, 199 ITfContextView *pContextView) 200{ 201 switch (lcode) 202 { 203 case TF_LC_CREATE: 204 return m_fnLayoutChange(3, m_fnEndEdit, pContextView); 205 case TF_LC_CHANGE: 206 return m_fnLayoutChange(2, m_fnEndEdit, pContextView); 207 case TF_LC_DESTROY: 208 return m_fnLayoutChange(4, m_fnEndEdit, pContextView); 209 default: 210 return E_INVALIDARG; 211 } 212} 213 214/// @implemented 215HRESULT CTextEventSink::_Advise(IUnknown *pUnknown, UINT uFlags) 216{ 217 m_pUnknown = NULL; 218 m_uFlags = uFlags; 219 220 ITfSource *pSource = NULL; 221 HRESULT hr = pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource); 222 if (SUCCEEDED(hr)) 223 { 224 ITfTextEditSink *pSink = static_cast<ITfTextEditSink*>(this); 225 if (uFlags & 1) 226 hr = pSource->AdviseSink(IID_ITfTextEditSink, pSink, &m_dwEditSinkCookie); 227 if (SUCCEEDED(hr) && (uFlags & 2)) 228 hr = pSource->AdviseSink(IID_ITfTextLayoutSink, pSink, &m_dwLayoutSinkCookie); 229 230 if (SUCCEEDED(hr)) 231 { 232 m_pUnknown = pUnknown; 233 pUnknown->AddRef(); 234 } 235 else 236 { 237 pSource->UnadviseSink(m_dwEditSinkCookie); 238 } 239 } 240 241 if (pSource) 242 pSource->Release(); 243 244 return hr; 245} 246 247/// @implemented 248HRESULT CTextEventSink::_Unadvise() 249{ 250 if (!m_pUnknown) 251 return E_FAIL; 252 253 ITfSource *pSource = NULL; 254 HRESULT hr = m_pUnknown->QueryInterface(IID_ITfSource, (void**)&pSource); 255 if (SUCCEEDED(hr)) 256 { 257 if (m_uFlags & 1) 258 hr = pSource->UnadviseSink(m_dwEditSinkCookie); 259 if (m_uFlags & 2) 260 hr = pSource->UnadviseSink(m_dwLayoutSinkCookie); 261 262 pSource->Release(); 263 } 264 265 m_pUnknown->Release(); 266 m_pUnknown = NULL; 267 268 return E_NOTIMPL; 269} 270 271/***********************************************************************/ 272 273/// @implemented 274CThreadMgrEventSink::CThreadMgrEventSink( 275 _In_ FN_INITDOCMGR fnInit, 276 _In_ FN_PUSHPOP fnPushPop, 277 _Inout_ LPVOID pvCallbackPV) 278{ 279 m_fnInit = fnInit; 280 m_fnPushPop = fnPushPop; 281 m_pCallbackPV = pvCallbackPV; 282 m_cRefs = 1; 283} 284 285/// @implemented 286STDMETHODIMP CThreadMgrEventSink::QueryInterface(REFIID riid, LPVOID* ppvObj) 287{ 288 static const QITAB c_tab[] = 289 { 290 QITABENT(CThreadMgrEventSink, ITfThreadMgrEventSink), 291 { NULL } 292 }; 293 return ::QISearch(this, c_tab, riid, ppvObj); 294} 295 296/// @implemented 297STDMETHODIMP_(ULONG) CThreadMgrEventSink::AddRef() 298{ 299 return ::InterlockedIncrement(&m_cRefs); 300} 301 302/// @implemented 303STDMETHODIMP_(ULONG) CThreadMgrEventSink::Release() 304{ 305 if (::InterlockedDecrement(&m_cRefs) == 0) 306 { 307 delete this; 308 return 0; 309 } 310 return m_cRefs; 311} 312 313INT CALLBACK 314CThreadMgrEventSink::DIMCallback( 315 UINT nCode, 316 ITfDocumentMgr *pDocMgr1, 317 ITfDocumentMgr *pDocMgr2, 318 LPVOID pUserData) 319{ 320 return E_NOTIMPL; 321} 322 323STDMETHODIMP CThreadMgrEventSink::OnInitDocumentMgr(ITfDocumentMgr *pdim) 324{ 325 if (!m_fnInit) 326 return S_OK; 327 return m_fnInit(0, pdim, NULL, m_pCallbackPV); 328} 329 330STDMETHODIMP CThreadMgrEventSink::OnUninitDocumentMgr(ITfDocumentMgr *pdim) 331{ 332 if (!m_fnInit) 333 return S_OK; 334 return m_fnInit(1, pdim, NULL, m_pCallbackPV); 335} 336 337STDMETHODIMP 338CThreadMgrEventSink::OnSetFocus(ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus) 339{ 340 if (!m_fnInit) 341 return S_OK; 342 return m_fnInit(2, pdimFocus, pdimPrevFocus, m_pCallbackPV); 343} 344 345STDMETHODIMP CThreadMgrEventSink::OnPushContext(ITfContext *pic) 346{ 347 if (!m_fnPushPop) 348 return S_OK; 349 return m_fnPushPop(3, pic, m_pCallbackPV); 350} 351 352STDMETHODIMP CThreadMgrEventSink::OnPopContext(ITfContext *pic) 353{ 354 if (!m_fnPushPop) 355 return S_OK; 356 return m_fnPushPop(4, pic, m_pCallbackPV); 357} 358 359void CThreadMgrEventSink::SetCallbackPV(_Inout_ LPVOID pv) 360{ 361 if (!m_pCallbackPV) 362 m_pCallbackPV = pv; 363} 364 365HRESULT CThreadMgrEventSink::_Advise(ITfThreadMgr *pThreadMgr) 366{ 367 m_pThreadMgr = NULL; 368 369 HRESULT hr = E_FAIL; 370 ITfSource *pSource = NULL; 371 if (pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK && 372 pSource->AdviseSink(IID_ITfThreadMgrEventSink, this, &m_dwCookie) == S_OK) 373 { 374 m_pThreadMgr = pThreadMgr; 375 pThreadMgr->AddRef(); 376 hr = S_OK; 377 } 378 379 if (pSource) 380 pSource->Release(); 381 382 return hr; 383} 384 385HRESULT CThreadMgrEventSink::_Unadvise() 386{ 387 HRESULT hr = E_FAIL; 388 ITfSource *pSource = NULL; 389 390 if (m_pThreadMgr) 391 { 392 if (m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource) == S_OK && 393 pSource->UnadviseSink(m_dwCookie) == S_OK) 394 { 395 hr = S_OK; 396 } 397 398 if (pSource) 399 pSource->Release(); 400 } 401 402 if (m_pThreadMgr) 403 { 404 m_pThreadMgr->Release(); 405 m_pThreadMgr = NULL; 406 } 407 408 return hr; 409} 410 411/***********************************************************************/ 412 413/// @implemented 414CActiveLanguageProfileNotifySink::CActiveLanguageProfileNotifySink( 415 _In_ FN_COMPARE fnCompare, 416 _Inout_opt_ void *pUserData) 417{ 418 m_dwConnection = (DWORD)-1; 419 m_fnCompare = fnCompare; 420 m_cRefs = 1; 421 m_pUserData = pUserData; 422} 423 424/// @implemented 425CActiveLanguageProfileNotifySink::~CActiveLanguageProfileNotifySink() 426{ 427} 428 429/// @implemented 430STDMETHODIMP CActiveLanguageProfileNotifySink::QueryInterface(REFIID riid, LPVOID* ppvObj) 431{ 432 static const QITAB c_tab[] = 433 { 434 QITABENT(CActiveLanguageProfileNotifySink, ITfActiveLanguageProfileNotifySink), 435 { NULL } 436 }; 437 return ::QISearch(this, c_tab, riid, ppvObj); 438} 439 440/// @implemented 441STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::AddRef() 442{ 443 return ::InterlockedIncrement(&m_cRefs); 444} 445 446/// @implemented 447STDMETHODIMP_(ULONG) CActiveLanguageProfileNotifySink::Release() 448{ 449 if (::InterlockedDecrement(&m_cRefs) == 0) 450 { 451 delete this; 452 return 0; 453 } 454 return m_cRefs; 455} 456 457/// @implemented 458STDMETHODIMP 459CActiveLanguageProfileNotifySink::OnActivated( 460 REFCLSID clsid, 461 REFGUID guidProfile, 462 BOOL fActivated) 463{ 464 if (!m_fnCompare) 465 return 0; 466 467 return m_fnCompare(clsid, guidProfile, fActivated, m_pUserData); 468} 469 470/// @implemented 471HRESULT 472CActiveLanguageProfileNotifySink::_Advise( 473 ITfThreadMgr *pThreadMgr) 474{ 475 m_pThreadMgr = NULL; 476 477 ITfSource *pSource = NULL; 478 HRESULT hr = pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource); 479 if (FAILED(hr)) 480 return E_FAIL; 481 482 hr = pSource->AdviseSink(IID_ITfActiveLanguageProfileNotifySink, this, &m_dwConnection); 483 if (SUCCEEDED(hr)) 484 { 485 m_pThreadMgr = pThreadMgr; 486 pThreadMgr->AddRef(); 487 hr = S_OK; 488 } 489 else 490 { 491 hr = E_FAIL; 492 } 493 494 if (pSource) 495 pSource->Release(); 496 497 return hr; 498} 499 500/// @implemented 501HRESULT 502CActiveLanguageProfileNotifySink::_Unadvise() 503{ 504 if (!m_pThreadMgr) 505 return E_FAIL; 506 507 ITfSource *pSource = NULL; 508 HRESULT hr = m_pThreadMgr->QueryInterface(IID_ITfSource, (void **)&pSource); 509 if (SUCCEEDED(hr)) 510 { 511 hr = pSource->UnadviseSink(m_dwConnection); 512 if (SUCCEEDED(hr)) 513 hr = S_OK; 514 } 515 516 if (pSource) 517 pSource->Release(); 518 519 if (m_pThreadMgr) 520 { 521 m_pThreadMgr->Release(); 522 m_pThreadMgr = NULL; 523 } 524 525 return hr; 526}