- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have a console application that is running a calculation and I would like to be able to do certain work like saving unsaved data and properly stopping the calculation if the Windows system is going to log off, shut down or restart.
I would like to be able to do something similar to handling the WM_QUERYENDSESSION message in MFC applications - this message is sent by the system to indicate shutdown or logoff.
What I have in my application now is handling interrupt signals, which looks like this:
interface function processBreakSignal ( signum ) ! SIG$INT - CTRL+CSIGNAL !dec$ attributes C :: processBreakSignal integer(4) :: processBreakSignal integer(2) :: signum end function function processTerminationSignal ( signum ) ! SIG$TERM - Termination request !dec$ attributes C :: processTerminationSignal integer(4) :: processTerminationSignal integer(2) :: signum end function end interface integer(4) :: status4 status4 = SIGNALQQ ( SIG$INT, processBreakSignal ) status4 = SIGNALQQ ( SIG$TERM, processTerminationSignal ) status4 = SIGNALQQ ( SIG$ABORT, processTerminationSignal ) integer(4) function processBreakSignal ( signum ) !dec$ attributes C :: processBreakSignal integer(2) :: signum ... processBreakSignal = signum return end
processTerminationSignal is coded in the same way like processBreakSignal.
If my application is running and I press Ctrl+C, everything is OK.
If I press Ctrl+Break, the system (Windows 7 Professional 64-bit) immediately closes my console application's window. I thought Ctrl+C and Ctrl+Break fire the same interrupt type SIG$INT, don't they?
Finally, is any of the interrupt types, e.g. SIG$TERM or SIG$ABORT, supposed to handle system restart/shutdown or logoff? Right now, just like with Ctrl+Break, it does not seems so - logoff or shutdown close the console window immediately.
What can I do to handle system shutdown/restart/logoff?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SetConsoleCtrlHandler might help. I've never played with it though.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As it happens, I was looking at SetConsoleCtrlHandler last week because the Fortran run-time library establishes such a handler in a console application. It is exactly intended for this purpose. If you call the API to register your handler, it will get called before the RTL's.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I replaced SIGNALQQ with SetConsoleCtrlHandler and my application is now handling Ctrl+C and even Ctrl+Break correctly. However, closing the window, logoff and shutdown/restart are still not handled correctly - if I close the console window or if I logoff/shutdown, the console window closes immediately and the code I have in the handler routine is not executed, so my application does not have time to do anything before the system is shut down or restarted.
Is there anything else I can do to prevent the system from closing my console application's window immediately?
This is the code I use to handle signals now (code is simplified and does not show operations I would like to do before logoff/shutdown/restart):
program ConsoleCtrlHandlerTest use kernel32, only : SetConsoleCtrlHandler, BOOL, TRUE integer(BOOL), external :: ConsoleCtrlHandlerRoutine !dec$ attributes stdcall :: ConsoleCtrlHandlerRoutine integer(BOOL) :: handlerSetResult handlerSetResult = SetConsoleCtrlHandler( loc(ConsoleCtrlHandlerRoutine), TRUE ) ... (calculation is running here) end integer(BOOL) function ConsoleCtrlHandlerRoutine ( code ) !dec$ attributes stdcall :: ConsoleCtrlHandlerRoutine use kernel32, only : BOOL, DWORD, TRUE, FALSE integer(dword) :: code select case (code) case (0) write(*,'(a)') ' Stopping due to Ctrl+C. ' ... ConsoleCtrlHandlerRoutine = TRUE case (1) write(*,'(a)') ' Stopping due to Ctrl+Break. ' ... ConsoleCtrlHandlerRoutine = TRUE case (2) write(*,'(a)') ' Stopping due to closing the application window. ' ... ConsoleCtrlHandlerRoutine = TRUE case (5) write(*,'(a)') ' Stopping due to system logoff. ' ... ConsoleCtrlHandlerRoutine = FALSE case (6) write(*,'(a)') ' Stopping due to system shutdown/restart. ' ... ConsoleCtrlHandlerRoutine = FALSE case default write(*,'(a)') ' Stopping due to unknown event. ' ConsoleCtrlHandlerRoutine = FALSE end select end function ConsoleCtrlHandlerRoutine
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, it does. But you don't see the write because the window closes. Change the writes in your test to write to a file instead and you'll see. I tried it.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My Windows GUI (ie, not a Quickwin console) app needs to run 24x7 and own its machine, and this is done in part by 1) subclassing the desktop which removes the Windows taskbar and start button (and also gets rid of Metro in Win8), and 2) setting low-level keyboard hooks to disable the various system keystroke interrupts. The only way to exit the app is via its explicit menu option, ensuring a graceful shutdown with data saving and the like for a later graceful restart. I don't know if this is useful for a console app, but if your app also needs to own its machine, a design which restricts user interactions can be more effective than trapping them after the fact.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If you want to go to that extreme - just make your application the shell!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I do not want to make my application that extreme; I was naive to think that dealing with logoff and shutdown cannot be so complicated.
Anyway, I still must be doing something wrong, because my application's window is immediately closed on logoff, but only on my computer (Windows 7 Professional 64-bit). I changed the code to simulate that a calculation is running and it needs certain time to do cleanup. The application writes to log files that the calculation simulation is running and that the cleanup operation is in progress.
If I log off on my computer, I do not see any file cleanup.log that should be written in the subroutine Cleanup that is called from the handler. If I try the same on another computer with Windows 7 Professional 64-bit, the file cleanup.log contains 5 entries, i.e. the application and the handler were running 5 seconds from the logoff signal and the application was then terminated. It works even differently on Windows XP Professional 64-bit - the cleanup (approximately 10 seconds) is completely finished and the application is then terminated.
As I focus on Windows 7/8, I need to find a way how to get more time than 5 seconds from logoff to do cleanup. Put another way, I need to explain Windows to wait for my application to do cleanup before logoff or shutdown are completed.
program ConsoleCtrlHandler
use ifcore use kernel32, only : SetConsoleCtrlHandler, BOOL, TRUE implicit none integer(BOOL), external :: ConsoleCtrlHandlerRoutine !dec$ attributes stdcall :: ConsoleCtrlHandlerRoutine integer(BOOL) :: handlerSetResult logical(4) :: pressed, emptyBuffer character(1) :: key integer(4) :: unit, iteration write(*,'(a)') ' Starting Console Ctrl Handler test, press any key to stop. ' write(*,'(a)') ' ' handlerSetResult = SetConsoleCtrlHandler( loc(ConsoleCtrlHandlerRoutine), TRUE ) unit = 101 OPEN ( UNIT=unit, FILE='simulation.log' ) iteration = 0 write(*,'(a,i0)') ' Simulating calculation, iteration: ', iteration write(unit,'(a,i0)') ' Simulating calculation, iteration: ', iteration pressed = .false. do while ( .NOT.pressed ) pressed = PEEKCHARQQ ( ) call SLEEPQQ ( 1000 ) iteration = iteration + 1 write(*,'(a,i0)') ' Simulating calculation, iteration: ', iteration write(unit,'(a,i0)') ' Simulating calculation, iteration: ', iteration enddo emptyBuffer = .false. do while ( .NOT.emptyBuffer ) key = GETCHARQQ() emptyBuffer = .NOT.PEEKCHARQQ() enddo CLOSE ( unit ) write(*,'(a)') ' ' write(*,'(a)') ' Console Ctrl Handler test finished. ' write(*,'(a)') ' ' end program ConsoleCtrlHandler integer(BOOL) function ConsoleCtrlHandlerRoutine ( code ) !dec$ attributes stdcall :: ConsoleCtrlHandlerRoutine use kernel32, only : BOOL, DWORD, TRUE, FALSE integer(dword) :: code call Cleanup ( code ) select case (code) case (0) ConsoleCtrlHandlerRoutine = TRUE case (1) ConsoleCtrlHandlerRoutine = TRUE case (2) ConsoleCtrlHandlerRoutine = TRUE case (5) ConsoleCtrlHandlerRoutine = FALSE case (6) ConsoleCtrlHandlerRoutine = FALSE case default ConsoleCtrlHandlerRoutine = FALSE end select end function ConsoleCtrlHandlerRoutine subroutine Cleanup ( code ) use ifcore integer(4) :: code, unit, step, maxSteps unit = 100 OPEN ( UNIT=unit, FILE='cleanup.log' ) select case (code) case (0) write(unit,'(a)') ' Cleanup initialized due to Ctrl+C ' case (1) write(unit,'(a)') ' Cleanup initialized due to Ctrl+Break ' case (2) write(unit,'(a)') ' Cleanup initialized due to window closing ' case (5) write(unit,'(a)') ' Cleanup initialized due to system logoff ' case (6) write(unit,'(a)') ' Cleanup initialized due to system shutdown/restart ' case default write(unit,'(a)') ' Cleanup initialized due to unknown event ' end select write(*,'(a)') ' Cleanup operation: started ' write(unit,'(a)') ' Cleanup operation: started ' cleaned = .false. maxSteps = 10 step = 1 do while ( step.le.maxSteps ) write(*,'(a,i0,a,i0)') ' Cleanup operation: step ', step, ' out of ', maxSteps write(unit,'(a,i0,a,i0)') ' Cleanup operation: step ', step, ' out of ', maxSteps call SLEEPQQ ( 1000 ) step = step+1 enddo write(*,'(a)') ' Cleanup operation: finished ' write(unit,'(a)') ' Cleanup operation: finished ' CLOSE ( unit ) return end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You might find this topic interesting:
Application Shutdown Changes in Windows Vista
http://msdn.microsoft.com/en-us/library/ms700677(v=vs.85).aspx
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You might find this topic interesting:
Application Shutdown Changes in Windows Vista
http://msdn.microsoft.com/en-us/library/ms700677(v=vs.85).aspx

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page