最近项目中使用到MFC,由于工程是DLL的,在使用ToolTip时碰到非模态对话框无法显示的问题。查了一番资料,发现原因是由于:虽然MFC Regular DLL派生了CWinApp类,并有一个theApp全局对象。但它不包含CWinApp::Run机制,主消息由exe负责接收、分发,导致DLL的PreTranslateMessage不生效。参考资料:https://www.cnblogs.com/hanford/p/6177904.html 第2.5 PreTranslateMessage小节。该文中提到使DLL调用PreTranslateMessage的方法,但对于NX二次开发来说无法实现,毕竟主exe是已经封装好的。又经过一阵搜索,发现钩子函数可以解决,具体方法如下:
第一步:在App类中定义钩子和对话框变量
class CTestApp : public CWinApp { public: CTestApp(); CTestDlg* m_dlg; HHOOK m_hHook;
第二步:构造函数中初始化成员变量
CTestApp::CTestApp():m_hHook(NULL),m_dlg(NULL) { // TODO: 在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 }
第三步:定义钩子函数
加粗部分千万不能省掉,需要判断消息是否属于该对话框,否则可能导致界面卡死
class CTestApp : public CWinApp { public: CTestApp(); CTestDlg* m_dlg; HHOOK m_hHook; // 重写 public: virtual BOOL InitInstance(); DECLARE_MESSAGE_MAP() virtual int ExitInstance(); static LRESULT CALLBACK GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam); };
LRESULT CALLBACK CTestApp::GetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE(AfxGetStaticModuleState( )); LPMSG lpMsg = (LPMSG)lParam; if( (AfxGetApp()->PreTranslateMessage(lpMsg)) && (lpMsg->hwnd == theApp.m_dlg->m_hWnd)) { theApp.m_dlg->PreTranslateMessage(lpMsg); } return CallNextHookEx(theApp.m_hHook, nCode, wParam, lParam); }
第四步:安装钩子
BOOL CTestApp::InitInstance() { BOOL bInit = CWinApp::InitInstance(); if (bInit) { // TODO: Add your own module initialization code here. m_hHook = ::SetWindowsHookEx( WH_GETMESSAGE, GetMessageProc, AfxGetInstanceHandle(), GetCurrentThreadId()); return CWinApp::InitInstance(); } return bInit; }
第五步:卸载钩子
int CTestApp::ExitInstance() { // TODO: 在此添加专用代码和/或调用基类 UnhookWindowsHookEx((HHOOK)m_hHook); return CWinApp::ExitInstance(); }
第六步:创建非模态对话框
static UF_MB_cb_status_t test( UF_MB_widget_t widget, UF_MB_data_t client_data, UF_MB_activated_button_p_t call_button ) { if (UF_initialize() != 0) return UF_MB_CB_ERROR; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (theApp.m_dlg == NULL) { theApp.m_dlg = new CTestDlg(); theApp.m_dlg->Create(CTestDlg::IDD); } theApp.m_dlg->ShowWindow(SW_NORMAL); UF_terminate(); return UF_MB_CB_CANCEL; }
大功告成!测试: