INT_PTR DialogBox( HINSTANCE hInstance,
LPCTSTR lpTemplate,
HWND hWndParent,
DLGPROC lpDialogFunc
);
这个函数根据对话框资源,创建一个模式对话框,这个对话框应该用EndDialog来结束。
hInstance 当前应用程序实例句柄。
lpTemplate 标识对话框模板资源,有两种使用方式:一种是把对话框模板的ID强制转为LPCTSTR,一种可以使用MAKEINTRESOURCE宏得到标识ID。
hWndParent 父窗口的句柄。
lpDialogFunc 对话框消息处理函数。
HWND CreateDialog( HINSTANCE hInstance,
LPCTSTR lpTemplate,
HWND hWndParent,
DLGPROC lpDialogFunc
);
这个函数根据对话框资源,创建一个非模式对话框,这个对话框应该用DestroyWindow来结束。
函数的参数跟上面的DialogBox用法相同。
模式对话框一般是在栈中生成的,所以EndDialog可能只是隐藏窗口,并没有销毁,当模式对话框对应的对象离开生命区时即销毁对话框。非模式的对话框一般在堆中,所以要主动用DestroyWindow销毁它。
DialogBox 函数自己处理消息循环(这个消息循环在user32.dll里面维护,看不到)且在对话框关闭后函数才会返回(返回值是EndDialog的第二个参数,所以可以用EndDialog的第二个参数来标识子控件的ID),而CreateDialog函数调用了CreateWindowEx函数来创建窗口并立即返回,之后这个窗口使用主窗口的消息循环(即这个窗口产生的消息可能直接发给这个窗口的处理函数,也可能进入主窗口的消息循环)。
不管是模式的还是非模式的对话框,对于不希望处理的消息,都不应该调用DefWindowProc来处理(否则会有问题),因为系统会主动对这些消息进行处理。对于不希望处理的消息,程序要做的只是return FALSE即可,而对于处理过的消息,则应该return TRUE。
这种情况跟主窗口的处理不同。主窗口对不希望处理的消息也要调用DefWindowProc来处理,而每个消息处理分支的返回值是无关紧要的(不像对话框那样一定要返回TRUE或FALSE那样)。
非模式对话框跟主窗口使用同一个消息循环,而因为非模式对话框的消息会被系统主动调用这个对话框的处理函数来处理,所以在消息循环中不应该再对这个消息进行转换和分发,可以把消息循环改成这样:
// 主消息循环:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
// 不是非模式对话框g_hFlashWnd的消息才分发
if ( !IsDialogMessage( g_hFlashWnd, &msg ) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
CreateDialog会发出WM_INITDIALOG消息。
一些例子代码:
/// 非模式对话框消息处理函数
BOOL __stdcall FlashWndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch ( msg )
{
case WM_INITDIALOG:
break;
case WM_PAINT:
break;
case WM_LBUTTONDOWN:
DestroyWindow( hWnd );
break;
default:
return FALSE; // 没处理过的消息
}
return TRUE; // 处理过的
}
///创建一个非模式对话框
g_hFlashWnd = CreateDialog( hInst, MAKEINTRESOURCE(IDD_FLASH), hWnd, (DLGPROC)FlashWndProc );
ShowWindow( g_hFlashWnd, SW_SHOW );
// WinTest.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
BOOL InitDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWndDlg = NULL;
MSG msg;
hWndDlg = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DialogProc, NULL);
if(hWndDlg == NULL)
{
MessageBox(NULL, "创建对话框失败.", "", MB_OK);
return 0;
}
RECT rtDlg;
GetWindowRect(hWndDlg, &rtDlg);
int nScreenX = GetSystemMetrics(SM_CXSCREEN);
int nScreenY = GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(hWndDlg,
HWND_TOP,
nScreenX / 2 - rtDlg.right / 2,
nScreenY / 2 - rtDlg.bottom / 2,
0,
0,
SWP_NOSIZE | SWP_SHOWWINDOW); //SWP_NOSIZE)
while(GetMessage(&msg, NULL, NULL, NULL))
{
if(msg.message == WM_KEYDOWN)
{
SendMessage(hWndDlg, msg.message, msg.wParam, msg.lParam);
}
else if(!IsDialogMessage(hWndDlg, &msg))// 如果消息没有被处理, 返回值为0
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
BOOL InitDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/*
响应WM_INITDIALOG消息时,如果函数调用SetFocus设置对话
框中控制中的一个焦点, 则对话框应用程序应该返回零值,否则对
话框应用程序应该返回非零值在,这种情况下系统对能够有焦点的
对话框中的第一个控制设置焦点。
*/
return TRUE;
}
BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return InitDialog(hWnd, uMsg, wParam, lParam);
case WM_KEYDOWN:
break;
case WM_COMMAND:
if(LOWORD(wParam) == IDOK)
{
// MessageBox(hWnd, "确定", "", MB_OK);
}
else if(LOWORD(wParam) == IDCANCEL)
{
DestroyWindow(hWnd);
}
return TRUE;
case WM_CLOSE:
DestroyWindow(hWnd);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
return FALSE; // 如果函数不处理消息,则对话框应用程序应该返回零值。
}