2006 年 6 月 22 日 20 時 0 分

型指定の列挙体


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


Initialize メソッドは終わった。
次は、GetColumnInfo メソッドで定義されている、
SHCOLUMNINFO 構造体だ。

今までと同じように、定義を参照する。
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/structures/shcolumninfo.asp

    typedef struct {
        SHCOLUMNID scid;
        VARTYPE vt;
        DWORD fmt;
        UINT cChars;
        DWORD csFlags;
        WCHAR wszTitle[MAX_COLUMN_NAME_LEN];
        WCHAR wszDescription[MAX_COLUMN_DESC_LEN];
    } SHCOLUMNINFO, *LPSHCOLUMNINFO;

この構造体が定義されている shlobj.h を参照し、
パッキングサイズを調べてみると、
#include <pshpack1.h> があるので、1 である。
パッキングの値くらいそろえて欲しいものだ。

また、周辺に定数の定義も見つかった。

    #define MAX_COLUMN_NAME_LEN 80
    #define MAX_COLUMN_DESC_LEN 128

さて、C# に変換してみよう。

    [StructLayout(LayoutKind.Sequential,
            Pack=1, CharSet=CharSet.Unicode)]
    public struct SHCOLUMNINFO {
        public SHCOLUMNID scid;
        public VARTYPE vt;
        public LVCFMT fmt;
        public uint cChars;
        public SHCOLSTATE csFlags;
        [MarshalAs(UnmanagedType.ByValTStr,
                SizeConst=MAX_COLUMN_NAME_LEN)]
        public string wszTitle;
        [MarshalAs(UnmanagedType.ByValTStr,
                SizeConst=MAX_COLUMN_DESC_LEN)]
        public string wszDescription;

        public const int MAX_COLUMN_NAME_LEN = 80;
        public const int MAX_COLUMN_DESC_LEN = 128;
    }

StructLayout については、昨日と同じだ。
SHCOLUMNID は別の構造体なので、後で定義する。
VARTYPE は 2 バイトの整数だが、
定数が決められているので、後で列挙体として定義する。

LVCFMT、SHCOLSTATE は、uint でも構わないのだが、
これらは単純な整数ではなく、
決められた定数の組み合わせなので、
これも後で列挙体として定義することにする。

文字配列バッファである wszTitle と wszDescription は、
昨日と同じく、MarshalAs を使って明示する。

MAX_COLUMN_NAME_LEN や MAX_COLUMN_DESC_LEN は、
この構造体のためだけに定義されているようなので、
構造体の中で const 宣言をする。

少し気持ち悪いが、const で定義した値は、
コンパイル時に全て値に置き換わるので、
const は構造体に対して何の影響も及ぼさない。
これは static readonly フィールドと異なる点だ。

では、SHCOLUMNID を調べよう。

    typedef struct {
        GUID fmtid;
        DWORD pid;
    } SHCOLUMNID, *LPSHCOLUMNID;

これは、shobjidl.h に定義がある。
パッキングサイズの指定は見つからないので 8 だ。
これも C# に変換する。

    [StructLayout(LayoutKind.Sequential, Pack=8)]
    public struct SHCOLUMNID {
        public Guid fmtid;
        public uint pid;
    }

文字列のフィールドが含まれないので、
StructLayout の CharSet は不要だ。
また、GUID 構造体は、.NET にも Guid として定義がある。

次は、VARTYPE だ、VARTYPE は、wtypes.h に、
typedef unsigned short VARTYPE とある。
また、値の定義は VARENUM として列挙してある。

全てを使うわけではないので、幾つかだけ取り出しておこう。
足らなかったら後で追加する。
VARTYPE も汎用なので、Constants.cs に定義する。
(Constants の外、namespace LoaferShellEx.Interop 内)

    // VARTYPE 値
    public enum VARTYPE : ushort {
        BSTR = 8,  // COM 文字列
        I4 = 3,    // 4 バイト符号付整数
        I8 = 20,   // 8 バイト符号付整数
        R4 = 4,    // 4 バイト単精度浮動小数
        R8 = 5,    // 8 バイト倍精度浮動小数
        BOOL = 11, // 2 バイトの真偽値
        DATE = 7,  // COM 日付型
    }

enum は値型であり、基底となる型を指定できる。
VARTYPE は、16 ビットなので、ushort にしておこう。

基底型に指定できるのは整数型だけだが、
基底型を指定しておくと、列挙体の値の表現範囲や、
下記で説明するフラグ演算の際に、
基底型によつ制限や演算が利用される。

また、基底型によって、値型である列挙体が占める
サイズを指定したことになるので、
API や COM で渡す際に、基底型の数値として渡される。

続いて、LVCFMT。これは、リストビューの定数だ。
リストビューに関する定義は commctrl.h に記載がある。
これも一部抜粋して C# にする。一応、Constants.cs へ。

    // ListView のカラム書式フラグ
    [Flags]
    public enum LVCFMT : uint{
        LEFT = 0x0000,
        RIGHT = 0x0001,
        CANTER = 0x0002,
    }

FlagsAttribute を指定すると、
列挙体の値を | などで組み合わせることができる。
一般的に「フラグ」と呼ばれるフィールドに使用する。

Flags を付けておくと ToString() で文字列にした際に、
カンマ区切りで分解して表示してくれるので便利だ。

今回は組み合わせるような値はないが、
本来の LVCFMT_XXXX は組み合わせて指定する値なので、
Flags を付けておくことにしよう。

そして、SHCOLSTATE。shobjidl.h で定義されてるらしい。
これらは、IColumnProvider 関係なので、
IColumnProvider.cs に定義を入れておこう。

    // カラムの型や特徴
    [Flags]
    public enum SHCOLSTATE : uint {
        TYPE_STR      = 0x1,
        TYPE_INT      = 0x2,
        TYPE_DATE     = 0x3,
        TYPEMASK      = 0xf,
        ONBYDEFAULT   = 0x10,
        SLOW          = 0x20,
        EXTENDED      = 0x40,
        SECONDARYUI   = 0x80,
        HIDDEN        = 0x100,
        PREFER_VARCMP = 0x200
    }

TYPE_STR | SLOW のように組み合わせて使用するので、
Flags を付けておくことにしよう。

ううむ。どうしても構造体や定数は、説明が長くなるな。
最後の構造体の説明は明日にしよう。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.