Thread View: borland.public.cppbuilder.nativeapi
28 messages
28 total messages
Started by A Nonymous
Thu, 08 Mar 2007 20:12
HELP: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Thu, 08 Mar 2007 20:12
Date: Thu, 08 Mar 2007 20:12
28 lines
2039 bytes
2039 bytes
I have an application that used to shutdown gracefully if it was running when Windows shutdown. Now I noticed that my application shuts down, but it also seems to cancel the Windows shutdown. I trap/handle the WM_QUERYENDSESSION and WM_ENDSESSION messages to save my files and close. I set the Msg.Result = 1 (ok to shutdown) in each handler so Windows should continue to shutdown. It use to work... I did some research and apparently any 3rd party component that is using AllocateHWnd and not calling DefaultWindowProc in the handler method can cause this problem. In that case the handler method is answering 0 to WM_QUERYENDSESSION which tells Windows to cancel the shutdown. This is a BIG application and I use a lot of components. I created a new project and have been adding components one at a time to see what kills the shutdown. With an almost 5 minute reboot cycle this is EXTREMELY time consuming. There must be a better way? Does anyone know any way of "tracing" a message so I can see where Msg.Result is being set incorrectly? I also created a test application that sends the WM_QUERYENDSESSION and WM_ENDSESSION messages to my app in an attempt to "fake" the shutdown, but it seems to report that my app is responding properly. Something is going wrong but I am having trouble finding it. Can anyone help?
Re: HELP: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Thu, 08 Mar 2007 20:33
Date: Thu, 08 Mar 2007 20:33
41 lines
2139 bytes
2139 bytes
More info:
My original code which has not changed in a LONG time and used to work
fine:
void __fastcall TFormMain::wmQueryEndSession(TMessage& Message)
{
Message.Result = 1;
SaveFile();
CloseFile();
Application->Terminate();
}
My fake shutdown app is just a form with a button and a memo. The
button press event looks like this:
void __fastcall TForm1::ButtonQueryEndSessionClick(TObject *Sender)
{
Memo->Lines->Append("Send WM_QueryEndSession Message:");
WPARAM wParam = 0;
LPARAM lParam = 0;
HWND H = FindWindow("TFormMain",NULL);
if(H)
{
Memo->Lines->Append("- Application window handle = " + IntToStr(H));
if (SendMessage(H,WM_QUERYENDSESSION,wParam,lParam))
Memo->Lines->Append("- Application responded OK to close.");
else
Memo->Lines->Append("- Application responded NOT OK to close.");
Memo->Lines->Append("- wParam = " + IntToStr(wParam));
Memo->Lines->Append("- lParam = " + IntToStr(lParam));
}
else
Memo->Lines->Append("- Application window handle NOT FOUND!");
Memo->Lines->Append("----------------------------------");
}
The send message return is true, and both wParam and lParam are 0. My
application is saving and closing it's files.
OK, so why doesn't windows shutdown?
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Thu, 08 Mar 2007 20:33
Date: Thu, 08 Mar 2007 20:33
44 lines
2539 bytes
2539 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98ED90968E734anonymoushotmailcom@207.105.83.66... > I trap/handle the WM_QUERYENDSESSION and WM_ENDSESSION > messages to save my files and close. I set the Msg.Result = 1 > (ok to shutdown) in each handler so Windows should continue > to shutdown. It use to work... According to the documentation, the return value for WM_ENDSESSION is 0, not 1. > I did some research and apparently any 3rd party component that > is using AllocateHWnd and not calling DefaultWindowProc in the > handler method can cause this problem. I would expect that. Any window message handler has to call DefWindowProc() for unhandled messages. > In that case the handler method is answering 0 to WM_QUERYENDSESSION > which tells Windows to cancel the shutdown. Correct. > This is a BIG application and I use a lot of components. I created > a new project and have been adding components one at a time to > see what kills the shutdown. With an almost 5 minute reboot cycle > this is EXTREMELY time consuming. There must be a better way? You would have to write a separate app that manually sends the shutdown messages to a desired window, and then see how that app responds to them. > I also created a test application that sends the WM_QUERYENDSESSION > and WM_ENDSESSION messages to my app in an attempt to "fake" > the shutdown, but it seems to report that my app is responding > properly. There is no way to differentiate between a real shutdown and a faked one. If the app responds one way to the fake shutdown, then it has to react the same way to the real shutdown as well. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Thu, 08 Mar 2007 20:59
Date: Thu, 08 Mar 2007 20:59
52 lines
2591 bytes
2591 bytes
"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote in news:45f07307
@newsgroups.borland.com:
>
> "A Nonymous" <anonymous@hotmail.com> wrote in message
> news:Xns98ED90968E734anonymoushotmailcom@207.105.83.66...
>
>> I trap/handle the WM_QUERYENDSESSION and WM_ENDSESSION
>> messages to save my files and close. I set the Msg.Result = 1
>> (ok to shutdown) in each handler so Windows should continue
>> to shutdown. It use to work...
>
> According to the documentation, the return value for WM_ENDSESSION is
> 0, not 1.
>
It doesn't appear to work that way. You may not have seen my addendum
when you posted this response, but take a look at it.
To simplify the problem I created a new application. I created only a
handlet for the WM_QUERYENDSESSION and WM_ENDSESSION messages.
void __fastcall TFormMain::wmQueryEndSession(TMessage& Message)
{
Message.Result = 1;
Application->Terminate();
}
void __fastcall TFormMain::wmEndSession(TMessage& Message)
{
Message.Result = 1;
}
The app terminates and Windows restarts.
I changed the Message.Result to 0 (in both) and the application
terminated but Windows did not restart. This is the problem I am trying
to resolve.
I used my "fake" shutdown app to send the shutdown messages to both
versions of the test applcation and with Message.Result = 1, the app
shuts down, I get a true response from the SnedMessage and both wParam
and lParam are 0.
The same operation with Message.Result = 0, the app shuts down, I get a
FALSE response from the SnedMessage and both wParam and lParam are still
0.
On my real app, the app shuts down, I get a true response from the
SnedMessage and both wParam and lParam are 0, BUT Windows does not
restart.
There must be something else? I just don't know how to find it.
Re: HELP: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Thu, 08 Mar 2007 21:56
Date: Thu, 08 Mar 2007 21:56
20 lines
1582 bytes
1582 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message
news:Xns98ED941B2E2C8anonymoushotmailcom@207.105.83.66...
> My original code which has not changed in a LONG time and used to
work
> fine:
Why don't you simply use the form's OnCloseQuery and OnClose events
instead? The VCL already handles the WM_QUERYENDSESSION and
WM_ENDSESSION messages. OnCloseQuery is triggered when
WM_QUERYENDSESSION is received.
> HWND H = FindWindow("TFormMain",NULL);
Have you tried sending the message to the hidden TApplication window
yet? That is the parent window for TForm, after all.
Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Dennis Jones
Date: Thu, 08 Mar 2007 22:35
Date: Thu, 08 Mar 2007 22:35
116 lines
5168 bytes
5168 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message
news:Xns98ED988E421A8anonymoushotmailcom@207.105.83.66...
>> According to the documentation, the return value for WM_ENDSESSION is
>> 0, not 1.
>>
> It doesn't appear to work that way. You may not have seen my addendum
> when you posted this response, but take a look at it.
I think you are right (I believe Remy is mistaken here). One of my
applications processes the WM_QUERYENDSESSION and WM_ENDSESSION messages,
and I do it this way (and it works perfectly):
MESSAGE void __fastcall TMainForm::WMEndSession(TMessage &msg)
{
// if WM_QUERYENDSESSION returned false, it's not okay to shutdown the
program
if ( msg.WParam == false ) return;
// if we get this far, it's okay to shut down the app
LogMsg("System is shutting down - Received end of session notification");
// if Windows is shutting down, we want to shut down the application
without user intervention;
// to accomplish this, we must stop the service first
SendMessage( this->Handle, WM_SERVICE_STOP, NoPrompt, 0 );
// now we know the service is not running; we can close the application
and we
// won't be queried about shutting down
Close();
}
//---------------------------------------------------------------------------
// handle WM_QUERYENDSESSION -- this isn't strictly necessary since we
always want to allow
// Windows to shut down, but it's here for completeness and for the sake of
logging
MESSAGE void __fastcall TMainForm::WMQueryEndSession(TMessage &msg)
{
LogMsg("System wants to shut down - Received end of session query
notification");
// when an application receives the WM_QUERYENDSESSION message, it must
tell Windows
// whether or not it is really okay to shut down;
// setting the message result to 'true' means it is okay to shut down
Windows
msg.Result = true;
}
//---------------------------------------------------------------------------
> To simplify the problem I created a new application. I created only a
> handlet for the WM_QUERYENDSESSION and WM_ENDSESSION messages.
>
> void __fastcall TFormMain::wmQueryEndSession(TMessage& Message)
> {
> Message.Result = 1;
> Application->Terminate();
> }
That seems fishy to me (calling Terminate from the WM_QUERYENDSESSION
handler). Perhaps you should wait until WM_ENDSESSION is received before
performing any shutdown procedures?
> void __fastcall TFormMain::wmEndSession(TMessage& Message)
> {
> Message.Result = 1;
> }
Not sure if the Result field needs to be set in WM_ENDSESSION (I don't do it
in my app).
> The app terminates and Windows restarts.
Comparing your code to mine, I believe that is correct and expected.
> I changed the Message.Result to 0 (in both) and the application
> terminated but Windows did not restart.
Right, setting Message.Result = 0 in WM_QUERYENDSESSION should abort the OS
shutdown.
> This is the problem I am trying
> to resolve.
>
> I used my "fake" shutdown app to send the shutdown messages to both
> versions of the test applcation and with Message.Result = 1, the app
> shuts down, I get a true response from the SnedMessage and both wParam
> and lParam are 0.
>
> The same operation with Message.Result = 0, the app shuts down, I get a
> FALSE response from the SnedMessage and both wParam and lParam are still
> 0.
>
> On my real app, the app shuts down, I get a true response from the
> SnedMessage and both wParam and lParam are 0, BUT Windows does not
> restart.
>
> There must be something else? I just don't know how to find it.
The only thing that seems odd to me is your WM_QUERYENDSESSION handler.
Terminating the application from there seems premature to me. It ought to
work okay, but I just can't help wondering if that has anything to do with
it (I know, I'm grasping at straws here). Instead of calling
Application->Terminate from your WM_WNEDQUERYSESSION handler, can you try
calling Close() from the WM_ENDSESSION handler (as I do in the snippets I
posted above)?
- Dennis
Re: HELP: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Thu, 08 Mar 2007 22:42
Date: Thu, 08 Mar 2007 22:42
48 lines
2686 bytes
2686 bytes
"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote in news:45f08683$1
@newsgroups.borland.com:
>
> "A Nonymous" <anonymous@hotmail.com> wrote in message
> news:Xns98ED941B2E2C8anonymoushotmailcom@207.105.83.66...
>
>> My original code which has not changed in a LONG time and used to
> work
>> fine:
>
> Why don't you simply use the form's OnCloseQuery and OnClose events
> instead? The VCL already handles the WM_QUERYENDSESSION and
> WM_ENDSESSION messages. OnCloseQuery is triggered when
> WM_QUERYENDSESSION is received.
>
I just tried that. I commented out the message map line so as not to
interfeer with the normal processing of the end session messages. I
then modified the OnQueryClose to not ask about saving, just save and
exit.
Same problem.
I want the shutdown on Windows shutdown to be non interactive, just save
and close. If the user manually closes the app, then I want to ask if
they want to save modified files.
>> HWND H = FindWindow("TFormMain",NULL);
>
> Have you tried sending the message to the hidden TApplication window
> yet? That is the parent window for TForm, after all.
>
>
> Gambit
>
>
>
Not sure what you are asking about here. Is that the window that
windows is actually sending the WM_QUERYENDSESSION to? How do I get the
handle, TApplication doesn't seem to work. Even if I send to the hidden
form using my "fake" shutdown app and it returns false from the end
session messages, how do I isolate the source.
The goal is to identify what is causing the problem. If it is a
component I have the source for I will try to fix it. If it is one I
don't have the source for then I will contact the vendor for a patch, or
replace the component with something else.
Re: My app closes, but cancels Windows shutdown?
Author: Dennis Jones
Date: Thu, 08 Mar 2007 22:42
Date: Thu, 08 Mar 2007 22:42
19 lines
1826 bytes
1826 bytes
"Dennis Jones" <nospam@nospam.com> wrote in message news:45f08f8f$1@newsgroups.borland.com... > >>> According to the documentation, the return value for WM_ENDSESSION is >>> 0, not 1. >>> >> It doesn't appear to work that way. You may not have seen my addendum >> when you posted this response, but take a look at it. > > I think you are right (I believe Remy is mistaken here). One of my > applications processes the WM_QUERYENDSESSION and WM_ENDSESSION messages, > and I do it this way (and it works perfectly): Apologies to Remy...he was referring to the return value for WM_ENDSESSION (I was thinking about WM_QUERYENDSESSION). Upon processing WM_ENDSESSION, the app should set the Result field to 0. - Dennis
Re: HELP: My app closes, but cancels Windows shutdown?
Author: Dennis Jones
Date: Thu, 08 Mar 2007 22:53
Date: Thu, 08 Mar 2007 22:53
120 lines
5233 bytes
5233 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message
news:Xns98EDAA07AFDF0anonymoushotmailcom@207.105.83.66...
>> Why don't you simply use the form's OnCloseQuery and OnClose events
>> instead? The VCL already handles the WM_QUERYENDSESSION and
>> WM_ENDSESSION messages. OnCloseQuery is triggered when
>> WM_QUERYENDSESSION is received.
>>
>
> I just tried that. I commented out the message map line so as not to
> interfeer with the normal processing of the end session messages. I
> then modified the OnQueryClose to not ask about saving, just save and
> exit.
>
Yeah, that's why I handle both the VCL events and the Windows messages, and
then also some of my own messages, because I have control over when the user
is prompted for confirmation. I ask the user for confirmation only if the
user is shutting down the application, but not if Windows is shutting down:
MESSAGE void __fastcall TMainForm::WM_Service_Stop(TMessage &Message)
{
bool CanStop = true;
if ( Message.WParam != NoPrompt )
{
StopQuery( CanStop );
}
if ( !CanStop )
{
return;
}
LogMsg("Application is stopping the service - Received service stop
notification");
Service->Stop();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormCloseQuery(TObject */*Sender*/, bool
&CanClose)
{
LogMsg("Application wants to shut down - Received close window request");
if ( Service->IsRunning() )
{
StopQuery( CanClose );
if ( !CanClose )
{
LogMsg("Application shut down cancelled");
}
}
}
//---------------------------------------------------------------------------
void TMainForm::StopQuery( bool &CanStop )
{
LogMsg("Application wants to stop the service - Received service stop
request");
AnsiString StopQueryMsg = "You are about to deactivate the service...";
if ( IDCANCEL == Application->MessageBox( StopQueryMsg.c_str(),
"Confirm",
MB_OKCANCEL |
MB_ICONWARNING ) )
{
LogMsg("Service stop cancelled");
CanStop = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormClose(TObject */*Sender*/,
TCloseAction &/*Action*/)
{
LogMsg("Application is shutting down - Received close window
notification");
SendMessage( this->Handle, WM_SERVICE_STOP, NoPrompt, 0 );
}
//---------------------------------------------------------------------------
MESSAGE void __fastcall TMainForm::WMEndSession(TMessage &msg)
{
// if WM_QUERYENDSESSION returned false, it's not okay to shutdown the
program
if ( msg.WParam == false ) return;
// if we get this far, it's okay to shut down the interface
LogMsg("System is shutting down - Received end of session notification");
// if Windows is shutting down, we want to shut down the application
without user intervention;
// to accomplish this, we must stop the interface service first
SendMessage( this->Handle, WM_SERVICE_STOP, NoPrompt, 0 );
// now we know the interface service is not running; we can close the
application and we
// won't be queried about shutting down
Close();
}
//---------------------------------------------------------------------------
// handle WM_QUERYENDSESSION -- this isn't strictly necessary since we
always want to allow
// Windows to shut down, but it's here for completeness and for the sake of
logging
MESSAGE void __fastcall TMainForm::WMQueryEndSession(TMessage &msg)
{
LogMsg("System wants to shut down - Received end of session query
notification");
// when an application receives the WM_QUERYENDSESSION message, it must
tell Windows
// whether or not it is really okay to shut down;
// setting the message result to 'true' means it is okay to shut down
Windows
msg.Result = true;
}
//---------------------------------------------------------------------------
- Dennis
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Thu, 08 Mar 2007 22:54
Date: Thu, 08 Mar 2007 22:54
147 lines
6247 bytes
6247 bytes
"Dennis Jones" <nospam@nospam.com> wrote in
news:45f08f8f$1@newsgroups.borland.com:
>
> "A Nonymous" <anonymous@hotmail.com> wrote in message
> news:Xns98ED988E421A8anonymoushotmailcom@207.105.83.66...
>
>>> According to the documentation, the return value for WM_ENDSESSION
>>> is 0, not 1.
>>>
>> It doesn't appear to work that way. You may not have seen my
>> addendum when you posted this response, but take a look at it.
>
> I think you are right (I believe Remy is mistaken here). One of my
> applications processes the WM_QUERYENDSESSION and WM_ENDSESSION
> messages, and I do it this way (and it works perfectly):
>
> MESSAGE void __fastcall TMainForm::WMEndSession(TMessage &msg)
> {
> // if WM_QUERYENDSESSION returned false, it's not okay to shutdown
> the
> program
> if ( msg.WParam == false ) return;
>
> // if we get this far, it's okay to shut down the app
> LogMsg("System is shutting down - Received end of session
> notification");
>
> // if Windows is shutting down, we want to shut down the
> application
> without user intervention;
> // to accomplish this, we must stop the service first
> SendMessage( this->Handle, WM_SERVICE_STOP, NoPrompt, 0 );
>
> // now we know the service is not running; we can close the
> application
> and we
> // won't be queried about shutting down
> Close();
> }
> //--------------------------------------------------------------------
-
> ------
>
> // handle WM_QUERYENDSESSION -- this isn't strictly necessary since we
> always want to allow
> // Windows to shut down, but it's here for completeness and for the
> sake of logging
> MESSAGE void __fastcall TMainForm::WMQueryEndSession(TMessage &msg)
> {
> LogMsg("System wants to shut down - Received end of session query
> notification");
>
> // when an application receives the WM_QUERYENDSESSION message, it
> must
> tell Windows
> // whether or not it is really okay to shut down;
> // setting the message result to 'true' means it is okay to shut
> down
> Windows
> msg.Result = true;
> }
> //--------------------------------------------------------------------
-
> ------
>
>
>> To simplify the problem I created a new application. I created only
>> a handlet for the WM_QUERYENDSESSION and WM_ENDSESSION messages.
>>
>> void __fastcall TFormMain::wmQueryEndSession(TMessage& Message)
>> {
>> Message.Result = 1;
>> Application->Terminate();
>> }
>
> That seems fishy to me (calling Terminate from the WM_QUERYENDSESSION
> handler). Perhaps you should wait until WM_ENDSESSION is received
> before performing any shutdown procedures?
>
>
>> void __fastcall TFormMain::wmEndSession(TMessage& Message)
>> {
>> Message.Result = 1;
>> }
>
> Not sure if the Result field needs to be set in WM_ENDSESSION (I don't
> do it in my app).
>
>
>> The app terminates and Windows restarts.
>
> Comparing your code to mine, I believe that is correct and expected.
>
>
>> I changed the Message.Result to 0 (in both) and the application
>> terminated but Windows did not restart.
>
> Right, setting Message.Result = 0 in WM_QUERYENDSESSION should abort
> the OS shutdown.
>
>
>> This is the problem I am trying
>> to resolve.
>>
>> I used my "fake" shutdown app to send the shutdown messages to both
>> versions of the test applcation and with Message.Result = 1, the app
>> shuts down, I get a true response from the SnedMessage and both
>> wParam and lParam are 0.
>>
>> The same operation with Message.Result = 0, the app shuts down, I get
>> a FALSE response from the SnedMessage and both wParam and lParam are
>> still 0.
>>
>> On my real app, the app shuts down, I get a true response from the
>> SnedMessage and both wParam and lParam are 0, BUT Windows does not
>> restart.
>>
>> There must be something else? I just don't know how to find it.
>
> The only thing that seems odd to me is your WM_QUERYENDSESSION
> handler. Terminating the application from there seems premature to me.
> It ought to work okay, but I just can't help wondering if that has
> anything to do with it (I know, I'm grasping at straws here). Instead
> of calling Application->Terminate from your WM_WNEDQUERYSESSION
> handler, can you try calling Close() from the WM_ENDSESSION handler
> (as I do in the snippets I posted above)?
>
> - Dennis
>
>
>
I need to do the terminate in the WM_QUERYENDSESSION because the files
are on the net and I need to bypass the normal cleanup code. When I
used to do it in the WM_ENDSESSION sometimes it got runtime errors
because other services had been shut down. When I moved everything to
the WM_QUERYENDSESSION and started using the terminate the shutdown was
100% reliable. It introduces a small memory leak, but when you are
rebooting this is not a problem.
This has worked for a couple of years, but about 6 mos ago I did a major
overhaul to the user interface and added a lot of graphics, a skin
capability and foreign language support. In the process I added a lot
of 3rd party components, and updated several of the component suites I
was using. Obviously I of these changes broke something I am just not
sure how to narrow it down.
Re: HELP: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Thu, 08 Mar 2007 22:57
Date: Thu, 08 Mar 2007 22:57
59 lines
3297 bytes
3297 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98EDAA07AFDF0anonymoushotmailcom@207.105.83.66... > I want the shutdown on Windows shutdown to be non interactive, > just save and close. That is exactly what the OnClose and OnCloseQuery events provide for you without using message hooks. It does work. I've used it many times before. > If the user manually closes the app, then I want to ask if > they want to save modified files. That is also easy to do. You can intercept the WM_SYSCOMMAND message. That is sent when the user closes the window, but not during a shutdown. You can use it to set a flag that your OnClose/Query handlers can check. > Not sure what you are asking about here. You do know that TForm windows are not standalone windows, right? The global TApplication object has its own hidden window that silently controls the TForm windows. > Is that the window that windows is actually sending the WM_QUERYENDSESSION to? It can be. > How do I get the handle, TApplication doesn't seem to work. TApplication has a Handle property. When you do your FindWindow(), look for the 'TApplication" classname instead of "TFormMain". You will also have to look for the TApplication.Title (what is displayed on the Taskbar button) as the caption to look for as well, since every VCL application has a TApplication class, so you want to make sure you use unique captions in your projects so you are searching for the right program. > how do I isolate the source. I already explained to you earlier. As far as the VCL is concerned, there is NO difference whatsoever between a real shutdown and a fake one. If the OS is not responding correctly to the VCL reporting that the shutdown is ok, then that is a problem in the OS itself, not the VCL. > The goal is to identify what is causing the problem. If it is a > component I have the source for I will try to fix it. You won't be able to do that until you have a reliable test environment with which to send fake shutdowns with. Onc you have that working properly, then you can debug the message handling inside the offending program to see who is handling the messages and how. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Dennis Jones
Date: Thu, 08 Mar 2007 23:01
Date: Thu, 08 Mar 2007 23:01
20 lines
2044 bytes
2044 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98EDAC20DAA4Eanonymoushotmailcom@207.105.83.66... > This has worked for a couple of years, but about 6 mos ago I did a major > overhaul to the user interface and added a lot of graphics, a skin > capability and foreign language support. In the process I added a lot > of 3rd party components, and updated several of the component suites I > was using. Obviously I of these changes broke something I am just not > sure how to narrow it down. Have you considered that it might not be YOUR application that is preventing Windows from shutting down? You said that your "fake" shutdown app is getting back the correct result. That would seem to indicate that even if there were other components in the mix using AllocateHWnd, that they are not affecting the application's ability to notify Windows that it is okay to shutdown. - Dennis
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Fri, 09 Mar 2007 00:08
Date: Fri, 09 Mar 2007 00:08
22 lines
2080 bytes
2080 bytes
"Dennis Jones" <nospam@nospam.com> wrote in message news:45f095bf$1@newsgroups.borland.com... > Have you considered that it might not be YOUR application that is > preventing Windows from shutting down? You said that your "fake" > shutdown app is getting back the correct result. That would seem to > indicate that even if there were other components in the mix using > AllocateHWnd, that they are not affecting the application's ability to > notify Windows that it is okay to shutdown. The other thing to take into account is that the test app which is sending the fake shutdown is sending the messages to only one window. If there are multiple top-level windows in the program being tested, such as due to AllocateHWnd() calls, then the shutdown messages need to be sent to each individual window, each window being tested separately from the other windows. Any one of them could be reporting an unacceptable shutdown. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Dennis Jones
Date: Fri, 09 Mar 2007 00:17
Date: Fri, 09 Mar 2007 00:17
30 lines
2619 bytes
2619 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message news:45f0a594@newsgroups.borland.com... > > "Dennis Jones" <nospam@nospam.com> wrote in message > news:45f095bf$1@newsgroups.borland.com... > >> Have you considered that it might not be YOUR application that is >> preventing Windows from shutting down? You said that your "fake" >> shutdown app is getting back the correct result. That would seem to >> indicate that even if there were other components in the mix using >> AllocateHWnd, that they are not affecting the application's ability > to >> notify Windows that it is okay to shutdown. > > The other thing to take into account is that the test app which is > sending the fake shutdown is sending the messages to only one window. > If there are multiple top-level windows in the program being tested, > such as due to AllocateHWnd() calls, then the shutdown messages need > to be sent to each individual window, each window being tested > separately from the other windows. Any one of them could be reporting > an unacceptable shutdown. Yeah, I just realized that a minute ago. The OP wasn't far off in asking about debugging the messages. Perhaps a windows message spy program (http://www.catch22.net/software/winspy.asp) would be useful. I've used programs like this in the past, but it has been a long time, so I have no idea which ones, if any, are any good. - Dennis
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Fri, 09 Mar 2007 03:33
Date: Fri, 09 Mar 2007 03:33
16 lines
1810 bytes
1810 bytes
"Dennis Jones" <nospam@nospam.com> wrote in message news:45f0a77f$1@newsgroups.borland.com... > Yeah, I just realized that a minute ago. The OP wasn't far off in > asking about debugging the messages. Perhaps a windows message spy > program (http://www.catch22.net/software/winspy.asp) would be > useful. Not very much. That will only which messages are arriving to which allocated windows, but the windows will change every time the program is re-run, and it will not help you trace through the actual code to know how the messages are being processed. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Fri, 09 Mar 2007 17:12
Date: Fri, 09 Mar 2007 17:12
82 lines
5274 bytes
5274 bytes
"Ok, let's start again... I use the FormCloseQuery FormClose events and check/ask if files need to be saved. The problem is that I also wanted/needed to detect when windows was shutting down because my app is designed to run unattended,like a service, and if the system was being shutdown with no one present, like by the UPS, I wanted it to just save and close. To do this I trap the WM_QUERYENDSESSION message which is sent when Windows shuts down. This is a technique that I have used for several years, and it worked fine in this application for more than 2 years. About 6 months ago I did a major overhaul to the presentation layer. i added a lot of graphics (some animated) along with user selectable skins. I also added foreign language support, and a few new features. In all of these changes, the close and end session routines did not change. I released the update and started getting calls from users that their systems would not shutdown if the new version my application was running. Previously they had no problems. I tested and discovered that indeed, my application closed but Windows would not shutdown. If I select shutdown again then Windows would shutdown. I started looking for similar problems and solutions on the Internet and came across a couple of articles that talked about 3rd party component that is using AllocateHWnd and not calling DefaultWindowProc in the handler method can cause this problem. Since I had just added a LOT of 3rd party components this looked like a good place to start. Actually the first thing I did was double check my code to make sure all of my message handlers were done properly. I can't debug the app while Windows is shutting down, because Windows always tries to kill the IDE first. So I started by creating a basic test application with my close and end session code. I ran it (outside the IDE) and restarted windows. It saved the temp file, closed and Windows restarted. This was a good starting place. I started adding components and restarting Windows so far everything works and this is very time consuming. Looking for a better solution, I created a fake shutdown utility that would send a WM_QUERYENDSESSION message to my app in hopes that I could debug my app to see how it responded to the message. Well it shuts down and returns true, which is what it is supposed to do according to everything I have read. I actually expected to see my app to return false. Now I have the situation where my real app returns true, but Windows shutdown is canceled. My test app returns true but windows shutdown works properly. If I set my test app to return false it also cancels windows shutdown. Some of the suggestion here were that windows might be sending WM_QUERYENDSESSION to some window other the the main form. This would certainly explain the situation where shutdown was canceled even though the main form returned true. OK, I modified my fake shutdown utility to find the handle of TApplication and TFormMain, and they are the same. According to the docs I have Windows should only be sending to the main form of the app, so child forms should not be involved? What other forms in my app could be involved? Another suggestion was changing the way the whole close query end session thing works. OK, I commented out the hook to the WM_QUERYENDSESSION routine so the message would not be trapped. I made sure the files in my app were not modified so it would not ask to save. I tried to restart Windows. My app closed quietly, but Windows did not restart. I guess the fundamental question is how to isolate the cause. Right now the most likely thing sounds like the hidden window theory. Tracing messages sent to my app and debugging with the fake shutdown doesn't seem to be revealing anything. I am thinking I need to find the mysterious hidden window. Perhaps some component is creating a window. How can I enumerate all window handles on my system? Sorry for "Gone With The Wind Volume Two"...
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Fri, 09 Mar 2007 18:37
Date: Fri, 09 Mar 2007 18:37
133 lines
6487 bytes
6487 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message
news:Xns98EE722D896C6anonymoushotmailcom@207.105.83.66...
> I can't debug the app while Windows is shutting down
You could have your app install an OS-level message hook for itself
via SetWindowsHookEx(), and then check all messages that are received.
Both the WH_CALLWNDPROC and WH_CALLWNDPROCRET hooks provide you the
specific HWND that is processing each message, and WH_CALLWNDPROCRET
gives you the final result of the message as well. So you could be
notified of all windows that receive WM_QUERYENDSESSION, check if any
of them return FALSE, and if so then log the HWND's class name. That
will, at least, tell you whether or not AllocateHWnd() is at fault to
begin with. The class name of the HWND that AllocateHWnd() creates is
"TPUtilWindow".
If that is the case, then you could use GetWindowLong() to get the
pointer to the HWND's window procedure, which will be a pointer to
Borland's proxy stub, and then extract the original TMethod from that
stub. That TMethod will point directly to the class method that was
passed to AllocateHWnd(). From that, you will have the 'this' pointer
for the object, which you could cast to a TComponent pointer and
access its properties normally. For example:
--- MyProject.cpp ---
HHOOK hHook = NULL;
LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM
lParam)
{
if( nCode == HC_ACTION )
{
CWPRETSTRUCT *ret = (CWPRETSTRUCT*) lParam;
if( (ret->message == WM_QUERYENDSESSION) && (ret->lResult
== FALSE) )
{
TCHAR szClassName[16] = {0};
GetClassName(ret->hwnd, szClassName, 15);
if( lstrcmp(szClassName, TEXT("TPUtilWindow")) == 0 )
{
LPBYTE ptr = (LPBYTE) GetWindowLong(ret->hwnd,
GWL_WNDPROC);
TComponent *comp = (TComponent*)
(((TMethod*)(ptr+5))->Data);
// log information about comp, such as its Name...
}
else
{
// log information about the HWND for later
inspection...
}
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow)
{
hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)
&CallWndRetProc, NULL, 0);
// normal app code here...
UnhookWindowsHookEx(hHook);
return 0;
}
> Looking for a better solution, I created a fake shutdown utility
that
> would send a WM_QUERYENDSESSION message to my app
> in hopes that I could debug my app to see how it responded to the
> message. Well it shuts down and returns true, which is what it is
> supposed to do according to everything I have read.
But you are only sending the message to the program's main window, not
to any of its secondary windows. You need to do that if you are going
to continue down that route.
> I actually expected to see my app to return false.
The main window will only return FALSE to that message if the
OnCloseQuery event hanlder sets the CanClose parameter to false (or if
any of the VCL's termination procedures return false after the TForm
is closed, but that is a separate issue). But any of the secondary
windows could be returning FALSE instead or TRUE to the message. You
are not checking for that yet.
> Some of the suggestion here were that windows might be sending
> WM_QUERYENDSESSION to some window other the the main
> form. This would certainly explain the situation where shutdown was
> canceled even though the main form returned true. OK, I modified
> my fake shutdown utility to find the handle of TApplication and
> TFormMain, and they are the same.
No, they are not the same. They are very distinct windows that are
separate from each other. AllocateHWnd() also creates a separate
window. And let's not forget the case where user/library code may be
calling CreateWindow/Ex() directly as well. You woud have to loop
through all running windows on the system, such as with EnumWindows(),
use GetWindowThreadProcessId() to determine which windows belong to
the target application, and then you can send your messages to all of
those windows.
> According to the docs I have Windows should only be
> sending to the main form of the app, so child forms should
> not be involved?
Not true. There is no such thing as a "main" window from the Win32
API's perspective. It sends the shutdown messages to all top-level
windows, regardless of how Borland has wrapped them.
> What other forms in my app could be involved?
Every TForm is involved, as are every AllocateWnd() window, and any
windows the user/library may be creating manually.
> Tracing messages sent to my app and debugging with the fake
> shutdown doesn't seem to be revealing anything.
That is because you are not doing it correctly yet.
> How can I enumerate all window handles on my system?
EnumWindows()
Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Bob Gonder
Date: Fri, 09 Mar 2007 19:36
Date: Fri, 09 Mar 2007 19:36
18 lines
1932 bytes
1932 bytes
A Nonymous wrote:
>I need to do the terminate in the WM_QUERYENDSESSION because the files
>are on the net and I need to bypass the normal cleanup code. When I
>used to do it in the WM_ENDSESSION sometimes it got runtime errors
>because other services had been shut down.
That sounds like a good idea, but.....Apparently there is no guarantee
that WM_QUERYENDSESSION will even be sent.....
{MSDN} http://msdn2.microsoft.com/en-us/library/aa376876.aspx
To force all applications to terminate, use ExitWindowsEx, and specify
the EXW_FORCE flag. This prevents the system from sending
WM_QUERYENDSESSION messages.
Apparently this only sends the WM_ENDSESSION message, which is why
everyone is telling you to do the save in that handler rather than the
Querry.
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Fri, 09 Mar 2007 21:37
Date: Fri, 09 Mar 2007 21:37
20 lines
2104 bytes
2104 bytes
This is great stuff, very enlightning.. I found the dumb typo (= instead of == in the comparison) and what do you know the HWND for the TApplication is not the same as the HWND of the TFormMain. Dumb mistake. :) I re read my docs and saw the statement about all top level windows... I don't know why my brain interprited that as all main forms... I modified my fake shutdown utility to list all window handles before sending the terminate to the main form. Wow! I had 635 handles before the shutdown, and after the shutdown there were 439. I was amazed to see that my app had 200 window handles. Now I just have to figure out this example code for tracing the messages. In concept I understand it, but I need to figure out how to implement it in my app. I just hope when I finally find the component it is one that I have the source for. I really appreciate the help and want to thank all who contributed.
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Fri, 09 Mar 2007 21:59
Date: Fri, 09 Mar 2007 21:59
24 lines
2357 bytes
2357 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98EE9F12960D1anonymoushotmailcom@207.105.83.66... > I modified my fake shutdown utility to list all window handles before > sending the terminate to the main form. Wow! I had 635 handles > before the shutdown, and after the shutdown there were 439. I > was amazed to see that my app had 200 window handles. It is very unlikely that it has 200 top-level windows, unless you have a lot of components creating hidden windows. I would expect the program to have 200 windows if you are taking all of the child windows into account, though. > Now I just have to figure out this example code for tracing the > messages. In concept I understand it, but I need to figure out how > to implement it in my app. Just copy/paste it as-is into the main source file of the project, where WinMain() is implemented. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Fri, 09 Mar 2007 22:50
Date: Fri, 09 Mar 2007 22:50
60 lines
3485 bytes
3485 bytes
"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote in news:45f1d8a5$1 @newsgroups.borland.com: > > "A Nonymous" <anonymous@hotmail.com> wrote in message > news:Xns98EE9F12960D1anonymoushotmailcom@207.105.83.66... > >> I modified my fake shutdown utility to list all window handles > before >> sending the terminate to the main form. Wow! I had 635 handles >> before the shutdown, and after the shutdown there were 439. I >> was amazed to see that my app had 200 window handles. > > It is very unlikely that it has 200 top-level windows, unless you have > a lot of components creating hidden windows. I would expect the > program to have 200 windows if you are taking all of the child windows > into account, though. > This surprised mee too. It may be due to some of theois 3rd party components. I only have about 40 total forms, and most of those are dynamically created as needed. (pop up edit dialogs,and such) >> Now I just have to figure out this example code for tracing the >> messages. In concept I understand it, but I need to figure out how >> to implement it in my app. > > Just copy/paste it as-is into the main source file of the project, > where WinMain() is implemented. > > > Gambit > > > Well you are right it was easy. I was concerned that I might have trouble writing to a log file from there or something, but it went in without a hitch. Now the bad news... It doesn't seem to work. I get nothing. In fact I tried setting a breakpoint on the if( nCode == HC_ACTION ) line and then using my fake shutdown utility to send a WM_QUERYENDSESSION. The app closed, but the break point was never reached. A dumb question that just occurred to me. Should the hHook = SetWindowsHookEx line be the first line in the WINAPI WinMani function or shold it come after the Application->Initialize()? Right now it is the first line, and the UnhookWindowsHookEx is on the second to last line just above the return 0; Is there something else I need to to to make this work? OK, I just checked one other thing. I put a break point on the SetWindowsHookEx and after I stepped over it hHook was still NULL. Is this normal? Anyhow I really appreciate the help.
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Sat, 10 Mar 2007 00:45
Date: Sat, 10 Mar 2007 00:45
30 lines
2597 bytes
2597 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98EEAB7C7DA52anonymoushotmailcom@207.105.83.66... > Now the bad news... It doesn't seem to work. I get nothing. > In fact I tried setting a breakpoint on the if( nCode == HC_ACTION ) > line and then using my fake shutdown utility to send a > WM_QUERYENDSESSION. The app closed, but the break > point was never reached. Then SetWindowsHookEx() is failing to install the hook. Try passing the value of WinMain's hInstance parameter to SetWindowsHookEx's hMod parameter. > Should the hHook = SetWindowsHookEx line be the first line > in the WINAPI WinMani function or shold it come after the > Application->Initialize()? In this situation, it doesn't really matter mcuh, since the forms have not been created yet. I would suggest calling it before, though, so it is in place before any VCL initializations occur. > OK, I just checked one other thing. I put a break point on the > SetWindowsHookEx and after I stepped over it hHook was > still NULL. Is this normal? No. That is a failure. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Sat, 10 Mar 2007 19:40
Date: Sat, 10 Mar 2007 19:40
45 lines
2606 bytes
2606 bytes
>> Now the bad news... It doesn't seem to work. I get nothing.
>> In fact I tried setting a breakpoint on the if( nCode == HC_ACTION )
>> line and then using my fake shutdown utility to send a
>> WM_QUERYENDSESSION. The app closed, but the break
>> point was never reached.
>
> Then SetWindowsHookEx() is failing to install the hook. Try passing
> the value of WinMain's hInstance parameter to SetWindowsHookEx's hMod
> parameter.
>
I did some reading and a null return is a failure, so I added a call to
GetLastError() and found that the error is 1428 "Cannot set non-local
hook without a module handle". This agrees with your above statement. So
I changed the:
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
to:
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
lpCmdLine, int nCmdShow)
as in your example. I changed the line:
hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)
&CallWndRetProc, NULL, 0);
to:
hHook = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)
&CallWndRetProc, hInstance, 0);
and now when I run, the entire IDE dissapears! WOW!
The MSDN docs say:
HHOOK SetWindowsHookEx( int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
What am I missing?
Sorry to seem so dumb.
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Sat, 10 Mar 2007 21:51
Date: Sat, 10 Mar 2007 21:51
36 lines
2718 bytes
2718 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message
news:Xns98EF8B2886544anonymoushotmailcom@207.105.83.66...
> I did some reading and a null return is a failure
Yes, it is. The weird thing is, when I run the exact code I gave you,
SetWindowsHookEx() does not return NULL, so it is not failing for me.
> I added a call to GetLastError() and found that the error is
> 1428 "Cannot set non-local hook without a module handle".
The thing is, the key to this approach is to install a local hook, so
that a DLL is not needed. What you could try doing is to pass the
return value of GetCurrentThreadId() to the dwThreadId parameter of
SetWindowsHookEx() instead of using a module handle, ie:
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
hHook = SetWindowsHookEx(WH_CALLWNDPROCRET,
(HOOKPROC)&CallWndRetProc, NULL, GetCurrentThreadId());
// ...
return 0;
}
If you have any worker threads that create windows, then they would
need their own local hooks, though.
> I changed the line:
<snip>
> and now when I run, the entire IDE dissapears! WOW!
I cannot reproduce that behavior.
Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Mark Jacobs
Date: Mon, 12 Mar 2007 10:37
Date: Mon, 12 Mar 2007 10:37
30 lines
2175 bytes
2175 bytes
I do it using a form-wide flag (bool clsing) to tell OnCloseQuery whether the
request to close is from the user or the OS, like this :-
//---------------------------------------------------------------------------
void __fastcall TForm1::WndProc(TMessage &Message)
{
if (Message.Msg==WM_QUERYENDSESSION) clsing=true;
TForm::WndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
if (!clsing)
{
ok=yorn("Are You Sure You Would Like to Exit");
if (!ok) { CanClose=false; return;}
}
CanClose=true; wrcfg();
delete mjtreg; delete curv; delete curs; delete vnms; delete txttoadd;
delete monlns; delete xpnd;
delete lavs; delete knms; delete jnki; delete svit;
if (BitBtn1->Enabled) if (yorn("Save Changes to Keys List"))
Memo1->Lines->SaveToFile(keyfnm);
}
//---------------------------------------------------------------------------
HTH,
--
Mark Jacobs
DK Computing
http://www.dkcomputing.co.uk
Re: My app closes, but cancels Windows shutdown?
Author: A Nonymous
Date: Tue, 13 Mar 2007 17:05
Date: Tue, 13 Mar 2007 17:05
23 lines
2336 bytes
2336 bytes
"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote in news:45f3285b$1
@newsgroups.borland.com:
> WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
> {
> hHook = SetWindowsHookEx(WH_CALLWNDPROCRET,
> (HOOKPROC)&CallWndRetProc, NULL, GetCurrentThreadId());
> // ...
> return 0;
> }
>
Thanks for all the help. This works. The hook is installed and the
routine works. The bad news is that it doesn't show anything wrong. There
are no false returns, at least none I can see. If any child thread can be
the culprit then it could be a child thread created by a 3rd party control.
I was tied up all day yesterday and did not work on my app at all. I am
going to get back on it today and see what else I can do to track this
down.
Can you think of anything else that would cause the Wndows shutdown to be
canceled?
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Tue, 13 Mar 2007 18:40
Date: Tue, 13 Mar 2007 18:40
24 lines
2483 bytes
2483 bytes
"A Nonymous" <anonymous@hotmail.com> wrote in message news:Xns98F270DA48944anonymoushotmailcom@207.105.83.66... > Thanks for all the help. This works. The hook is installed and the > routine works. The bad news is that it doesn't show anything wrong. > There are no false returns, at least none I can see. If any child thread > can be the culprit then it could be a child thread created by a 3rd party > control. Then I suggest you implement the hook inside a DLL and install it globally for all windows in all processes. When it does detect a FALSE return somewhere, you can log which process and thread was responsible, and then narrow the tracing from there. > Can you think of anything else that would cause the Wndows > shutdown to be canceled? There is no other way. Gambit
Re: My app closes, but cancels Windows shutdown?
Author: Remy Lebeau (TeamB)
Date: Fri, 16 Mar 2007 00:36
Date: Fri, 16 Mar 2007 00:36
45 lines
3341 bytes
3341 bytes
"Mike K" <nospam@nospam.net> wrote in message news:45f9bb86$1@newsgroups.borland.com... > what if my app needs a few seconds to clean up, and the OnCloseQuery() > method has come and gone? Then you will need to set CanClose to false in the OnCloseQuery event, hide the form so the user thinks it is closed, and then close it again when you are actually ready for it. Alternatively, you could have the OnCloseQuery handler show the shutdown form non-modally, then disable the closing form so the user can't interact with it, and run a temporary message loop until all actions have been finished before then finally exiting from the handler. That way, the closing is blocked, but the shutdown continues. > I have a large app that opens a shutdown form and iterates through > several timer loops waiting for databases to close, queues to flush, > files to close, etc. Sounds like things that should probably be threaded instead. Then you simply wait for the threads to terminate. > As soon as I leave the form's OnShow method (relying on the > timers to come back) I return to the OnCLoseQuery() which > exits (with CanClose set FALSE), and my control is lost. > > The shutdown timers, once they're happy, eventually call > Application->Terminate(). That is fine. OnCloseQuery is not triggered once Terminate() is called. The form is simply destroyed. So you could keep setting CanClose to false anytime the form wants to be closed, and then the app will force it closed when it is ready. > Can I use SendMessage() to send a belated message to windows > that Yes, NOW I'm ready, or is it too late by then? No. It is too late. Gambit
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads