atexit equivalent for wxApp? (Task Manager End Process) Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

atexit equivalent for wxApp? (Task Manager End Process)

Post by davebee »

I have a wxTaskBarIcon base application. Upon exit it must perform some cleanup and some system validity check (Windows XP/Vista).

When exiting via context menu (EVT_MENU ==> wxTaskBarIcon::OnMenuExit()), there is no problem: not only can I perform the validity check in wxTaskBarIcon::OnMenuExit() but wxApp::OnExit() is invoked as well.

However, when terminating my application via Task Manager's 'End Process' button - or by logging off the account - neither wxTaskBarIcon::OnMenuExit() nor wxApp::OnExit() get called.

I even tried wxApp::OnFatalException() (after enabling ::wxHandleFatalExceptions() of course) - to no avail.

Once upon a time, when I used plain C/C++, I was able to handle such ungraceful exits using
atexit().

What are my options in a wxApp based applications? Is it not possible to handle signals in wxWidgets?

What am overlooking here?

Thanks,
Dave

P.S. In my search for an answer I found the following thread http://forums.wxwidgets.org/viewtopic.php?t=19010 but its conclusion is incorrect: EVT_CLOSE is *not* called when terminating the application via Task Manager's End Process button.
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
computerquip
Experienced Solver
Experienced Solver
Posts: 72
Joined: Fri Feb 20, 2009 7:13 pm
Location: $(#wx)\src

Post by computerquip »

davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

Thanks, but this is exactly what I was not looking for. :)

In my original message I described that I already handle graceful exit perfectly. The problem is only when closing the application via Task Manager or by logging off (in those cases, the aforementioned URL is irrelevant).

Additional ideas are welcome.
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

to my best knowledge it's not possible (at all) in Win32 to catch killing a process through taskmanager (i'd gladly be corrected here as i tried it myself and didn't find a way)

To catch system shutdown or user logoff you can use wxCloseEvent in wxWidgets:
http://docs.wxwidgets.org/stable/wx_wxc ... closeevent
Use the source, Luke!
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

doublemax wrote:To catch system shutdown or user logoff you can use wxCloseEvent in wxWidgets:
http://docs.wxwidgets.org/stable/wx_wxc ... closeevent
Perhaps I have a misconception here, but isn't wxCloseEvent same as EVT_CLOSE?

