ダイアログ: メモリ上にテンプレートを作成する例 (2)
ここでは、DLGTEMPLATE、DLGITEMTEMPLATE 構造体を使った例を示します。
作成例 2
HGLOBAL hgbl;
LPDLGTEMPLATE lpdt;
LPDLGITEMTEMPLATE lpdit;
LPWORD lpw;
LPBYTE lpb;
LPWSTR lpwsz;
int nChar;
// 実際は、サイズはデータが収まりきるように
// あらかじめ計算しておく必要があります。
// GMEM_ZEROINIT であらかじめデータを 0 に設定しておきます。
// (省略されているメンバは 0 になります)
hgbl = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 1024);
if (!hgbl)
ErrorAndExit();
// ダイアログボックスの初期値を設定します。
// ※ hgbl と lpdt のアドレスは同じになります (GMEM_FIXED のため)。
lpdt = (LPDLGTEMPLATE) GlobalLock(hgbl);
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
| DS_MODALFRAME | WS_CAPTION | DS_SETFONT; // フォント付き
lpdt->cdit = 2; // コントロールの数
lpdt->x = 10; lpdt->y = 10;
lpdt->cx = 100; lpdt->cy = 100;
// 次のメンバの設定に移ります。
lpw = (LPWORD) (lpdt + 1);
// <Menu ID>
// *lpw++ = の文は、その位置に値を設定した後 ++ を行います。
// (つまり *lpw = 0; lpw++; と同じ)
// 正式には lpw++ がインクリメントする前のアドレスを返し、
// そのアドレスに対して *XXX = 0 を行っています。
*lpw++ = 0;
// <Window Class>
*lpw++ = 0;
// <Dialog Title>
lpwsz = (LPWSTR) lpw;
// MultiByteToWideChar 関数で ANSI 文字列を Unicode 文字列に変換します。
// 戻り値 (書き込んだ文字列の長さ) に NULL 文字が含まれているので + 1 しません。
nChar = MultiByteToWideChar(CP_ACP, 0, "ダイアログ テスト", -1, lpwsz, 50);
// lpw = (LPWORD) lpwsz は必要ありません (アドレスが同じであるため)。
lpw += nChar;
// WORD fontSize
// ※ DS_SETFONT を指定しなかった場合、コントロールの設定に
// 移るまでのデータ設定は行いません。
*lpw++ = 9;
// WCHAR fontName[]
lpwsz = (LPWSTR) lpw;
nChar = MultiByteToWideChar(CP_ACP, 0, "MS P明朝", -1, lpwsz, 50);
lpw += nChar;
// コントロールの設定に移ります。
// 移る前に DWORD 境界に揃えます。
lpw = (LPWORD) (((DWORD_PTR) lpw + 3) & ~((DWORD_PTR) 3));
lpdit = (LPDLGITEMTEMPLATE) lpw;
// OK ボタンを作ります。
lpdit->x = 10; lpdit->y = 70;
lpdit->cx = 60; lpdit->cy = 14;
lpdit->id = IDOK; // OK ボタンの ID
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
// 次のメンバの設定に移ります。
lpw = (LPWORD) (lpdit + 1);
// <Window Class>
// これでも構いません。
// lpwsz = (LPWSTR) lpw;
// nChar = MultiByteToWideChar(CP_ACP, 0, "Button", -1, lpwsz, 50);
// lpw += nChar;
*lpw++ = 0xFFFF; // 数値指定に必要
*lpw++ = 0x0080; // ボタンのウィンドウクラスを指定します。
// <Control Text>
lpwsz = (LPWSTR) lpw;
nChar = MultiByteToWideChar(CP_ACP, 0, "OK", -1, lpwsz, 50);
lpw += nChar;
// WORD SizeOfCreationData
// 特にデータは無いため、0 で終わります。
// ※ データがある場合、データのサイズ + sizeof(WORD) (= 2) を設定します。
*lpw++ = 0;
// 次のコントロールの設定に移ります。
lpw = (LPWORD) (((DWORD_PTR) lpw + 3) & ~((DWORD_PTR) 3));
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 9;
lpdit->id = IDC_STATIC; // スタティックコントロールによくある ID (IDC_STATIC = -1)
lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
lpw = (LPWORD) (lpdit + 1);
// <Window Class>
// これでも構いません。
// lpwsz = (LPWSTR) lpw;
// nChar = MultiByteToWideChar(CP_ACP, 0, "Static", -1, lpwsz, 50);
// lpw += nChar;
*lpw++ = 0xFFFF;
*lpw++ = 0x0082; // スタティックコントロールのウィンドウクラスを指定します。
// <Control Text>
lpwsz = (LPWSTR) lpw;
nChar = MultiByteToWideChar(CP_ACP, 0, "メッセージ", -1, lpwsz, 50);
lpw += nChar;
// WORD SizeOfCreationData
// 特にデータは無いため、0 で終わります。
*lpw++ = 0;
// データ設定は終了しました。ロックを解除します。
GlobalUnlock(hgbl);
// DialogBoxIndirect を呼び出して作成します。GMEM_FIXED なので
// LPDLGTEMPLATE の引数には hgbl をそのまま指定します。
// (hInst、hWndOwner、DialogProc は既に定義されているものとします。)
DialogBoxIndirect(hInst, (LPDLGTEMPLATE) hgbl, hWndOwner, (DLGPROC) DialogProc);
// メモリを解放します。
GlobalFree(hgbl);