CWnd m_hWnd疑惑

MFC中,对话框窗口的功能主要由CWndCDialog两个类实现。

MFC通过CDialog来封装对话框的功能。CDialogCWnd继承了窗口类的功能(包括CWnd实现的有关功能),并添加了新的成员变量和函数来处理对话框。

CDialog的成员变量有:

protected:

UINT m_nIDHelp; // Help ID (0 for none, see HID_BASE_RESOURCE)

LPCTSTR m_lpszTemplateName;  // name or MAKEINTRESOURCE

HGLOBAL m_hDialogTemplate; // indirect (m_lpDialogTemplate == NULL)

// indirect if (m_lpszTemplateName == NULL)

LPCDLGTEMPLATE m_lpDialogTemplate;

void* m_lpDialogInit;           // DLGINIT resource data

CWnd* m_pParentWnd;             // parent/owner window

HWND m_hWndTop;        // top level parent window (may be disabled)

成员变量保存了创建对话框的模板资源、对话框父窗口对象、顶层窗口句柄等信息。三个关于模板资源的成员变量m_lpszTemplateNamem_hDialogTemplatem_lpDialogTemplate对应了三种模板资源,但在创建对话框时,只要一个模板资源就可以了,可以使用其中的任意一类。

(1)       构造函数:

CDialog( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL );

CDialog( UINT nIDTemplate, CWnd* pParentWnd = NULL );

CDialog( );

CDialog重载了三个构造函数。其中,第三个是缺省构造函数;第一个和第二个构造函数从指定的对话框模板资源创建,pParentWnd指定了父窗口或所属窗口,若空则设置父窗口为应用程序主窗口。

(2)       初始化函数

BOOL Create( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL );

BOOL Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );

BOOL CreateIndirect( LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL );

BOOL CreateIndirect( HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL );

BOOL InitModalIndirect( LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL );

BOOL InitModalIndirect( HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL );

Create用来根据模板创建无模式对话框;CreateInDirect用来根据内存中的模板创建无模式对话框;InitModalIndirect用来根据内存中的模板创建模式对话框。它们都提供了两个重载版本。

(3)       对话框操作函数

void MapDialogRect( LPRECT lpRect ) const;

void NextDlgCtrl( ) const;

void PrevDlgCtrl( ) const;

void GotoDlgCtrl( CWnd* pWndCtrl );

void SetDefID( UINT nID );

void SetHelpID( UINT nIDR );

void EndDialog( int nResult );

(4)       虚拟函数

virtual int DoModal( );

virtual  BOOL OnInitDialog( );

virtual  void OnSetFont( CFont* pFont );

virtual void OnOK( );

virtual void OnCancel( );

模式对话框的实现

MFC下,所有的窗口类都使用了同一个窗口过程,CDialog也不例外。CDialog对象在创建Windows对话框时,采用了类似于CWnd的创建函数过程,采用子类化的手段将Windows提供给对话框的窗口过程取代为AfxWndProc或者AfxCallWndProc,同时提供了对话框过程AfxDlgProc。那么,这些“过程”是如何实现或者协调的呢?下文将予以分析。

MFC对话框过程AfxDlgProc的原型和实现如下:

BOOL CALLBACK AfxDlgProc(HWND hWnd,

UINT message, PARAM, LPARAM)    {

if (message == WM_INITDIALOG)      {

//处理WM_INITDIALOG消息

CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog,

CWnd::FromHandlePermanent(hWnd));

                  if (pDlg != NULL)

return pDlg->OnInitDialog();

else

return 1;

}

return 0;

}

由上可以看出,MFC的对话框函数AfxDlgProc仅处理消息WM_INITDIALOG,其他都留给对话框窗口过程处理。

AfxDlgProc处理WM_INITDIALOG消息时调用虚拟函数OnInitDialog,给程序员一个机会处理对话框的初始化。

本小节讨论对话框的窗口过程。

AfxWndProc是所有的MFC窗口类使用的窗口过程,它取代了模式对话框原来的窗口过程(Windows提供),那么,MFC如何完成Win32下对话框窗口的功能呢?

考查模式对话框的创建过程。CDialog::DoModal用来创建模式对话框窗口并执行有关任务,和DoModal相关的是MFC内部使用的成员函数CDialog::PreModalCDialog::PostModal。下面分别讨论它们的实现。

HWND CDialog::PreModal()         {

// cannot call DoModal on a dialog already constructed as modeless

ASSERT(m_hWnd == NULL);

// allow OLE servers to disable themselves

AfxGetApp()->EnableModeless(FALSE);

// 得到父窗口

CWnd* pWnd = CWnd::GetSafeOwner(m_pParentWnd, &m_hWndTop);

// 如同CWnd处理其他窗口的创建,设置一个窗口创建HOOK

AfxHookWindowCreate(this);

//返回父窗口的句柄

return pWnd->GetSafeHwnd();

}

 