If so, I could swear that I tried this already (my code is full of EVT_CLOSE / OnCloseWindow() handlers - they are all invoked nicely when I exit the program nicely (i.e. via context menu item in the taskbaricon), but when the application is terminated via Task Manager (or user logoff), they are not called for some reason.

Hmmm... perhaps I am missing something. Are you sure they will be invoked on user logoff?
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

i was referring to EVT_QUERY_END_SESSION and EVT_END_SESSION.
They need to get handled at wxApp level (not in your wxFrame)
And yes, i'm sure they will get called.

However, there was an important change regarding this in 2.9.x which was not backported to 2.8.9. If you use 2.8.9 you might want to consider backporting the changes in wxApp::OnEndSession in /wx/src/msw/app.cpp (it's only a few lines)
Use the source, Luke!
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

doublemax wrote:However, there was an important change regarding this in 2.9.x which was not backported to 2.8.9. If you use 2.8.9 you might want to consider backporting the changes in wxApp::OnEndSession in /wx/src/msw/app.cpp (it's only a few lines)
Thank you! I am still using 2.6.3 (yes, I know...) - I will check this and post an update.
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

actually i'm maintaining an old project based on wx2.6.1 myself and backported the few lines, shouldn't be a problem.
Use the source, Luke!
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

:( I just tried this and wxApp::OnEndSession doesn't work.

OnEndSession is not a wxApp built-in function. I first added it to the wxApp-derived class, then added it to the event table:

Code: Select all

BEGIN_EVENT_TABLE(CMyApp, wxApp)
  EVT_END_SESSION(CMyApp::OnEndSession)
END_EVENT_TABLE()
All this function does is log a message to a log file (using wxLogStream).

Even when exiting gracefully (via context menu) this function is not called (I can see the OnCloseWindow and wxApp::OnExit logs in the log file but not OnEndSession).

I must be implementing it incorrectly. I couldn't find a sample that actually uses EVT_END_SESSION. Any tips regarding how to implement it?

What did you mean by 'backporting'? Is there some critical code that was introduced only in 2.9.x without which EVT_END_SESSION will work?

Thanks!

P.S. in the link you supplied there is no wxApp::OnEndSession. But in a wxPython page, I found that it is actually implemented (in version 2.8.x?). Then I found a post from about a year ago that suggests a bug in the implementation:

http://lists.wxwidgets.org/pipermail/wx ... 71543.html

Now I am totally confused...
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

All this function does is log a message to a log file (using wxLogStream).
i'm not sure if this works, if wxLogstream uses buffered output it might not have the chance to flush its buffer. try lowlevel fopen/write/close
Even when exiting gracefully (via context menu) this function is not called
this is normal. It's not called when closing the application this way.
What did you mean by 'backporting'? Is there some critical code that was introduced only in 2.9.x without which EVT_END_SESSION will work?
by backporting i mean applying the changes from wx 2.9.x to your wx 2.6.x sources and recompile the library.

In the old version, the EVT_END_SESSION handler is the last code that will be executed in your application because Windows will kill the process immediately afterwards. That means wxApp::OnExit(), wxFrame or wxApp dtors will *not* get called.

In the new code the application terminates more "cleanly".
Use the source, Luke!
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

Thanks. This greatly clarifies the picture. I just downloaded version 2.8.9 as well as the daily snapshot (CVS head) and I can see the difference:

Both in 2.6.3 and 2.8.9 wxApp::OnEndSession is implemented as:

Code: Select all

    if (GetTopWindow())
        GetTopWindow()->Close(true);
whereas in 2.9.x (2009-02-25 snapshot) it is implemented as:

Code: Select all

   if ( !wxTopLevelWindows.empty() )
        wxTopLevelWindows[0]->SetHWND(0);

    const int rc = OnExit();
    wxEntryCleanup();
    exit(rc);
Now, I see that app.h wxApp::OnEndSession is not implemented as a virtual function. I wonder whether I can simply override it in my application's wxApp-derived class. I don't feel like rebuilding 2.6.3... I prefer migrating to 2.8.9 instead (but we all know that when this is done, it takes more than just the time to build it...)

Thank you again for your great tips!
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

doublemax wrote: try lowlevel fopen/write/close
OK - I just finished trying this - and it still doesn't log anything to the log file.

So, I set some breakpoints in the debugger and got the following interesting results:
Upon Windows Task Manager "End Process" call, non of these "OnExit" function are called:
  1. CMyApp::OnFatalException()
    CMyApp::OnEndSession
    CMyApp::OnExit()
    AtExit() (yes, I registered an atexit() function in CMyApp init)
On the other hand, when exiting gracefully (using context menu), the following functions are called:
  1. CMyApp::OnExit()
    AtExit()
It is clear that I did something wrong with my implementation of CMyApp::OnEndSession. I didn't modify the 2.6.3 code. I simply defined an EVT_END_SESSION handler for MyApp (with the same name as wxApp's OnEndSession). Was that a mistake?
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax »

like i mentioned before, i don't think it's possible to detect when your application gets killed through the task manager.

EVT_END_SESSION should be triggered when the user logs off.
Use the source, Luke!
davebee
Earned some good credits
Earned some good credits
Posts: 106
Joined: Fri Oct 06, 2006 1:39 am

Post by davebee »

doublemax wrote:EVT_END_SESSION should be triggered when the user logs off.
You are absolutely correct - it works! and without having to recompile 2.6.3. :)
doublemax wrote:like i mentioned before, i don't think it's possible to detect when your application gets killed through the task manager.
Sorry, I overlooked your distinction between Task Manager and Logoff. Now that I re-read it I see that you actually made that distinction. Thank you!

I now have to find a creative way around Windows Task Manager's "horrible" 'End Process' (I guess that there is some wisdom in creating a kill mechanism that cannot be intercepted in any way - even Notepad does not attempt to save data when killed by Task Manager).

BTW, because I overlooked the distinction between Task Manager and Logoff, I mistakenly concluded that wxLogStream is not valid in OnEndSession. This is not the case and wxLogStream works very well in OnEndSession. :)
wxMSW-2.6.3 / Visual C++ 2005 EE / Windows XP SP2

(was: wxMSW-2.6.3 / Visual C++ 6.0 SP6 / Windows 2000 SP5)
Post Reply