Vlastnosti (společné elementy)
Text Services Framework (TSF) poskytuje vlastnosti, které přidružují metadata k rozsahu textu. Mezi tyto vlastnosti patří, ale nejsou omezeny na atributy zobrazení, jako je tučný text, identifikátor jazyka textu a nezpracovaná data poskytovaná textovou službou, jako jsou zvuková data přidružená k textu ze služby speech text.
Následující příklad ukazuje, jak lze zobrazit hypotetickou vlastnost barvy textu s možnými hodnotami červené (R), zelené (G) nebo modré (B).
COLOR: RR GGGGGGGG
TEXT: this is some colored text
Vlastnosti různých typů se můžou překrývat. Vezměte například předchozí příklad a přidejte textový atribut, který může být tučný (B) nebo kurzíva (I).
ATTRIB:BBBBBBB IIIIIIIIIIII
COLOR: RR GGGGGGGG
TEXT: this is some colored text
Text "this" by byl tučný, "is" by byl tučný i červený, "some" by se normálně zobrazoval, "barevný" by byl zelený a kurzíva a "text" by byl kurzíva.
Vlastnosti stejného typu se nesmí překrývat. Například následující situace není povolená, protože "is" a "barevné" mají překrývající se hodnoty stejných typů.
COLOR: GGG GGGG RRR BBBBGGG
COLOR: RR GGGGGGGG
TEXT: this is some colored text
Typy vlastností
TSF definuje tři různé typy vlastností.
Typ vlastnosti | Popis |
---|---|
Statický | Objekt statické vlastnosti ukládá data vlastnosti s textem. Ukládá také rozsah textových informací pro každou oblast, na kterou se vlastnost vztahuje. ITfReadOnlyProperty::GetType vrátí GUID_TFCAT_PROPSTYLE_STATIC kategorii. |
Static-Compact | Statický kompaktní objekt vlastnosti je identický se statickým objektem vlastnosti s výjimkou static-kompaktní vlastnost neukládá data rozsahu. Pokud je požadována oblast pokrytá statickou kompaktní vlastností, vytvoří se rozsah pro každou skupinu sousedních vlastností. Statické kompaktní vlastnosti představují nejúčinnější způsob ukládání vlastností na základě jednotlivých znaků. ITfReadOnlyProperty::GetType vrátí kategorii GUID_TFCAT_PROPSTYLE_STATICCOMPACT. |
Zvyk | Objekt vlastní vlastnosti ukládá informace o rozsahu pro každou oblast, na kterou se vlastnost vztahuje. Neukládá však skutečná data pro vlastnost. Místo toho vlastní vlastnost ukládá ITfPropertyStore objekt. Správce TSF používá tento objekt pro přístup k datům vlastností a jejich údržbu. ITfReadOnlyProperty::GetType vrátí kategorii GUID_TFCAT_PROPSTYLE_CUSTOM. |
Práce s vlastnostmi
Hodnota vlastnosti a atributy jsou získány pomocí ITfReadOnlyProperty rozhraní a upraveny pomocí ITfProperty rozhraní.
Pokud je vyžadován konkrétní typ vlastnosti, použije se ITfContext::GetProperty. ITfContext::GetProperty vyžaduje identifikátor GUID, který identifikuje vlastnost k získání. TSF definuje sadu předdefinovaných identifikátorů vlastností použité nebo textové služby může definovat vlastní identifikátory vlastností. Pokud se používá vlastní vlastnost, musí poskytovatel vlastností publikovat vlastnost guid a formát získaných dat.
Chcete-li například získat CLSID pro vlastníka rozsahu textu, zavolejte ITfContext::GetProperty získat objekt vlastnosti, volání ITfProperty::FindRange získat rozsah, který zcela pokrývá vlastnost, pak volání ITfReadOnlyProperty::GetValue získat TfGuidAtom, který představuje CLSID textové služby, která vlastní text. Následující příklad ukazuje funkci, která při zadání kontextu, rozsahu a souboru cookie pro úpravy získá CLSID textové služby, která vlastní text.
HRESULT GetTextOwner( ITfContext *pContext,
ITfRange *pRange,
TfEditCookie ec,
CLSID *pclsidOwner)
{
HRESULT hr;
ITfProperty *pProp;
*pclsidOwner = GUID_NULL;
hr = pContext->GetProperty(GUID_PROP_TEXTOWNER, &pProp);
if(S_OK == hr)
{
ITfRange *pPropRange;
hr = pProp->FindRange(ec, pRange, &pPropRange, TF_ANCHOR_START);
if(S_OK == hr)
{
VARIANT var;
VariantInit(&var);
hr = pProp->GetValue(ec, pPropRange, &var);
if(S_OK == hr)
{
if(VT_I4 == var.vt)
{
/*
var.lVal is a TfGuidAtom that represents the CLSID of the
text owner. Use ITfCategoryMgr to obtain the CLSID from
the TfGuidAtom.
*/
ITfCategoryMgr *pCatMgr;
hr = CoCreateInstance( CLSID_TF_CategoryMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITfCategoryMgr,
(LPVOID*)&pCatMgr);
if(SUCCEEDED(hr))
{
hr = pCatMgr->GetGUID((TfGuidAtom)var.lVal, pclsidOwner);
if(SUCCEEDED(hr))
{
/*
*pclsidOwner now contains the CLSID of the text
service that owns the text at the selection.
*/
}
pCatMgr->Release();
}
}
else
{
//Unrecognized VARIANT type
hr = E_FAIL;
}
VariantClear(&var);
}
pPropRange->Release();
}
pProp->Release();
}
return hr;
}
Vlastnosti lze také získat IEnumTfProperties rozhraní z ITfContext::EnumProperties.
Trvalé úložiště vlastností
Vlastnosti jsou často pro aplikaci transparentní a používají se jednou nebo více textovými službami. Aby bylo možné zachovat data vlastností, například při ukládání do souboru, musí aplikace serializovat data vlastnosti, když jsou uložena a unserializovat data vlastnosti při obnovení dat. V tomto případě by se aplikace neměla zajímat o jednotlivé vlastnosti, ale měla by zobrazit výčet všech vlastností v kontextu a uložit je.
Při ukládání dat vlastností by aplikace měla provést následující kroky.
- Získejte enumerátor vlastnosti voláním ITfContext::EnumProperties.
- Výčet každé vlastnosti voláním IEnumTfProperties::Next.
- Pro každou vlastnost získejte enumerátor rozsahu voláním ITfReadOnlyProperty::EnumRanges.
- Výčet jednotlivých oblastí ve vlastnosti voláním IEnumTfRanges::Next.
- Pro každou oblast ve vlastnosti volejte ITextStoreACPServices::Serialize s vlastností, rozsahem, TF_PERSISTENT_PROPERTY_HEADER_ACP struktury a objekt streamu implementovaný aplikací.
- Zapište obsah struktury TF_PERSISTENT_PROPERTY_HEADER_ACP do trvalé paměti.
- Zapište obsah objektu streamu do trvalé paměti.
- Pokračujte v předchozích krocích pro všechny oblasti ve všech vlastnostech.
- Aplikace by měla do datového proudu napsat nějaký typ ukončovací funkce, aby při obnovení dat bylo možné identifikovat zastavovací bod.
HRESULT SaveProperties( ITfContext *pContext,
ITextStoreACPServices *pServices,
TfEditCookie ec,
IStream *pStream)
{
HRESULT hr;
IEnumTfProperties *pEnumProps;
TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader;
ULONG uWritten;
//Enumerate the properties in the context.
hr = 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(ec, &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)
{
LARGE_INTEGER li;
//Reset the temporary stream pointer.
li.QuadPart = 0;
pTempStream->Seek(li, STREAM_SEEK_SET, NULL);
//Get the property header and data for the range.
hr = 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(PropHeader), &uWritten);
//Reset the temporary stream 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(PropHeader));
hr = pStream->Write(&PropHeader, sizeof(PropHeader), &uWritten);
return hr;
}
ITextStoreACPServices::SerializeITfPropertyStore::Serialize
Při obnovování dat vlastností by aplikace měla provést následující kroky.
Nastavte ukazatel datového proudu na začátek první TF_PERSISTENT_PROPERTY_HEADER_ACP struktury.
Přečtěte si strukturu TF_PERSISTENT_PROPERTY_HEADER_ACP.
Volání ITfContext::GetProperty s guidType člen struktury TF_PERSISTENT_PROPERTY_HEADER_ACP.
V tuto chvíli může aplikace provést jednu ze dvou věcí.
- Vytvořte instanci ITfPersistentPropertyLoaderACP objekt, který musí aplikace implementovat. Potom volejte ITextStoreACPServices::Unserialize s NULL pro pStream a ITfPersistentPropertyLoaderACP ukazatel.
- Předejte vstupní datový proud do ITextStoreACPServices::Unserialize a NULL pro pLoader.
První metoda je upřednostňovaná, protože je nejúčinnější. Implementace druhé metody způsobí, že se všechna data vlastností čtou z datového proudu během ITextStoreACPServices::Unserialize volání. První metoda způsobí, že data vlastností se na vyžádání načítají později.
Opakujte předchozí kroky, dokud nebudou všechny bloky vlastností neserializovány.
HRESULT LoadProperties( ITfContext *pContext,
ITextStoreACPServices *pServices,
IStream *pStream)
{
HRESULT hr;
ULONG uRead;
TF_PERSISTENT_PROPERTY_HEADER_ACP PropHeader;
/*
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(PropHeader), &uRead);
while( SUCCEEDED(hr) &&
(sizeof(PropHeader) == uRead) &&
(0 != PropHeader.cb))
{
ITfProperty *pProp;
hr = pContext->GetProperty(PropHeader.guidType, &pProp);
if(SUCCEEDED(hr))
{
/*
Have TSF read the property data from the stream. This call
requests a read-only lock, so be sure it can be granted
or else this method will fail.
*/
CTSFPersistentPropertyLoader *pLoader = new CTSFPersistentPropertyLoader(&PropHeader, pStream);
hr = pServices->Unserialize(pProp, &PropHeader, NULL, pLoader);
pProp->Release();
}
//Read the next header.
hr = pStream->Read(&PropHeader, sizeof(PropHeader), &uRead);
}
return hr;
}