dll 中的无模式对话框,快捷键失灵
按钮上的快捷键,TAB键,都没有效果了。什么原因啊? 问题点数:50、回复次数:6Top
1 楼kingzai(stevenzhu)回复于 2005-01-26 19:45:54 得分 20
PRB: Modeless Dialog Box in a DLL Does Not Process TAB Key (233263)
http://support.microsoft.com/default.aspx?kbid=233263
SYMPTOMS
When a modeless dialog box is launched from a dynamic-link library (DLL), the TAB key and the arrow keys do not move the focus from control to control as you would expect.
CAUSE
For a modeless dialog box to process a TAB key, the message pump needs to call the IsDialogMessage API. However, if you are writing a DLL and do not have access to the .exe's source code, you cannot modify the message pump to do this.
RESOLUTION
To work around this problem, you can use a WH_GETMESSAGE hook to capture the keystroke messages and call the IsDialogMessage API. If IsDialogMessage returns TRUE, then do not pass the message on to the message pump. Set the hook when handling WM_INITDIALOG and unset it when handling the WM_DESTROY message.
STATUS
This behavior is by design.
MORE INFORMATION
The following code illustrates how to set and unset the hook as well as how to use IsDialogMessage() to process TAB key messages: BOOL CALLBACK DllDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch ( uMsg )
{
case WM_INITDIALOG:
hHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc,
NULL, GetCurrentThreadId() );
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
DestroyWindow( hwndDlg );
hwndDllDlg = NULL;
}
return TRUE;
case WM_DESTROY:
UnhookWindowsHookEx( hHook );
return FALSE;
}
return FALSE;
}
The hook procedure, GetMsgProc, should resemble the following:
LRESULT FAR PASCAL GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
LPMSG lpMsg = (LPMSG) lParam;
if ( nCode >= 0 && PM_REMOVE == wParam )
{
// Don't translate non-input events.
if ( (lpMsg->message >= WM_KEYFIRST && lpMsg->message <= WM_KEYLAST) )
{
if ( IsDialogMessage(hwndDllDlg, lpMsg) )
{
// The value returned from this hookproc is ignored,
// and it cannot be used to tell Windows the message has been handled.
// To avoid further processing, convert the message to WM_NULL
// before returning.
lpMsg->message = WM_NULL;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
}
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
Top
2 楼orbit(走了走了)回复于 2005-01-26 20:22:47 得分 24
MFC中处理快捷键是在PreTranslateMessage中完成的,dll中没有消息循环,也就是没有周期性的调用CWinApp::PreTranslateMessage函数,所以从MainFrame窗口开始的各个窗口类的PreTranslateMessage都没有被调用,所以没有处理Tab键。
有两个方法解决这个问题:
1。在dll中创建一个线程(从CWinThread派生),在线程中创建无模式对话框,将无模式对话框的窗口指针赋值给线程类的m_pMainWnd
2。在dll中创建一个导出函数,如BOOL FunctionName(MSG *pMsg),在函数中通过无模式对话框的窗口指针调用对话框类的PreTranslateMessage,在调用这个dll的主程序的CxxxWinApp类的PreTranslateMessage函数(从CWinApp派生)中调用FunctionName。Top
3 楼sks(可子)回复于 2005-01-27 09:01:39 得分 0
谢谢两位的回复。
我先尝试了导出函数的方法,但是好像不灵。不知道为什么。然后用 kingzai 给出的方法成功了。但是调试的时候遇到几个问题。
1.GetMsgProc这个函数里面不能使用this指针,所以我用了一个static *pThis变量来指向this,这样就可以使用 pThis->m_hWnd 了。
2.GetMsgProc函数的最后一句中 hHook 应该在哪里定义呢?我的做法是定义成this的成员变量,然后用 pThis->m_hHook 。但总觉得这个方法比较龌龊。
请大家指点一下。谢谢Top
4 楼kingzai(stevenzhu)回复于 2005-01-27 09:37:40 得分 4
写钩子函数hHook一般是写在共享代码段的,全局变量,你查一下钩子的通用写法便知Top
5 楼windyhui(冷月清风)回复于 2005-01-28 14:57:39 得分 2
帮你顶一下Top
6 楼sks(可子)回复于 2005-01-31 11:13:53 得分 0
还有一个很重要的问题。用了那个钩子的方法后,对话框上的编辑框内输入汉字时,都变成乱码。
我想了一个办法,判断当前焦点是否为输入框,是的话,就跳过这条消息。但总觉得这不是好办法。
而且还有,自己定义了快捷键后,要在pretransmessage这个函数中添加一句话
TranslateAccelerator( pThis->m_hWnd, pThis->m_hAccel, lpMsg)
我把这句话放在那个GetMsgProc函数中,会有一些副作用。当那个非模式对话框没有焦点时,也可以接受快捷键的消息。
总的来说,似乎MS提供的这个方法有很多不完备的地方,也许我对“钩子”的使用还了解吧。
我觉得用线程的方法可能会从根本上解决问题。那位仁兄能提供详细一点的说明吗?我想不明白应该怎么做。Top




