Eigenschappen (algemene elementen)
Text Services Framework (TSF) biedt eigenschappen die metagegevens koppelen aan een tekstbereik. Deze eigenschappen omvatten, maar zijn niet beperkt tot, weergavekenmerken zoals vetgedrukte tekst, de taal-id van de tekst en onbewerkte gegevens die worden geleverd door een tekstservice, zoals de audiogegevens die zijn gekoppeld aan tekst uit de spraaktekstservice.
In het volgende voorbeeld ziet u hoe een hypothetische tekstkleureigenschap met mogelijke waarden rood (R), groen (G) of blauw (B) kan worden bekeken.
COLOR: RR GGGGGGGG
TEXT: this is some colored text
Eigenschappen van verschillende typen kunnen elkaar overlappen. Neem bijvoorbeeld het vorige voorbeeld en voeg een tekstkenmerk toe dat vet (B) of cursief (I) kan zijn.
ATTRIB:BBBBBBB IIIIIIIIIIII
COLOR: RR GGGGGGGG
TEXT: this is some colored text
De tekst "this" zou vet zijn, "is" zou zowel vet als rood zijn, "sommige" zou normaal worden weergegeven, "gekleurde" zou groen en cursief zijn en "tekst" cursief zou zijn.
Eigenschappen van hetzelfde type mogen niet overlappen. De volgende situatie is bijvoorbeeld niet toegestaan omdat 'is' en 'gekleurd' overlappende waarden van dezelfde typen hebben.
COLOR: GGG GGGG RRR BBBBGGG
COLOR: RR GGGGGGGG
TEXT: this is some colored text
Eigenschapstypen
TSF definieert drie verschillende typen eigenschappen.
Eigenschapstype | Beschrijving |
---|---|
Statisch | In een statisch eigenschapsobject worden de eigenschapsgegevens met tekst opgeslagen. Het slaat ook het tekstbereik op voor elk bereik waarop de eigenschap van toepassing is. ITfReadOnlyProperty::GetType retourneert de GUID_TFCAT_PROPSTYLE_STATIC categorie. |
Static-Compact | Een statisch compact eigenschapsobject is identiek aan een statisch eigenschapsobject, behalve een statische compacte eigenschap slaat geen bereikgegevens op. Wanneer het bereik dat wordt gedekt door een eigenschap statisch compact wordt aangevraagd, wordt er een bereik gemaakt voor elke groep aangrenzende eigenschappen. Statische compacte eigenschappen zijn de meest efficiënte manier om eigenschappen per teken op te slaan. ITfReadOnlyProperty::GetType retourneert de GUID_TFCAT_PROPSTYLE_STATICCOMPACT categorie. |
Gewoonte | In een aangepast eigenschapsobject worden de bereikgegevens opgeslagen voor elk bereik waarop de eigenschap van toepassing is. De werkelijke gegevens voor de eigenschap worden echter niet opgeslagen. In plaats daarvan slaat een aangepaste eigenschap een ITfPropertyStore-object op. De TSF-manager gebruikt dit object om de eigenschapsgegevens te openen en te onderhouden. ITfReadOnlyProperty::GetType retourneert de GUID_TFCAT_PROPSTYLE_CUSTOM categorie. |
Werken met eigenschappen
De eigenschapswaarde en -kenmerken worden verkregen met behulp van de interface ITfReadOnlyProperty en gewijzigd met behulp van de interface ITfProperty.
Als een specifiek eigenschapstype is vereist, wordt ITfContext::GetProperty gebruikt. ITfContext::GetProperty vereist een GUID- waarmee de eigenschap wordt geïdentificeerd die moet worden opgehaald. TSF definieert een set vooraf gedefinieerde eigenschaps-id's gebruikt of een tekstservice kan eigen eigenschaps-id's definiëren. Als een aangepaste eigenschap wordt gebruikt, moet de eigenschapsprovider de eigenschap publiceren GUID- en de indeling van de verkregen gegevens.
Als u bijvoorbeeld de CLSID- voor de eigenaar van een tekstbereik wilt ophalen, roept u ITfContext::GetProperty- aan om het eigenschapsobject te verkrijgen, ITfProperty::FindRange aanroepen om het bereik te verkrijgen dat de eigenschap volledig omvat, roept u vervolgens ITfReadOnlyProperty::GetValue aan om een TfGuidAtom- te verkrijgen die de CLSID- van de tekstservice vertegenwoordigt die eigenaar is van de tekst. In het volgende voorbeeld ziet u een functie die, gezien een context, bereik en een bewerkingscooky, de CLSID- van de tekstservice krijgt die eigenaar is van de tekst.
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;
}
Eigenschappen kunnen ook worden geïnventariseerd door een IEnumTfProperties interface te verkrijgen van ITfContext::EnumProperties.
Permanente opslag van eigenschappen
Eigenschappen zijn vaak transparant voor een toepassing en worden gebruikt door een of meer tekstservices. Als u de eigenschapsgegevens wilt behouden, zoals bij het opslaan in een bestand, moet een toepassing de eigenschapsgegevens serialiseren wanneer deze worden opgeslagen en de eigenschapsgegevens ongedaan maken wanneer de gegevens worden hersteld. In dit geval mag de toepassing niet geïnteresseerd zijn in afzonderlijke eigenschappen, maar moet alle eigenschappen in de context worden opgesomd en opgeslagen.
Wanneer u eigenschapsgegevens opslaat, moet een toepassing de volgende stappen uitvoeren.
- Haal een enumerator op door ITfContext::EnumPropertiesaan te roepen.
- Inventariseer elke eigenschap door IEnumTfProperties::Nextaan te roepen.
- Haal voor elke eigenschap een bereik-enumerator op door ITfReadOnlyProperty::EnumRangesaan te roepen.
- Inventariseer elk bereik in de eigenschap door IEnumTfRanges::Nextaan te roepen.
- Roep voor elk bereik in de eigenschap ITextStoreACPServices::Serialize aan met de eigenschap, het bereik, een TF_PERSISTENT_PROPERTY_HEADER_ACP structuur en een stroomobject dat door de toepassing is geïmplementeerd.
- Schrijf de inhoud van de TF_PERSISTENT_PROPERTY_HEADER_ACP structuur naar permanent geheugen.
- Schrijf de inhoud van het streamobject naar permanent geheugen.
- Ga door met de vorige stappen voor alle bereiken in alle eigenschappen.
- De toepassing moet een type afsluiter naar de stroom schrijven, zodat, wanneer de gegevens worden hersteld, een stoppunt kan worden geïdentificeerd.
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
Wanneer u eigenschapsgegevens herstelt, moet een toepassing de volgende stappen uitvoeren.
Stel de streampointer in op het begin van de eerste TF_PERSISTENT_PROPERTY_HEADER_ACP structuur.
Lees de TF_PERSISTENT_PROPERTY_HEADER_ACP structuur.
Roep ITfContext::GetProperty- aan met het guidType lid van de TF_PERSISTENT_PROPERTY_HEADER_ACP-structuur.
De toepassing kan op dit moment een van de twee dingen doen.
- Maak een exemplaar van een ITfPersistentPropertyLoaderACP-object dat de toepassing moet implementeren. Roep vervolgens ITextStoreACPServices::Unserialize aan met NULL- voor pStream- en de ITfPersistentPropertyLoaderACP aanwijzer.
- Geef de invoerstroom door aan ITextStoreACPServices::Unserialize en NULL- voor pLoader-.
De eerste methode heeft de voorkeur omdat dit de meest efficiënte methode is. Als u de tweede methode implementeert, worden alle eigenschapsgegevens uit de stream gelezen tijdens de ITextStoreACPServices::Unserialize aanroep. De eerste methode zorgt ervoor dat de eigenschapsgegevens later op aanvraag worden gelezen.
Herhaal de vorige stappen totdat alle eigenschapsblokken niet worden geserialiseerd.
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;
}