重载CDialog::PreCreateWindow是无效的

 

一般的窗口的创建是使用Create函数,这个函数在创建窗口之前调用了PreCreateWindow函数,并且允许在创建创建之前在PreCreateWindow注册一个拥有自定义窗口样式的新的窗口类,来创建一个拥有自定义类名新的窗口。而模式对话框是通过CreateDialogIndirect来创建的,在这当中并没有调用PreCreateWindow函数,重载的PreCreateWindow函数根本就不被执行,因此在这个函数里修改对话框的窗口类是没有用的。

 

CDialog是通过CDialog::DoModal()函数创建窗口的,下面是MFC中DoModal函数的代码:


int CDialog::DoModal()

 

{


 

       // 载入资源


       LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;

 

       HGLOBAL hDialogTemplate = m_hDialogTemplate;


       HINSTANCE hInst = AfxGetResourceHandle();

 

       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);

 

 


       if (lpDialogTemplate == NULL)

 

              return -1;


 

       HWND hWndParent = PreModal();


       AfxUnhookWindowCreate();

 

       BOOL bEnableParent = FALSE;


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

 

       {


              ::EnableWindow(hWndParent, FALSE);

 

              bEnableParent = TRUE;


       }

 

 


       TRY

 

       {


              // 创建无模式对话框

 

              AfxHookWindowCreate(this);


              if (CreateDlgIndirect(lpDialogTemplate,

 

                                          CWnd::FromHandle(hWndParent), hInst))


              {

 

                     if (m_nFlags & WF_CONTINUEMODAL)


                     {

 

                            // 进入模式循环


                            DWORD dwFlags = MLF_SHOWONIDLE;

 

                            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)

 

       {


       ......

 

       }


      END_CATCH_ALL

 

       if (bEnableParent)


              ::EnableWindow(hWndParent, TRUE);

 

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


              ::SetActiveWindow(hWndParent);

 

 


       // destroy modal window

 

       DestroyWindow();


       PostModal();

 

 


       // 解锁、释放资源

 

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


              UnlockResource(hDialogTemplate);

 

       if (m_lpszTemplateName != NULL)


              FreeResource(hDialogTemplate);

 

 


       return m_nModalResult;

 

}


在这个函里先是载入了对话框资源,然后通过LockResource函数,使DLGTEMPLATE类型指针指向相关的内存,然后把这个指针作为参数传递给了CreateDlgIndirect函数(调用了::CreateDialogIndirect)。DLGTEMPLATE的定义如下:

 

typedef struct {


DWORD style;

 

DWORD dwExtendedStyle;


WORD cdit;

 

short x;


short y;

 

short cx;


short cy;

 

} DLGTEMPLATE, *LPDLGTEMPLATE;


这个结构体保存着创建对话框需要的样式、位置等信息,在DoModal函数里它是通过对话框资源得到的,那对话框资源里一定有它需要的东西。下面是从rc文件中摘录的对话框的信息:

 

IDD_AAAA_DIALOG DIALOGEX 0, 0, 320, 200


STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU

 

EXSTYLE WS_EX_APPWINDOW


CAPTION "aaaa"

 

FONT 9, "宋体"


BEGIN

 

    DEFPUSHBUTTON   "确定",IDOK,260,10,50,14


    PUSHBUTTON      "取消",IDCANCEL,260,23,50,14

 

    LTEXT           "TODO: 在这里设置对话控制。",IDC_STATIC,50,90,200,8


END

 

第一行是对话框的位置信息,第二行是对话框的样式,第三行是扩展样式,它们的内容就是在对话框编辑器修改属性时得到的内容。


重载PreCreateWindow的目的不外乎是想在其中修改默认的窗口类的样式信息,然后达到修改窗口样式的目的。而对话框能在资源编辑器里修改它的所有应有的样式,而这些样式在DoModal函数里能被读出来,并传递给CreateDialoagIndirect函数,创建对话框。所以,一般的时候不需要修改对话框的类信息,因此,大多数的MFC程序的对话框都是使用默认的类名:#32770。

 

但是,对话框的类名也不是不能修改的。在上面的对话框模板的文本中,没有关于窗口类的任何信息。然而若是以关键字“DIALOGEX”查询MSDN发现在这里是可以使用“CLASS”选项指定新的对话框类。修改上面的对话框模板:


IDD_AAAA_DIALOG DIALOGEX 0, 0, 320, 200

 

STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU


EXSTYLE WS_EX_APPWINDOW

 

CAPTION "aaaa"


FONT 9, "宋体"

 

CLASS "My New Dialog Class"


BEGIN

 

    DEFPUSHBUTTON   "确定",IDOK,260,10,50,14


    PUSHBUTTON      "取消",IDCANCEL,260,23,50,14

 

    LTEXT           "TODO: 在这里设置对话控制。",IDC_STATIC,50,90,200,8


END

 

我们指定了新的对话框类名,还需要注册新的窗口类,但是又不能在PreCreateWindow函数里注册,所以只能对话框创建之前的其他地方进行注册,InitInstance函数是个非常好的选择:


         WNDCLASS wndClass;

 

         ::GetClassInfo(AfxGetInstanceHandle(), "#32770", &wndClass);\\拷贝默认的窗口类的信息


         wndClass.lpszClassName = " My New Dialog Class ";\\修改类名

 

         RegisterClass(&wndClass);


这样,这个对话框就有了新的类名。

转载于:https://my.oschina.net/tonyyang/blog/11337

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值