Considerazioni sull'archiviazione delle proprietà

IPropertyStorage::ReadMultiple legge quante delle proprietà specificate nella matrice rgpspec sono disponibili nel set di proprietà. Se viene letta una delle proprietà richieste, una richiesta di recupero di una proprietà che non esiste non è un errore. È invece necessario che VT_EMPTY venga scritto per tale proprietà nella matrice rgvar[] al ritorno. Quando nessuna delle proprietà richieste esiste, il metodo deve restituire S_FALSE e impostare VT_EMPTY in ogni PROPVARIANT. Se viene restituito un altro errore, non vengono recuperati valori di proprietà e il chiamante non deve preoccuparsi del rilascio.

Il parametro rgpspec è una matrice di strutture PROPSPEC , che specificano per ogni proprietà il relativo identificatore di proprietà o, se ne viene assegnato uno, un identificatore di stringa. È possibile eseguire il mapping di una stringa a un identificatore di proprietà chiamando IPropertyStorage::WritePropertyNames. L'uso degli identificatori di proprietà è tuttavia molto più efficiente rispetto all'uso di stringhe.

Le proprietà richieste dal nome stringa (PRSPEC_LPWSTR) vengono mappate senza distinzione tra maiuscole e minuscole agli identificatori di proprietà (ID) specificati nel set di proprietà corrente (e in base alle impostazioni locali di sistema correnti).

Quando il tipo di proprietà è VT_LPSTR e la proprietà viene letta da un set di proprietà ANSI, ovvero la tabella codici per il set di proprietà viene impostata su un valore diverso da Unicode, il valore della proprietà utilizza la stessa tabella codici del set di proprietà. Quando una proprietà VT_LPSTR viene letta da un set di proprietà Unicode, il valore della proprietà usa la tabella codici ANSI predefinita corrente del sistema, ovvero la tabella codici restituita dalla funzione GetACP .

Un PROPVARIANT, ad eccezione di quelli che sono puntatori ai flussi e alle risorse di archiviazione, è detto semplice PROPVARIANT. Questi semplici PROPVARIANTricevono i dati in base al valore, quindi una chiamata a IPropertyStorage::ReadMultiple fornisce una copia dei dati di cui è proprietario il chiamante. Per creare o aggiornare queste proprietà, chiamare IPropertyStorage::WriteMultiple.

Al contrario, i tipi varianti VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE e VT_STORED_OBJECT sono proprietà non semplici, perché anziché fornire un valore, il metodo recupera un puntatore all'interfaccia indicata, da cui i dati possono quindi essere letti. Questi tipi consentono l'archiviazione di grandi quantità di informazioni tramite una singola proprietà. Esistono diversi problemi che si verificano nell'uso di proprietà nonsimple.

Per creare queste proprietà, come per le altre proprietà, chiamare IPropertyStorage::WriteMultiple. Anziché chiamare lo stesso metodo per aggiornare, è tuttavia più efficiente chiamare IPropertyStorage::ReadMultiple per ottenere il puntatore dell'interfaccia al flusso o all'archiviazione, quindi scrivere dati usando i metodi IStream o IStorage . Un flusso o una risorsa di archiviazione aperta tramite una proprietà viene sempre aperto in modalità diretta, quindi non viene introdotto un livello aggiuntivo di transazione annidata. Tuttavia, potrebbe essere ancora presente una transazione nel set di proprietà nel suo complesso, a seconda della modalità di apertura o creazione tramite IPropertySetStorage. Inoltre, i tag di modalità di accesso e condivisione specificati quando il set di proprietà viene aperto o creato, vengono passati a flussi o archivi basati su proprietà.

