Considérations relatives au stockage des propriétés

IPropertyStorage::ReadMultiple lit autant de propriétés spécifiées dans le tableau rgpspec que dans le jeu de propriétés. Tant que l’une des propriétés demandées est lue, une demande de récupération d’une propriété qui n’existe pas n’est pas une erreur. Au lieu de cela, VT_EMPTY doit être écrit pour cette propriété dans le tableau rgvar[] lors du retour. Quand aucune des propriétés demandées n’existe, la méthode doit retourner S_FALSE et définir VT_EMPTY dans chaque PROPVARIANT. Si une autre erreur est retournée, aucune valeur de propriété n’est récupérée et l’appelant n’a pas à se soucier de les libérer.

Le paramètre rgpspec est un tableau de structures PROPSPEC , qui spécifient pour chaque propriété son identificateur de propriété ou, le cas échéant, un identificateur de chaîne. Vous pouvez mapper une chaîne à un identificateur de propriété en appelant IPropertyStorage::WritePropertyNames. Toutefois, l’utilisation d’identificateurs de propriété est susceptible d’être beaucoup plus efficace que l’utilisation de chaînes.

Les propriétés demandées par le nom de chaîne (PRSPEC_LPWSTR) sont mappées de manière non sensible à la casse aux identificateurs de propriété (ID) tels qu’ils sont spécifiés dans le jeu de propriétés actuel (et en fonction des paramètres régionaux système actuels).

Lorsque le type de propriété est VT_LPSTR et que la propriété est lue à partir d’un jeu de propriétés ANSI, c’est-à-dire que la page de codes du jeu de propriétés a une valeur autre qu’Unicode, la valeur de la propriété utilise la même page de codes que le jeu de propriétés. Lorsqu’une propriété VT_LPSTR est lue à partir d’un jeu de propriétés Unicode, la valeur de la propriété utilise la page de codes ANSI par défaut actuelle du système, c’est-à-dire la page de codes retournée par la fonction GetACP .

Un PROPVARIANT, à l’exception de ceux qui sont des pointeurs vers des flux et des stockages, est appelé PROPVARIANT simple. Ces simples PROPVARIANTreçoivent des données par valeur. Par conséquent, un appel à IPropertyStorage::ReadMultiple fournit une copie des données que l’appelant possède alors. Pour créer ou mettre à jour ces propriétés, appelez IPropertyStorage::WriteMultiple.

En revanche, les types de variantes VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE et VT_STORED_OBJECT sont des propriétés non simples, car au lieu de fournir une valeur, la méthode récupère un pointeur vers l’interface indiquée, à partir de laquelle les données peuvent ensuite être lues. Ces types permettent de stockage de grandes quantités d’informations via une seule propriété. L’utilisation de propriétés non simples pose plusieurs problèmes.

Pour créer ces propriétés, comme pour les autres propriétés, appelez IPropertyStorage::WriteMultiple. Toutefois, plutôt que d’appeler la même méthode à mettre à jour, il est plus efficace d’appeler D’abord IPropertyStorage::ReadMultiple pour obtenir le pointeur d’interface vers le flux ou le stockage, puis d’écrire des données à l’aide des méthodes IStream ou IStorage . Un flux ou un stockage ouvert via une propriété est toujours ouvert en mode direct, de sorte qu’aucun niveau supplémentaire de transaction imbriquée n’est introduit. Toutefois, il peut toujours y avoir une transaction sur le jeu de propriétés dans son ensemble, selon la façon dont il a été ouvert ou créé via IPropertySetStorage. En outre, les balises de mode d’accès et de partage spécifiées lors de l’ouverture ou de la création du jeu de propriétés sont passées à des flux ou stockages basés sur des propriétés.

