- 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