Considerações sobre o armazenamento de propriedades

IPropertyStorage::ReadMultiple lê quantas das propriedades especificadas na matriz rgpspec forem encontradas no conjunto de propriedades. Desde que qualquer uma das propriedades solicitadas seja lida, uma solicitação para recuperar uma propriedade que não existe não é um erro. Em vez disso, isso deve fazer com que VT_EMPTY sejam gravados para essa propriedade na matriz rgvar[] no retorno. Quando nenhuma das propriedades solicitadas existir, o método deverá retornar S_FALSE e definir VT_EMPTY em cada PROPVARIANT. Se qualquer outro erro for retornado, nenhum valor de propriedade será recuperado e o chamador não precisará se preocupar em liberá-los.

O parâmetro rgpspec é uma matriz de estruturas PROPSPEC , que especificam para cada propriedade seu identificador de propriedade ou, se um for atribuído, um identificador de cadeia de caracteres. Você pode mapear uma cadeia de caracteres para um identificador de propriedade chamando IPropertyStorage::WritePropertyNames. No entanto, é provável que o uso de identificadores de propriedade seja significativamente mais eficiente do que o uso de cadeias de caracteres.

As propriedades solicitadas pelo nome da cadeia de caracteres (PRSPEC_LPWSTR) são mapeadas sem diferenciação de maiúsculas e minúsculas para identificadores de propriedade (IDs) conforme são especificadas no conjunto de propriedades atual (e de acordo com a localidade atual do sistema).

Quando o tipo de propriedade é VT_LPSTR e a propriedade é lida de um conjunto de propriedades ANSI, ou seja, a página de código do conjunto de propriedades é definida como algo diferente de Unicode, o valor da propriedade usa a mesma página de código que o conjunto de propriedades. Quando uma propriedade VT_LPSTR é lida de um conjunto de propriedades Unicode, o valor da propriedade usa a página de código ANSI padrão atual do sistema, ou seja, a página de código retornada da função GetACP .

Um PROPVARIANT, exceto aqueles que são ponteiros para fluxos e armazenamentos, é chamado de PROPVARIANT simples. Esses PROPVARIANTssimples recebem dados por valor, portanto, uma chamada para IPropertyStorage::ReadMultiple fornece uma cópia dos dados que o chamador então possui. Para criar ou atualizar essas propriedades, chame IPropertyStorage::WriteMultiple.

Por outro lado, os tipos variantes VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE e VT_STORED_OBJECT são propriedades não simples, pois, em vez de fornecer um valor, o método recupera um ponteiro para a interface indicada, da qual os dados podem ser lidos. Esses tipos permitem o armazenamento de grandes quantidades de informações por meio de uma única propriedade. Há vários problemas que surgem no uso de propriedades não simples.

Para criar essas propriedades, como para as outras propriedades, chame IPropertyStorage::WriteMultiple. Em vez de chamar o mesmo método para atualizar, no entanto, é mais eficiente primeiro chamar IPropertyStorage::ReadMultiple para obter o ponteiro da interface para o fluxo ou armazenamento e, em seguida, gravar dados usando os métodos IStream ou IStorage . Um fluxo ou armazenamento aberto por meio de uma propriedade sempre é aberto no modo direto, portanto, um nível adicional de transação aninhada não é introduzido. No entanto, ainda pode haver uma transação no conjunto de propriedades como um todo, dependendo de como ela foi aberta ou criada por meio de IPropertySetStorage. Além disso, as marcas de modo de acesso e compartilhamento especificadas quando o conjunto de propriedades é aberto ou criado, são passadas para fluxos ou armazenamentos baseados em propriedade.

Os tempos de vida de ponteiros de armazenamento ou fluxo baseados em propriedade, embora teoricamente independentes de seus ponteiros IPropertyStorage e IPropertySetStorage associados, na verdade, dependem efetivamente deles. Os dados visíveis por meio do fluxo ou armazenamento estão relacionados à transação no objeto de armazenamento de propriedades do qual são recuperados, assim como para um objeto de armazenamento (que dá suporte a IStorage) com subobjetos de armazenamento e fluxo contidos. Se a transação no objeto pai for anulada, os ponteiros IStream e IStorage existentes subordinados a esse objeto não estarão mais acessíveis. Como IPropertyStorage é a única interface no objeto de armazenamento de propriedades, o tempo de vida útil dos ponteiros IStream e IStorage contidos é limitado pelo tempo de vida da interface IPropertyStorage .

A implementação também deve lidar com a situação em que a mesma propriedade com valor de fluxo ou armazenamento é solicitada várias vezes por meio da mesma instância da interface IPropertyStorage . Por exemplo, na implementação do arquivo composto COM, a abertura terá êxito ou falhará dependendo se a propriedade já está aberta ou não.

Outro problema é várias aberturas no modo transacionado. O resultado depende do nível de isolamento especificado por meio de uma chamada aos métodos IPropertySetStorage (o método Open ou Create , por meio dos sinalizadores STGM) no momento em que o armazenamento de propriedades foi aberto.

Se a chamada para abrir o conjunto de propriedades especificar acesso de leitura/gravação, as propriedades com valor IStorage e IStream sempre serão abertas com acesso de leitura/gravação. Em seguida, os dados podem ser gravados por meio dessas interfaces, alterando o valor da propriedade , que é a maneira mais eficiente de atualizar essas propriedades. O valor da propriedade em si não tem um nível adicional de aninhamento de transação, portanto, as alterações têm escopo na transação (se houver) no objeto de armazenamento de propriedades.

Propriedades de armazenamento e fluxo

