#include "private.h" #include "proputil.h" #include "immxutil.h" #include "helpers.h" //+--------------------------------------------------------------------------- // // HrVariantToBlob // // cbvalue: on sizeof VARTYPE // //---------------------------------------------------------------------------- HRESULT HrVariantToBlob(VARIANT *pv, void *pvalue, ULONG *pcbvalue, VARTYPE vt) { HRESULT hr = S_OK; SAFEARRAY *psa = NULL; void *pdata = NULL; int lb, ub; int iElemSize; ULONG cbvalue; while (V_VT(pv) == (VT_BYREF | VT_VARIANT)) pv = V_VARIANTREF(pv); if (V_VT(pv) != (VT_ARRAY | vt)) return E_FAIL; psa = V_ARRAY(pv); hr = SafeArrayLock(psa); if (FAILED(hr)) goto Ret; hr = SafeArrayGetLBound(psa, 1, (LONG *)&lb); if (FAILED(hr)) goto Ret; hr = SafeArrayGetUBound(psa, 1, (LONG *)&ub); if (FAILED(hr)) goto Ret; iElemSize = SafeArrayGetElemsize(psa); cbvalue = ub - lb + 1; if (cbvalue * iElemSize > *pcbvalue) { hr = E_FAIL; goto Ret; } hr = SafeArrayAccessData(psa, (void **)&pdata); if (FAILED(hr)) goto Ret; memcpy(pvalue, pdata, cbvalue * iElemSize); hr = SafeArrayUnaccessData(psa); if (FAILED(hr)) goto Ret; *pcbvalue = cbvalue; Ret: if (psa) SafeArrayUnlock(psa); return hr; } //+--------------------------------------------------------------------------- // // HrBlobToVariant // // cbvalue: on sizeof VARTYPE // //---------------------------------------------------------------------------- HRESULT HrBlobToVariant(const void *value, ULONG cbvalue, VARIANT *pv, VARTYPE vt) { HRESULT hr = S_OK; SAFEARRAY *psa = NULL; SAFEARRAYBOUND rsabound[1]; void *pdata = NULL; int iElemSize; rsabound[0].lLbound = 0; rsabound[0].cElements = cbvalue; if (!(psa = SafeArrayCreate(vt, 1, rsabound))) { hr = E_OUTOFMEMORY; goto Ret; } iElemSize = SafeArrayGetElemsize(psa); hr = SafeArrayAccessData(psa, (void **)&pdata); if (FAILED(hr)) goto Ret; memcpy(pdata, value, cbvalue * iElemSize); hr = SafeArrayUnaccessData(psa); if (FAILED(hr)) goto Ret; V_VT(pv) = VT_ARRAY | vt; V_ARRAY(pv) = psa; psa = NULL; Ret: if (psa) SafeArrayDestroy(psa); return hr; } //+--------------------------------------------------------------------------- // // GetGUIDPropertyData // //---------------------------------------------------------------------------- HRESULT GetGUIDPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, TfGuidAtom *pguid) { VARIANT var; HRESULT hr = E_FAIL; *pguid = TF_INVALID_GUIDATOM; if (SUCCEEDED(pProp->GetValue(ec, pRange, &var))) { if (var.vt == VT_I4) *pguid = (TfGuidAtom)var.lVal; // no need to VariantClear because VT_I4 hr = S_OK; } return hr; } //+--------------------------------------------------------------------------- // // SetGUIDPropertyData // //---------------------------------------------------------------------------- HRESULT SetGUIDPropertyData(LIBTHREAD *plt, TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, REFGUID rguid) { VARIANT var; GUID guid = rguid; var.vt = VT_I4; GetGUIDATOMFromGUID(plt, guid, (TfGuidAtom *)&var.lVal); return pProp->SetValue(ec, pRange, &var); } //+--------------------------------------------------------------------------- // // VarToLangId // //---------------------------------------------------------------------------- WORD VarToWORD(VARIANT *pv) { if (V_VT(pv) == VT_I2) return (WORD)V_I2(pv); return 0; } //+--------------------------------------------------------------------------- // // SetLangToVar // //---------------------------------------------------------------------------- void SetWORDToVar(VARIANT *pv, WORD w) { V_VT(pv) = VT_I2; V_I2(pv) = w; } //+--------------------------------------------------------------------------- // // GetDWORDPropertyData // //---------------------------------------------------------------------------- HRESULT GetDWORDPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, DWORD *pdw) { VARIANT var; HRESULT hr = E_FAIL; if (pProp->GetValue(ec, pRange, &var) == S_OK) { Assert(var.vt == VT_I4); // expecting DWORD *pdw = var.lVal; // no need to VariantClear because VT_I4 hr = S_OK; } return hr; } //+--------------------------------------------------------------------------- // // SetDWORDPropertyData // //---------------------------------------------------------------------------- HRESULT SetDWORDPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, DWORD dw) { VARIANT var; if (!dw) { return pProp->Clear(ec, pRange); } var.vt = VT_I4; var.lVal = dw; return pProp->SetValue(ec, pRange, &var); } //+--------------------------------------------------------------------------- // // GetBSTRPropertyData // //---------------------------------------------------------------------------- HRESULT GetBSTRPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, BSTR *pbstr) { VARIANT var = { 0 }; HRESULT hr = E_FAIL; *pbstr = NULL; if (pProp->GetValue(ec, pRange, &var) != S_OK) return E_FAIL; if (var.vt != VT_BSTR) goto Exit; *pbstr = SysAllocString(var.bstrVal); if (*pbstr) hr = S_OK; else hr = E_OUTOFMEMORY; Exit: VariantClear(&var); return hr; } //+--------------------------------------------------------------------------- // // SetBSTRPropertyData // //---------------------------------------------------------------------------- HRESULT SetBSTRPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, BSTR bstr) { VARIANT var; HRESULT hr; if (!bstr) return pProp->Clear(ec, pRange); var.vt = VT_BSTR; var.bstrVal = SysAllocString(bstr); if (!var.bstrVal) return E_OUTOFMEMORY; hr = pProp->SetValue(ec, pRange, &var); VariantClear(&var); return hr; } //+--------------------------------------------------------------------------- // // GetUnknownPropertyData // //---------------------------------------------------------------------------- HRESULT GetUnknownPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, IUnknown **ppunk) { VARIANT var = { 0 }; *ppunk = NULL; if (pProp->GetValue(ec, pRange, &var) != S_OK) return E_FAIL; if (var.vt != VT_UNKNOWN) goto Exit; *ppunk = var.punkVal; (*ppunk)->AddRef(); Exit: VariantClear(&var); return (*ppunk == NULL) ? E_FAIL : S_OK; } //+--------------------------------------------------------------------------- // // SetUnknownPropertyData // //---------------------------------------------------------------------------- HRESULT SetUnknownPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, IUnknown *punk) { VARIANT var; if (!punk) return pProp->Clear(ec, pRange); var.vt = VT_UNKNOWN; var.punkVal = punk; return pProp->SetValue(ec, pRange, &var); } //+--------------------------------------------------------------------------- // // GetReadingStrPropertyData // //---------------------------------------------------------------------------- HRESULT GetReadingStrPropertyData(TfEditCookie ec, ITfProperty *pProp, ITfRange *pRange, BSTR *pbstr) { return GetBSTRPropertyData(ec, pProp, pRange, pbstr); } //+--------------------------------------------------------------------------- // // SetIntAttribute // //---------------------------------------------------------------------------- void SetIntAttribute(IXMLDOMElement *pElem, WCHAR *pszTag, int nData) { WCHAR wch[32]; NumToW((DWORD)nData, wch); SetCharAttribute(pElem, pszTag, wch); } //+--------------------------------------------------------------------------- // // SetCharAttribute // //---------------------------------------------------------------------------- void SetCharAttribute(IXMLDOMElement *pElem, WCHAR *pszTag, WCHAR *pszData) { VARIANT var; BSTR bstrTmp = SysAllocString(pszTag); BSTR bstrTmp2; if (!bstrTmp) return; bstrTmp2 = SysAllocString(pszData); if (bstrTmp2) { V_VT(&var) = VT_BSTR; V_BSTR(&var) = bstrTmp2; pElem->setAttribute(bstrTmp, var); } VariantClear(&var); SysFreeString(bstrTmp); } //+--------------------------------------------------------------------------- // // GetIntAttribute // //---------------------------------------------------------------------------- HRESULT GetIntAttribute(IXMLDOMElement *pElem, WCHAR *pszTag, int *pnRet) { WCHAR wch[32]; if (FAILED(GetCharAttribute(pElem, pszTag, wch, ARRAYSIZE(wch)))) return E_FAIL; *pnRet = (int)WToNum(wch); return S_OK; } //+--------------------------------------------------------------------------- // // GetCharAttribute // //---------------------------------------------------------------------------- HRESULT GetCharAttribute(IXMLDOMElement *pElem, WCHAR *pszTag, WCHAR *pszData, int nSize) { BSTR bstrTmp; VARIANT var; int nData = 0; HRESULT hr = E_FAIL; *pszData = L'\0'; QuickVariantInit(&var); bstrTmp = SysAllocString(pszTag); if (!bstrTmp) return E_OUTOFMEMORY; if (SUCCEEDED(pElem->getAttribute(bstrTmp, &var))) { if (V_VT(&var) == VT_BSTR) { if (wcsncpy(pszData, V_BSTR(&var), nSize)) hr = S_OK; } } SysFreeString(bstrTmp); VariantClear(&var); return hr; } //+--------------------------------------------------------------------------- // // SetTextAndProperty // //---------------------------------------------------------------------------- HRESULT SetTextAndProperty(LIBTHREAD *plt, TfEditCookie ec, ITfContext *pic, ITfRange *pRange, const WCHAR *pchText, LONG cchText, LANGID langid, const GUID *pattr) { HRESULT hr; // Issue: sometimes we want to set TFST_CORRECTION hr = pRange->SetText(ec, 0, pchText, cchText); if (SUCCEEDED(hr) && cchText) { ITfProperty *pProp = NULL; // set langid if (SUCCEEDED(hr = pic->GetProperty(GUID_PROP_LANGID, &pProp))) { SetLangIdPropertyData(ec, pProp, pRange, langid); pProp->Release(); } if (pattr) { // set attr if (SUCCEEDED(hr = pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp))) { hr = SetAttrPropertyData(plt, ec, pProp, pRange, *pattr); pProp->Release(); } } } return hr; } //+--------------------------------------------------------------------------- // // SetTextAndReading // //---------------------------------------------------------------------------- HRESULT SetTextAndReading(LIBTHREAD *plt, TfEditCookie ec, ITfContext *pic, ITfRange *pRange, const WCHAR *pchText, LONG cchText, LANGID langid, const WCHAR *pszRead) { ITfProperty *pProp; HRESULT hr; hr = SetTextAndProperty(plt, ec, pic, pRange, pchText, cchText, langid, NULL); if (SUCCEEDED(hr = pic->GetProperty(GUID_PROP_READING, &pProp))) { BSTR bstr = SysAllocString(pszRead); if (bstr) { SetBSTRPropertyData(ec, pProp, pRange, bstr); SysFreeString(bstr); } else { hr = E_OUTOFMEMORY; } pProp->Release(); } return hr; } //+--------------------------------------------------------------------------- // // IsOwnerAndFocus // // This is service function for EnumTrackTextAndFocus. // //---------------------------------------------------------------------------- BOOL IsOwnerAndFocus(LIBTHREAD *plt, TfEditCookie ec, REFCLSID rclsid, ITfReadOnlyProperty *pProp, ITfRange *pRange) { IEnumTfPropertyValue *pEnumPropVal; BOOL bRet = FALSE; VARIANT var; ULONG iTextOwner; ULONG iFocus; TF_PROPERTYVAL rgValue[2]; if (SUCCEEDED(pProp->GetValue(ec, pRange, &var))) { Assert(var.vt == VT_UNKNOWN); if (SUCCEEDED(var.punkVal->QueryInterface(IID_IEnumTfPropertyValue, (void **)&pEnumPropVal))) { if (pEnumPropVal->Next(2, rgValue, NULL) == S_OK) { Assert(rgValue[0].varValue.vt == VT_I4); Assert(rgValue[1].varValue.vt == VT_I4); // Issue: should we change the spec so the order is guaranteed maintained? if (IsEqualGUID(rgValue[0].guidId, GUID_PROP_TEXTOWNER)) { Assert(IsEqualGUID(rgValue[1].guidId, GUID_PROP_COMPOSING)); iTextOwner = 0; iFocus = 1; } else { iTextOwner = 1; iFocus = 0; } // does the owner match rclisd? if (IsEqualTFGUIDATOM(plt, (TfGuidAtom)rgValue[iTextOwner].varValue.lVal, rclsid)) { // is the focus property set (not VT_EMPTY) and is it set TRUE? bRet = (rgValue[iFocus].varValue.vt == VT_I4 && rgValue[iFocus].varValue.lVal != 0); } } pEnumPropVal->Release(); } VariantClear(&var); } return bRet; } //+--------------------------------------------------------------------------- // // EnumTrackTextAndFocus // //---------------------------------------------------------------------------- HRESULT EnumTrackTextAndFocus(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, ITfReadOnlyProperty **ppProp, IEnumTfRanges **ppEnumTrack) { static const GUID *rgguidProp[2] = { &GUID_PROP_TEXTOWNER, &GUID_PROP_COMPOSING }; ITfReadOnlyProperty *pPropTrack = NULL; HRESULT hr; *ppEnumTrack = NULL; *ppProp = NULL; if (SUCCEEDED(hr = pic->TrackProperties(rgguidProp, ARRAYSIZE(rgguidProp), 0, NULL, &pPropTrack))) { hr = pPropTrack->EnumRanges(ec, ppEnumTrack, pRange); *ppProp = pPropTrack; } return hr; } //+--------------------------------------------------------------------------- // // IsGUIDProp // //---------------------------------------------------------------------------- BOOL IsGUIDProp(LIBTHREAD *plt, TfEditCookie ec, REFGUID rclsid, ITfProperty *pProp, ITfRange *pRange) { TfGuidAtom guidatom; if (SUCCEEDED(GetGUIDPropertyData(ec, pProp, pRange, &guidatom))) { if (IsEqualTFGUIDATOM(plt, guidatom, rclsid)) { return TRUE; } } return FALSE; } //+--------------------------------------------------------------------------- // // AdjustRangeByProperty // //---------------------------------------------------------------------------- HRESULT AdjustRangeByTextOwner(TfEditCookie ec, ITfContext *pic, ITfRange *pRange, ITfRange **ppRange, REFCLSID rclsid) { ITfProperty *pProp; ITfRange *pRangeStart = NULL; ITfRange *pRangeEnd = NULL; HRESULT hr = E_FAIL; if (SUCCEEDED(pic->GetProperty(GUID_PROP_TEXTOWNER, &pProp))) { BOOL fEmpty = FALSE; pRange->IsEmpty(ec, &fEmpty); if (fEmpty) { pProp->FindRange(ec, pRange, &pRangeStart, TF_ANCHOR_START); } else { pProp->FindRange(ec, pRange, &pRangeStart, TF_ANCHOR_START); pProp->FindRange(ec, pRange, &pRangeEnd, TF_ANCHOR_END); } pProp->Release(); } if (!pRangeStart) goto Exit; if (pRangeEnd) { pRangeStart->ShiftEndToRange(ec, pRangeEnd, TF_ANCHOR_END); } pRangeStart->Clone(ppRange); hr = S_OK; Exit: SafeRelease(pRangeStart); SafeRelease(pRangeEnd); return hr; } //+--------------------------------------------------------------------------- // // AdjustRangeByAttribute // //---------------------------------------------------------------------------- HRESULT AdjustRangeByAttribute(LIBTHREAD *plt, TfEditCookie ec, ITfContext *pic, ITfRange *pRange, ITfRange **ppRange, const GUID *rgRGuid, int cGuid) { ITfProperty *pProp; ITfRange *pRangeStart = NULL; ITfRange *pRangeEnd = NULL; HRESULT hr = E_FAIL; if (SUCCEEDED(pic->GetProperty(GUID_PROP_ATTRIBUTE, &pProp))) { IEnumTfRanges *pEnumProp; if (SUCCEEDED(pProp->EnumRanges(ec, &pEnumProp, pRange))) { ITfRange *pRangeProp; // // first range. // while (!pRangeStart && pEnumProp->Next(1, &pRangeProp, NULL) == S_OK) { for ( int i = 0; i < cGuid; i++ ) { if (IsGUIDProp(plt, ec, rgRGuid[i], pProp, pRangeProp)) { pRangeProp->Clone(&pRangeStart); } } pRangeProp->Release(); } if (pRangeStart) { // // last range. // while (pEnumProp->Next(1, &pRangeProp, NULL) == S_OK) { for ( int i = 0; i < cGuid; i++ ) { if (IsGUIDProp(plt, ec, rgRGuid[i], pProp, pRangeProp)) { SafeRelease(pRangeEnd); pRangeProp->Clone(&pRangeEnd); } } pRangeProp->Release(); } } pEnumProp->Release(); } pProp->Release(); } if (!pRangeStart) goto Exit; if (pRangeEnd) { pRangeStart->ShiftEndToRange(ec, pRangeEnd, TF_ANCHOR_END); } pRangeStart->Clone(ppRange); hr = S_OK; Exit: SafeRelease(pRangeStart); SafeRelease(pRangeEnd); return hr; }