Modeless dialogs Vs.TAB key, arrow keys, and accelerator keys (II)
I think the last solution is an overkill. Remember what was the problem:
In some point the pump gets the modeless window handler and it is not able to get the corresponding window to call the PreTranslateMessage member funcion.
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
...
for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
{
//FromHandlePermanent will return NULL, causing our issue
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
{
if (pWnd->PreTranslateMessage(pMsg))
return TRUE;
}
}
...
}
So we put a hook to the thread, the result: thousands of callings to our PreTranslateMessage member funcion with another thousand messages being delivered through the hook.
So I was doing some researching and I found the IsDialogMessage function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645498(v=vs.85).aspx
It determines whether a message is intended for the specified dialog box and, if it is, processes the message. So we can do the following in our CWinApp derived class:
BOOL YourCWinApp ::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
CWnd *pWndPermanent = CWnd::FromHandlePermanent(pMsg->hwnd);
//If FromHandlePermanent returns NULL then it should be a control of a modeless windows
//or a modeless window itself.
if (!pWndPermanent && pMsg->hwnd)
{
//If it's a control inside the modeless window, we have to get the top parent
HWND hTopParent= AppGetTopParent(pMsg->hwnd);
return IsDialogMessage(hTopParent, pMsg);
}
}
}
return CRazorEXE::PreTranslateMessage(pMsg);
}
HWND AppGetTopParent(HWND hWnd)
{
#define APP_IsSet(flag, flagToTest) ((flag&(flagToTest))==(flagToTest))
#define APP_GetWindowStyle(hwnd) ((LONG_PTR)(GetWindowLongPtr(hwnd, GWL_STYLE)))
#define APP_IsChildWindow(hwnd) APP_IsSet(APP_GetWindowStyle(hwnd), WS_CHILD)
if(hWnd == NULL)
return NULL;
HWND hWndParent = hWnd;
while(hWndParent != NULL && APP_IsChildWindow(hWndParent) == TRUE)
hWndParent = ::GetParent(hWndParent);
return hWndParent;
}
In some point the pump gets the modeless window handler and it is not able to get the corresponding window to call the PreTranslateMessage member funcion.
BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
{
...
for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
{
//FromHandlePermanent will return NULL, causing our issue
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
if (pWnd != NULL)
{
if (pWnd->PreTranslateMessage(pMsg))
return TRUE;
}
}
...
}
So we put a hook to the thread, the result: thousands of callings to our PreTranslateMessage member funcion with another thousand messages being delivered through the hook.
So I was doing some researching and I found the IsDialogMessage function:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms645498(v=vs.85).aspx
It determines whether a message is intended for the specified dialog box and, if it is, processes the message. So we can do the following in our CWinApp derived class:
BOOL YourCWinApp ::PreTranslateMessage(MSG* pMsg)
{
switch (pMsg->message)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
CWnd *pWndPermanent = CWnd::FromHandlePermanent(pMsg->hwnd);
//If FromHandlePermanent returns NULL then it should be a control of a modeless windows
//or a modeless window itself.
if (!pWndPermanent && pMsg->hwnd)
{
//If it's a control inside the modeless window, we have to get the top parent
HWND hTopParent= AppGetTopParent(pMsg->hwnd);
return IsDialogMessage(hTopParent, pMsg);
}
}
}
return CRazorEXE::PreTranslateMessage(pMsg);
}
HWND AppGetTopParent(HWND hWnd)
{
#define APP_IsSet(flag, flagToTest) ((flag&(flagToTest))==(flagToTest))
#define APP_GetWindowStyle(hwnd) ((LONG_PTR)(GetWindowLongPtr(hwnd, GWL_STYLE)))
#define APP_IsChildWindow(hwnd) APP_IsSet(APP_GetWindowStyle(hwnd), WS_CHILD)
if(hWnd == NULL)
return NULL;
HWND hWndParent = hWnd;
while(hWndParent != NULL && APP_IsChildWindow(hWndParent) == TRUE)
hWndParent = ::GetParent(hWndParent);
return hWndParent;
}
Welcome!, did you find it useful?
ResponderEliminar