Keywords: non-modal, modal, hook, wh_CBT, CBTPROC,
1, intent
Sometimes we want to display non-modular windows as a modal window. For example, in the "File" menu of IE, select "Print", the "Print" dialog box is non-modal (maybe we don't know how Microsoft's design intention, generally said that the "print" dialog box should be mode State). How do I display the "Print" dialog as modality in this case (this dialog is Black Box to us)?
2. Simple implementation
Simply put, the modal window is displayed, and its parent window is disable, so the modal window is present "Modal", so as long as the parent window disable can be implemented before displaying our non-modular window, as follows:
......
AFXGETMAINWND () -> EnableWindow (false); // turn the main window disable, the displayed non-modal window is modal
ShowmodelessWindow ();
......
The problem is that the non-modular window is immediately returned immediately, then where is the code of the parent window ENABLE? The clumping method is to use the clock, constantly detect if the displayed non-modular window has been closed. If it is closed, the parent window enable.
Of course, it is better way.
3, WH_CBT HOOK
For details on the WH_CBT hook, please refer to MSDN, we only need to know that the system will call the WH_CBT hook function before the window is created and destroyed, which is what we need. The specific is to hang our WH_CBT hook processing function before displaying the non-modal window, and the handle created by the non-modal window can be obtained from the WPARAM parameter when the ncode of the hook function is HCBT_CREATEWND (creating a window), saves it, And compare the WPARAM parameters when the ncode of the hook function is HCBT_DESTROYWND (destroy window), and if the match is matched, the Enable status of the main window is restored.
2, realize
1) First define two variables, here is a global static variable.
Static hHOOK G_HHOOK = NULL;
Static hwnd g_hwnddialog = null; // to save the window handle
2) Add another function CBTPROC, because it is a callback function, pay attention to static as static.
Static Lresult Callback CBTProc (Int Ncode, WPARAM WPARAM, LPARAM LPARAM);
3) hook
Suppose below is a function of calling the "Print" dialog in a browser
Void cMyhtmlView :: onfileprint ()
{
AFXGETMAINWND () -> EnableWindow (FALSE);
g_hwnddialog = 0; // may be called multiple times, you need to reset the variables of the saved window handle
g_hook = setwindowshookex (wh_CBT, CBTPROC, NULL, GETCURRENTTHREADID ());
IF (! g_hhook)
{
AFXGETMAINWND () -> EnableWindow (TRUE);
Return;
}
Call the "Print" dialog
}
Lresult Callback CMYHTMLVIEW :: CBTPROC (int Ncode, WPARAM WPARAM, LPARAM LPARAM)
{
Switch (ncode)
{
Case HCBT_CREATEWND:
{
HWnd hwnd = (hwnd) wparam;
LPCBT_CREATEWND PCBT = (LPCBT_CREATEWND) LPARAM;
LpCreateStruct PCS = PCBT-> LPCS; if (DWORD) PCS-> LPSZCLASS == 0x00008002) / / # 32770, "Print" dialog box class name
{
IF (g_hwnddialog == 0)
g_hwnddialog = hwnd; // Save only the handle of the "Print" window
}
Break;
}
Case HCBT_DESTROYWND:
{
HWnd hwnd = (hwnd) wparam;
IF (hwnd == g_hwnddialog)
{
AFXGETMAINWND () -> EnableWindow (TRUE); // Restore Window Status
UnHookWindowsHookex (g_hhook); // remove hook
}
Break;
}
}
Return CallNexthookex (G_HHHOOK, NCODE, WPARAM, LPARAM);
}
Very simple, more importantly, this method is really effective.
Reference:
MSDN: CBTPROC
Quote Address: Use the WH_CBT Hook to display the Non-Modular dialog box as a modal dialog