Поделиться через


Рекомендации по хранилищу свойств

IPropertyStorage::ReadMultiple считывает столько свойств, указанных в массиве rgpspec , сколько найдено в наборе свойств. Пока считывается любое из запрошенных свойств, запрос на получение несуществующего свойства не является ошибкой. Вместо этого VT_EMPTY должны быть записаны для этого свойства в массив rgvar[] при возврате. Если ни одно из запрошенных свойств не существует, метод должен вернуть S_FALSE и задать VT_EMPTY в каждом PROPVARIANT. Если возвращается какая-либо другая ошибка, значения свойств не извлекаются, и вызывающему объекту не нужно беспокоиться об их освобождении.

Параметр rgpspec представляет собой массив структур PROPSPEC , которые указывают для каждого свойства либо его идентификатор свойства, либо, если он назначен, строковый идентификатор. Вы можете сопоставить строку с идентификатором свойства, вызвав метод IPropertyStorage::WritePropertyNames. Однако использование идентификаторов свойств, скорее всего, будет значительно более эффективным, чем использование строк.

Свойства, запрашиваемые строковым именем (PRSPEC_LPWSTR), сопоставляются с идентификаторами свойств без учета регистра, указанными в текущем наборе свойств (и в соответствии с текущим языковым стандартом системы).

Если тип свойства VT_LPSTR и свойство считывается из набора свойств ANSI, то есть кодовая страница набора свойств имеет значение, отличное от Юникода, значение свойства использует ту же кодовую страницу, что и набор свойств. Когда свойство VT_LPSTR считывается из набора свойств Юникода, значение свойства использует текущую кодовую страницу ANSI системы по умолчанию, то есть кодовую страницу, возвращенную функцией GetACP .

PROPVARIANT, за исключением тех, которые являются указателями на потоки и хранилища, называется простым PROPVARIANT. Эти простые propvariantполучают данные по значению, поэтому вызов IPropertyStorage::ReadMultiple предоставляет копию данных, которыми затем владеет вызывающий объект. Чтобы создать или обновить эти свойства, вызовите IPropertyStorage::WriteMultiple.

В отличие от этого, типы вариантов VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE и VT_STORED_OBJECT являются не простыми свойствами, так как вместо предоставления значения метод извлекает указатель на указанный интерфейс, из которого затем можно считывать данные. Эти типы позволяют хранить большие объемы информации с помощью одного свойства. При использовании неимпляковых свойств возникает несколько проблем.

Чтобы создать эти свойства, как и другие, вызовите метод IPropertyStorage::WriteMultiple. Вместо того чтобы вызывать один и тот же метод для обновления, эффективнее сначала вызвать IPropertyStorage::ReadMultiple , чтобы получить указатель интерфейса на поток или хранилище, а затем записать данные с помощью методов IStream или IStorage . Поток или хранилище, открытые через свойство , всегда открываются в прямом режиме, поэтому дополнительный уровень вложенной транзакции не вводится. Однако в наборе свойств по-прежнему может существовать транзакция в целом в зависимости от того, как он был открыт или создан с помощью IPropertySetStorage. Кроме того, теги режима доступа и общего доступа, указанные при открытии или создании набора свойств, передаются в потоки или хранилища на основе свойств.

Время существования потоков на основе свойств или указателей хранилища, хотя теоретически не зависит от связанных с ними указателей IPropertyStorage и IPropertySetStorage , фактически зависит от них. Данные, видимые в потоке или хранилище, связаны с транзакцией в объекте хранилища свойств, из которого они извлекаются, так же, как и для объекта хранилища (поддерживающего IStorage) с автономным потоком и вложенными объектами хранилища. Если транзакция в родительском объекте прервана, существующие указатели IStream и IStorage , подчиненные объекту, больше не будут доступны. Поскольку IPropertyStorage является единственным интерфейсом в объекте хранилища свойств, полезное время существования содержащихся указателей IStream и IStorage ограничивается временем существования интерфейса IPropertyStorage .

Реализация также должна иметь дело с ситуацией, когда одно и то же свойство с значением потока или хранилища запрашивается несколько раз через один и тот же экземпляр интерфейса IPropertyStorage . Например, в реализации составного файла COM открытие будет выполнено успешно или неудачно в зависимости от того, открыто ли свойство.

Другая проблема заключается в нескольких открытиях в режиме транзакций. Результат зависит от уровня изоляции, указанного с помощью вызова методов IPropertySetStorage (метода Open или Create с помощью флагов STGM) на момент открытия хранилища свойств.

Если вызов для открытия набора свойств указывает доступ на чтение и запись, свойства IStorage и IStream всегда открываются с доступом на чтение и запись. Затем данные можно записать через эти интерфейсы, изменив значение свойства, что является наиболее эффективным способом обновления этих свойств. Само значение свойства не имеет дополнительного уровня вложенности транзакций, поэтому изменения определяются в рамках транзакции (если таковые имеются) в объекте хранилища свойств.

Свойства хранилища и потока

