Auf Englisch lesen

Freigeben über


Eigenschaften (Allgemeine Elemente)

Text Services Framework (TSF) stellt Eigenschaften bereit, die Metadaten einem Textbereich zuordnen. Zu diesen Eigenschaften gehören, jedoch nicht beschränkt auf Anzeigeattribute wie fett formatierten Text, die Sprach-ID des Texts und rohe Daten, die von einem Textdienst bereitgestellt werden, z. B. die Audiodaten, die mit Text aus dem Sprachtextdienst verknüpft sind.

Im folgenden Beispiel wird veranschaulicht, wie eine hypothetische Textfarbeseigenschaft mit möglichen Werten von Rot (R), Grün (G) oder Blau (B) angezeigt werden kann.

COLOR:      RR      GGGGGGGG
TEXT:  this is some colored text

Eigenschaften unterschiedlicher Typen können sich überlappen. Nehmen Sie beispielsweise das vorherige Beispiel, und fügen Sie ein Textattribute hinzu, das entweder fett (B) oder kursiv (I) sein kann.

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

Der Text "this" wäre fett, "is" wäre sowohl fett als auch rot, "some" würde normal angezeigt, "farbige" wäre grün und kursiv und "Text" kursiv formatiert.

Eigenschaften desselben Typs können nicht überlappen. Die folgende Situation ist beispielsweise nicht zulässig, da "is" und "colored" überlappende Werte derselben Typen aufweisen.

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

Eigenschaftentypen

TSF definiert drei verschiedene Eigenschaftentypen.

Eigenschaftstyp Beschreibung
statischen Ein statisches Eigenschaftsobjekt speichert die Eigenschaftendaten mit Text. Außerdem werden der Textbereich für jeden Bereich gespeichert, für den die Eigenschaft gilt. ITfReadOnlyProperty::GetType gibt die GUID_TFCAT_PROPSTYLE_STATIC Kategorie zurück.
Static-Compact Ein static-compact-Eigenschaftsobjekt ist identisch mit einem statischen Eigenschaftsobjekt, mit der Ausnahme, dass eine statische Kompakteigenschaft keine Bereichsdaten speichert. Wenn der von einer statischen Kompakteigenschaft abgedeckte Bereich angefordert wird, wird für jede Gruppe angrenzender Eigenschaften ein Bereich erstellt. Statische kompakte Eigenschaften sind die effizienteste Möglichkeit, Eigenschaften pro Zeichen zu speichern. ITfReadOnlyProperty::GetType gibt die GUID_TFCAT_PROPSTYLE_STATICCOMPACT Kategorie zurück.
Benutzerdefiniert Ein benutzerdefiniertes Eigenschaftsobjekt speichert die Bereichsinformationen für jeden Bereich, für den die Eigenschaft gilt. Die tatsächlichen Daten für die Eigenschaft werden jedoch nicht gespeichert. Stattdessen speichert eine benutzerdefinierte Eigenschaft ein ITfPropertyStore-Objekt. Der TSF-Manager verwendet dieses Objekt, um auf die Eigenschaftendaten zuzugreifen und diese zu verwalten. ITfReadOnlyProperty::GetType gibt die GUID_TFCAT_PROPSTYLE_CUSTOM Kategorie zurück.

 

Arbeiten mit Eigenschaften

Der Eigenschaftswert und die Attribute werden mithilfe der ITfReadOnlyProperty-Schnittstelle abgerufen und mithilfe der ITfProperty-Schnittstelle geändert.

Wenn ein bestimmter Eigenschaftstyp erforderlich ist, wird ITfContext::GetProperty verwendet. ITfContext::GetProperty erfordert eine GUID , die die abzurufende Eigenschaft identifiziert. TSF definiert einen Satz vordefinierter Eigenschaftenbezeichner, die verwendet werden, oder ein Textdienst kann eigene Eigenschaftenbezeichner definieren. Wenn eine benutzerdefinierte Eigenschaft verwendet wird, muss der Eigenschaftenanbieter die Eigenschaften-GUID und das Format der abgerufenen Daten veröffentlichen.

