Delen via


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.

  1. Haal een enumerator op door ITfContext::EnumPropertiesaan te roepen.
  2. Inventariseer elke eigenschap door IEnumTfProperties::Nextaan te roepen.
  3. Haal voor elke eigenschap een bereik-enumerator op door ITfReadOnlyProperty::EnumRangesaan te roepen.
  4. Inventariseer elk bereik in de eigenschap door IEnumTfRanges::Nextaan te roepen.
  5. 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.
  6. Schrijf de inhoud van de TF_PERSISTENT_PROPERTY_HEADER_ACP structuur naar permanent geheugen.
  7. Schrijf de inhoud van het streamobject naar permanent geheugen.
  8. Ga door met de vorige stappen voor alle bereiken in alle eigenschappen.
  9. 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.

  1. Stel de streampointer in op het begin van de eerste TF_PERSISTENT_PROPERTY_HEADER_ACP structuur.

  2. Lees de TF_PERSISTENT_PROPERTY_HEADER_ACP structuur.

  3. Roep ITfContext::GetProperty- aan met het guidType lid van de TF_PERSISTENT_PROPERTY_HEADER_ACP-structuur.

  4. De toepassing kan op dit moment een van de twee dingen doen.

    1. 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.
    2. 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.

  5. 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;
}