Le durate dei puntatori di flusso o di archiviazione basati su proprietà, anche se in teoria indipendenti dai puntatori IPropertyStorage e IPropertySetStorage associati dipendono in effetti da essi. I dati visibili tramite il flusso o l'archiviazione sono correlati alla transazione nell'oggetto di archiviazione delle proprietà da cui vengono recuperati, come per un oggetto di archiviazione (che supporta IStorage) con oggetti secondari di archiviazione e flusso indipendente. Se la transazione nell'oggetto padre viene interrotta, i puntatori IStream e IStorage esistenti subordinati a tale oggetto non sono più accessibili. Poiché IPropertyStorage è l'unica interfaccia dell'oggetto di archiviazione delle proprietà, la durata utile dei puntatori IStream e IStorage contenuti è vincolata dalla durata dell'interfaccia IPropertyStorage .

L'implementazione deve anche gestire la situazione in cui la stessa proprietà con valori di flusso o archiviazione viene richiesta più volte tramite la stessa istanza dell'interfaccia IPropertyStorage . Nell'implementazione del file composto COM, ad esempio, l'apertura avrà esito positivo o negativo a seconda che la proprietà sia già aperta o meno.

Un altro problema è l'apertura multipla in modalità transazionata. Il risultato dipende dal livello di isolamento specificato tramite una chiamata ai metodi IPropertySetStorage , ovvero il metodo Open o Create , tramite i flag STGM, al momento dell'apertura dell'archiviazione delle proprietà.

Se la chiamata per aprire il set di proprietà specifica l'accesso in lettura/scrittura, le proprietà IStorage e IStream-valued vengono sempre aperte con accesso in lettura/scrittura. I dati possono quindi essere scritti tramite queste interfacce, modificando il valore della proprietà, che è il modo più efficiente per aggiornare queste proprietà. Il valore della proprietà non dispone di un livello aggiuntivo di annidamento delle transazioni, pertanto le modifiche vengono con ambito nella transazione (se presente) nell'oggetto di archiviazione delle proprietà.

Proprietà di archiviazione e flusso

Per scrivere un flusso o un oggetto di archiviazione in un set di proprietà, è necessario che il set di proprietà sia stato creato come nonsimple. Per altre informazioni sui set di proprietà semplici e nonsimple, vedere la sezione Storage and Stream Objects for a Property Set .For more information on simple and nonsimple property sets, see the section titled Storage and Stream Objects for a Property Set. I tipi di proprietà seguenti, come specificato nel campo vt degli elementi della matrice rgvar , sono tipi di flusso o di archiviazione: VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT VT_STORED_OBJECT.

Per scrivere un flusso o un oggetto di archiviazione come proprietà in un set di proprietà non semplice, chiamare IPropertyStorage::WriteMultiple. Anche se si chiama anche questo metodo per aggiornare le proprietà semplici, non è un modo efficiente per aggiornare gli oggetti di flusso e di archiviazione in un set di proprietà. Ciò è dovuto al fatto che l'aggiornamento di una di queste proprietà tramite una chiamata a WriteMultiple crea nell'oggetto di archiviazione delle proprietà una copia dei dati passati e i puntatori IStorage o IStream non vengono mantenuti oltre la durata di questa chiamata. In genere è più efficiente aggiornare direttamente gli oggetti di flusso o di archiviazione chiamando IPropertyStorage::ReadMultiple per ottenere il puntatore dell'interfaccia al flusso o all'archiviazione, quindi scrivendo i dati tramite i metodi IStream o IStorage .

Ad esempio, è possibile chiamare IPropertyStorage::WriteMultiple per scrivere un flusso NULL o un oggetto di archiviazione. L'implementazione creerà quindi un oggetto vuoto nel set di proprietà. È quindi possibile ottenere l'accesso a questo oggetto chiamando IPropertyStorage::ReadMultiple. Al termine dell'aggiornamento di questo oggetto non è necessario scriverlo nel set di proprietà, perché gli aggiornamenti venivano inseriti direttamente nel set di proprietà.