La durée de vie des pointeurs de flux ou de stockage basés sur des propriétés, bien qu’elles soient théoriquement indépendantes de leurs pointeurs IPropertyStorage et IPropertySetStorage associés, en fait, en dépendent effectivement. Les données visibles via le flux ou le stockage sont liées à la transaction sur l’objet de stockage de propriété à partir duquel elles sont récupérées, tout comme pour un objet de stockage (prenant en charge IStorage) avec un flux et des sous-objets de stockage contenus. Si la transaction sur l’objet parent est abandonnée, les pointeurs IStream et IStorage existants subordonnés à cet objet ne sont plus accessibles. Étant donné que IPropertyStorage est la seule interface de l’objet de stockage de propriété, la durée de vie utile des pointeurs IStream et IStorage contenus est limitée par la durée de vie de l’interface IPropertyStorage .

L’implémentation doit également traiter la situation où la même propriété de flux ou de stockage est demandée plusieurs fois par le biais de la même interface IPropertyStorage instance. Par exemple, dans l’implémentation du fichier composé COM, l’ouverture réussit ou échoue selon que la propriété est déjà ouverte ou non.

Un autre problème est l’ouverture de plusieurs ouvertures en mode transactionné. Le résultat dépend du niveau d’isolation spécifié par un appel aux méthodes IPropertySetStorage (méthode Open ou Create , par le biais des indicateurs STGM) au moment de l’ouverture du stockage de propriétés.

Si l’appel pour ouvrir le jeu de propriétés spécifie l’accès en lecture-écriture, les propriétés IStorage et IStream sont toujours ouvertes avec un accès en lecture-écriture. Les données peuvent ensuite être écrites via ces interfaces, ce qui modifie la valeur de la propriété, ce qui est le moyen le plus efficace de mettre à jour ces propriétés. La valeur de la propriété elle-même n’a pas de niveau supplémentaire d’imbrication des transactions. Les modifications sont donc étendues sous la transaction (le cas échéant) sur l’objet de stockage de propriété.

Propriétés de stockage et de flux

Pour écrire un flux ou un objet de stockage dans un jeu de propriétés, le jeu de propriétés doit avoir été créé comme non simple. Pour plus d’informations sur les ensembles de propriétés simples et non simples, consultez la section intitulée Storage and Stream Objects for a Property Set. Les types de propriétés suivants, comme spécifié dans le champ vt des éléments de tableau rgvar , sont des types de flux ou de stockage : VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT, VT_STORED_OBJECT.

Pour écrire un flux ou un objet de stockage en tant que propriété dans un jeu de propriétés non simple, appelez IPropertyStorage::WriteMultiple. Bien que vous appeliez également cette méthode pour mettre à jour des propriétés simples, il ne s’agit pas d’un moyen efficace de mettre à jour des objets de flux et de stockage dans un jeu de propriétés. En effet, la mise à jour d’une de ces propriétés via un appel à WriteMultiple crée dans l’objet de stockage de propriété une copie des données passées, et les pointeurs IStorage ou IStream ne sont pas conservés au-delà de la durée de cet appel. Il est généralement plus efficace de mettre à jour des objets de flux ou de stockage directement en appelant D’abord IPropertyStorage::ReadMultiple pour obtenir le pointeur d’interface vers le flux ou le stockage, puis en écrivant des données via les méthodes IStream ou IStorage .

Par exemple, vous pouvez appeler IPropertyStorage::WriteMultiple pour écrire un flux NULL ou un objet de stockage. L’implémentation crée ensuite un objet vide dans le jeu de propriétés. Vous pouvez ensuite accéder à cet objet en appelant IPropertyStorage::ReadMultiple. Lorsque vous avez terminé la mise à jour de cet objet, vous n’avez pas besoin de l’écrire dans le jeu de propriétés, car vos mises à jour allaient directement dans le jeu de propriétés.

Un flux ou un stockage ouvert via une propriété est toujours ouvert en mode direct, de sorte qu’aucun niveau supplémentaire de transaction imbriquée n’est introduit. Il peut encore y avoir une transaction sur la propriété définie dans son ensemble. (Par exemple, si iPropertyStorage a été obtenu en appelant IPropertySetStorage::Open avec l’indicateur STGM_TRANSACTED défini dans le paramètre grfmode .) En outre, un flux ou un stockage basé sur des propriétés est ouvert en mode lecture-écriture, si possible, compte tenu du mode sur le jeu de propriétés ; sinon, le mode lecture est utilisé.

