Consideraciones sobre el almacenamiento de propiedades

IPropertyStorage::ReadMultiple lee tantas propiedades especificadas en la matriz rgpspec como se encuentran en el conjunto de propiedades. Siempre que se lea cualquiera de las propiedades solicitadas, una solicitud para recuperar una propiedad que no existe no es un error. En su lugar, esto debe hacer que se escriba VT_EMPTY para esa propiedad en la matriz rgvar[] devuelta. Cuando no existe ninguna de las propiedades solicitadas, el método debe devolver S_FALSE y establecer VT_EMPTY en cada PROPVARIANT. Si se devuelve cualquier otro error, no se recupera ningún valor de propiedad y el autor de la llamada no debe preocuparse por liberarlos.

El parámetro rgpspec es una matriz de estructuras PROPSPEC , que especifican para cada propiedad su identificador de propiedad o, si se asigna uno, un identificador de cadena. Puede asignar una cadena a un identificador de propiedad llamando a IPropertyStorage::WritePropertyNames. Sin embargo, es probable que el uso de identificadores de propiedad sea significativamente más eficaz que el uso de cadenas.

Las propiedades solicitadas por nombre de cadena (PRSPEC_LPWSTR) se asignan sin distinción entre mayúsculas y minúsculas a identificadores de propiedad (identificadores) tal como se especifican en el conjunto de propiedades actual (y según la configuración regional del sistema actual).

Cuando el tipo de propiedad se VT_LPSTR y la propiedad se lee desde un conjunto de propiedades ANSI, es decir, la página de códigos del conjunto de propiedades se establece en algo distinto de Unicode, el valor de la propiedad usa la misma página de códigos que el conjunto de propiedades. Cuando se lee una propiedad VT_LPSTR de un conjunto de propiedades Unicode, el valor de la propiedad usa la página de códigos ANSI predeterminada actual del sistema, es decir, la página de códigos devuelta desde la función GetACP .

Un PROPVARIANT, excepto aquellos que son punteros a flujos y almacenamientos, se denomina PROPVARIANT simple. Estos simples PROPVARIANTreciben datos por valor, por lo que una llamada a IPropertyStorage::ReadMultiple proporciona una copia de los datos que posee el autor de la llamada. Para crear o actualizar estas propiedades, llame a IPropertyStorage::WriteMultiple.

En cambio, los tipos de variante VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE y VT_STORED_OBJECT son propiedades no sencillas, ya que, en lugar de proporcionar un valor, el método recupera un puntero a la interfaz indicada, a partir de la cual se pueden leer los datos. Estos tipos permiten el almacenamiento de grandes cantidades de información a través de una sola propiedad. Hay varios problemas que surgen al usar propiedades que no son de ejemplo.

Para crear estas propiedades, como para las demás propiedades, llame a IPropertyStorage::WriteMultiple. Sin embargo, en lugar de llamar al mismo método para actualizar, es más eficaz llamar primero a IPropertyStorage::ReadMultiple para obtener el puntero de interfaz a la secuencia o el almacenamiento y, a continuación, escribir datos mediante los métodos IStream o IStorage . Un flujo o almacenamiento abierto a través de una propiedad siempre se abre en modo directo, por lo que no se introduce un nivel adicional de transacción anidada. Sin embargo, puede haber una transacción en el conjunto de propiedades en su conjunto, dependiendo de cómo se abrió o creó a través de IPropertySetStorage. Además, las etiquetas de modo de acceso y uso compartido especificadas cuando se abre o crea el conjunto de propiedades, se pasan a secuencias o almacenamientos basados en propiedades.

La duración de los punteros de flujo o almacenamiento basados en propiedades, aunque teóricamente independiente de sus punteros IPropertyStorage e IPropertySetStorage asociados, de hecho, dependen eficazmente de ellos. Los datos visibles a través de la secuencia o el almacenamiento están relacionados con la transacción en el objeto de almacenamiento de propiedades desde el que se recupera, al igual que para un objeto de almacenamiento (compatible con IStorage) con subobjetos de almacenamiento y secuencia contenidos. Si se anula la transacción en el objeto primario, los punteros IStream e IStorage existentes subordinados a ese objeto ya no son accesibles. Dado que IPropertyStorage es la única interfaz del objeto de almacenamiento de propiedades, la duración útil de los punteros IStream e IStorage contenidos está limitada por la duración de la interfaz IPropertyStorage .

La implementación también debe tratar con la situación en la que se solicita la misma propiedad con valores de flujo o almacenamiento varias veces a través de la misma instancia de interfaz IPropertyStorage . Por ejemplo, en la implementación del archivo compuesto COM, la apertura se realizará correctamente o producirá un error en función de si la propiedad ya está abierta o no.

Otro problema es que se abre varios en modo transaccionado. El resultado depende del nivel de aislamiento que se especificó a través de una llamada a los métodos IPropertySetStorage (ya sea el método Open o Create , a través de las marcas STGM) en el momento en que se abrió el almacenamiento de propiedades.

Si la llamada para abrir el conjunto de propiedades especifica el acceso de lectura y escritura, las propiedades IStorage e IStream-valued siempre se abren con acceso de lectura y escritura. Los datos se pueden escribir a través de estas interfaces, cambiando el valor de la propiedad, que es la manera más eficaz de actualizar estas propiedades. El propio valor de propiedad no tiene un nivel adicional de anidamiento de transacciones, por lo que los cambios se limitan a la transacción (si existe) en el objeto de almacenamiento de propiedades.

Propiedades de almacenamiento y secuencia