void CDialog::PostModal(){

//取消窗口创建前链接的HOOK

AfxUnhookWindowCreate();   // just in case

//MFC对话框对象和对应的Windows对话框窗口分离

Detach();               // just in case

 

// m_hWndTop是当前对话框的父窗口或所属窗口,则恢复它

if (::IsWindow(m_hWndTop))

::EnableWindow(m_hWndTop, TRUE);

m_hWndTop = NULL;

AfxGetApp()->EnableModeless(TRUE);

}

 

int CDialog::DoModal()

{

// can be constructed with a resource template or InitModalIndirect

ASSERT(m_lpszTemplateName != NULL ||

m_hDialogTemplate != NULL || m_lpDialogTemplate != NULL);

//加载对话框资源

LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;

HGLOBAL hDialogTemplate = m_hDialogTemplate;

HINSTANCE hInst = AfxGetResourceHandle();

//查找资源(见9.5.2节),找到了就加载它

if (m_lpszTemplateName != NULL){

hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);

HRSRC hResource =

::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);

hDialogTemplate = LoadResource(hInst, hResource);

}

//锁定加载的资源

if (hDialogTemplate != NULL)

lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

// return -1 in case of failure to load the dialog template resource

if (lpDialogTemplate == NULL)

return -1;

 

//创建对话框前禁止父窗口,为此要调用PreModal得到父窗口句柄

HWND hWndParent = PreModal();

AfxUnhookWindowCreate();

CWnd* pParentWnd = CWnd::FromHandle(hWndParent);

BOOL bEnableParent = FALSE;

if (hWndParent != NULL && ::IsWindowEnabled(hWndParent)){

::EnableWindow(hWndParent, FALSE);

bEnableParent = TRUE;

}

 

//创建对话框,注意是无模式对话框

TRY

{

//链接一个HOOKHOOK链以处理窗口创建,

//如同4.4.1节描述的CWnd类窗口创建一样

AfxHookWindowCreate(this);

//CreateDlgIndirect间接调用::CreateDlgIndirect

//最终调用了::CreateWindowEX来创建对话框窗口。

//HOOK过程_AfxCbtFilterHook用子类化的方法

//取代原来的窗口过程为AfxWndProc

if (CreateDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst))

{

if (m_nFlags & WF_CONTINUEMODAL)

{

// enter modal loop

DWORD dwFlags = MLF_SHOWONIDLE;

//RunModalLoop接管整个应用程序的消息处理

if (GetStyle() & DS_NOIDLEMSG)

dwFlags |= MLF_NOIDLEMSG;

VERIFY(RunModalLoop(dwFlags) == m_nModalResult);

}

 

// hide the window before enabling the parent, etc.

if (m_hWnd != NULL)

SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|

SWP_NOSIZE|SWP_NOMOVE|

SWP_NOACTIVATE|SWP_NOZORDER);

}

}

CATCH_ALL(e)

{

DELETE_EXCEPTION(e);

m_nModalResult = -1;

}

END_CATCH_ALL

 

//Enable并且激活父窗口

if (bEnableParent)

::EnableWindow(hWndParent, TRUE);

if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)

::SetActiveWindow(hWndParent);

 

//::EndDialog仅仅关闭了窗口,现在销毁窗口

DestroyWindow();

 

PostModal();

 

// 必要的话,解锁/释放资源

if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)

UnlockResource(hDialogTemplate);

if (m_lpszTemplateName != NULL)

FreeResource(hDialogTemplate);

 

return m_nModalResult;

}

DoModal的实现可以看出:

它首先Disable对话框窗口的父窗口;然后使用::CreateIndrectDialog创建对话框窗口,使用子类化的方法用AfxWndProc替换了原来的窗口过程,并把原来的窗口过程保存在CWnd的成员变量m_pfnSuper中。原来的窗口过程就是::DialogBox等创建对话框窗口时指定的,是Windows内部提供的对话框“窗口类”的窗口过程。取代(Subclass)原来“窗口类”的窗口过程的方法如同 4.4.1节描述的CWnd::Create。在::CreateIndirectDialog创建对话框窗口后,会发送WM_INITDIALOG消息给对话框的对话框过程(必要的话,还有WM_SETFONT消息)。但是MFC取代了原来的对话框窗口过程,这两个消息如何送给对话框过程呢?处理方法如下节所描述。

 

疑问的是上面红色部分代码“CreateDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst)”执行后CWnd::m_hWnd变量的值从无到有,但是找不到给CWnd::m_hWnd赋值的语句。CWnd::m_hWnd是在什么时候赋值的呢?请大家指点一下,谢谢

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值