Имена в IStorage
Набор свойств идентифицируется с идентификатором формата (FMTID) в интерфейсе IPropertySetStorage. В интерфейсеIStorageнабор свойств называется строкой Юникода со значением NULL с максимальной длиной 32 символов. Чтобы обеспечить взаимодействие, необходимо установить сопоставление между FMTID и соответствующей строкой Юникода, завершающей значение NULL.
Преобразование набора свойств из FMTID в строковое имя
При преобразовании из FMTID в соответствующее имя строки Юникода сначала убедитесь, что FMTID является хорошо известным значением, перечисленным в следующей таблице. В этом случае используйте соответствующее известное имя строки.
FMTID | Имя строки | Семантический |
---|---|---|
F29F85E0-4FF9-1068-AB91-08002B27B3D9 | "\005SummaryInformation" | Сводная информация о COM2 |
D5CDD502-2E9C-101B-9397-08002B2CF9AE D5CDD505-2E9C-101B-9397-08002B2CF9AE |
"\005DocumentSummaryInformation" | Сводная информация о документе Office и пользовательские свойства. |
Заметка
Набор свойств DocumentSummaryInformation и UserDefined является уникальным в том, что он содержит два раздела. Несколько разделов не допускаются в любом другом наборе свойств. Дополнительные сведения см. в формата сериализованного набора свойств структурированного хранилища, а также наборы свойств DocumentSummaryInformation и UserDefined. Первый раздел был определен как часть COM; Второй был определен Microsoft Office.
Если FMTID не является хорошо известным значением, используйте следующую процедуру для алгоритмического формирования имени строки.
Алгоритмически формирует строковое имя
- При необходимости преобразуйте FMTID в маленький байтовый порядок.
- Возьмите 128 бит FMTID и рассмотрите их как одну длинную битовую строку, объединяя каждую из байтов вместе. Первый бит 128-разрядного значения является наименее значительным битом первого байта в памяти FMTID; Последний бит 128-разрядного значения является самым значительным из последнего байта в памяти FMTID. Расширьте эти 128 бит до 130 бит, добавив два ноля битов в конец.
- Разделить 130 бит на группы из пяти битов; таких групп будет 26. Рассмотрим каждую группу как целое число с обратным битом приоритета. Например, первый из 128 бит является наименее значительным битом первой группы из пяти битов; Пятый из 128 бит является самым значительным битом первой группы.
- Сопоставляйте каждое из этих целых чисел в виде индекса в массив тридцати двух символов: ABCDEFGHIJKLMNOPQRSTUVWXYZ012345. Это дает последовательность из 26 символов Юникода, которые используют только прописные символы и цифры. Учитывает регистр и не учитывает регистр, что приводит к тому, что каждый символ будет уникальным в любом языковом стандарте.
- Создайте последнюю строку, объединив строку "\005" на передней части этих 26 символов, для общей длины 27 символов.
В следующем примере кода показано, как сопоставить fmTID со строкой свойства.
#define CBIT_BYTE 8
#define CBIT_CHARMASK 5
#define CCH_MAP (1 << CBIT_CHARMASK) // 32
#define CHARMASK (CCH_MAP - 1) // 0x1f
CHAR awcMap[CCH_MAP + 1] = "abcdefghijklmnopqrstuvwxyz012345";
WCHAR MapChar(ULONG I) {
return((WCHAR) awcMap[i & CHARMASK]);
}
VOID GuidToPropertyStringName(GUID *pguid, WCHAR awcname[]) {
BYTE *pb = (BYTE *) pguid;
BYTE *pbEnd = pb + sizeof(*pguid);
ULONG cbitRemain = CBIT_BYTE;
WCHAR *pwc = awcname;
*pwc++ = ((WCHAR) 0x0005);
while (pb < pbEnd) {
ULONG i = *pb >> (CBIT_BYTE - cbitRemain);
if (cbitRemain >= CBIT_CHARMASK) {
*pwc = MapChar(i);
if (cbitRemain == CBIT_BYTE &&
*pwc >= L'a' && *pwc <= L'z')
{
*pwc += (WCHAR) (L'A' - L'a');
}
pwc++;
cbitRemain -= CBIT_CHARMASK;
if (cbitRemain == 0) {
pb++;
cbitRemain = CBIT_BYTE;
}
}
else {
if (++pb < pbEnd) {
i |= *pb << cbitRemain;
}
*pwc++ = MapChar(i);
cbitRemain += CBIT_BYTE - CBIT_CHARMASK;
}
}
*pwc = L'\0';
}
Преобразование набора свойств из имени строки в FMTID
Преобразователи имен строк свойств в идентификаторы GUID должны принимать строчные буквы как синонимы их верхних регистров.
В следующем примере кода показано, как сопоставить строку свойства с FMTID.
#include "stdafx.h"
#define _INC_OLE
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define CBIT_CHARMASK 5
#define CBIT_BYTE 8
#define CBIT_GUID (CBIT_BYTE * sizeof(GUID))
#define CWC_PROPSET (1 + (CBIT_GUID + CBIT_CHARMASK-1)/CBIT_CHARMASK)
#define WC_PROPSET0 ((WCHAR) 0x0005)
#define CCH_MAP (1 << CBIT_CHARMASK) // 32
#define CHARMASK (CCH_MAP - 1) // 0x1f
CHAR awcMap[CCH_MAP + 1] = "abcdefghijklmnopqrstuvwxyz012345";
#define CALPHACHARS ('z' - 'a' + 1)
GUID guidSummary =
{ 0xf29f85e0,0x4ff9, 0x1068,
{ 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 } };
WCHAR wszSummary[] = L"SummaryInformation";
GUID guidDocumentSummary =
{ 0xd5cdd502,
0x2e9c, 0x101b,
{ 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
WCHAR wszDocumentSummary[] = L"DocumentSummaryInformation";
__inline WCHAR
MapChar(IN ULONG i)
{
return((WCHAR) awcMap[i & CHARMASK]);
}
ULONG PropertySetNameToGuid(
IN ULONG cwcname,
IN WCHAR const awcname[],
OUT GUID *pguid)
{
ULONG Status = ERROR_INVALID_PARAMETER;
WCHAR const *pwc = awcname;
if (pwc[0] == WC_PROPSET0)
{
//Note: cwcname includes the WC_PROPSET0, and
//sizeof(wsz...) includes the trailing L'\0', but
//the comparison excludes both the leading
//WC_PROPSET0 and the trailing L'\0'.
if (cwcname == sizeof(wszSummary)/sizeof(WCHAR) &&
wcsnicmp(&pwc[1], wszSummary, cwcname - 1) == 0)
{
*pguid = guidSummary;
return(NO_ERROR);
}
if (cwcname == CWC_PROPSET)
{
ULONG cbit;
BYTE *pb = (BYTE *) pguid - 1;
ZeroMemory(pguid, sizeof(*pguid));
for (cbit = 0; cbit < CBIT_GUID; cbit +=
CBIT_CHARMASK)
{
ULONG cbitUsed = cbit % CBIT_BYTE;
ULONG cbitStored;
WCHAR wc;
if (cbitUsed == 0)
{
pb++;
}
wc = *++pwc - L'A'; //assume uppercase
if (wc > CALPHACHARS)
{
wc += (WCHAR) (L'A' - L'a'); //try lowercase
if (wc > CALPHACHARS)
{
wc += L'a' - L'0' + CALPHACHARS;
if (wc > CHARMASK)
{
goto fail; //invalid character
}
}
}
*pb |= (BYTE) (wc << cbitUsed);
cbitStored = min(CBIT_BYTE - cbitUsed,
CBIT_CHARMASK);
//If the translated bits will not fit in the
//current byte
if (cbitStored < CBIT_CHARMASK)
{
wc >>= CBIT_BYTE - cbitUsed;
if (cbit + cbitStored == CBIT_GUID)
{
if (wc != 0)
{
goto fail; //extra bits
}
break;
}
pb++;
*pb |= (BYTE) wc;
}
}
Status = NO_ERROR;
}
}
fail:
return(Status);
}
При попытке открыть существующий набор свойств в IPropertySetStorage::Open, fmTID (root) преобразуется в строку, как описано выше. Если элемент IStorage этого имени существует, он используется. В противном случае открытие завершается ошибкой.
При создании нового набора свойств указанное выше сопоставление определяет используемое строковое имя.