Compartilhar via


Considerações sobre o armazenamento de propriedades

IPropertyStorage::ReadMultiple lê quantas das propriedades especificadas na matriz de rgpspec, como são 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 diferenciar maiúsculas de 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.

UmPROPVARIANT, exceto aqueles que são ponteiros para fluxos e armazenamentos, é chamado de PROPVARIANTsimples. Esses de PROPVARIANT simples 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 de variante 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 simplificadas.

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 chamar primeiro IPropertyStorage::ReadMultiple para obter o ponteiro de 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 suas IPropertyStorage e ponteiros IPropertySetStorage, 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 (com suporte IStorage) com sub-objetos de fluxo e armazenamento contidos. Se a transação no objeto pai for anulada, os IStream existentes e IStorage ponteiros 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 do IStream contido e ponteiros de IStorage é 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 do mesmo instância de interface IPropertyStorage. Por exemplo, na implementação de 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 para métodos deIPropertySetStorage(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 o acesso de leitura/gravação, IStorage e IStreampropriedades com valor de leitura sempre serão abertas com acesso de leitura/gravação. Os dados podem então 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 são no escopo da 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 simplificado. Para obter mais informações sobre conjuntos de propriedades simples e não simplificados, 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 de 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 IStorage ou ponteiros de IStream não são mantidos além da duração dessa chamada. Geralmente, é mais eficiente atualizar os objetos de fluxo ou armazenamento diretamente chamando primeiro IPropertyStorage::ReadMultiple para obter o ponteiro da interface para o fluxo ou armazenamento e, em seguida, gravar dados por meio dos métodos IStream ou IStorage.

Por exemplo, você pode chamar IPropertyStorage::WriteMultiple para gravar um null fluxo ou 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 o 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, considerando 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 é iniciada 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 de busca 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 será bem-sucedida. A propriedade de armazenamento ou fluxo aberta anteriormente é colocada no estado revertido (todas as chamadas para ela retornarão STG_E_REVERTED erro).

Se o método WriteMultiple retornar um erro ao escrever 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 estruturaPROPVARIANTespecificada incluir o sinalizador VT_BYREF em seu membro vt, a propriedade associada será uma propriedade de referência. Uma propriedade de referência é automaticamente desreferenciada antes de gravar o valor no conjunto de propriedades. Por exemplo, se o vt membro 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.

Anotações para 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 que você evite usar VT_LPSTR valores e use valores VT_LPWSTR. 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.

de implementação de arquivoIPropertyStorage-Compound

implementação do sistema de arquivos IPropertyStorage-NTFS

de implementação autônoma do IPropertyStorage