exception handler in OnInitDialog()
Rick Rankin -- RickR@fscrater.com Wednesday, October 30, 1996 Environment: Win 95, VC++ 4.1 Does anyone know if there is a way to catch an exception thrown in an overridden CMyDialog::OnInitDialog() method, outside of the OnInitDialog() method? e.g. BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); //I would like to catch this exception //outside of this method AfxThrowResourceException(); return TRUE; } When I attempt this I get the following illegal operation error: EX caused a stack fault in module MSVCR40D.DLL at 0137:1020837c. Registers: EAX=00000000 CS=0137 EIP=1020837c EFLGS=00010282 EBX=00405b88 SS=013f ESP=0063eba4 EBP=00000000 ECX=00405b40 DS=013f ESI=0063ee04 FS=44c7 EDX=00405b88 ES=013f EDI=0063f230 GS=0000 Bytes at CS:EIP: 8b 45 00 50 53 51 57 e8 b8 fe ff ff 8b 4c 24 44 Stack dump: 0063ee04 00000000 00405b70 1020803c 0063ee04 0063f230 0063ed38 0063ed10 00405b40 00405b88 5f8bc718 00405b70 00000000 00000000 0063ec64 0063ee04 I have tried to catch this exception in: CAboutDlg::WindowProc, CAboutDlg::DefWindowProc, CEXApp::ProcessWndProcException, and finally in: int CEXApp::Run() { try { return CWinApp::Run(); } catch(...) { AfxMessageBox( "caught in Run()" ); } } with no success. Any help would be appreciated.
Rick Rankin -- RickR@fscrater.com Wednesday, October 30, 1996 Environment: Win 95, VC++ 4.1 Does anyone know if there is a way to catch an exception thrown in an overridden CMyDialog::OnInitDialog() method, outside of the OnInitDialog() method? e.g. BOOL CAboutDlg::OnInitDialog() { CDialog::OnInitDialog(); //I would like to catch this exception //outside of this method AfxThrowResourceException(); return TRUE; } When I attempt this I get the following illegal operation error: EX caused a stack fault in module MSVCR40D.DLL at 0137:1020837c. Registers: EAX=00000000 CS=0137 EIP=1020837c EFLGS=00010282 EBX=00405b88 SS=013f ESP=0063eba4 EBP=00000000 ECX=00405b40 DS=013f ESI=0063ee04 FS=44c7 EDX=00405b88 ES=013f EDI=0063f230 GS=0000 Bytes at CS:EIP: 8b 45 00 50 53 51 57 e8 b8 fe ff ff 8b 4c 24 44 Stack dump: 0063ee04 00000000 00405b70 1020803c 0063ee04 0063f230 0063ed38 0063ed10 00405b40 00405b88 5f8bc718 00405b70 00000000 00000000 0063ec64 0063ee04 I have tried to catch this exception in: CAboutDlg::WindowProc, CAboutDlg::DefWindowProc, CEXApp::ProcessWndProcException, and finally in: int CEXApp::Run() { try { return CWinApp::Run(); } catch(...) { AfxMessageBox( "caught in Run()" ); } } with no success. Any help would be appreciated.
Doug Brubacher -- Doug_Brubacher@compuware.com Monday, November 04, 1996 I did not have a good answer to this question when I originally saw it so I did not reply, but now that the question has returned I'll at least give you what I know (can suggest). In my experimenting I tried catching the exception in the procedure that calls DoModal for the dialog but MFC was catching it first. I also tried catching it in PreTranslateMessage but this didn't work either. Further investigation uncovered this nifty piece of code from MFC's dlgcore.cpp: ////////////////////////////////////////////////////////////////////// /////// // AfxDlgProc - does nothing since all messages are handled via AfxWndProc BOOL CALLBACK AfxDlgProc(HWND hWnd, UINT message, WPARAM, LPARAM) { if (message == WM_INITDIALOG) { // special case for WM_INITDIALOG CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, CWnd::FromHandlePermanent(hWnd)); if (pDlg != NULL) return pDlg->OnInitDialog(); else return 1; } return 0; } I found this by setting a break point in my OnInitDialog and looking at what was available in the call stack. This was the only non-operating system item other than my OnInitDialog that was available. Thus you can't catch the exception the way the questioner wants. WM_INITDIALOG is a Windows message and OnInitDialog is being called directly by AfxDlgProc bypassing any other message routing that would offer us the opportunity to insert a try/catch. I would suggest that the questioner call CDialog::EndDialog(nResult) rather than AfxThrowResourceException(). You can of course return any value, not just IDCANCEL or IDOK, to differentiate this from the typical return value from DoModal(). At that point you could handle the condition appropriately or if you really want throw the Resource Exception at that point. Regards, Doug Brubacher DouglasB@msn.com
Pradeep Tapadiya -- pradeep@nuview.com Wednesday, November 06, 1996 Hi, I think you can override CWinThread::ProcessWndProcException to process CException based exceptions. To process exceptions at a global level, you can override CWinApp::ProcessWndProcException (as CWinApp is derived from CWinThread). To proces exceptions at the level that you want, you would need to implement a separate message loop. The easiest way would be to create a CWinThread based thread and display your dialog in this thread. Disclaimer: I have never used ProcesssWndProcException API. Pradeep > In my experimenting I tried catching the exception in the procedure > that calls DoModal for the dialog but MFC was catching it first. I > also tried catching it in PreTranslateMessage but this didn't work > either. Further investigation uncovered this nifty piece of code from > MFC's dlgcore.cpp: > > ////////////////////////////////////////////////////////////////////// > /////// > // AfxDlgProc - does nothing since all messages are handled via > AfxWndProc > > BOOL CALLBACK AfxDlgProc(HWND hWnd, UINT message, WPARAM, LPARAM) > { > if (message == WM_INITDIALOG) > { > // special case for WM_INITDIALOG > CDialog* pDlg = DYNAMIC_DOWNCAST(CDialog, > CWnd::FromHandlePermanent(hWnd)); > if (pDlg != NULL) > return pDlg->OnInitDialog(); > else > return 1; > } > return 0; > } > > I found this by setting a break point in my OnInitDialog and looking > at what was available in the call stack. This was the only > non-operating system item other than my OnInitDialog that was > available. Thus you can't catch the exception the way the questioner > wants. WM_INITDIALOG is a Windows message and OnInitDialog is being > called directly by AfxDlgProc bypassing any other message routing that > would offer us the opportunity to insert a try/catch. > > I would suggest that the questioner call CDialog::EndDialog(nResult) > rather than AfxThrowResourceException(). You can of course return any > value, not just IDCANCEL or IDOK, to differentiate this from the > typical return value from DoModal(). At that point you could handle > the condition appropriately or if you really want throw the Resource > Exception at that point. > > Regards, > > Doug Brubacher > DouglasB@msn.com > >
Pradeep Tapadiya -- pradeep@nuview.com Thursday, November 07, 1996 Environment: VC++4.2b, NT 4.0 Howdy netters, In the application that we are working on, we collect some real-time data at a specified time interval (default is one second) and display it in different MDI views. While handling user commands, some of the functions that we call may take several seconds to return. In a single-thread model, the views will not get updated during this time. The calls are meant to be blocking in the sense that we don't want the user to be able to do anything (except maybe minimize the app window) while the call is in progress. However, we don't want the view updates to stop. The way we handle it currently is 1) popup a modal dialog box from the UI thread 2) override OnInitDialog to spawn a worker thread that in turn calls the blocking function. 3) Activate a 1 second timer. At each WM_TIMER, we check if the thread has killed itself. This also gives us a chance to update our dialog box (we display a stop clock in the dialog box). This works fine. We have achieved what we wanted to, i.e., 1) The views are getting updated at the specfied time interval. 2) The user cannot do anything during a blocking command is being processed. What I would like to do is to have two UI threads: one that just collects data and updates the views (and does nothing else), and the other that handles all other activities. This way, I don't need to create a thread each time I process a user command. If a function blocks for several seconds, that's fine. The view updates are not being stopped because of this. So I wrote a test program that spawns a UI thread (CWinThread derived class). Here is the InitInstance code for this class. BOOL CMyWinThread::InitInstance() { CWinApp* pApp = AfxGetApp(); for (;;) { Sleep(1 * 1000); POSITION pos = pApp->GetFirstDocTemplatePosition(); if (NULL == pos) continue; CDocTemplate* pTemplate = pApp->GetNextDocTemplate(pos); if (NULL == pTemplate) continue; POSITION docPos = pTemplate->GetFirstDocPosition(); if (NULL == docPos) continue; CDocument* pDoc = pTemplate->GetNextDoc(docPos); if (NULL == pDoc) continue; pDoc->UpdateAllViews(NULL, 0); } return TRUE; } However, the call to UpdateAllViews causes an assertion that I am trying to use CObject based pointer from one thread in another thread. Seems like this is not the correct way of using a UI thread. Can someone please enlighten me if it is possible to do what I wish to do? Thank you for your help. Pradeep
Doug Boone -- dboone@fasttax.com Monday, November 11, 1996 To me you're doing this the hard way. I'd approach it something like this: 1) create thread to do something useful. 2) At the beginning of each On*() command (except OnUpdate) check to see if that thread is still active. (WaitForSingleObject() with timeout zero and look for a timed-out error.) a) if the thread is active, just beep to give the user feedback that you know they've pressed a key but you can't process it right now. b) If the thread is not active, then process the user's request. I would just create the thread inside the dialog and a semaphore to go with it. When the user types in something that should make activity occur you take ownership of the semaphore and tell the thread what to do. When the thread completes it releases the semaphore. If the UI section can't get ownership of the semaphore then it just beeps. ---------- > From: Pradeep Tapadiya> To: mfc-l@netcom.com > Subject: RE: exception handler in OnInitDialog() > Date: Thursday, November 07, 1996 6:08 PM > > Environment: VC++4.2b, NT 4.0 > > Howdy netters, > > In the application that we are working on, we collect some > real-time data at a specified time interval (default is one > second) and display it in different MDI views. While > handling user commands, some of the functions that we call > may take several seconds to return. In a single-thread model, > the views will not get updated during this time. > > The calls are meant to be blocking in the sense that we don't want > the user to be able to do anything (except maybe minimize the app window) > while the call is in progress. However, we don't want the view updates > to stop. > > The way we handle it currently is > > 1) popup a modal dialog box from the UI thread > 2) override OnInitDialog to spawn a worker thread > that in turn calls the blocking function. > 3) Activate a 1 second timer. At each WM_TIMER, we > check if the thread has killed itself. This also > gives us a chance to update our dialog box (we display > a stop clock in the dialog box). > > This works fine. We have achieved what we wanted to, i.e., > 1) The views are getting updated at the specfied time interval. > 2) The user cannot do anything during a blocking command is > being processed. > > What I would like to do is to have two UI threads: one > that just collects data and updates the views (and does > nothing else), and the other that handles all other > activities. This way, I don't need to create a thread > each time I process a user command. If a function blocks > for several seconds, that's fine. The view updates are > not being stopped because of this. > > So I wrote a test program that spawns a UI thread (CWinThread > derived class). Here is the InitInstance code for this > class. > > BOOL CMyWinThread::InitInstance() > { > CWinApp* pApp = AfxGetApp(); > > for (;;) { > Sleep(1 * 1000); > > POSITION pos = pApp->GetFirstDocTemplatePosition(); > if (NULL == pos) > continue; > > CDocTemplate* pTemplate = pApp->GetNextDocTemplate(pos); > if (NULL == pTemplate) > continue; > > POSITION docPos = pTemplate->GetFirstDocPosition(); > if (NULL == docPos) > continue; > > CDocument* pDoc = pTemplate->GetNextDoc(docPos); > if (NULL == pDoc) > continue; > > pDoc->UpdateAllViews(NULL, 0); > } > > return TRUE; > } > > However, the call to UpdateAllViews causes an assertion that > I am trying to use CObject based pointer from one thread > in another thread. Seems like this is not the correct way of > using a UI thread. > > Can someone please enlighten me if it is possible to do > what I wish to do? > > Thank you for your help. > > Pradeep
| Вернуться в корень Архива |