// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "Private.h" #include "SampleIME.h" #include "CompositionProcessorEngine.h" #include "LanguageBar.h" #include "Globals.h" #include "Compartment.h" //+--------------------------------------------------------------------------- // // CSampleIME::_UpdateLanguageBarOnSetFocus // //---------------------------------------------------------------------------- void CSampleIME::_UpdateLanguageBarOnSetFocus(_In_ ITfDocumentMgr *pDocMgrFocus) { BOOL needDisableButtons = FALSE; if (!pDocMgrFocus) { needDisableButtons = TRUE; } else { IEnumTfContexts* pEnumContext = nullptr; if (FAILED(pDocMgrFocus->EnumContexts(&pEnumContext)) || !pEnumContext) { needDisableButtons = TRUE; } else { ULONG fetched = 0; ITfContext* pContext = nullptr; if (FAILED(pEnumContext->Next(1, &pContext, &fetched)) || fetched != 1) { needDisableButtons = TRUE; } if (!pContext) { // context is not associated needDisableButtons = TRUE; } else { pContext->Release(); } } if (pEnumContext) { pEnumContext->Release(); } } CCompositionProcessorEngine* pCompositionProcessorEngine = nullptr; pCompositionProcessorEngine = _pCompositionProcessorEngine; pCompositionProcessorEngine->SetLanguageBarStatus(TF_LBI_STATUS_DISABLED, needDisableButtons); } //+--------------------------------------------------------------------------- // // CCompositionProcessorEngine::SetLanguageBarStatus // //---------------------------------------------------------------------------- VOID CCompositionProcessorEngine::SetLanguageBarStatus(DWORD status, BOOL isSet) { if (_pLanguageBar_IMEMode) { _pLanguageBar_IMEMode->SetStatus(status, isSet); } if (_pLanguageBar_DoubleSingleByte) { _pLanguageBar_DoubleSingleByte->SetStatus(status, isSet); } if (_pLanguageBar_Punctuation) { _pLanguageBar_Punctuation->SetStatus(status, isSet); } } //+--------------------------------------------------------------------------- // // CLangBarItemButton::ctor // //---------------------------------------------------------------------------- CLangBarItemButton::CLangBarItemButton(REFGUID guidLangBar, LPCWSTR description, LPCWSTR tooltip, DWORD onIconIndex, DWORD offIconIndex, BOOL isSecureMode) { DWORD bufLen = 0; DllAddRef(); // initialize TF_LANGBARITEMINFO structure. _tfLangBarItemInfo.clsidService = Global::SampleIMECLSID; // This LangBarItem belongs to this TextService. _tfLangBarItemInfo.guidItem = guidLangBar; // GUID of this LangBarItem. _tfLangBarItemInfo.dwStyle = (TF_LBI_STYLE_BTN_BUTTON | TF_LBI_STYLE_SHOWNINTRAY); // This LangBar is a button type. _tfLangBarItemInfo.ulSort = 0; // The position of this LangBar Item is not specified. StringCchCopy(_tfLangBarItemInfo.szDescription, ARRAYSIZE(_tfLangBarItemInfo.szDescription), description); // Set the description of this LangBar Item. // Initialize the sink pointer to NULL. _pLangBarItemSink = nullptr; // Initialize ICON index and file name. _onIconIndex = onIconIndex; _offIconIndex = offIconIndex; // Initialize compartment. _pCompartment = nullptr; _pCompartmentEventSink = nullptr; _isAddedToLanguageBar = FALSE; _isSecureMode = isSecureMode; _status = 0; _refCount = 1; // Initialize Tooltip _pTooltipText = nullptr; if (tooltip) { size_t len = 0; if (StringCchLength(tooltip, STRSAFE_MAX_CCH, &len) != S_OK) { len = 0; } bufLen = static_cast(len) + 1; _pTooltipText = (LPCWSTR) new (std::nothrow) WCHAR[ bufLen ]; if (_pTooltipText) { StringCchCopy((LPWSTR)_pTooltipText, bufLen, tooltip); } } } //+--------------------------------------------------------------------------- // // CLangBarItemButton::dtor // //---------------------------------------------------------------------------- CLangBarItemButton::~CLangBarItemButton() { DllRelease(); CleanUp(); } //+--------------------------------------------------------------------------- // // CLangBarItemButton::CleanUp // //---------------------------------------------------------------------------- void CLangBarItemButton::CleanUp() { if (_pTooltipText) { delete [] _pTooltipText; _pTooltipText = nullptr; } ITfThreadMgr* pThreadMgr = nullptr; HRESULT hr = CoCreateInstance(CLSID_TF_ThreadMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfThreadMgr, (void**)&pThreadMgr); if (SUCCEEDED(hr)) { _UnregisterCompartment(pThreadMgr); _RemoveItem(pThreadMgr); pThreadMgr->Release(); pThreadMgr = nullptr; } if (_pCompartment) { delete _pCompartment; _pCompartment = nullptr; } if (_pCompartmentEventSink) { delete _pCompartmentEventSink; _pCompartmentEventSink = nullptr; } } //+--------------------------------------------------------------------------- // // CLangBarItemButton::QueryInterface // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::QueryInterface(REFIID riid, _Outptr_ void **ppvObj) { if (ppvObj == nullptr) { return E_INVALIDARG; } *ppvObj = nullptr; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITfLangBarItem) || IsEqualIID(riid, IID_ITfLangBarItemButton)) { *ppvObj = (ITfLangBarItemButton *)this; } else if (IsEqualIID(riid, IID_ITfSource)) { *ppvObj = (ITfSource *)this; } if (*ppvObj) { AddRef(); return S_OK; } return E_NOINTERFACE; } //+--------------------------------------------------------------------------- // // CLangBarItemButton::AddRef // //---------------------------------------------------------------------------- STDAPI_(ULONG) CLangBarItemButton::AddRef() { return ++_refCount; } //+--------------------------------------------------------------------------- // // CLangBarItemButton::Release // //---------------------------------------------------------------------------- STDAPI_(ULONG) CLangBarItemButton::Release() { LONG cr = --_refCount; assert(_refCount >= 0); if (_refCount == 0) { delete this; } return cr; } //+--------------------------------------------------------------------------- // // GetInfo // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::GetInfo(_Out_ TF_LANGBARITEMINFO *pInfo) { _tfLangBarItemInfo.dwStyle |= TF_LBI_STYLE_SHOWNINTRAY; *pInfo = _tfLangBarItemInfo; return S_OK; } //+--------------------------------------------------------------------------- // // GetStatus // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::GetStatus(_Out_ DWORD *pdwStatus) { if (pdwStatus == nullptr) { E_INVALIDARG; } *pdwStatus = _status; return S_OK; } //+--------------------------------------------------------------------------- // // SetStatus // //---------------------------------------------------------------------------- void CLangBarItemButton::SetStatus(DWORD dwStatus, BOOL fSet) { BOOL isChange = FALSE; if (fSet) { if (!(_status & dwStatus)) { _status |= dwStatus; isChange = TRUE; } } else { if (_status & dwStatus) { _status &= ~dwStatus; isChange = TRUE; } } if (isChange && _pLangBarItemSink) { _pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); } return; } //+--------------------------------------------------------------------------- // // Show // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::Show(BOOL fShow) { fShow; if (_pLangBarItemSink) { _pLangBarItemSink->OnUpdate(TF_LBI_STATUS); } return S_OK; } //+--------------------------------------------------------------------------- // // GetTooltipString // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::GetTooltipString(_Out_ BSTR *pbstrToolTip) { *pbstrToolTip = SysAllocString(_pTooltipText); return (*pbstrToolTip == nullptr) ? E_OUTOFMEMORY : S_OK; } //+--------------------------------------------------------------------------- // // OnClick // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::OnClick(TfLBIClick click, POINT pt, _In_ const RECT *prcArea) { click;pt; prcArea; BOOL isOn = FALSE; _pCompartment->_GetCompartmentBOOL(isOn); _pCompartment->_SetCompartmentBOOL(isOn ? FALSE : TRUE); return S_OK; } //+--------------------------------------------------------------------------- // // InitMenu // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::InitMenu(_In_ ITfMenu *pMenu) { pMenu; return S_OK; } //+--------------------------------------------------------------------------- // // OnMenuSelect // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::OnMenuSelect(UINT wID) { wID; return S_OK; } //+--------------------------------------------------------------------------- // // GetIcon // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::GetIcon(_Out_ HICON *phIcon) { BOOL isOn = FALSE; if (!_pCompartment) { return E_FAIL; } if (!phIcon) { return E_FAIL; } *phIcon = nullptr; _pCompartment->_GetCompartmentBOOL(isOn); DWORD status = 0; GetStatus(&status); // If IME is working on the UAC mode, the size of ICON should be 24 x 24. int desiredSize = 16; if (_isSecureMode) // detect UAC mode { desiredSize = _isSecureMode ? 24 : 16; } if (isOn && !(status & TF_LBI_STATUS_DISABLED)) { if (Global::dllInstanceHandle) { *phIcon = reinterpret_cast(LoadImage(Global::dllInstanceHandle, MAKEINTRESOURCE(_onIconIndex), IMAGE_ICON, desiredSize, desiredSize, 0)); } } else { if (Global::dllInstanceHandle) { *phIcon = reinterpret_cast(LoadImage(Global::dllInstanceHandle, MAKEINTRESOURCE(_offIconIndex), IMAGE_ICON, desiredSize, desiredSize, 0)); } } return (*phIcon != NULL) ? S_OK : E_FAIL; } //+--------------------------------------------------------------------------- // // GetText // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::GetText(_Out_ BSTR *pbstrText) { *pbstrText = SysAllocString(_tfLangBarItemInfo.szDescription); return (*pbstrText == nullptr) ? E_OUTOFMEMORY : S_OK; } //+--------------------------------------------------------------------------- // // AdviseSink // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::AdviseSink(__RPC__in REFIID riid, __RPC__in_opt IUnknown *punk, __RPC__out DWORD *pdwCookie) { // We allow only ITfLangBarItemSink interface. if (!IsEqualIID(IID_ITfLangBarItemSink, riid)) { return CONNECT_E_CANNOTCONNECT; } // We support only one sink once. if (_pLangBarItemSink != nullptr) { return CONNECT_E_ADVISELIMIT; } // Query the ITfLangBarItemSink interface and store it into _pLangBarItemSink. if (punk == nullptr) { return E_INVALIDARG; } if (punk->QueryInterface(IID_ITfLangBarItemSink, (void **)&_pLangBarItemSink) != S_OK) { _pLangBarItemSink = nullptr; return E_NOINTERFACE; } // return our cookie. *pdwCookie = _cookie; return S_OK; } //+--------------------------------------------------------------------------- // // UnadviseSink // //---------------------------------------------------------------------------- STDAPI CLangBarItemButton::UnadviseSink(DWORD dwCookie) { // Check the given cookie. if (dwCookie != _cookie) { return CONNECT_E_NOCONNECTION; } // If there is nno connected sink, we just fail. if (_pLangBarItemSink == nullptr) { return CONNECT_E_NOCONNECTION; } _pLangBarItemSink->Release(); _pLangBarItemSink = nullptr; return S_OK; } //+--------------------------------------------------------------------------- // // _AddItem // //---------------------------------------------------------------------------- HRESULT CLangBarItemButton::_AddItem(_In_ ITfThreadMgr *pThreadMgr) { HRESULT hr = S_OK; ITfLangBarItemMgr* pLangBarItemMgr = nullptr; if (_isAddedToLanguageBar) { return S_OK; } hr = pThreadMgr->QueryInterface(IID_ITfLangBarItemMgr, (void **)&pLangBarItemMgr); if (SUCCEEDED(hr)) { hr = pLangBarItemMgr->AddItem(this); if (SUCCEEDED(hr)) { _isAddedToLanguageBar = TRUE; } pLangBarItemMgr->Release(); } return hr; } //+--------------------------------------------------------------------------- // // _RemoveItem // //---------------------------------------------------------------------------- HRESULT CLangBarItemButton::_RemoveItem(_In_ ITfThreadMgr *pThreadMgr) { HRESULT hr = S_OK; ITfLangBarItemMgr* pLangBarItemMgr = nullptr; if (!_isAddedToLanguageBar) { return S_OK; } hr = pThreadMgr->QueryInterface(IID_ITfLangBarItemMgr, (void **)&pLangBarItemMgr); if (SUCCEEDED(hr)) { hr = pLangBarItemMgr->RemoveItem(this); if (SUCCEEDED(hr)) { _isAddedToLanguageBar = FALSE; } pLangBarItemMgr->Release(); } return hr; } //+--------------------------------------------------------------------------- // // _RegisterCompartment // //---------------------------------------------------------------------------- BOOL CLangBarItemButton::_RegisterCompartment(_In_ ITfThreadMgr *pThreadMgr, TfClientId tfClientId, REFGUID guidCompartment) { _pCompartment = new (std::nothrow) CCompartment(pThreadMgr, tfClientId, guidCompartment); if (_pCompartment) { // Advice ITfCompartmentEventSink _pCompartmentEventSink = new (std::nothrow) CCompartmentEventSink(_CompartmentCallback, this); if (_pCompartmentEventSink) { _pCompartmentEventSink->_Advise(pThreadMgr, guidCompartment); } else { delete _pCompartment; _pCompartment = nullptr; } } return _pCompartment ? TRUE : FALSE; } //+--------------------------------------------------------------------------- // // _UnregisterCompartment // //---------------------------------------------------------------------------- BOOL CLangBarItemButton::_UnregisterCompartment(_In_ ITfThreadMgr *pThreadMgr) { pThreadMgr; if (_pCompartment) { // Unadvice ITfCompartmentEventSink if (_pCompartmentEventSink) { _pCompartmentEventSink->_Unadvise(); } // clear ITfCompartment _pCompartment->_ClearCompartment(); } return TRUE; } //+--------------------------------------------------------------------------- // // _CompartmentCallback // //---------------------------------------------------------------------------- // static HRESULT CLangBarItemButton::_CompartmentCallback(_In_ void *pv, REFGUID guidCompartment) { CLangBarItemButton* fakeThis = (CLangBarItemButton*)pv; GUID guid = GUID_NULL; fakeThis->_pCompartment->_GetGUID(&guid); if (IsEqualGUID(guid, guidCompartment)) { if (fakeThis->_pLangBarItemSink) { fakeThis->_pLangBarItemSink->OnUpdate(TF_LBI_STATUS | TF_LBI_ICON); } } return S_OK; }