Comme mentionné précédemment, lorsqu’un flux ou un objet de stockage est écrit dans un jeu de propriétés avec la méthode WriteMultiple , une copie de l’objet est effectuée. Lorsqu’une telle copie est effectuée sur un objet de flux, l’opération de copie commence à la position de recherche actuelle de la source. La position de recherche n’est pas définie en cas d’échec, mais en cas de réussite, elle se trouve à la fin du flux ; le pointeur de recherche n’est pas restauré à sa position d’origine.

Si une propriété de flux ou de stockage a été lue à partir d’un jeu de propriétés avec ReadMultiple, est toujours maintenue ouverte et qu’un appel ultérieur à WriteMultiple pour la même propriété est effectué, l’opération WriteMultiple réussit. Le flux ou la propriété de stockage précédemment ouvert est placé dans l’état rétabli (tous les appels à celui-ci retournent STG_E_REVERTED erreur).

Si la méthode WriteMultiple renvoie une erreur lors de l’écriture d’un tableau de propriétés, ou même de propriétés non simples individuelles, la quantité de données réellement écrites n’est pas définie.

Propriétés de référence

Si une structure PROPVARIANT spécifiée inclut l’indicateur VT_BYREF dans son membre vt , la propriété associée est une propriété de référence. Une propriété de référence est automatiquement déréférencée avant d’écrire la valeur dans le jeu de propriétés. Par exemple, si le membre vt de la structure PROPVARIANT spécifie une valeur de type VT_BYREF | VT_I4, la valeur réelle écrite est un type VT_I4. Un appel suivant à la méthode IPropertyStorage::ReadMultiple retourne une valeur en tant que VT_I4. L’utilisation de propriétés de référence est similaire à l’appel de la fonction VariantCopyInd . VariantCopyInd libère la variante de destination et effectue une copie du VARIANTARG source, en effectuant l’indirection nécessaire si la source est spécifiée pour être VT_BYREF. Cette fonction est utile lorsqu’une copie d’une variante est nécessaire et pour garantir qu’elle n’est pas VT_BYREF, par exemple lors de la gestion des arguments dans une implémentation de IDispatch::Invoke.

Notes pour les appelants

Il est recommandé de créer des jeux de propriétés au format Unicode, en ne définissant pas l’indicateur PROPSETFLAG_ANSI dans le paramètre grfFlags de IPropertySetStorage::Create. Il est également recommandé d’éviter d’utiliser des valeurs VT_LPSTR et d’utiliser des valeurs VT_LPWSTR à la place. Lorsque la page de codes du jeu de propriétés est Unicode, VT_LPSTR valeurs de chaîne sont converties en Unicode lorsqu’elles sont stockées, puis de nouveau en valeurs de chaîne multioctets lorsqu’elles sont récupérées. Lorsque la page de codes du jeu de propriétés n’est pas Unicode, les noms de propriétés, les chaînes VT_BSTR et les valeurs de propriété non simples sont convertis en chaînes multioctets lorsqu’ils sont stockés, puis reconvertis en Unicode lors de leur récupération, le tout à l’aide de la page de codes ANSI système actuelle.

Notes pour les responsables de l’implémentation

Lors de l’allocation d’un identificateur de propriété, l’implémentation peut choisir n’importe quelle valeur qui n’est pas actuellement utilisée dans le jeu de propriétés pour un identificateur de propriété, tant qu’elle n’est pas égale à 0 ou 1 ou supérieure à 0x80000000, qui sont toutes des valeurs réservées. Le paramètre propidNameFirst établit une valeur minimale pour les identificateurs de propriété dans l’ensemble et doit être supérieur à 1 et inférieur à 0x80000000. Consultez la section Remarques ci-dessus.

Implémentation de fichier composé IPropertyStorage

Implémentation du système de fichiers IPropertyStorage-NTFS

Implémentation autonome IPropertyStorage