このアーカイブは同期化されません。 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 を付けておくことにしよう。
ううむ。どうしても構造体や定数は、説明が長くなるな。
最後の構造体の説明は明日にしよう。