WM_ENDSESSION - Where is the runtime picking this up?

I’ve got a subclassed procedure trapping for EndSession and QueryEndSession, but somehow the Runtime is picking this up so I’m getting the message:
Application Still Active
Quit the Application before quitting windows.

Cant use the debugger in this situation because unlike the IDE, the debugger does shut down.

The subclassed procedure is picking up the code, but somehow so is the runtime.
I am daisychaining multiple subclass procedures if that is a problem, instead of the usual one procedure.
eg
WM_PowerBroadcast
WM_Mouse
WM_Systray
WM_PostSendMessage

all have code in them to handle those specific windows messages.

WM_Notifications   Procedure(phWnd, pwMsg, pwParam, plParam)

    Code

    Case pwMsg
    OF ISEQ:WM_QUERYENDSESSION  ! Sent when the system is asking applications if it's okay to end the session.

        Compile('_***_',ISEQ:Debug)
        DSS('Main : Init : WM_Notifications : OF ISEQ:WM_QUERYENDSESSION' )
        _***_

        Post(UserEvent:PrepareShutdown)

        Return True

    OF ISEQ:WM_ENDSESSION       ! Sent after the decision has been made to end the session, letting applications know it's happening.

        Compile('_***_',ISEQ:Debug)
        DSS('Main : Init : WM_Notifications : OF ISEQ:WM_ENDSESSION' )
        _***_

        Post(UserEvent:Shutdown)

        Return True

    End

    Return ISWA_CallWindowProc( GMFPA:WM_PowerBroadcastPA, phWnd, pwMsg, pwParam, plParam )

Any ideas?

TIA

Did you see Carl’s gist? How to detect Windows is Closing Down / System Shutdown? - #4 by CarlBarnes

I did, the funny thing is, this code was working, but now its not. I’ve obviously made some change to another part of the app which is now throwing up the message when testing the shutdown.

I’ll try to resort the app back to an earlier version and reintroduce the changes bit by bit and test each change with the shutdown process.

Edit.

So found the cause. I shifted some code from a windowless thread onto a threaded window, and its the window causing the popup message. But the interesting thing about this thread/child window is its not running or appearing to run through the accept loop in parrallel with the main frame. The mainframe does its stuff and once completed, then the thread/child window does it stuff, if debugview and my logging of msgs in a file is to be believed.

Anyway having established the cause, now its a case of making some changes to get it to work in parrallel, like I would expect it to.

Edit2.
So the thread/child window is also getting the EndSession & QueryEndSession messages, so putting in some handlers now as the app shutting down properly or as required.

I thought just the main frame handled all the Window Messages, but obviously not, so back to the synchronisation objects to get the data saved properly in various threads before the filemanagers close.

Been reading this.

What I’m seeing is 7/100ths of a second between WM_QueryEndSession and WM_EndSession, and then the App is killed mid shutdown.

WM_QueryEndSession and WM_EndSession is received by each threaded Window starting with lowest thread number first.

So I have code which saves everything when a WM_QueryEndSession is received.

I have a final record thats written when WM_EndSession is received just incase the shutdown is really happening as per wParam.

Problem is the process is killed by windows before even the single record is saved when WM_EndSession is received.

This negates the advice given out by Raymond Chen.

Its such a blunt instrument the shutdown procedure is, there doesnt appear to be any way to shutdown the app gracefully because windows is killing the processes too quickly.

When shutting the app down manually, I only need 34/100ths of a second to shutdown properly.

So does anyone have any suggestions?

From memory, and its been like 25 years since i added this to WinEvent, the first event returns a value ‐ yes or no. If you return no then the second event us not triggered.

But as long as your program (eventually) ends itself (like in the next few seconds) it doesnt mater, as soon as it ends itself, Windows ends too.

You’ve likely seen that “programs preventing windows closing” screen, and then seen programs disappear from that screen.

Of course you can also call your close logging directly from inside the event processor, before returning a value.

Like i say this is all from memory a long time ago, so treat with a pinch of salt.

Yeah thats the correct.
QueryEndSession - Asks apps if they can shutdown.
If any apps Return False (No), then the shutdown process is generally aborted except Forced Shutdowns.
If all Return True (Yes), then EndSession is sent out and Windows Shutdown proceeds.

