void CMarkTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec) { ITfRange *pRangeComposition; ITfContext *pContext; ITfProperty *pDisplayAttributeProperty; // we need a range and the context it lives in if (_pComposition->GetRange(&pRangeComposition) != S_OK) return; if (pRangeComposition->GetContext(&pContext) != S_OK) { pContext = NULL; goto Exit; } // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) != S_OK) goto Exit; // clear the value over the range pDisplayAttributeProperty->Clear(ec, pRangeComposition); pDisplayAttributeProperty->Release(); Exit: pRangeComposition->Release(); SafeRelease(pContext); }
BOOL CTextService::_SetCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext, TfGuidAtom gaDisplayAttribute) { ITfRange *pRangeComposition; ITfProperty *pDisplayAttributeProperty; HRESULT hr; // we need a range and the context it lives in if (_pComposition->GetRange(&pRangeComposition) != S_OK) return FALSE; hr = E_FAIL; // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) == S_OK) { VARIANT var; // set the value over the range // the application will use this guid atom to lookup the acutal rendering information var.vt = VT_I4; // we're going to set a TfGuidAtom var.lVal = gaDisplayAttribute; hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var); pDisplayAttributeProperty->Release(); } pRangeComposition->Release(); return (hr == S_OK); }
BOOL CSampleIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange) { if (ppRange == nullptr) { return FALSE; } *ppRange = nullptr; // find GUID_PROP_COMPOSING ITfProperty* pPropComp = nullptr; IEnumTfRanges* enumComp = nullptr; /* GetProperty(GUID_PROP_COMPOSING, ...) -- nonzero if text is part of a composition */ HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp); if (FAILED(hr) || pPropComp == nullptr) { return FALSE; } /* EnumRanges: Obtains an enumeration of ranges that contain unique values of the property GUID_PROP_COMPOSING within the given range */ hr = pPropComp->EnumRanges(ec, &enumComp, pSelection); if (FAILED(hr) || enumComp == nullptr) { pPropComp->Release(); return FALSE; } BOOL isCompExist = FALSE; VARIANT var; ULONG fetched = 0; while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1) { hr = pPropComp->GetValue(ec, *ppRange, &var); if (hr == S_OK) { if (var.vt == VT_I4 && var.lVal != 0) { isCompExist = TRUE; break; } } (*ppRange)->Release(); *ppRange = nullptr; } pPropComp->Release(); enumComp->Release(); return isCompExist; }
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext) { ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty) == S_OK) { pProperty->Clear(ec, pRange); SafeRelease(&pProperty); } SafeRelease(&pRange); } }
BOOL CTextService::_SetCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext, ITfRange *pRange, TfGuidAtom gaDisplayAttribute) { HRESULT hr = E_FAIL; ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty) == S_OK) { VARIANT var; var.vt = VT_I4; var.lVal = gaDisplayAttribute; hr = pProperty->SetValue(ec, pRange, &var); SafeRelease(&pProperty); } return (hr == S_OK); }
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext) { if(_IsComposing()) { ITfRange *pRange = nullptr; if(SUCCEEDED(_pComposition->GetRange(&pRange)) && (pRange != nullptr)) { ITfProperty *pProperty = nullptr; if(SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty)) && (pProperty != nullptr)) { pProperty->Clear(ec, pRange); SafeRelease(&pProperty); } SafeRelease(&pRange); } } }
BOOL CSampleIME::_SetCompositionLanguage(TfEditCookie ec, _In_ ITfContext *pContext) { HRESULT hr = S_OK; BOOL ret = TRUE; LANGID langidProfile = 0; GetLanguageProfile(&langidProfile); ITfRange* pRangeComposition = nullptr; ITfProperty* pLanguageProperty = nullptr; // we need a range and the context it lives in hr = _pComposition->GetRange(&pRangeComposition); if (FAILED(hr)) { ret = FALSE; goto Exit; } // get our the language property hr = pContext->GetProperty(GUID_PROP_LANGID, &pLanguageProperty); if (FAILED(hr)) { ret = FALSE; goto Exit; } VARIANT var; var.vt = VT_I4; // we're going to set DWORD var.lVal = langidProfile; hr = pLanguageProperty->SetValue(ec, pRangeComposition, &var); if (FAILED(hr)) { ret = FALSE; goto Exit; } pLanguageProperty->Release(); pRangeComposition->Release(); Exit: return ret; }
void CTextService::_ClearCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext) { ITfRange *pRangeComposition; ITfProperty *pDisplayAttributeProperty; // get the compositon range. if (_pComposition->GetRange(&pRangeComposition) != S_OK) return; // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) == S_OK) { // clear the value over the range pDisplayAttributeProperty->Clear(ec, pRangeComposition); pDisplayAttributeProperty->Release(); } pRangeComposition->Release(); }
BOOL CTextService::_SetCompositionDisplayAttributes(TfEditCookie ec, ITfContext *pContext, ITfRange *pRange, TfGuidAtom gaDisplayAttribute) { HRESULT hr = E_FAIL; ITfProperty *pProperty = nullptr; if(SUCCEEDED(pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pProperty)) && (pProperty != nullptr)) { VARIANT var; VariantInit(&var); V_VT(&var) = VT_I4; V_I4(&var) = gaDisplayAttribute; hr = pProperty->SetValue(ec, pRange, &var); VariantClear(&var); SafeRelease(&pProperty); } return SUCCEEDED(hr); }
STDAPI CStaticPropertyEditSession::DoEditSession(TfEditCookie ec) { ITfProperty *pProperty; TF_SELECTION tfSelection; ULONG cFetched; if (_pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK || cFetched != 1) return S_FALSE; if (_pContext->GetProperty(c_guidPropStatic, &pProperty) == S_OK) { VARIANT var; var.vt = VT_BSTR; var.bstrVal = SysAllocString(_sz); pProperty->SetValue(ec, tfSelection.range, &var); pProperty->Release(); } tfSelection.range->Release(); return S_OK; }
BOOL CMarkTextService::_SetCompositionDisplayAttributes(TfEditCookie ec) { ITfRange *pRangeComposition; ITfContext *pContext; ITfProperty *pDisplayAttributeProperty; VARIANT var; HRESULT hr; // we need a range and the context it lives in if (_pComposition->GetRange(&pRangeComposition) != S_OK) return FALSE; hr = E_FAIL; if (pRangeComposition->GetContext(&pContext) != S_OK) { pContext = NULL; goto Exit; } // get our the display attribute property if (pContext->GetProperty(GUID_PROP_ATTRIBUTE, &pDisplayAttributeProperty) != S_OK) goto Exit; // set the value over the range // the application will use this guid atom to lookup the acutal rendering information var.vt = VT_I4; // we're going to set a TfGuidAtom var.lVal = _gaDisplayAttribute; // our cached guid atom for c_guidMarkDisplayAttribute hr = pDisplayAttributeProperty->SetValue(ec, pRangeComposition, &var); pDisplayAttributeProperty->Release(); Exit: pRangeComposition->Release(); SafeRelease(pContext); return (hr == S_OK); }
BOOL CDIME::_SetCompositionLanguage(TfEditCookie ec, _In_ ITfContext *pContext) { debugPrint(L"CDIME::_SetCompositionLanguage()"); HRESULT hr = S_OK; BOOL ret = TRUE; if (pContext == nullptr || _pComposition == nullptr) { debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pContext or _pComposition"); ret = FALSE; goto Exit; } ITfRange* pRangeComposition = nullptr; ITfProperty* pLanguageProperty = nullptr; // we need a range and the context it lives in hr = _pComposition->GetRange(&pRangeComposition); if (FAILED(hr) || pRangeComposition == nullptr) { if (FAILED(hr)) debugPrint(L"CDIME::_SetCompositionLanguage() _pComposition->GetRange() failed"); else debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pRangeComposition"); ret = FALSE; goto Exit; } // get our the language property hr = pContext->GetProperty(GUID_PROP_LANGID, &pLanguageProperty); if (FAILED(hr) || pLanguageProperty == nullptr) { if (FAILED(hr)) debugPrint(L"CDIME::_SetCompositionLanguage() pContext->GetProperty() failed hr = %x", hr); else debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pLanguageProperty"); ret = FALSE; goto Exit; } VARIANT var; var.vt = VT_I4; // we're going to set DWORD var.lVal = _langid; hr = pLanguageProperty->SetValue(ec, pRangeComposition, &var); if (FAILED(hr) || pRangeComposition == nullptr) { if (FAILED(hr)) debugPrint(L"CDIME::_SetCompositionLanguage() pLanguageProperty->SetValue() failed hr = %x", hr); else debugPrint(L"CDIME::_SetCompositionLanguage() failed with null pRangeComposition "); ret = FALSE; goto Exit; } pLanguageProperty->Release(); pRangeComposition->Release(); Exit: return ret; }
BOOL CDIME::_FindComposingRange(TfEditCookie ec, _In_ ITfContext *pContext, _In_ ITfRange *pSelection, _Outptr_result_maybenull_ ITfRange **ppRange) { debugPrint(L"CDIME::_FindComposingRange()"); if (pContext == nullptr || ppRange == nullptr) { debugPrint(L"CDIME::_FindComposingRange() failed with null pContext or pRange"); return FALSE; } *ppRange = nullptr; // find GUID_PROP_COMPOSING ITfProperty* pPropComp = nullptr; IEnumTfRanges* enumComp = nullptr; HRESULT hr = pContext->GetProperty(GUID_PROP_COMPOSING, &pPropComp); if (FAILED(hr) || pPropComp == nullptr) { if (FAILED(hr)) debugPrint(L"CDIME::_FindComposingRange() pContext->GetProperty() failed"); else debugPrint(L"CDIME::_FindComposingRange() failed with null pPropComp"); return FALSE; } hr = pPropComp->EnumRanges(ec, &enumComp, pSelection); if (FAILED(hr) || enumComp == nullptr) { if (FAILED(hr)) debugPrint(L"CDIME::_FindComposingRange() pPropComp->EnumRanges failed"); else debugPrint(L"CDIME::_FindComposingRange() failed with null enumComp"); pPropComp->Release(); return FALSE; } BOOL isCompExist = FALSE; VARIANT var; ULONG fetched = 0; while (enumComp->Next(1, ppRange, &fetched) == S_OK && fetched == 1) { debugPrint(L"CDIME::_FindComposingRange() enumComp->Next() "); hr = pPropComp->GetValue(ec, *ppRange, &var); if (hr == S_OK) { if (var.vt == VT_I4 && var.lVal != 0) { WCHAR rangeText[4096]; rangeText[0] = NULL; fetched = 0; hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched); if (SUCCEEDED(hr)) { if (lastReadingString.GetLength() > 0) // The last reading string is null when composing is just started and the range should be empty. { debugPrint(L"CDIME::_FindComposingRange() text in range = %s with %d character, last reading string = %s with %d characters", rangeText, fetched, lastReadingString.Get(), lastReadingString.GetLength()); UINT cmpCount = (int)lastReadingString.GetLength(); BOOL rangeMatchReadingString = FALSE; if (fetched > 0 && fetched > cmpCount) { LONG shifted = 0; // range contains other characters than last reading string, and these characters should be skipped with shifting the start anchor (*ppRange)->ShiftStart(ec, fetched - cmpCount, &shifted, NULL); debugPrint(L"CDIME::_FindComposingRange() shift start anchor with %d characters", shifted); rangeText[0] = NULL; hr = (*ppRange)->GetText(ec, 0, rangeText, 4096, &fetched); if (SUCCEEDED(hr)) debugPrint(L"CDIME::_FindComposingRange() text in range with shited anchor = %s with %d character", rangeText, fetched); } // The range we are composing should always matched with the last reading string. rangeMatchReadingString = CompareString(GetLocale(), 0, rangeText, cmpCount, lastReadingString.Get(), cmpCount) == CSTR_EQUAL; if (rangeMatchReadingString) { isCompExist = TRUE; debugPrint(L"CDIME::_FindComposingRange() text in this range mathced with last reading string. isCompExist = TRUE"); break; } } } else { debugPrint(L"CDIME::_FindComposingRange() cannot getText from range isCompExist = TRUE"); } } } debugPrint(L"CDIME::_FindComposingRange() release *ppRange"); if(*ppRange) (*ppRange)->Release(); *ppRange = nullptr; } pPropComp->Release(); enumComp->Release(); return isCompExist; }
HRESULT CTextService::_SetText(TfEditCookie ec, ITfContext *pContext, const std::wstring &text, LONG cchCursor, LONG cchOkuri, BOOL fixed) { TF_SELECTION tfSelection; ULONG cFetched = 0; LONG cch, cchRes; if(pContext == NULL && _pCandidateList != NULL) //辞書登録用 { _pCandidateList->_SetText(text, fixed, FALSE, FALSE); return S_OK; } if(!_IsComposing()) { if(!_StartComposition(pContext)) { return S_FALSE; } } if(pContext->GetSelection(ec, TF_DEFAULT_SELECTION, 1, &tfSelection, &cFetched) != S_OK) { return S_FALSE; } if(cFetched != 1) { SafeRelease(&tfSelection.range); return S_FALSE; } ITfRange *pRange; if(_IsComposing() && _pComposition->GetRange(&pRange) == S_OK) { if(_IsRangeCovered(ec, tfSelection.range, pRange)) { pRange->SetText(ec, 0, text.c_str(), (LONG)text.size()); // shift from end to start. // shift over mathematical operators (U+2200-U+22FF) is rejected by OneNote. if(cchCursor == 0) { cchRes = (LONG)cursoridx - (LONG)kana.size(); if((complement && okuriidx != 0) || (!cx_showmodemark && okuriidx != 0 && cursoridx <= okuriidx && cursoridx < kana.size())) { cchRes += 1; } } else { cchRes = cchCursor - (LONG)text.size(); if(cchRes > 0) { cchRes = 0; } else if(cchRes < -(LONG)text.size()) { cchRes = -(LONG)text.size(); } } tfSelection.range->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStartToRange(ec, pRange, TF_ANCHOR_END); tfSelection.range->ShiftStart(ec, cchRes, &cch, NULL); //decide cursor position tfSelection.range->Collapse(ec, TF_ANCHOR_START); pContext->SetSelection(ec, 1, &tfSelection); //composition attribute if(!fixed) { ITfRange *pRangeClone; if(pRange->Clone(&pRangeClone) == S_OK) { pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); if(cchCursor == 0 || !showentry) { if(inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } } if(!display_attribute_series[1] || !inputkey) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[2]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputOkuri); } if(hintmode && text.find_first_of(CHAR_SKK_HINT) != std::wstring::npos) { LONG hintpos = (LONG)text.find_first_of(CHAR_SKK_HINT); if(cchOkuri < hintpos) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, hintpos, &cch, NULL); _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeInputText); } } } } else { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvMark); if(cx_showmodemark) { pRangeClone->ShiftStart(ec, 1, &cch, NULL); } if(!display_attribute_series[4]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvText); } if(cchOkuri != 0) { pRangeClone->ShiftStartToRange(ec, pRange, TF_ANCHOR_START); pRangeClone->ShiftStart(ec, cchOkuri, &cch, NULL); if(!display_attribute_series[5]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvOkuri); } } pRangeClone->ShiftEndToRange(ec, pRange, TF_ANCHOR_END); pRangeClone->ShiftStartToRange(ec, tfSelection.range, TF_ANCHOR_END); if(!display_attribute_series[6]) { _SetCompositionDisplayAttributes(ec, pContext, pRangeClone, _gaDisplayAttributeConvAnnot); } } SafeRelease(&pRangeClone); } } // for Excel's PHONETIC function if(fixed && !text.empty()) { ITfProperty *pProperty; if(pContext->GetProperty(GUID_PROP_READING, &pProperty) == S_OK) { VARIANT var; var.vt = VT_BSTR; std::wstring phone(kana); if(okuriidx == 0) { switch(inputmode) { case im_hiragana: case im_katakana: case im_katakana_ank: //接辞 if(!abbrevmode && kana.size() >= 2) { if(kana.front() == L'>') { phone = kana.substr(1); } else if(kana.back() == L'>') { phone = kana.substr(0, kana.size() - 1); } } break; default: break; } } else { if(kana.size() > (okuriidx + 1)) { phone = kana.substr(0, okuriidx) + kana.substr(okuriidx + 1); } else if(kana.size() >= okuriidx) { phone = kana.substr(0, okuriidx); } } if(!phone.empty()) { var.bstrVal = SysAllocString(phone.c_str()); pProperty->SetValue(ec, pRange, &var); SysFreeString(var.bstrVal); } SafeRelease(&pProperty); } } } SafeRelease(&pRange); } SafeRelease(&tfSelection.range); return S_OK; }
void CTSFEditWnd::_Save(IStream *pStream) { if(pStream) { HRESULT hr; //write the plain UNICODE text into the stream LPWSTR pwsz; LONG cch; ULONG uWritten; LARGE_INTEGER li; ULONG uSize; //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //get the text if(SUCCEEDED(_GetText(&pwsz, &cch))) { TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader; //write the size, in BYTES, of the text uSize = cch * sizeof(WCHAR); hr = pStream->Write(&uSize, sizeof(ULONG), &uWritten); //write the text, including the NULL_terminator, into the stream hr = pStream->Write(pwsz, uSize, &uWritten); //free the memory allocated by _GetText GlobalFree(pwsz); //enumerate the properties in the context IEnumTfProperties *pEnumProps; hr = m_pContext->EnumProperties(&pEnumProps); if(SUCCEEDED(hr)) { ITfProperty *pProp; ULONG uFetched; while(SUCCEEDED(pEnumProps->Next(1, &pProp, &uFetched)) && uFetched) { //enumerate all the ranges that contain the property IEnumTfRanges *pEnumRanges; hr = pProp->EnumRanges(m_EditCookie, &pEnumRanges, NULL); if(SUCCEEDED(hr)) { IStream *pTempStream; //create a temporary stream to write the property data to hr = CreateStreamOnHGlobal(NULL, TRUE, &pTempStream); if(SUCCEEDED(hr)) { ITfRange *pRange; while(SUCCEEDED(pEnumRanges->Next(1, &pRange, &uFetched)) && uFetched) { //reset the temporary stream's pointer li.QuadPart = 0; pTempStream->Seek(li, STREAM_SEEK_SET, NULL); //get the property header and data for the range hr = m_pServices->Serialize(pProp, pRange, &PropHeader, pTempStream); /* Write the property header into the primary stream. The header also contains the size of the property data. */ hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten); //reset the temporary stream's pointer li.QuadPart = 0; pTempStream->Seek(li, STREAM_SEEK_SET, NULL); //copy the property data from the temporary stream into the primary stream ULARGE_INTEGER uli; uli.QuadPart = PropHeader.cb; hr = pTempStream->CopyTo(pStream, uli, NULL, NULL); pRange->Release(); } pTempStream->Release(); } pEnumRanges->Release(); } pProp->Release(); } pEnumProps->Release(); } //write a property header with zero size and guid into the stream as a terminator ZeroMemory(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP)); hr = pStream->Write(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uWritten); } } }
void CTSFEditWnd::_Load(IStream *pStream) { if(NULL == pStream) { return; } //can't do this if someone has a lock if(_IsLocked(TS_LF_READ)) { return; } _ClearText(); HRESULT hr; ULONG uRead; LARGE_INTEGER li; ULONG uSize; //set the stream pointer to the start of the stream li.QuadPart = 0; pStream->Seek(li, STREAM_SEEK_SET, NULL); //get the size of the text, in BYTES. This is the first ULONG in the stream hr = pStream->Read(&uSize, sizeof(ULONG), &uRead); if(SUCCEEDED(hr) && (sizeof(ULONG) == uRead)) { LPWSTR pwsz; //allocate a buffer for the text plus one NULL character pwsz = (LPWSTR)GlobalAlloc(GPTR, uSize + sizeof(WCHAR)); if(NULL != pwsz) { //get the plain UNICODE text from the stream hr = pStream->Read(pwsz, uSize, &uRead); if(SUCCEEDED(hr) && (uSize == uRead)) { TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader; //put the text into the edit control, but don't send a change notification BOOL fOldNotify = m_fNotify; m_fNotify = FALSE; SetWindowTextW(m_hwndEdit, pwsz); m_fNotify = fOldNotify; /* Read each property header and property data from the stream. The list of properties is terminated by a TF_PERSISTENT_PROPERTY_HEADER_ACP structure with a cb member of zero. */ hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead); while( SUCCEEDED(hr) && (sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP) == uRead) && (0 != PropHeader.cb)) { ITfProperty *pProp; hr = m_pContext->GetProperty(PropHeader.guidType, &pProp); if(SUCCEEDED(hr)) { /* Have TSF read the property data from the stream. This call will request a read lock, so make sure it can be granted or else this method will fail. */ CTSFPersistentPropertyLoader *pLoader = new CTSFPersistentPropertyLoader(&PropHeader, pStream); hr = m_pServices->Unserialize(pProp, &PropHeader, NULL, pLoader); pProp->Release(); } hr = pStream->Read(&PropHeader, sizeof(TF_PERSISTENT_PROPERTY_HEADER_ACP), &uRead); } } GlobalFree(pwsz); } } }