ダイアログ: メモリ上にテンプレートを作成
ダイアログ ボックスは、普通はリソースから作成するか、システムが提供するメッセージボックスを表示させる以外では作成できません。しかし、リソースのデータと同じダイアログ テンプレートを作成することによって、動的にダイアログを作成することが出来ます。
Win16 版のものは Win32 のとは異なります。「Win16 でメモリ上にテンプレートを作成」をご覧下さい。
ダイアログ テンプレート
ダイアログ テンプレートは、DLGTEMPLATE 構造体を先頭とするバイナリ データです。メモリ上で DLGTEMPLATE の直後にはメニュー、キャプション (タイトルバーの文字列) や、必要があればフォントデータなどが続きます。
その後には、コントロールの数だけ DLGITEMTEMPLATE 構造体が来ます。その後にコントロールのクラス名、テキスト、データが続きます。
以下は DLGTEMPLATE、DLGITEMTEMPLATE 構造体の定義です。
typedef struct { DWORD style; DWORD dwExtendedStyle; WORD cdit; short x; short y; short cx; short cy; // <Menu ID>; // <Window Class>; // <Dialog Title>; // WORD fontSize; // WCHAR fontName[]; // DLGITEMTEMPLATE controls[cdit]; } DLGTEMPLATE, FAR* LPDLGITEMPLATE;
typedef struct { // BYTE padding[]; DWORD style; DWORD dwExtendedStyle; short x; short y; short cx; short cy; WORD id; // <Window Class>; // <Control Text>; // WORD SizeOfCreationData; // BYTE CreationData[SizeOfCreationData]; } DLGITEMTEMPLATE, FAR* LPDLGITEMTEMPLATE;
※ 上記の定義でコメントアウトしている部分は、実際には設定する内容によって型やサイズ・メモリ上での位置が変わってしまうため、明確な定義をすることが出来ません。
構造体のメンバ
- style
- ダイアログ、またはコントロールのスタイルです。(WS_ 、DS_ など)
- dwExtendedStyle
- ダイアログ、またはコントロールの拡張スタイルです。(WS_EX_ など)
- cdit
- ダイアログが持つコントロールの数です。(Count of DLGITEMTEMPLATE の略)
- x, y, cx, cy
- ダイアログ、またはコントロールのサイズです。このサイズはダイアログベース単位で指定する必要があります。ピクセルからこの単位に変換するには、GetDialogBaseUnits 関数を使う方法がありますが、本来はフォントのサイズを計算に含める必要があり、おすすめできません。
- id
- コントロールの ID です。なお、IDOK (= 1) を指定し、スタイルに BS_DEFPUSHBUTTON を指定すると既定のボタン (エディットコントロールで Enter をしたときに自動的に押されるボタン) に、IDCANCEL (= 2) を指定するとキャンセルボタン (ESC キーを押すと自動的に押されるボタン) になります。
- <Menu ID>
- メニューリソースの ID を指定します。整数値で指定する場合は、このメンバは WORD[2] となり、最初に 0xFFFF、2 番目に ID を指定します。
ID を文字列で指定する場合は、このメンバは NULL で終わる Unicode 文字列となります。NULL 文字の次の位置が、次のメンバの始点となります。
指定しない場合 (メニュー無し) は、WORD サイズで 0 を指定します。(空の文字列と同じ) - <Window Class>
- ウィンドウのクラスを指定します。指定方法は <Menu ID> と同じです。
ここでも整数値が指定できます。最初に 0xFFFF を指定した後、以下の値を指定すると、クラス名の文字列を入れなくてもそのクラスで作成できます。
値 コントロール 0x0080 ボタン (Button) 0x0081 エディットコントロール (Edit) 0x0082 スタティックコントロール (Static) 0x0083 リストボックス (ListBox) 0x0084 スクロールバー (ScrollBar) 0x0085 コンボボックス (ComboBox) - <Dialog Title>、<Control Text>
- ダイアログのタイトル、コントロールのテキストを指定します。指定方法は <Menu ID> と同じです。
ダイアログのタイトルの場合は文字列のみですが、コントロールのテキストの場合、最初が 0xFFFF なら、このメンバは WORD[2] となり、次に来る WORD 値 (最初の値は左の通り 0xFFFF) は ID です。この ID はスタティック コントロールなどで、画像を表示する際にリソースから読み込む時のリソース ID となります。 - fontSize
- フォントのサイズをポイント単位で指定します。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- fontName
- フォントの名前を、NULL で終わる Unicode 文字列で指定します。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- padding
- 次のメンバ (ここでは style) が「DWORD 境界」(16 進数で下 1 桁が 0、4、8、C となるような位置) に来るようにサイズを調節します。メモリのスタート地点が DWORD 境界である場合、次のコードで行えます。(pb はメモリ上のデータで、コントロールデータの最初の位置にあるとします。)
pb = (BYTE FAR*) (((DWORD_PTR) pb + 3) & ~((DWORD_PTR) 3));
- SizeOfCreationData, CreationData
- WM_CREATE メッセージの lParam のデータで渡される任意のデータを指定します。SizeOfCreationData はそのサイズで、0 を指定した場合は CreationData は存在しません。なお、SizeOfCreationData には SizeOfCreationData 分のサイズ (sizeof(WORD)) も含みます。
ダイアログ テンプレート拡張版
また、拡張版として DLGTEMPLATEEX、DLGITEMTEMPLATEEX 構造体も存在します。Windows 95、Windows NT 3.51 以降で使用できます。(DLGTEMPLATE は Windows NT 3.1 で使用可)
typedef struct { WORD dlgVer; WORD signature; DWORD helpID; DWORD exStyle; DWORD style; WORD cDlgItems; short x; short y; short cx; short cy; // <Menu ID>; // <Window Class>; // <Dialog Title>; // WORD fontSize; // WORD fontWeight; // BYTE fontItalic; // BYTE fontCharset; // WCHAR fontName[]; // DLGITEMTEMPLATEEX controls[cDlgItems]; } DLGTEMPLATEEX, FAR* LPDLGTEMPLATEEX;
typedef struct { // BYTE padding[]; DWORD helpID; DWORD exStyle; DWORD style; short x; short y; short cx; short cy; DWORD id; // <Window Class>; // <Control Text>; // WORD SizeOfCreationData; // BYTE CreationData[SizeOfCreationData]; } DLGITEMTEMPLATEEX, FAR* LPDLGITEMTEMPLATEEX;
※ 上記の定義でコメントアウトしている部分は、実際には設定する内容によって型やサイズ・メモリ上での位置が変わってしまうため、明確な定義をすることが出来ません。
構造体のメンバ
- dlgVer
- ダイアログテンプレートのバージョンを指定します。この値は 1 になります。
- signature
- このダイアログテンプレートが拡張版かどうかを示すフラグを指定します。。この値は 0xFFFF になります。(これが 0xFFFF でない場合、このテンプレートは拡張版ではありません (つまり DLGTEMPLATE 構造体)。)
- helpID
- WM_HELP メッセージの HELPINFO 構造体で使用されるヘルプ ID を指定します。詳しくは WM_HELP、HELPINFO 構造体を調べてください。
- exStyle
- ダイアログ、またはコントロールの拡張スタイルです。(WS_EX_ など)
- style
- ダイアログ、またはコントロールのスタイルです。(WS_ 、DS_ など)
- cDlgItems
- ダイアログが持つコントロールの数です (DLGTEMPLATE 構造体の cdit に同じ)。
- x, y, cx, cy
- ダイアログ、またはコントロールのサイズです (DLGTEMPLATE、DLGITEMTEMPLATE 構造体と同じ)。
- id
- コントロールの ID です (DLGTEMPLATE 構造体と同じ)。ただし、サイズは DWORD で、0x10000 (65536) を超える ID も設定可能です。
※ マイクロソフトのドキュメントでは WORD 値になっていますが、それだと正しく動きません。 - <Menu ID>
- メニューリソースの ID を指定します (DLGTEMPLATE 構造体と同じ)。
- <Window Class>
- ウィンドウのクラスを指定します (DLGTEMPLATE、DLGITEMTEMPLATE 構造体と同じ)。
- <Dialog Title>、<Control Text>
- ダイアログのタイトル、コントロールのテキストを指定します (DLGTEMPLATE、DLGITEMTEMPLATE 構造体と同じ)。
- fontSize
- フォントのサイズをポイント単位で指定します (DLGTEMPLATE 構造体と同じ)。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- fontWeight
- フォントのウェイト (標準は FW_NORMAL (= 400)、太字は FW_BOLD (= 700) ) を指定します (LOGFONT 構造体の lfWeight に同じ)。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。また、どのような値を指定しても、FW_NORMAL に変更されるそうです。
- fontItalic
- フォントがイタリック (斜体) かどうかを指定します (LOGFONT 構造体の lfItalic に同じ)。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- fontCharset
- フォントの文字セットを指定します (LOGFONT 構造体の lfCharset に同じ)。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- fontName
- フォントの名前を、NULL で終わる Unicode 文字列で指定します。ただし、DS_SETFONT または DS_SHELLFONT スタイルが無い場合、このメンバを指定することは出来ません。
- padding
- 次のメンバ (ここでは helpID) が「DWORD 境界」に来るようにサイズを調節します (DLGITEMTEMPLATE 構造体とほぼ同じ ← 次に来るメンバが違うだけ)。
- SizeOfCreationData, CreationData
- WM_CREATE メッセージの lParam のデータで渡される任意のデータを指定します (DLGITEMTEMPLATE 構造体と同じ)。ただし、SizeOfCreationData には SizeOfCreationData 分のサイズ (sizeof(WORD)) は含まれません。
作成例
ここでは、DLGTEMPLATEEX、DLGITEMTEMPLATEEX 構造体を使った例を示します。(→ DLGTEMPLATE、DLGITEMTEMPLATE 構造体を使った例)
// ※ DLGTEMPLATEEX、DLGITEMTEMPLATEEX は元々定義されていません。 // 上記の定義をヘッダーなどに含めてください。 HGLOBAL hgbl; LPDLGTEMPLATEEX lpdtex; LPDLGITEMTEMPLATEEX lpditex; LPWORD lpw; LPBYTE lpb; LPWSTR lpwsz; int nChar; // 実際は、サイズはデータが収まりきるように // あらかじめ計算しておく必要があります。 // GMEM_ZEROINIT であらかじめデータを 0 に設定しておきます。 // (省略されているメンバは 0 になります) hgbl = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, 1024); if (!hgbl) ErrorAndExit(); // ダイアログボックスの初期値を設定します。 // ※ hgbl と lpdtex のアドレスは同じになります (GMEM_FIXED のため)。 lpdtex = (LPDLGTEMPLATEEX) GlobalLock(hgbl); lpdtex->dlgVer = 1; lpdtex->signature = 0xFFFF; lpdtex->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT; // フォント付き lpdtex->cDlgItems = 2; // コントロールの数 lpdtex->x = 10; lpdtex->y = 10; lpdtex->cx = 100; lpdtex->cy = 100; // 次のメンバの設定に移ります。 lpw = (LPWORD) (lpdtex + 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; // WORD fontWeight *lpw++ = FW_NORMAL; // BYTE fontItalic、BYTE fontCharset // 2 つをまとめて MAKEWORD マクロを使っても設定できます。 // *lpw++ = MAKEWORD(FALSE, DEFAULT_CHARSET) lpb = (LPBYTE) lpw; *lpb++ = FALSE; *lpb++ = DEFAULT_CHARSET; lpw = (LPWORD) lpb; // 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)); lpditex = (LPDLGITEMTEMPLATEEX) lpw; // OK ボタンを作ります。 lpditex->x = 10; lpditex->y = 70; lpditex->cx = 60; lpditex->cy = 14; lpditex->id = IDOK; // OK ボタンの ID lpditex->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; // 次のメンバの設定に移ります。 lpw = (LPWORD) (lpditex + 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 で終わります。 *lpw++ = 0; // 次のコントロールの設定に移ります。 lpw = (LPWORD) (((DWORD_PTR) lpw + 3) & ~((DWORD_PTR) 3)); lpditex = (LPDLGITEMTEMPLATEEX) lpw; lpditex->x = 10; lpditex->y = 10; lpditex->cx = 40; lpditex->cy = 9; lpditex->id = IDC_STATIC; // スタティックコントロールによくある ID (IDC_STATIC = -1) lpditex->style = WS_CHILD | WS_VISIBLE | SS_LEFT; lpw = (LPWORD) (lpditex + 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);
最終更新日: 2005/04/17