Dela via


Egenskaper (vanliga element)

Text Services Framework (TSF) tillhandahåller egenskaper som associerar metadata med ett textintervall. Dessa egenskaper omfattar, men är inte begränsade till, visningsattribut som fet text, språkidentifierare för texten och rådata som tillhandahålls av en texttjänst, till exempel ljuddata som är associerade med text från taltexttjänsten.

I följande exempel visas hur en hypotetisk textfärgsegenskap med möjliga värden för rött (R), grönt (G) eller blått (B) kan visas.

COLOR:      RR      GGGGGGGG
TEXT:  this is some colored text

Egenskaper för olika typer kan överlappa varandra. Ta till exempel föregående exempel och lägg till ett textattribut som kan vara fetstil (B) eller kursivt (I).

ATTRIB:BBBBBBB      IIIIIIIIIIII
COLOR:      RR      GGGGGGGG
TEXT:  this is some colored text

Texten "this" skulle vara fet, "is" skulle vara både fet och röd, "vissa" skulle visas normalt, "färgad" skulle vara grön och kursiv och "text" skulle kursiviseras.

Egenskaper av samma typ kan inte överlappa varandra. Följande situation är till exempel inte tillåten eftersom "är" och "färgad" har överlappande värden av samma typer.

COLOR: GGG GGGG RRR BBBBGGG     
COLOR:      RR      GGGGGGGG
TEXT:  this is some colored text

Egenskapstyper

TSF definierar tre olika typer av egenskaper.

Egenskapstyp Beskrivning
Statisk Ett statiskt egenskapsobjekt lagrar egenskapsdata med text. Den lagrar också textinformationsintervallet för varje intervall som egenskapen gäller för. ITfReadOnlyProperty::GetType returnerar kategorin GUID_TFCAT_PROPSTYLE_STATIC.
Static-Compact Ett statiskt kompakt egenskapsobjekt är identiskt med ett statiskt egenskapsobjekt, förutom att en statisk kompakt egenskap inte lagrar intervalldata. När intervallet som omfattas av en statisk kompakt egenskap begärs skapas ett intervall för varje grupp med intilliggande egenskaper. Statisk-kompakta egenskaper är det mest effektiva sättet att lagra egenskaper per tecken. ITfReadOnlyProperty::GetType returnerar kategorin GUID_TFCAT_PROPSTYLE_STATICCOMPACT.
Sed Ett anpassat egenskapsobjekt lagrar intervallinformationen för varje intervall som egenskapen gäller för. Den lagrar dock inte faktiska data för egenskapen. I stället lagrar en anpassad egenskap ett ITfPropertyStore-objekt. TSF-chefen använder det här objektet för att komma åt och underhålla egenskapsdata. ITfReadOnlyProperty::GetType returnerar kategorin GUID_TFCAT_PROPSTYLE_CUSTOM.

 

Arbeta med egenskaper

Egenskapsvärdet och attributen hämtas med hjälp av gränssnittet ITfReadOnlyProperty och ändras med hjälp av gränssnittet ITfProperty.

Om en specifik egenskapstyp krävs används ITfContext::GetProperty. ITfContext::GetProperty kräver en GUID- som identifierar egenskapen som ska hämtas. TSF definierar en uppsättning fördefinierade egenskapsidentifierare används eller en texttjänst kan definiera sina egna egenskapsidentifierare. Om en anpassad egenskap används måste egenskapsprovidern publicera egenskapen GUID- och formatet på de data som hämtas.

Om du till exempel vill hämta CLSID- för ägaren av ett textintervall anropar du ITfContext::GetProperty för att hämta egenskapsobjektet, anropa ITfProperty::FindRange för att hämta det intervall som helt täcker egenskapen och anropa sedan ITfReadOnlyProperty::GetValue för att få en TfGuidAtom- som representerar CLSID- för texttjänsten som äger texten. I följande exempel visas en funktion som med tanke på en kontext, ett intervall och en redigeringscookie hämtar CLSID- för texttjänsten som äger texten.

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

Egenskaper kan också räknas upp genom att hämta ett IEnumTfProperties--gränssnitt från ITfContext::EnumProperties.

Beständig lagring av egenskaper

Egenskaperna är ofta transparenta för ett program och används av en eller flera texttjänster. För att bevara egenskapsdata, till exempel när du sparar i en fil, måste ett program serialisera egenskapsdata när de lagras och inteialisera egenskapsdata när data återställs. I det här fallet bör programmet inte vara intresserat av enskilda egenskaper, men bör räkna upp alla egenskaper i kontexten och lagra dem.

När du lagrar egenskapsdata bör ett program utföra följande steg.

  1. Hämta en egenskapsuppräknare genom att anropa ITfContext::EnumProperties.
  2. Räkna upp varje egenskap genom att anropa IEnumTfProperties::Nästa.
  3. För varje egenskap hämtar du en intervalluppräknare genom att anropa ITfReadOnlyProperty::EnumRanges.
  4. Räkna upp varje intervall i egenskapen genom att anropa IEnumTfRanges::Nästa.
  5. För varje intervall i egenskapen anropar du ITextStoreACPServices::Serialisera med egenskapen, intervallet, en TF_PERSISTENT_PROPERTY_HEADER_ACP struktur och ett stream-objekt som implementeras av programmet.
  6. Skriv innehållet i TF_PERSISTENT_PROPERTY_HEADER_ACP struktur till beständiga minne.
  7. Skriv innehållet i strömobjektet till beständiga minne.
  8. Fortsätt föregående steg för alla intervall i alla egenskaper.
  9. Programmet bör skriva någon typ av avslutare i dataströmmen så att en stopppunkt kan identifieras när data återställs.
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::SerialiseraITfPropertyStore::Serialisera

När du återställer egenskapsdata bör ett program utföra följande steg.

  1. Ange strömpekaren till början av den första TF_PERSISTENT_PROPERTY_HEADER_ACP strukturen.

  2. Läs TF_PERSISTENT_PROPERTY_HEADER_ACP struktur.

  3. Anropa ITfContext::GetProperty med guidType- medlem i TF_PERSISTENT_PROPERTY_HEADER_ACP-strukturen.

  4. Programmet kan göra en av två saker just nu.

    1. Skapa en instans av en ITfPersistentPropertyLoaderACP objekt som programmet måste implementera. Anropa sedan ITextStoreACPServices::Unserialize with NULL for pStream and the ITfPersistentPropertyLoaderACP pointer.
    2. Skicka indataströmmen till ITextStoreACPServices::Unserialize and NULL for pLoader.

    Den första metoden är att föredra eftersom den är den mest effektiva. Om du implementerar den andra metoden kommer alla egenskapsdata att läsas från strömmen under ITextStoreACPServices::Unserialize-anrop. Den första metoden gör att egenskapsdata läse på begäran vid ett senare tillfälle.

  5. Upprepa föregående steg tills alla egenskapsblock inte harialiserats.

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