Para gravar um fluxo ou objeto de armazenamento em um conjunto de propriedades, o conjunto de propriedades deve ter sido criado como não simples. Para obter mais informações sobre conjuntos de propriedades simples e não simples, consulte a seção intitulada Storage and Stream Objects for a Property Set. Os seguintes tipos de propriedade, conforme especificado no campo vt dos elementos da matriz rgvar , são tipos de fluxo ou armazenamento: VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT VT_STORED_OBJECT.

Para gravar um fluxo ou objeto de armazenamento como uma propriedade em um conjunto de propriedades não simples, chame IPropertyStorage::WriteMultiple. Embora você também chame esse método para atualizar propriedades simples, não é uma maneira eficiente de atualizar objetos de fluxo e armazenamento em um conjunto de propriedades. Isso ocorre porque a atualização de uma dessas propriedades por meio de uma chamada para WriteMultiple cria no objeto de armazenamento de propriedades uma cópia dos dados passados e os ponteiros IStorage ou IStream não são retidos além da duração dessa chamada. Geralmente, é mais eficiente atualizar objetos de fluxo ou armazenamento diretamente chamando IPropertyStorage::ReadMultiple para obter o ponteiro da interface para o fluxo ou armazenamento e, em seguida, gravando dados por meio dos métodos IStream ou IStorage .

Por exemplo, você pode chamar IPropertyStorage::WriteMultiple para gravar um fluxo NULL ou um objeto de armazenamento. Em seguida, a implementação criará um objeto vazio no conjunto de propriedades. Em seguida, você pode obter acesso a esse objeto chamando IPropertyStorage::ReadMultiple. Quando terminar de atualizar esse objeto, você não precisará gravá-lo no conjunto de propriedades, pois suas atualizações estavam indo diretamente para o conjunto de propriedades.

Um fluxo ou armazenamento aberto por meio de uma propriedade sempre é aberto no modo direto, portanto, um nível adicional de transação aninhada não é introduzido. Ainda pode haver uma transação no conjunto de propriedades como um todo. (Por exemplo, se iPropertyStorage foi obtido chamando IPropertySetStorage::Open com o sinalizador STGM_TRANSACTED definido no parâmetro grfmode .) Além disso, um fluxo ou armazenamento baseado em propriedade é aberto no modo de leitura/gravação, se possível, dado o modo no conjunto de propriedades; caso contrário, o modo de leitura será usado.

Conforme mencionado anteriormente, quando um fluxo ou objeto de armazenamento é gravado em um conjunto de propriedades com o método WriteMultiple , uma cópia do objeto é feita. Quando essa cópia é feita em um objeto de fluxo, a operação de cópia começa na posição de busca atual da origem. A posição de busca é indefinida em caso de falha, mas, com êxito, está no final do fluxo; o ponteiro seek não é restaurado para sua posição original.

Se uma propriedade de fluxo ou armazenamento tiver sido lida de um conjunto de propriedades com ReadMultiple, ainda estiver aberta e uma chamada subsequente para WriteMultiple para a mesma propriedade for feita, a operação WriteMultiple terá êxito. A propriedade de armazenamento ou fluxo aberto anteriormente é colocada no estado revertido (todas as chamadas a ela retornarão STG_E_REVERTED erro).

Se o método WriteMultiple retornar um erro ao gravar uma matriz de propriedades ou até mesmo propriedades individuais não simples, a quantidade de dados realmente gravados será indefinida.

Propriedades de referência

Se uma estrutura PROPVARIANT especificada incluir o sinalizador VT_BYREF em seu membro vt , a propriedade associada será uma propriedade de referência. Uma propriedade de referência é desreferenciada automaticamente antes de gravar o valor no conjunto de propriedades. Por exemplo, se o membro vt da estrutura PROPVARIANT especificar um valor do tipo VT_BYREF | VT_I4, o valor real gravado é um tipo VT_I4. Uma chamada subsequente para o método IPropertyStorage::ReadMultiple retorna um valor como VT_I4. Usar propriedades de referência é semelhante a chamar a função VariantCopyInd . VariantCopyInd libera a variante de destino e faz uma cópia do VARIANTARG de origem, executando a indireção necessária se a origem for especificada para ser VT_BYREF. Essa função é útil quando uma cópia de uma variante é necessária e para garantir que ela não seja VT_BYREF, por exemplo, ao manipular argumentos em uma implementação de IDispatch::Invoke.

Notas aos Chamadores

É recomendável que os conjuntos de propriedades sejam criados como Unicode, não definindo o sinalizador PROPSETFLAG_ANSI no parâmetro grfFlags de IPropertySetStorage::Create. Também é recomendável evitar o uso de valores VT_LPSTR e usar VT_LPWSTR valores. Quando a página de código do conjunto de propriedades é Unicode, VT_LPSTR valores de cadeia de caracteres são convertidos em Unicode quando armazenados e de volta para valores de cadeia de caracteres multibyte quando recuperados. Quando a página de código do conjunto de propriedades não é Unicode, nomes de propriedade, cadeias de caracteres VT_BSTR e valores de propriedade não simples são convertidos em cadeias de caracteres multibyte quando armazenados e convertidos novamente em Unicode quando recuperados, todos usando a página de código ANSI do sistema atual.

Notas aos Implementadores

Ao alocar um identificador de propriedade, a implementação pode escolher qualquer valor que não esteja atualmente em uso no conjunto de propriedades para um identificador de propriedade, desde que não seja 0 ou 1 ou maior que 0x80000000, todos os quais são valores reservados. O parâmetro propidNameFirst estabelece um valor mínimo para identificadores de propriedade dentro do conjunto e deve ser maior que 1 e menor que 0x80000000. Consulte a seção Comentários acima.

Implementação de arquivo composto IPropertyStorage

Implementação do sistema de arquivos IPropertyStorage-NTFS

Implementação autônoma de IPropertyStorage