IStorage の名前

プロパティ セットは、 IPropertySetStorage インターフェイスの形式識別子 (FMTID) で識別されます。 IStorage インターフェイスでは、プロパティ セットの名前は、最大長が 32 文字の null で終わる Unicode 文字列で指定されます。 相互運用性を有効にするには、FMTID と対応する null で終わる Unicode 文字列間のマッピングを確立する必要があります。

FMTID から文字列名にプロパティ セットを変換する

FMTID から対応する Unicode 文字列名に変換する場合は、最初に FMTID が既知の値であることを確認します(次の表を参照)。 その場合は、対応する既知の文字列名を使用します。

FMTID 文字列名 セマンティック
F29F85E0-4FF9-1068-AB91-08002B27B3D9 "\005SummaryInformation" COM2 の概要情報
D5CDD502-2E9C-101B-9397-08002B2CF9AE D5CDD505-2E9C-101B-9397-08002B2CF9AE
"\005DocumentSummaryInformation" Office ドキュメントの概要情報とユーザー定義プロパティ。

Note

DocumentSummaryInformation および UserDefined プロパティ セットは、2 つのセクションが含まれているという点で一意です。 他のプロパティ セットでは、複数のセクションを使用できません。 詳細については、「 構造化ストレージのシリアル化されたプロパティ セットの形式」および 「DocumentSummaryInformation および UserDefined プロパティ セット」を参照してください。 最初のセクションは COM の一部として定義されました。2 つ目は Microsoft Office によって定義されました。

FMTID が既知の値でない場合は、次の手順を使用して、文字列名をアルゴリズムで形成します。

文字列名をアルゴリズムで形成するには

  1. 必要に応じて、FMTID をリトル エンディアンバイト順に変換します。
  2. FMTID の 128 ビットを取得し、各バイトを連結して 1 つの長いビット文字列と見なします。 128 ビット値の最初のビットは、FMTID のメモリ内の最初のバイトの最下位ビットです。128 ビット値の最後のビットは、FMTID のメモリ内の最後のバイトの最上位ビットです。 末尾に 2 つのゼロ ビットを追加して、これらの 128 ビットを 130 ビットに拡張します。
  3. 130 ビットを 5 ビットのグループに分割します。このようなグループは 26 個存在します。 各グループは、ビットの優先順位が逆の整数と考えてください。 たとえば、128 ビットの最初のビットは、5 ビットの最初のグループの最下位ビットです。128 ビットの 5 番目は、最初のグループの最上位ビットです。
  4. これらの各整数をインデックスとして、ABCDEFGHIJKLMNOPQRSTUVWXYZ012345 という 32 文字の配列にマップします。 これにより、大文字と数字のみを使用する 26 個の Unicode 文字のシーケンスが生成されます。 大文字と小文字を区別し、大文字と小文字を区別しない考慮事項は適用されず、ロケールで各文字が一意になります。
  5. 文字列 "\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 が前述のように文字列に変換されます。 その名前の IStorage の要素が存在する場合は、その要素が使用されます。 それ以外の場合、オープンは失敗します。

新しいプロパティ セットを作成するときに、上記のマッピングによって使用される文字列名が決まります。