На самом деле это KB976038 проблема.Причина, по которой это касается только команд, вызванных сочетаниями клавиш, заключается в том, что MFC вызывает их через функцию :: TranslateAccelerator (m_hWnd, hAccel, pMsg).Эта функция некоторое время переходит в режим ядра (см. Дамп стека ниже), а затем возвращается в режим пользователя, и в этом заключается проблема.
Идея реализации специального обработчика команд-заглушек для каждого сочетания клавиш, а затем установкаWM_COMMAND обратно в очередь сообщений, как я уже упоминал в вопросе, определенно не годится.
Для правильного решения проблемы я переопределил функцию OnCommand в классе CMainFrame следующим образом:
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
__try
{
if (LOWORD(wParam) != ID_PAGEUP && LOWORD(wParam) != ID_PAGEDOWN)
GetApp()->DestroyIntellisenseDlg() ;
return CMDIFrameWnd::OnCommand(wParam, lParam) ;
}
__except(RecordExceptionInfo(GetExceptionInformation(), ""))
}
Теперь каждый раз, когда происходит сбой в одной из команд, она будет перехватываться командойФункция RecordExceptionInfo.Для реализации функции RecordExceptionInfo, посмотрите на отличную статью Ханса Дитриха о Codeproject .
Дампы стека
Дамп стека для команды, вызываемой через меню: Мы не переходим в режим ядра до появления функции OnAppAbout:
testcrash1.exe!Ctestcrash1App::OnAppAbout() Line 151 C++
testcrash1.exe!_AfxDispatchCmdMsg(CCmdTarget * pTarget, unsigned int nID, int nCode, void (void)* pfn, void * pExtra, unsigned int nSig, AFX_CMDHANDLERINFO * pHandlerInfo) Line 82 C++
testcrash1.exe!CCmdTarget::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 381 + 0x27 bytes C++
testcrash1.exe!CFrameWnd::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 978 + 0x23 bytes C++
testcrash1.exe!CMainFrame::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 198 C++
testcrash1.exe!CWnd::OnCommand(unsigned int wParam, long lParam) Line 2729 C++
testcrash1.exe!CFrameWnd::OnCommand(unsigned int wParam, long lParam) Line 371 C++
testcrash1.exe!CFrameWndEx::OnCommand(unsigned int wParam, long lParam) Line 367 + 0x10 bytes C++
testcrash1.exe!CWnd::OnWndMsg(unsigned int message, unsigned int wParam, long lParam, long * pResult) Line 2101 + 0x1e bytes C++
testcrash1.exe!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam) Line 2087 + 0x20 bytes C++
testcrash1.exe!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Line 257 + 0x1c bytes C++
testcrash1.exe!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Line 420 C++
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 bytes
user32.dll!_DispatchMessageWorker@8() + 0xed bytes
user32.dll!_DispatchMessageW@4() + 0xf bytes
testcrash1.exe!AfxInternalPumpMessage() Line 183 C++
testcrash1.exe!CWinThread::PumpMessage() Line 900 C++
testcrash1.exe!CWinThread::Run() Line 629 + 0xd bytes C++
testcrash1.exe!CWinApp::Run() Line 832 C++
testcrash1.exe!AfxWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 47 + 0xd bytes C++
Дамп стека для команды, вызываемой с помощью сочетания клавиш.Перед переходом в функцию OnAppAbout перейдем в режим ядра, следите за строкой, начинающейся с NTDLL:
testcrash1.exe!Ctestcrash1App::OnAppAbout() Line 151 C++
testcrash1.exe!_AfxDispatchCmdMsg(CCmdTarget * pTarget, unsigned int nID, int nCode, void (void)* pfn, void * pExtra, unsigned int nSig, AFX_CMDHANDLERINFO * pHandlerInfo) Line 82 C++
testcrash1.exe!CCmdTarget::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 381 + 0x27 bytes C++
testcrash1.exe!CFrameWnd::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 978 + 0x23 bytes C++
testcrash1.exe!CMainFrame::OnCmdMsg(unsigned int nID, int nCode, void * pExtra, AFX_CMDHANDLERINFO * pHandlerInfo) Line 198 C++
testcrash1.exe!CWnd::OnCommand(unsigned int wParam, long lParam) Line 2729 C++
testcrash1.exe!CFrameWnd::OnCommand(unsigned int wParam, long lParam) Line 371 C++
testcrash1.exe!CFrameWndEx::OnCommand(unsigned int wParam, long lParam) Line 367 + 0x10 bytes C++
testcrash1.exe!CWnd::OnWndMsg(unsigned int message, unsigned int wParam, long lParam, long * pResult) Line 2101 + 0x1e bytes C++
testcrash1.exe!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam) Line 2087 + 0x20 bytes C++
testcrash1.exe!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Line 257 + 0x1c bytes C++
testcrash1.exe!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) Line 420 C++
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 bytes
user32.dll!_DispatchClientMessage@24() + 0x51 bytes
user32.dll!___fnDWORD@4() + 0x2b bytes
ntdll.dll!_KiUserCallbackDispatcher@12() + 0x2e bytes
user32.dll!_NtUserTranslateAccelerator@12() + 0x15 bytes
user32.dll!_TranslateAcceleratorW@12() + 0x1c464 bytes
testcrash1.exe!CFrameWnd::PreTranslateMessage(tagMSG * pMsg) Line 254 + 0x1b bytes C++
testcrash1.exe!CFrameWndEx::PreTranslateMessage(tagMSG * pMsg) Line 290 C++
testcrash1.exe!CWnd::WalkPreTranslateTree(HWND__ * hWndStop, tagMSG * pMsg) Line 3311 + 0x14 bytes C++
testcrash1.exe!AfxInternalPreTranslateMessage(tagMSG * pMsg) Line 233 + 0x12 bytes C++
testcrash1.exe!CWinThread::PreTranslateMessage(tagMSG * pMsg) Line 777 + 0x9 bytes C++
testcrash1.exe!AfxPreTranslateMessage(tagMSG * pMsg) Line 252 + 0x11 bytes C++
testcrash1.exe!AfxInternalPumpMessage() Line 178 + 0x18 bytes C++
testcrash1.exe!CWinThread::PumpMessage() Line 900 C++
testcrash1.exe!CWinThread::Run() Line 629 + 0xd bytes C++