Чтобы записать поток или объект хранилища в набор свойств, набор свойств должен быть создан как nonsimple. Дополнительные сведения о простых и неимплированных наборах свойств см. в разделе Storage and Stream Objects for a Property Set. Следующие типы свойств, указанные в поле vt элементов массива rgvar , являются типами потоков или хранилищ: VT_STREAM, VT_STORAGE, VT_STREAMED_OBJECT VT_STORED_OBJECT.

Чтобы записать объект потока или хранилища в качестве свойства в не простом наборе свойств, вызовите метод IPropertyStorage::WriteMultiple. Хотя этот метод также вызывается для обновления простых свойств, он не является эффективным способом обновления объектов потока и хранилища в наборе свойств. Это связано с тем, что обновление одного из этих свойств с помощью вызова WriteMultiple создает в объекте хранилища свойств копию переданных данных, а указатели IStorage или IStream не сохраняются дольше времени этого вызова. Обычно более эффективно обновлять объекты потока или хранилища напрямую, сначала вызывая IPropertyStorage::ReadMultiple , чтобы получить указатель интерфейса на поток или хранилище, а затем записать данные с помощью методов IStream или IStorage .

Например, можно вызвать IPropertyStorage::WriteMultiple для записи потока NULL или объекта хранилища. Затем реализация создаст пустой объект в наборе свойств. Затем можно получить доступ к этому объекту, вызвав метод IPropertyStorage::ReadMultiple. После завершения обновления этого объекта не нужно записывать его в набор свойств, так как обновления переходили непосредственно в набор свойств.

Поток или хранилище, открытые через свойство , всегда открываются в прямом режиме, поэтому дополнительный уровень вложенной транзакции не вводится. По-прежнему может существовать транзакция для набора свойств в целом. (Например, если IPropertyStorage был получен путем вызова IPropertySetStorage::Open с флагом STGM_TRANSACTED, установленным в параметре grfmode .) Кроме того, поток на основе свойств или хранилище открывается в режиме чтения и записи, если это возможно, при использовании режима набора свойств; в противном случае используется режим чтения.

Как упоминалось ранее, при записи потока или объекта хранилища в набор свойств с помощью метода WriteMultiple создается копия объекта . Когда такая копия выполняется в объекте потока, операция копирования начинается с текущей позиции поиска источника. Позиция поиска не определена при сбое, но при успешном выполнении она находится в конце потока; Указатель поиска не восстанавливается в исходное положение.

Если свойство потока или хранилища было считано из свойства, заданного с помощью ReadMultiple, по-прежнему остается открытым и последующий вызов WriteMultiple для того же свойства, операция WriteMultiple будет выполнена успешно. Ранее открытое свойство потока или хранилища помещается в возвращенное состояние (все вызовы к нему будут возвращать STG_E_REVERTED ошибку).

Если метод WriteMultiple возвращает ошибку при записи массива свойств или даже отдельных не простых свойств, объем фактически записанных данных не определен.

Свойства ссылки

Если указанная структура PROPVARIANT включает флаг VT_BYREF в член vt , связанное свойство является ссылочным свойством. Свойство ссылки автоматически разыменовывается перед записью значения в набор свойств. Например, если член vt структуры PROPVARIANT указывает значение типа VT_BYREF | VT_I4, записанное значение является типом VT_I4. Последующий вызов метода IPropertyStorage::ReadMultiple возвращает значение в виде VT_I4. Использование ссылочных свойств аналогично вызову функции VariantCopyInd . VariantCopyInd освобождает вариант назначения и создает копию исходного VARIANTARG, выполняя необходимое косвенное обращение, если источник указан для VT_BYREF. Эта функция полезна, когда требуется копия варианта и гарантирует, что она не VT_BYREF, например при обработке аргументов в реализации IDispatch::Invoke.

Примечания для тех, кто вызывает этот метод

Рекомендуется создавать наборы свойств как Юникод, не устанавливая флаг PROPSETFLAG_ANSI в параметре grfFlagsобъекта IPropertySetStorage::Create. Также рекомендуется избегать использования VT_LPSTR значений и использовать вместо него VT_LPWSTR значения. Если кодовая страница набора свойств имеет значение Юникод, VT_LPSTR строковые значения преобразуются в Юникод при хранении и обратно в многобайтовые строковые значения при извлечении. Если кодовая страница набора свойств не является Юникодом, имена свойств, VT_BSTR строки и не простые значения свойств преобразуются в многобайтовые строки при хранении и преобразуются обратно в Юникод при извлечении, используя текущую системную кодовую страницу ANSI.

Примечания для тех, кто реализует этот метод

При выделении идентификатора свойства реализация может выбрать любое значение, которое в данный момент не используется в наборе свойств для идентификатора свойства, если оно не равно 0, 1 или больше 0x80000000, все из которых являются зарезервированными значениями. Параметр propidNameFirst устанавливает минимальное значение идентификаторов свойств в наборе и должно быть больше 1 и меньше 0x80000000. См. раздел "Примечания" выше.

Реализация составного файла IPropertyStorage

Реализация файловой системы IPropertyStorage-NTFS

Автономная реализация IPropertyStorage