Rufen Sie beispielsweise zum Abrufen der CLSID für den Besitzer eines Textbereichs ITfContext::GetProperty auf, um das Eigenschaftsobjekt abzurufen, rufen Sie ITfProperty::FindRange auf, um den Bereich abzurufen, der die Eigenschaft vollständig abdeckt, und rufen Sie dann ITfReadOnlyProperty::GetValue auf, um ein TfGuidAtom abzurufen, das die CLSID des Textdiensts darstellt, der den Text besitzt. Das folgende Beispiel zeigt eine Funktion, die aufgrund eines Kontexts, eines Bereichs und eines Bearbeitungscookies die CLSID des Textdiensts abruft, der den Text besitzt.

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

Eigenschaften können auch durch Abrufen einer IEnumTfProperties-Schnittstelle von ITfContext::EnumProperties aufgezählt werden.

Permanenter Speicher von Eigenschaften

Häufig sind Eigenschaften für eine Anwendung transparent und werden von einem oder mehreren Textdiensten verwendet. Um die Eigenschaftsdaten beizubehalten, z. B. beim Speichern in einer Datei, muss eine Anwendung die Eigenschaftsdaten serialisieren, wenn sie gespeichert wird, und die Eigenschaftsdaten beim Wiederherstellen der Daten nicht deialisieren. In diesem Fall sollte die Anwendung nicht an einzelnen Eigenschaften interessiert sein, sondern alle Eigenschaften im Kontext aufzählen und speichern.

Beim Speichern von Eigenschaftsdaten sollte eine Anwendung die folgenden Schritte ausführen.

  1. Rufen Sie eine Eigenschaftsenumerator ab, indem Sie ITfContext::EnumProperties aufrufen.
  2. Auflisten der einzelnen Eigenschaften durch Aufrufen von IEnumTfProperties::Next.
  3. Rufen Sie für jede Eigenschaft einen Bereichsenumerator ab, indem Sie ITfReadOnlyProperty::EnumRanges aufrufen.
  4. Aufzählen Sie jeden Bereich in der Eigenschaft, indem Sie IEnumTfRanges::Next aufrufen.
  5. Rufen Sie für jeden Bereich in der Eigenschaft ITextStoreACPServices::Serialize mit der Eigenschaft, dem Bereich, einer TF_PERSISTENT_PROPERTY_HEADER_ACP-Struktur und einem von der Anwendung implementierten Streamobjekt auf.
  6. Schreiben Sie den Inhalt der TF_PERSISTENT_PROPERTY_HEADER_ACP Struktur in beständigen Arbeitsspeicher.
  7. Schreiben Sie den Inhalt des Datenstromobjekts in beständigen Arbeitsspeicher.
  8. Fahren Sie mit den vorherigen Schritten für alle Bereiche in allen Eigenschaften fort.
  9. Die Anwendung sollte einen Typ von Terminator in den Datenstrom schreiben, damit beim Wiederherstellen der Daten ein Stopppunkt identifiziert werden kann.
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

Beim Wiederherstellen von Eigenschaftendaten sollte eine Anwendung die folgenden Schritte ausführen.

  1. Legen Sie den Datenstromzeiger auf den Anfang der ersten TF_PERSISTENT_PROPERTY_HEADER_ACP Struktur fest.

  2. Lesen Sie die TF_PERSISTENT_PROPERTY_HEADER_ACP Struktur.

  3. Rufen Sie ITfContext::GetProperty mit dem guidType-Element der TF_PERSISTENT_PROPERTY_HEADER_ACP-Struktur auf.

  4. Die Anwendung kann an diesem Punkt eines von zwei Dingen ausführen.

    1. Erstellen Sie eine Instanz eines ITfPersistentPropertyLoaderACP-Objekts , das die Anwendung implementieren muss. Rufen Sie dann ITextStoreACPServices::Unserialize mit NULL für pStream und den ITfPersistentPropertyLoaderACP-Zeiger auf.
    2. Übergeben Sie den Eingabedatenstrom an ITextStoreACPServices::Unserialize und NULL für pLoader.

    Die erste Methode wird bevorzugt, da sie die effizienteste ist. Durch die Implementierung der zweiten Methode werden alle Eigenschaftendaten während des Aufrufs von ITextStoreACPServices::Unserialize aus dem Datenstrom gelesen. Die erste Methode bewirkt, dass die Eigenschaftendaten zu einem späteren Zeitpunkt bei Bedarf gelesen werden.

  5. Wiederholen Sie die vorherigen Schritte, bis alle Eigenschaftsblöcke nichtialisiert werden.

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