Un flusso o una risorsa di archiviazione aperta tramite una proprietà viene sempre aperto in modalità diretta, quindi non viene introdotto un livello aggiuntivo di transazione annidata. È comunque possibile che sia presente una transazione per l'intero set di proprietà. Ad esempio, se IPropertyStorage è stato ottenuto chiamando IPropertySetStorage::Open con il flag STGM_TRANSACTED impostato nel parametro grfmode . Inoltre, un flusso o una risorsa di archiviazione basata su proprietà viene aperto in modalità di lettura/scrittura, se possibile, data la modalità sul set di proprietà; in caso contrario, viene usata la modalità di lettura.

Come accennato in precedenza, quando un flusso o un oggetto di archiviazione viene scritto in un set di proprietà con il metodo WriteMultiple , viene creata una copia dell'oggetto . Quando tale copia viene eseguita su un oggetto flusso, l'operazione di copia inizia in corrispondenza della posizione di ricerca corrente dell'origine. La posizione di ricerca non è definita in caso di errore, ma in caso di esito positivo si trova alla fine del flusso; il puntatore di ricerca non viene ripristinato nella posizione originale.

Se una proprietà di flusso o di archiviazione è stata letta da un set di proprietà con ReadMultiple, viene comunque mantenuta aperta e viene eseguita una chiamata successiva a WriteMultiple per la stessa proprietà, l'operazione WriteMultiple avrà esito positivo. La proprietà di archiviazione o flusso aperta in precedenza viene inserita nello stato ripristinato (tutte le chiamate a tale flusso restituiranno STG_E_REVERTED errore).

Se il metodo WriteMultiple restituisce un errore durante la scrittura di una matrice di proprietà o anche singole proprietà non semplici, la quantità di dati effettivamente scritti non è definita.

Proprietà riferimento

Se una struttura PROPVARIANT specificata include il flag VT_BYREF nel relativo membro vt , la proprietà associata è una proprietà di riferimento. Una proprietà di riferimento viene dereferenziata automaticamente prima di scrivere il valore nel set di proprietà. Ad esempio, se il membro vt della struttura PROPVARIANT specifica un valore di tipo VT_BYREF | VT_I4, il valore effettivo scritto è un tipo VT_I4. Una chiamata successiva al metodo IPropertyStorage::ReadMultiple restituisce un valore come VT_I4. L'uso delle proprietà di riferimento è simile alla chiamata alla funzione VariantCopyInd . VariantCopyInd libera la variante di destinazione e crea una copia dell'oggetto VARIANTARG di origine, eseguendo l'indiretto necessario se l'origine viene specificata per essere VT_BYREF. Questa funzione è utile quando è necessaria una copia di una variante e per garantire che non sia VT_BYREF, ad esempio quando si gestiscono gli argomenti in un'implementazione di IDispatch::Invoke.

Note per i chiamanti

È consigliabile creare set di proprietà come Unicode, non impostando il flag PROPSETFLAG_ANSI nel parametro grfFlags di IPropertySetStorage::Create. È anche consigliabile evitare di usare valori VT_LPSTR e usare invece valori VT_LPWSTR. Quando la tabella codici del set di proprietà è Unicode, VT_LPSTR i valori stringa vengono convertiti in Unicode quando vengono archiviati e di nuovo in valori stringa multibyte quando vengono recuperati. Quando la tabella codici del set di proprietà non è Unicode, i nomi delle proprietà, le stringhe VT_BSTR e i valori delle proprietà non semplici vengono convertiti in stringhe multibyte quando vengono archiviate e convertite nuovamente in Unicode quando vengono recuperate, tutte usando la tabella codici ANSI di sistema corrente.

Note per gli implementatori

Quando si alloca un identificatore di proprietà, l'implementazione può scegliere qualsiasi valore attualmente in uso nel set di proprietà per un identificatore di proprietà, purché non sia 0 o 1 o maggiore di 0x80000000, tutti valori riservati. Il parametro propidNameFirst stabilisce un valore minimo per gli identificatori di proprietà all'interno del set e deve essere maggiore di 1 e minore di 0x80000000. Vedere la sezione Osservazioni sopra.

Implementazione di file IPropertyStorage-Compound

Implementazione del file system IPropertyStorage-NTFS

Implementazione autonoma di IPropertyStorage