Para escribir una secuencia o un objeto de almacenamiento en un conjunto de propiedades, el conjunto de propiedades debe haberse creado como nomple. Para obtener más información sobre los conjuntos de propiedades simples y nomples, vea la sección titulada Storage and Stream Objects for a Property Set(Objetos de almacenamiento y stream para un conjunto de propiedades). Los siguientes tipos de propiedad, como se especifican en el campo vt de los elementos de matriz rgvar , son tipos de secuencia o almacenamiento: VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT, VT_STORED_OBJECT.

Para escribir una secuencia o un objeto de almacenamiento como una propiedad en un conjunto de propiedades no simple, llame a IPropertyStorage::WriteMultiple. Aunque también llamaría a este método para actualizar propiedades sencillas, no es una manera eficaz de actualizar los objetos de secuencia y almacenamiento en un conjunto de propiedades. Esto se debe a que la actualización de una de estas propiedades a través de una llamada a WriteMultiple crea en el objeto de almacenamiento de propiedades una copia de los datos pasados y los punteros IStorage o IStream no se conservan más allá de la duración de esta llamada. Normalmente es más eficaz actualizar los objetos de flujo o almacenamiento directamente llamando primero a IPropertyStorage::ReadMultiple para obtener el puntero de interfaz a la secuencia o el almacenamiento y, a continuación, escribir datos a través de los métodos IStream o IStorage .

Por ejemplo, puede llamar a IPropertyStorage::WriteMultiple para escribir una secuencia NULL o un objeto de almacenamiento. A continuación, la implementación creará un objeto vacío en el conjunto de propiedades. A continuación, puede obtener acceso a este objeto llamando a IPropertyStorage::ReadMultiple. Cuando termine de actualizar este objeto, no necesita escribirlo en el conjunto de propiedades, ya que las actualizaciones se encontraban directamente en el conjunto de propiedades.

Un flujo o almacenamiento abierto a través de una propiedad siempre se abre en modo directo, por lo que no se introduce un nivel adicional de transacción anidada. Todavía puede haber una transacción en la propiedad establecida como un todo. (Por ejemplo, si IPropertyStorage se obtuvo llamando a IPropertySetStorage::Open con la marca STGM_TRANSACTED establecida en el parámetro grfmode ). Además, se abre una secuencia o almacenamiento basado en propiedades en modo de lectura y escritura, si es posible, dado el modo en el conjunto de propiedades; De lo contrario, se usa el modo de lectura.

Como se mencionó anteriormente, cuando se escribe una secuencia o un objeto de almacenamiento en un conjunto de propiedades con el método WriteMultiple , se realiza una copia del objeto . Cuando se realiza dicha copia en un objeto de secuencia, la operación de copia comienza en la posición de búsqueda actual del origen. La posición de búsqueda no está definida en caso de error, pero si se realiza correctamente, está al final de la secuencia; el puntero seek no se restaura a su posición original.

Si se ha leído una secuencia o una propiedad de almacenamiento de un conjunto de propiedades con ReadMultiple, se mantiene abierta y se realiza una llamada posterior a WriteMultiple para la misma propiedad, la operación WriteMultiple se realizará correctamente. La propiedad stream o storage abierta anteriormente se coloca en el estado revertido (todas las llamadas a ella devolverán STG_E_REVERTED error).

Si el método WriteMultiple devuelve un error al escribir una matriz de propiedades, o incluso propiedades individuales no sencillas, la cantidad de datos realmente escritos es indefinido.

Propiedades de referencia

Si una estructura PROPVARIANT especificada incluye la marca VT_BYREF en su miembro vt , la propiedad asociada es una propiedad de referencia. Una propiedad de referencia se desreferencia automáticamente antes de escribir el valor en el conjunto de propiedades. Por ejemplo, si el miembro vt de la estructura PROPVARIANT especifica un valor de tipo VT_BYREF | VT_I4, el valor real escrito es un tipo VT_I4. Una llamada posterior al método IPropertyStorage::ReadMultiple devuelve un valor como VT_I4. El uso de propiedades de referencia es similar a llamar a la función VariantCopyInd . VariantCopyInd libera la variante de destino y realiza una copia del variantARG de origen, realizando la indirecta necesaria si se especifica que el origen sea VT_BYREF. Esta función es útil cuando se necesita una copia de una variante y para garantizar que no se VT_BYREF, por ejemplo, al controlar argumentos en una implementación de IDispatch::Invoke.

Notas a los autores de las llamadas

Se recomienda que los conjuntos de propiedades se creen como Unicode, no estableciendo la marca de PROPSETFLAG_ANSI en el parámetro grfFlags de IPropertySetStorage::Create. También se recomienda evitar el uso de valores de VT_LPSTR y usar VT_LPWSTR valores en su lugar. Cuando la página de códigos del conjunto de propiedades es Unicode, VT_LPSTR valores de cadena se convierten en Unicode cuando se almacenan y vuelven a valores de cadena multibyte cuando se recuperan. Cuando la página de códigos del conjunto de propiedades no es Unicode, los nombres de propiedad, las cadenas VT_BSTR y los valores de propiedad no simples se convierten en cadenas multibyte cuando se almacenan y se convierten de nuevo en Unicode cuando se recuperan, todo ello con la página de códigos ANSI del sistema actual.

Notas a los implementadores

Al asignar un identificador de propiedad, la implementación puede elegir cualquier valor que no esté actualmente en uso en el conjunto de propiedades para un identificador de propiedad, siempre que no sea 0 o 1 o mayor que 0x80000000, todos los cuales son valores reservados. El parámetro propidNameFirst establece un valor mínimo para los identificadores de propiedad dentro del conjunto y debe ser mayor que 1 y menor que 0x80000000. Consulte la sección Comentarios anterior.

Implementación del archivo compuesto de IPropertyStorage

Implementación del sistema de archivos IPropertyStorage-NTFS

Implementación independiente de IPropertyStorage