EndSession - there should be a period of time for the app to shutdown BUT the OS can kill any and all processes if its wants.

What I’m seeing is there is no default 20 second wait for the App.

There is a HKCU App timeout setting, mentioned here.

The reg setting can be found in XP as well, and exists on my (virtual) machines.

HKEY_CURRENT_USER\Control Panel\Desktop
WaitToKillAppTimeout = “20000”

There is also a regsetting to prevent auto termination of apps, which does not look like it might apply to the shutdown process, because mine is set to zero and apps still get auto terminated.

HKEY_CURRENT_USER\Control Panel\Desktop
AutoEndTasks = “0” ; prevents forced termination

So I’m stuck in a situation where the app seems to be killed prematurely by windows after WM_EndSession and there’s nothing I can do about it.

If I shutdown on WM_QueryEndSession, which will save all data down cleanly but this goes against what Raymond Chen is suggesting, plus there is also the risk the Shutdown process is aborted and thats when I still want my app to be working.

Chen does state

In practice, displaying a prompt is usually not a good idea because if you don’t respond to the message after a few seconds, the system will shut down without you.

I’m not displaying anything, but earlier on in the post he mentions starting a background thread to perform the data save.

When you get the WM_END­SESSION message, you wait until that background operation completes before telling the system, “I’m good; you can shut down now.”

Here he’s suggested waiting in a subclassed procedure before Returning True or False.

Problem is, these windows are paused and thus cant save any data because these are subclassed procedures, and Chen should know this. The only things accessible to them is global data and global functions, unless this is a Clarion issue?

I note the Clarion Frame Extension class sends a Notify from the subclassed procedure, if using the systray template, which puts a msg in the msg queue, but there’s no chance of being able to save the data on WM_EndSession using this template & class, because the windows are paused.

from WinExt.clw

    OF WM_QUERYENDSESSION
      IF GloCurrentWinExt.AllowShutDown
         GloCurrentWinExt.OnShutDown=GloCurrentWinExt.ProcessShutDown()
         IF GloCurrentWinExt.OnShutDown
            RETURN(GloCurrentWinExt.OnShutDown)
         ELSE
            RETURN(False)
         END
      !ELSE
      !   RETURN(False)
      END
    OF WM_ENDSESSION
      IF GloCurrentWinExt.AllowShutDown
         NOTIFY(Event:CloseDown,THREAD())
         RETURN(True)
      !ELSE
      !   RETURN(False)
      END

So apart from storing everything in Globals which then brings back object synchronisation issues and random thread locking, I’m out of ideas.

A Loop Sleep(10) before the WM_EndSession Return T/F doesnt work either.

OF WM_EndSession

   Loop
       IF Condition
           Sleep(10)
       Else
           Break
       End
  End

Return True

I’m not sure what you mean by “the windows are paused”? I’m also not sure why local stuff is out of scope here? I’m not recalling any limitations with that.

I am guessing that you’re saying that other threads are “not handling events” while you are subclassing the event on the frame? Presumably those threads are being driven by an Event loop (timers etc) of their own?

The windows (mainframe and a SDI window) have subclassed procedures.
When they intercept the WM_QueryEndSession and WM_EndSession, than can pass it on to the next subclassed procedure, or hand it back to the original window for processing, or call another procedure/function which goes off and does something else, essentially pausing the window until the procedure/function returns.

The runtime will throw up the error message, this app needs to be closed before windows can be shut down, if it gets the EndSession message.

Only three threads.
_main : Thread 1
Main Frame : Thread 2
SDI Window : Thread 3

Threads 2 & 3 handle events by virtue of being a window.

Raymond Chen is not a Clarion programmer.

In C/C++ he does not have to subclass to get WM_END­SESSION messages. You should know this.

1 Like

I know he’s not a clarion programmer and I didnt know he didnt have to subclass, I dont program in C/C++ I try to program in Clarion.

So are you saying we should learn to program in C/C++? How does that fit when Python seems to be the language of choice in educational places?

Edit.
More on Critical Sections.

Lock Convoys.

The original post is not available on the Wayback machine.