基于对话框的应用程序与基于SDI和MDI的程序,在程序执行路径上有所不同。对话框的执行路径是:
1.刚开始都是差不多的:_tWinMain——>AfxWinMain——>theApp.InitInstance()
2.接下来有所不同:theApp.InitInstance()——>int nResponse = dlg.DoModal()(注意不是SDI和MDI中的ProcessShellCommand(),——>CreateDlgIndirect()
——>CreateDialogIndirect——>...——>CreateWindowEx().
一般的窗口的创建是使用Create函数,这个函数在创建窗口之前调用了PreCreateWindow函数,并且允许在创建创建之前在PreCreateWindow注册一个拥有自定义窗口样式的新的窗口类,来创建一个拥有自定义类名新的窗口。而模式对话框是通过CreateDialogIndirect来创建的,在这当中并没有调用PreCreateWindow函数,重载的PreCreateWindow函数根本就不被执行,因此在这个函数里修改对话框的窗口类是没有用的。
CDialog是通过CDialog::DoModal()函数创建窗口的,下面是MFC中DoModal函数的代码:
代码
1
int
CDialog::DoModal()
2

{
3
// 载入资源
4
LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
5
HGLOBAL hDialogTemplate = m_hDialogTemplate;
6
HINSTANCE hInst = AfxGetResourceHandle();
7
if (m_lpszTemplateName != NULL)
8
{
9
hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
10
HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
11
hDialogTemplate = LoadResource(hInst, hResource);
12
}
13
if (hDialogTemplate != NULL)
14
lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);
15
if (lpDialogTemplate == NULL)
16
return -1;
17
HWND hWndParent = PreModal();
18
AfxUnhookWindowCreate();
19
BOOL bEnableParent = FALSE;
20
if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
21
{
22
::EnableWindow(hWndParent, FALSE);
23
bEnableParent = TRUE;
24
}
25
TRY
26
{
27
// 创建无模式对话框
28
AfxHookWindowCreate(this);
29
if (CreateDlgIndirect(lpDialogTemplate,
30
CWnd::FromHandle(hWndParent), hInst))
31
{
32
if (m_nFlags & WF_CONTINUEMODAL)
33
{
34
// 进入模式循环
35
DWORD dwFlags = MLF_SHOWONIDLE;
36
if (GetStyle() & DS_NOIDLEMSG)
37
dwFlags |= MLF_NOIDLEMSG;
38
VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
39
}
40
// hide the window before enabling the parent, etc.
41
if (m_hWnd != NULL)
42
SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
43
SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
44
}
45
}
46
CATCH_ALL(e)
47
{
48


49
}
50
END_CATCH_ALL
51
if (bEnableParent)
52
::EnableWindow(hWndParent, TRUE);
53
if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
54
::SetActiveWindow(hWndParent);
55
// destroy modal window
56
DestroyWindow();
57
PostModal();
58
// 解锁、释放资源
59
if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
60
UnlockResource(hDialogTemplate);
61
if (m_lpszTemplateName != NULL)
62
FreeResource(hDialogTemplate);
63
return m_nModalResult;
64
}
在这个函数里先是载入了对话框资源,然后通过LockResource函数,使DLGTEMPLATE类型指针指向相关的内存,然后把这个指针作为参数传递给了CreateDlgIndirect函数(调用了::CreateDialogIndirect)。DLGTEMPLATE的定义如下:
代码
1
typedef
struct
{
2
DWORD style;
3
DWORD dwExtendedStyle;
4
WORD cdit;
5
short x;
6
short y;
7
short cx;
8
short cy;
9
}
DLGTEMPLATE,
*
LPDLGTEMPLATE;
我们看看CreateDlgIndirect函数的源码:
代码
1
BOOL CWnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate,
2
CWnd
*
pParentWnd, HINSTANCE hInst)
3

