Überlegungen zur Eigenschaftsspeicherung
IPropertyStorage::ReadMultiple liest so viele der im rgpspec-Array angegebenen Eigenschaften wie im Eigenschaftensatz. Solange eine der angeforderten Eigenschaften gelesen wird, ist eine Anforderung zum Abrufen einer Eigenschaft, die nicht vorhanden ist, kein Fehler. Stattdessen muss dies dazu führen, dass VT_EMPTY für diese Eigenschaft bei der Rückgabe in das rgvar[]-Array geschrieben wird. Wenn keine der angeforderten Eigenschaften vorhanden ist, sollte die Methode S_FALSE zurückgeben und VT_EMPTY in jeder PROPVARIANT-Methode festlegen. Wenn ein anderer Fehler zurückgegeben wird, werden keine Eigenschaftswerte abgerufen, und der Aufrufer muss sich nicht um ihre Freigabe kümmern.
Der rgpspec-Parameter ist ein Array von PROPSPEC-Strukturen , die für jede Eigenschaft entweder den Eigenschaftenbezeichner oder, falls einer zugewiesen ist, einen Zeichenfolgenbezeichner angeben. Sie können eine Zeichenfolge einem Eigenschaftenbezeichner zuordnen, indem Sie IPropertyStorage::WritePropertyNames aufrufen. Die Verwendung von Eigenschaftsbezeichnern ist jedoch wahrscheinlich wesentlich effizienter als die Verwendung von Zeichenfolgen.
Eigenschaften, die vom Zeichenfolgennamen (PRSPEC_LPWSTR) angefordert werden, werden eigenschaftsbezeichnern (IDs) nicht berücksichtigt, da sie im aktuellen Eigenschaftensatz (und entsprechend dem aktuellen Systemgebietsschema) angegeben werden.
Wenn der Eigenschaftentyp VT_LPSTR ist und die Eigenschaft aus einem ANSI-Eigenschaftssatz gelesen wird, d. h. die Codepage für den Eigenschaftensatz auf etwas anderes als Unicode festgelegt ist, verwendet der Wert der Eigenschaft dieselbe Codepage wie der Eigenschaftensatz. Wenn eine VT_LPSTR Eigenschaft aus einem Unicode-Eigenschaftssatz gelesen wird, verwendet der Wert der Eigenschaft die aktuelle ANSI-Standardcodepage des Systems, d. h. die Codepage, die von der GetACP-Funktion zurückgegeben wird.
Eine PROPVARIANT, mit Ausnahme derjenigen, die zeiger auf Streams und Speicher sind, wird als einfache PROPVARIANT bezeichnet. Diese einfachen PROPVARIANTsempfangen Daten nach Wert, sodass ein Aufruf von IPropertyStorage::ReadMultiple eine Kopie der Daten bereitstellt, die der Aufrufer dann besitzt. Um diese Eigenschaften zu erstellen oder zu aktualisieren, rufen Sie IPropertyStorage::WriteMultiple auf.
Im Gegensatz dazu sind die Variantentypen VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE und VT_STORED_OBJECT nicht einfache Eigenschaften, da die Methode anstelle eines Werts einen Zeiger auf die angegebene Schnittstelle abruft, aus der die Daten dann gelesen werden können. Diese Typen ermöglichen das Speichern großer Mengen von Informationen über eine einzelne Eigenschaft. Es gibt mehrere Probleme, die bei der Verwendung nicht einfacher Eigenschaften auftreten.
Um diese Eigenschaften wie für die anderen Eigenschaften zu erstellen, rufen Sie IPropertyStorage::WriteMultiple auf. Anstatt die gleiche Methode zum Aktualisieren aufzurufen, ist es jedoch effizienter, zuerst IPropertyStorage::ReadMultiple aufzurufen, um den Schnittstellenzeiger auf den Stream oder Speicher abzurufen, und dann Daten mit den Methoden IStream oder IStorage zu schreiben. Ein Stream oder Speicher, der über eine Eigenschaft geöffnet wird, wird immer im direkten Modus geöffnet, sodass keine zusätzliche Ebene geschachtelter Transaktionen eingeführt wird. Je nachdem, wie sie über IPropertySetStorage geöffnet oder erstellt wurde, kann jedoch weiterhin eine Transaktion für die Eigenschaft als Ganzes festgelegt werden. Darüber hinaus werden die Beim Öffnen oder Erstellen des Eigenschaftensatzes angegebenen Zugriffs- und Freigabemodustags an eigenschaftsbasierte Streams oder Speicher übergeben.
Die Lebensdauer von eigenschaftsbasierten Datenstrom- oder Speicherzeigern, obwohl theoretisch unabhängig von ihren zugeordneten IPropertyStorage - und IPropertySetStorage-Zeigern , hängen tatsächlich effektiv von ihnen ab. Die über den Stream oder Speicher sichtbaren Daten beziehen sich auf die Transaktion des Eigenschaftsspeicherobjekts, aus dem sie abgerufen werden, genauso wie für ein Speicherobjekt (unterstützt IStorage) mit enthaltenen Stream- und Speicherunterobjekten. Wenn die Transaktion für das übergeordnete Objekt abgebrochen wird, kann nicht mehr auf vorhandene IStream - und IStorage-Zeiger zugegriffen werden, die diesem Objekt untergeordnet sind. Da IPropertyStorage die einzige Schnittstelle für das Eigenschaftsspeicherobjekt ist, wird die Lebensdauer der enthaltenen IStream - und IStorage-Zeiger durch die Lebensdauer der IPropertyStorage-Schnittstelle begrenzt.
Die Implementierung muss auch die Situation behandeln, in der dieselbe Stream- oder Speicherwerteigenschaft mehrmals über dieselbe IPropertyStorage-Schnittstelle instance angefordert wird. In der COM-Verbunddateiimplementierung ist beispielsweise das Öffnen erfolgreich oder schlägt fehl, je nachdem, ob die Eigenschaft bereits geöffnet ist oder nicht.
Ein weiteres Problem sind mehrere Geöffnete im Transaktionsmodus. Das Ergebnis hängt von der Isolationsstufe ab, die durch einen Aufruf der IPropertySetStorage-Methoden (entweder die Open- oder Create-Methode über die STGM-Flags) zum Zeitpunkt des Öffnens des Eigenschaftsspeichers angegeben wurde.
Wenn der Aufruf zum Öffnen des Eigenschaftensatzes Lese-/Schreibzugriff angibt, werden die Eigenschaften IStorage und IStream-valued immer mit Lese-/Schreibzugriff geöffnet. Daten können dann über diese Schnittstellen geschrieben werden, wodurch der Wert der Eigenschaft geändert werden kann. Dies ist die effizienteste Möglichkeit, diese Eigenschaften zu aktualisieren. Der Eigenschaftswert selbst verfügt nicht über eine zusätzliche Ebene der Transaktionsschachtelung, sodass Änderungen unter der Transaktion (falls vorhanden) für das Eigenschaftsspeicherobjekt festgelegt werden.
Speicher- und Streameigenschaften
Um ein Stream- oder Speicherobjekt in einen Eigenschaftensatz zu schreiben, muss der Eigenschaftensatz als Nonsimple erstellt worden sein. Weitere Informationen zu einfachen und nicht einfachen Eigenschaftensätzen finden Sie im Abschnitt Speicher- und Streamobjekte für einen Eigenschaftensatz. Die folgenden Eigenschaftentypen sind, wie im Feld vt der rgvar-Arrayelemente angegeben, Stream- oder Speichertypen: VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT, VT_STORED_OBJECT.
Um ein Stream- oder Speicherobjekt als Eigenschaft in einem nicht einfachen Eigenschaftensatz zu schreiben, rufen Sie IPropertyStorage::WriteMultiple auf. Sie würden diese Methode auch aufrufen, um einfache Eigenschaften zu aktualisieren, es ist jedoch keine effiziente Möglichkeit, Stream- und Speicherobjekte in einem Eigenschaftensatz zu aktualisieren. Dies liegt daran, dass beim Aktualisieren einer dieser Eigenschaften durch einen Aufruf von WriteMultiple im Eigenschaftsspeicherobjekt eine Kopie der übergebenen Daten erstellt wird, und die IStorage - oder IStream-Zeiger werden nicht über die Dauer dieses Aufrufs hinaus beibehalten. In der Regel ist es effizienter, Stream- oder Speicherobjekte direkt zu aktualisieren, indem Zuerst IPropertyStorage::ReadMultiple aufgerufen wird, um den Schnittstellenzeiger auf den Stream oder Speicher abzurufen, und dann Daten über die IStream - oder IStorage-Methoden zu schreiben.
Sie können beispielsweise IPropertyStorage::WriteMultiple aufrufen, um einen NULL-Stream oder ein Speicherobjekt zu schreiben. Die Implementierung erstellt dann ein leeres Objekt im Eigenschaftensatz. Sie können dann Zugriff auf dieses Objekt erhalten, indem Sie IPropertyStorage::ReadMultiple aufrufen. Wenn Sie die Aktualisierung dieses Objekts abgeschlossen haben, müssen Sie es nicht in den Eigenschaftensatz schreiben, da Ihre Updates direkt in den Eigenschaftensatz eingegliedert wurden.
Ein Stream oder Speicher, der über eine Eigenschaft geöffnet wird, wird immer im direkten Modus geöffnet, sodass keine zusätzliche Ebene geschachtelter Transaktionen eingeführt wird. Es kann weiterhin eine Transaktion für die Eigenschaft geben, die als Ganzes festgelegt ist. (Beispielsweise, wenn IPropertyStorage durch Aufrufen von IPropertySetStorage::Open mit dem im grfmode-Parameter festgelegten STGM_TRANSACTED-Flag abgerufen wurde.) Darüber hinaus wird ein eigenschaftsbasierter Stream oder Speicher nach Möglichkeit im Lese-/Schreibmodus geöffnet, wenn möglich, wenn der Modus für den Eigenschaftensatz verwendet wird. Andernfalls wird der Lesemodus verwendet.
Wie bereits erwähnt, wird beim Schreiben eines Stream- oder Speicherobjekts in eine Eigenschaft mit der WriteMultiple-Methode eine Kopie des Objekts erstellt. Wenn eine solche Kopie für ein Streamobjekt erstellt wird, beginnt der Kopiervorgang an der aktuellen Suchposition der Quelle. Die Suchposition ist für fehler undefiniert, aber bei Erfolg am Ende des Datenstroms; der Suchzeiger wird nicht in seiner ursprünglichen Position wiederhergestellt.
Wenn eine Stream- oder Speichereigenschaft aus einem Eigenschaftssatz mit ReadMultiple gelesen wurde, weiterhin geöffnet gehalten wird und ein nachfolgender Aufruf von WriteMultiple für dieselbe Eigenschaft erfolgt, ist der WriteMultiple-Vorgang erfolgreich. Die zuvor geöffnete Stream- oder Speichereigenschaft wird im wiederhergestellten Zustand versetzt (alle Aufrufe geben STG_E_REVERTED Fehler zurück).
Wenn die WriteMultiple-Methode beim Schreiben eines Arrays von Eigenschaften oder sogar einzelner nicht einfacher Eigenschaften einen Fehler zurückgibt, ist die Tatsächlich geschriebene Datenmenge nicht definiert.
Verweiseigenschaften
Wenn eine angegebene PROPVARIANT-Struktur das VT_BYREF-Flag in ihrem vt-Member enthält, ist die zugeordnete Eigenschaft eine Verweiseigenschaft. Eine Verweiseigenschaft wird automatisch abgeleitet, bevor der Wert in den Eigenschaftssatz geschrieben wird. Beispiel: Wenn das vt-Member der PROPVARIANT-Struktur einen Wert vom Typ VT_BYREF | VT_I4 ist der tatsächlich geschriebene Wert ein VT_I4-Typ. Ein nachfolgendes Aufrufen der IPropertyStorage::ReadMultiple-Methode gibt einen Wert als VT_I4 zurück. Die Verwendung von Verweiseigenschaften ähnelt dem Aufrufen der VariantCopyInd-Funktion . VariantCopyInd gibt die Zielvariante frei und erstellt eine Kopie der Quelle VARIANTARG, wobei die erforderliche Indirektierung ausgeführt wird, wenn die Quelle für VT_BYREF angegeben wird. Diese Funktion ist nützlich, wenn eine Kopie einer Variante benötigt wird, und um sicherzustellen, dass sie nicht VT_BYREF wird, z. B. bei der Behandlung von Argumenten in einer Implementierung von IDispatch::Invoke.
Hinweise für Aufrufer
Es wird empfohlen, Eigenschaftssätze als Unicode zu erstellen, indem das flag PROPSETFLAG_ANSI im grfFlags-Parameter von IPropertySetStorage::Create nicht festgelegt wird. Es wird auch empfohlen, die Verwendung VT_LPSTR-Werte zu vermeiden und stattdessen VT_LPWSTR Werte zu verwenden. Wenn die Codepage des Eigenschaftssatzes Unicode ist, werden VT_LPSTR Zeichenfolgenwerte beim Speichern in Unicode und beim Abrufen wieder in Multibyte-Zeichenfolgenwerte konvertiert. Wenn die Codepage des Eigenschaftensatzes nicht Unicode ist, werden Eigenschaftennamen, VT_BSTR Zeichenfolgen und nicht einfache Eigenschaftswerte beim Speichern in Multibytezeichenfolgen konvertiert und beim Abrufen wieder in Unicode konvertiert, alles mit der aktuellen System-ANSI-Codepage.
Hinweise für Ausführende
Beim Zuweisen eines Eigenschaftsbezeichners kann die Implementierung einen beliebigen Wert auswählen, der derzeit nicht im Eigenschaftensatz für einen Eigenschaftenbezeichner verwendet wird, solange er nicht 0 oder 1 oder größer als 0x80000000 ist, wobei alle werte reserviert sind. Der parameter propidNameFirst legt einen Mindestwert für Eigenschaftsbezeichner innerhalb der Gruppe fest und muss größer als 1 und kleiner als 0x80000000 sein. Weitere Informationen finden Sie weiter oben im Abschnitt "Hinweise".
Zugehörige Themen