Visual Studioが自動生成したソースを元にダイアログベースのアプリケーションの作り方を調べてみました。
Todayプラグインで日本語入力させるのは諦めました...。
ポイントは 4つ、
- CreateWindowの代わりに CreateDialogを使う
- WNDCLASSの cbWndExtraに DLGWINDOWEXTRAを指定する
- メッセージループで IsDialogMessageを呼ぶ
- WM_INITDIALOGメッセージでダイアログを初期化する
1. CreateWindowの代わりに
CreateDialogを使う
表示したいダイアログをリソースエディタで作成しておき、
CreateDialogで登録します。
このとき、ウィンドウプロシージャが DLGPROC型でないというエラーが出たのでキャストしてみました。
g_hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)WndProc);
2. WNDCLASSの cbWndExtraに DLGWINDOWEXTRAを指定する
この辺を読む限り、cbWndExtraに
DLGWINDOWEXTRAを指定する必要があるみたいです。
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGAPP));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
3. メッセージループで
IsDialogMessageを呼ぶ
CreateDialogのドキュメントによると、ダイアログボックスの動作をサポートするために IsDialogMessageを呼ぶ必要があるそうです。
ただ、プラットホームSDKのドキュメントにはそのような記述がありましたが WM6 SDKのドキュメントには記述がありませんでした。
本当に必要なのでしょうか?
if (!g_hWnd || !IsDialogMessage(g_hWnd, &msg))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
4. WM_INITDIALOGメッセージでダイアログを初期化する
初期化は WM_CREATEではなく、WM_INITDIALOGで行います。
また、ダイアログの設定には
SHInitDialogを使用します。
自動生成されたソースの WM_CREATEで行っていた SHACTIVATEINFOの初期化もここにもって来ました。
case WM_INITDIALOG:
{
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_WANTSCROLLBAR;
shidi.hDlg = hWnd;
SHInitDialog(&shidi);
memset(&s_sai, 0, sizeof (s_sai));
s_sai.cbSize = sizeof (s_sai);
break;
}
後は不要な部分を削除する程度でダイアログを表示できるようになりました。
#include "stdafx.h"
#include "DialogApp.h"
#include <windows.h>
#include <commctrl.h>
#define MAX_LOADSTRING 100
HINSTANCE g_hInst;
HWND g_hWnd;
ATOM MyRegisterClass(HINSTANCE, LPTSTR);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
if (!InitInstance(hInstance, nCmdShow)) {
return FALSE;
}
HACCEL hAccelTable;
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DIALOGAPP));
while (GetMessage(&msg, NULL, 0, 0)) {
if (!g_hWnd || !IsDialogMessage(g_hWnd, &msg)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGAPP));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
g_hInst = hInstance;
SHInitExtraControls();
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_DIALOGAPP, szWindowClass, MAX_LOADSTRING);
g_hWnd = FindWindow(szWindowClass, szTitle);
if (g_hWnd) {
SetForegroundWindow((HWND)((ULONG) g_hWnd | 0x00000001));
return 0;
}
if (!MyRegisterClass(hInstance, szWindowClass)) {
return FALSE;
}
g_hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)WndProc);
if (!g_hWnd) {
return FALSE;
}
ShowWindow(g_hWnd, nCmdShow);
UpdateWindow(g_hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
static SHACTIVATEINFO s_sai;
switch (message) {
case WM_INITDIALOG:
{
SHINITDLGINFO shidi;
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_WANTSCROLLBAR;
shidi.hDlg = hWnd;
SHInitDialog(&shidi);
memset(&s_sai, 0, sizeof (s_sai));
s_sai.cbSize = sizeof (s_sai);
break;
}
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case IDOK:
SendMessage (hWnd, WM_CLOSE, 0, 0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_ACTIVATE:
SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE);
break;
case WM_SETTINGCHANGE:
SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}