{ ASSERT(lpDialogTemplate != NULL);
4
if (pParentWnd != NULL)
5
ASSERT_VALID(pParentWnd);
6
7
if (hInst == NULL)
8
hInst = AfxGetInstanceHandle();
9
10
#ifndef _AFX_NO_OCC_SUPPORT
11
_AFX_OCC_DIALOG_INFO occDialogInfo;
12
COccManager* pOccManager = afxOccManager;
13
#endif
14
15
HGLOBAL hTemplate = NULL;
16
17
HWND hWnd = NULL;
18
#ifdef _DEBUG
19
DWORD dwError = 0;
20
#endif
21
22
TRY
23
{
24
VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
25
AfxDeferRegisterClass(AFX_WNDCOMMCTLSNEW_REG);
26
27
#ifndef _AFX_NO_OCC_SUPPORT
28
// separately create OLE controls in the dialog template
29
if (pOccManager != NULL)
30
{
31
if (!SetOccDialogInfo(&occDialogInfo))
32
return FALSE;
33
34
lpDialogTemplate = pOccManager->PreCreateDialog(&occDialogInfo,
35
lpDialogTemplate);
36
}
37
38
if (lpDialogTemplate == NULL)
39
return FALSE;
40
#endif //!_AFX_NO_OCC_SUPPORT
41
42
// If no font specified, set the system font.
43
CString strFace;
44
WORD wSize = 0;
45
BOOL bSetSysFont = !CDialogTemplate::GetFont(lpDialogTemplate, strFace,
46
wSize);
47
48
// On DBCS systems, also change "MS Sans Serif" or "Helv" to system font.
49
if ((!bSetSysFont) && GetSystemMetrics(SM_DBCSENABLED))
50
{
51
bSetSysFont = (strFace == _T("MS Shell Dlg") ||
52
strFace == _T("MS Sans Serif") || strFace == _T("Helv"));
53
if (bSetSysFont && (wSize == 8))
54
wSize = 0;
55
}
56
57
if (bSetSysFont)
58
{
59
CDialogTemplate dlgTemp(lpDialogTemplate);
60
dlgTemp.SetSystemFont(wSize);
61
hTemplate = dlgTemp.Detach();
62
}
63
64
if (hTemplate != NULL)
65
lpDialogTemplate = (DLGTEMPLATE*)GlobalLock(hTemplate);
66
67
// setup for modal loop and creation
68
m_nModalResult = -1;
69
m_nFlags |= WF_CONTINUEMODAL;
70
71
// create modeless dialog
72
AfxHookWindowCreate(this);
73
hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,
74
pParentWnd->GetSafeHwnd(), AfxDlgProc);
75
#ifdef _DEBUG
76
dwError = ::GetLastError();
77
#endif
78
}
79
CATCH_ALL(e)
80
{
81
DELETE_EXCEPTION(e);
82
m_nModalResult = -1;
83
}
84
END_CATCH_ALL
85
.
86
ASSERT(hWnd == m_hWnd);
87
return TRUE;
88
}
函数CreateDialogIndirect在MSDN中的解释为:The CreateDialogIndirect macro creates a modeless dialog box from a dialog box template in memory,意思是他根据对话框模板在内存中创建一个无模的对话框。他是一个API函数,最终也是调用CreateWindowEx实现窗口(对话框)的创建。
这个结构体保存着创建对话框需要的样式、位置等信息,在DoModal函数里它是通过对话框资源得到的,那对话框资源里一定有它需要的东西。
下面是从rc文件中摘录的对话框的信息:
代码
1
IDD_AAAA_DIALOG DIALOGEX
0
,
0
,
320
,
200
2
STYLE DS_MODALFRAME
|
WS_POPUP
|
WS_VISIBLE
|
WS_CAPTION
|
WS_SYSMENU
3
EXSTYLE WS_EX_APPWINDOW
4
CAPTION
"
aaaa
"
5
FONT
9
,
"
宋体
"
6
BEGIN
7
DEFPUSHBUTTON
"
确定
"
,IDOK,
260
,
10
,
50
,
14
8
PUSHBUTTON
"
取消
"
,IDCANCEL,
260
,
23
,
50
,
14
9
LTEXT
"
TODO: 在这里设置对话控制。
"
,IDC_STATIC,
50
,
90
,
200
,
8
10
END
11
第一行是对话框的位置信息,第二行是对话框的样式,第三行是扩展样式,它们的内容就是在对话框编辑器修改属性时得到的内容。
重载PreCreateWindow的目的不外乎是想在其中修改默认的窗口类的样式信息,然后达到修改窗口样式的目的。而对话框能在资源编辑器里修改它的所有应有的样式,而这些样式在DoModal函数里能被读出来,并传递给CreateDialoagIndirect函数,创建对话框。