Board index » cppbuilder » InvalidWindowhandle after Close() or Application->Terminate()

InvalidWindowhandle after Close() or Application->Terminate()


2007-02-02 10:29:56 PM
cppbuilder64
Hello,
Under certain circumstances my app does not close correctly.
I got the de{*word*81} msg 'EWin32Error - code 1400'. Invalid window
handle.
When I single step through the last actions before terminating
I can watch that the app cames out of 'Application->Run();' in
WinMain and returns with 0 at its end. After this it runs
a several times through the default WndProc function of my...
if(Message.Msg != WM_VENDCHAR2CC_MSG)
{
if(Message.Msg != WM_USER + 0x100){
TForm::WndProc(Message);
}
...own WndProc function in the main form. After a couple of msgs
it crashes at line 941 in forms.hpp
#pragma option push -w-inl
Quote
>HERE>>/* TCustomForm.Destroy */ inline __fastcall virtual ~TForm(void) { }
#pragma option pop
When i the press F8 again it tells me 'ExternalExeption C0000025
Does anybody know additional facilities which can I use to detect
the reason for this crash.
compiler: BCB5
 
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"Roland" < XXXX@XXXXX.COM >wrote:
Quote

[...] After this it runs several times through the default
WndProc function of my...
if(Message.Msg != WM_VENDCHAR2CC_MSG)
{
if(Message.Msg != WM_USER + 0x100){
TForm::WndProc(Message);
}

...own WndProc function in the main form. After a couple of msgs
it crashes at line 941 in forms.hpp
It seems that your application is trying to process messages
after it has been destroyed and I can only think of a few
things that would cause that.
It might be that you have incorrectly subclassed the method
instead of overriding it. Please show your header declaration
and unit implementation for it's WndProc method.
Just looking at the small sample above, my best guess is that
you're posting or sending a message to the main form and your
implementation surrounding that is flawed. Please show that
code as well.
If the problem is not with the above, it's going to be hard
to track down. Do you have any worker threads? Are you using
any hooks? Are you subclassing any other control's WndProc?
Are you dynamically allocating any objects? Are you doing
anything 'tricky'? If so ... what?
~ JD
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"JD" < XXXX@XXXXX.COM >wrote:
Quote
It might be that you have incorrectly subclassed the method
instead of overriding it. Please show your header declaration
and unit implementation for it's WndProc method.
void __fastcall WndProc(TMessage &Message);
(I also tried:
virtual void __fastcall WndProc(TMessage &Message);
but with the same effect)
Quote
Just looking at the small sample above, my best guess is that
you're posting or sending a message to the main form and your
implementation surrounding that is flawed. Please show that
code as well.
It is very much, may I send it via email?
Quote
If the problem is not with the above, it's going to be hard
to track down. Do you have any worker threads?
Yes one but it is terminated before, I terminate it and delete it and set it to NULL;
In Principe after the user force the Close() command I check
the tread if it runs and set CanClose to false. I terminate the
thread. When it returns in OnTerminated I post:
PostMessage(Handle, WM_USER + 0x100, 1, 2); //Close();
Then I delete all the objects with no problems and execute
Close() again.
Are you using any hooks?
No
Quote
Are you subclassing any other control's WndProc? No
Are you dynamically allocating any objects?
Yes I delete them at least in the respecting destructor, if possible as next as possible using try{}__finally...
Quote
Are you doing
anything 'tricky'? If so ... what?
As I see nothing tricky.
The app uses the API functions to deal with the comport
to comunicate with and via modems encapsulated in a component.
One read thread takes care for the incomming characters.
I have no problems when I call to outside. The problem only
appears when a device calls from outside.
Quote

~ JD

 

{smallsort}

Re:InvalidWindowhandle after Close() or Application->Terminate()

"Roland" < XXXX@XXXXX.COM >wrote:
Quote

[...] (I also tried:
virtual void __fastcall WndProc(TMessage &Message);
but with the same effect)
That is the correct definition and it should in the protected
section of the header.
Quote
>Just looking at the small sample above, my best guess is that
>you're posting or sending a message to the main form and your
>implementation surrounding that is flawed. Please show that
>code as well.

It is very much, may I send it via email?
As most do, I prefere that you post to the attachment group
where attachments are allowed. Not only do I not have to post
an address that gets spammed, others who might be interested
can take a look at it as well.
However, I don't think that you'll need to do that because
I'm reasonably confident that the problem is with your threads
and how you're closing the form and that code can be reduced
to a managable size that can be posted here.
Quote
>Do you have any worker threads?

Yes one but it is terminated before, I terminate it and
delete it and set it to NULL;

In Principe after the user force the Close() command I check
the tread if it runs and set CanClose to false. I terminate
the thread. When it returns in OnTerminated I post:

PostMessage(Handle, WM_USER + 0x100, 1, 2); //Close();

Then I delete all the objects with no problems and execute
Close() again.
Your description of what you're doing here is consistant with
your crash. I think that you have overly complicated shutting
down the thread and that you've failed to wait for the thread
to shutdown before you proceed to close the application.
To be clear, when you call TThread::Terminate, all it does is
set the thread's Terminated flag and then execution continues
on in the main thread. In the mean time, the worker thread
continues to run as well. It's up to you (the programmer) to
code the worker thread to periodically check Terminated and
exit the Execute method gracefully. For example:
void __fastcall TMyThread::Execute()
{
while( ! Terminated )
{
// some code
if( ! Terminated )
{
// some code
}
if( ! Terminated && ! SomeOtherCondition )
{
// some code
}
}
}
It seems obviouse to me that the thread's OnTerminate event
is posting the custom message to the main form after it's
began to be destroyed. If this is the case, you can correct
it by removing the thread's OnTerminate event, the MainForm's
OnClose event and by moving the code for destroying the thread
into the main forms destructor. For example:
public:
__fastcall ~TForm1();
//-------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
FThread->Terminate();
FThread->WaitFor();
delete FThread;
}
//-------------------------------------------------------------
~ JD
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"JD" < XXXX@XXXXX.COM >wrote:
Quote
Your description of what you're doing here is consistant with
your crash. I think that you have overly complicated shutting
down the thread and that you've failed to wait for the thread
to shutdown before you proceed to close the application.

To be clear, when you call TThread::Terminate, all it does is
set the thread's Terminated flag and then execution continues
on in the main thread. In the mean time, the worker thread
continues to run as well. It's up to you (the programmer) to
code the worker thread to periodically check Terminated and
exit the Execute method gracefully. For example:

void __fastcall TMyThread::Execute()
{
while( ! Terminated )
{
// some code
if( ! Terminated )
{
// some code
}
if( ! Terminated && ! SomeOtherCondition )
{
// some code
}
}
}

It seems obviouse to me that the thread's OnTerminate event
is posting the custom message to the main form after it's
began to be destroyed. If this is the case, you can correct
it by removing the thread's OnTerminate event, the MainForm's
OnClose event and by moving the code for destroying the thread
into the main forms destructor. (For example:....)
Because of this behaviour I used an Event and a boolean var to
signalize that it has left the while loop. Here is the complete
code (untrimmed) for the Thread.
//=========================== ComReadThread.h =================================
#ifndef ComReadThreadH
#define ComReadThreadH
//---------------------------------------------------------------------------
#include <Classes.hpp>
enum TThreadInfoType {
thitIdle = 0,
thitBeforeMainWhile,
thitAfterMainWhile
};
typedef void __fastcall (__closure *TThreadRxEvent)( BYTE * RxBuf, DWORD Len, bool bFromGetOvResult);
typedef void __fastcall (__closure *TThreadErrEvent)(DWORD dwErr);
typedef void __fastcall (__closure *TThreadReadyToTerminateEvent)(DWORD dwErr);
typedef void __fastcall (__closure *TThreadInfoEvent)(TThreadInfoType Info);
//---------------------------------------------------------------------------
class TComRead : public TThread
{
private:
TThreadRxEvent FOnThreadRxEvent;
TThreadErrEvent FOnThreadErrEvent;
TThreadReadyToTerminateEvent FThreadReadyToTerminateEvent;
TThreadInfoEvent FThreadInfoEvent;
HANDLE FhCom;
BYTE FRxBuf[1024];
void __fastcall CommPortTerminateThraed(void);
void __fastcall CommPortQueryReqToClose(void);
protected:
void __fastcall Execute();
public:
bool bRS232_Thraed_Alive;
bool bRequestToClose;
bool bReadyToClose;
__fastcall TComRead(bool CreateSuspended, HANDLE h);
__property TThreadReadyToTerminateEvent OnReadyToTerminate = {read = FThreadReadyToTerminateEvent,write = FThreadReadyToTerminateEvent};
__property TThreadRxEvent OnRxEvent = {read = FOnThreadRxEvent, write = FOnThreadRxEvent};
__property TThreadErrEvent OnRxError = {read = FOnThreadErrEvent, write = FOnThreadErrEvent};
__property TThreadInfoEvent OnThreadInfo = {read = FThreadInfoEvent, write = FThreadInfoEvent};
};
//---------------------------------------------------------------------------
#endif
//=========================== ComReadThread.cpp =============================
#include <vcl.h>
#pragma hdrstop
#include "ComPort.h"
#include "ComReadThread.h"
#pragma package(smart_init)
extern TComPort * cp;
//---------------------------------------------------------------------------
__fastcall TComRead::TComRead(bool CreateSuspended, HANDLE h)
: TThread(CreateSuspended)
{
FhCom = h;
bRS232_Thraed_Alive = false;
}
void __fastcall TComRead::CommPortTerminateThraed(void)
{
cp->TerminateThraedFunction();
}
void __fastcall TComRead::CommPortQueryReqToClose(void)
{
bRequestToClose = cp->m_bRequestToClose;
}
//---------------------------------------------------------------------------
void __fastcall TComRead::Execute()
{
int i;
bool b;
DWORD r;
DWORD err;
DWORD done;
bool read_pending = false;
bool bTerminationExecuted = false;
OVERLAPPED ord;
DWORD dwRbuf_len = 1;
memset(&ord, 0, sizeof(OVERLAPPED));
ord.hEvent = CreateEvent(0, TRUE, FALSE, 0);
bRS232_Thraed_Alive = true;
bRequestToClose = false;
if(OnThreadInfo)
OnThreadInfo(thitBeforeMainWhile);
while(!Terminated)
{
//bRequestToClose wird geupdatet...
Synchronize(CommPortQueryReqToClose);
if(bRequestToClose){
if(!bTerminationExecuted){
bTerminationExecuted = true;
Synchronize(CommPortTerminateThraed);
}
else{
Sleep(1);
}
}
else {
if( read_pending )
{
r = WaitForSingleObject( ord.hEvent, // handle of object to wait for
100 ); //'INFINITE time-out interval in milliseconds
switch(r)
{
case WAIT_OBJECT_0:
if(GetOverlappedResult(FhCom , &ord, &done, FALSE))
{
if(OnRxEvent && done>0) {
OnRxEvent(FRxBuf,done,true);
done = 0;
}
}
done = 0;
read_pending = false;
break;
case WAIT_TIMEOUT:
if(OnRxError)OnRxError(WAIT_TIMEOUT);
break;
case WAIT_FAILED:
if(OnRxError)OnRxError(WAIT_FAILED);
break;
}
}
else
{
if (ReadFile(FhCom, FRxBuf, dwRbuf_len, &done, &ord))
{
// read ok
FRxBuf[done] = '\0';
if(OnRxEvent && done>0) {
OnRxEvent(FRxBuf,done,false);
}
done = 0;
read_pending = false;
}
else
{
err = GetLastError();
if(err != ERROR_IO_PENDING)
{
if(OnRxError)OnRxError(err);
}
else {
read_pending = true;
}
}
}
}
}// end of while
if(ord.hEvent){
CloseHandle(ord.hEvent);
ord.hEvent = NULL;
}
if(OnThreadInfo)
OnThreadInfo(thitAfterMainWhile);
bRS232_Thraed_Alive = false;
}
//---------------------------------------------------------------------------
The tread is part of a component. I think I post it later.
Part (or better external part) of the component is also a
multimedia timer (that has its own thread) responsible for
the detection of timeouts. Both the readthread and the timer
can fire an event called OnReceive(...,...,bool). Bool
indicates Timeout or not.
So the PostMessage does not come from OnTerminate but from OnThreadInfo(thitAfterMainWhile)
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"Roland" < XXXX@XXXXX.COM >wrote:
Quote

[...] So the PostMessage does not come from OnTerminate but
from OnThreadInfo(thitAfterMainWhile)
I'm even more convinvced now that the problem is with how
you're shutting down the thread. I was a bit baffeled at how
OnTerminate would cause that because by then the thread should
be done running but since that's where I thought PostMessage
was being called, it has to be it.
In any case, the issues is that PostMessage is sending the
main form the custom message after the main form is destroyed.
The only way that that can happen is if the thread is still
running. So, again I say that you're not correctly stopping
the thread before you delete it and close the form.
Try using the WaitFor sample that I posted and if that doesn't
work, I'll look at the thread code that you posted.
~ JD
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

It is not as easy as it looks like. I made another attempt. I terminated the thread in that let's say complicate way. After it terminates I deleted it and set its pointer to NULL. Am I right that it can not longer run when it was deleted? I can delete it without any problems. After this I post the message and the same happens too.
In difference to the main Form I have to switch the thread on and off more often, not only to close the complete app. and this works. I have to do it i.e. for the modem reinitialing and I can do it as often as I want no problems.
Interesting is also, in that case when I can close the app properly a window is flashing over the screen for a very short time but obviously it will be destroyed properly. Is there any tool available or something else to track the involved window handles down from outside the compiler?
"JD" < XXXX@XXXXX.COM >wrote:
Quote

"Roland" < XXXX@XXXXX.COM >wrote:
>
>[...] So the PostMessage does not come from OnTerminate but
>from OnThreadInfo(thitAfterMainWhile)

I'm even more convinvced now that the problem is with how
you're shutting down the thread. I was a bit baffeled at how
OnTerminate would cause that because by then the thread should
be done running but since that's where I thought PostMessage
was being called, it has to be it.

In any case, the issues is that PostMessage is sending the
main form the custom message after the main form is destroyed.
The only way that that can happen is if the thread is still
running. So, again I say that you're not correctly stopping
the thread before you delete it and close the form.

Try using the WaitFor sample that I posted and if that doesn't
work, I'll look at the thread code that you posted.

~ JD

 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"Roland" < XXXX@XXXXX.COM >wrote:
Quote

Please trim your posts and Please wrap your lines when you
post.
Quote
It is not as easy as it looks like.
Sure it is. Just comment out the PostMessage or do what ever
during destruction to prevent that message from being sent
(like setting that event to NULL) and add the calls to
Terminate, WaitFor and delete to the form's destructor.
Quote
I made another attempt. I terminated the thread in that
let's say complicate way. After it terminates I deleted it
and set its pointer to NULL.
But did you use WaitFor? That is the whole issue here ... that
the thread is still running when the main thread is destroyed.
Quote
Am I right that it can not longer run when it was deleted?
Yes and no. If you delete it while it's executing code, it's
still going to execute to some degree. That's why you need to
WaitFor before you delete it.
Quote
I can delete it without any problems. After this I post the
message and the same happens too.
This doesn't make sense to me because you said that one of the
threads events was posting the message. Please post the code
where you allocate and delete the thread and shut down the
application - including the call to PostMessage. While you're
at it, zip the cpp and header files and post those to the
attachment group.
Quote
In difference to the main Form I have to switch the thread
on and off more often, not only to close the complete app.
I'll look at the thread next.
Quote
Interesting is also, in that case when I can close the app
properly a window is flashing over the screen for a very
short time but obviously it will be destroyed properly.
This could be bad. I don't know.
Quote
Is there any tool available or something else to track the
involved window handles down from outside the compiler?
The compiler comes with WinSight32 which will track all child windows and the messages sent and received by them.
~ JD
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"JD" < XXXX@XXXXX.COM >wrote:
Quote
But did you use WaitFor? That is the whole issue here ... that
the thread is still running when the main thread is destroyed.
Not at the beginning of our discussion but after you have
mentioned it I used it.
Quote
Please post the code
where you allocate and delete the thread and shut down the
application - including the call to PostMessage. While you're
at it, zip the cpp and header files and post those to the
attachment group.
May sound silly but I only used this group where can I find
the attachment group?
I need 1 or 2 days because I have to do a lot of othe rthings.
~Roland
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

Today I found my fault! I now use Synchronise to let my
OnRxEvent run in the context of the main thread and my
app can be closed properly.
//-------------------------------------------------------------
void __fastcall TComRead::FireRxEvent()
{
OnRxEvent(FRxBuf,done,bSrc);
}
//-------------------------------------------------------------
....
while(!Terminated)
{
if( read_pending )
{
r = WaitForSingleObject( ord.hEvent, 100 );
switch(r)
{
case WAIT_OBJECT_0:
if(GetOverlappedResult(FhCom , &ord, &done, FALSE))
{
if(OnRxEvent && !Terminated && done>0) {
bSrc = true;
Synchronize(FireRxEvent);
done = 0;
}
}
done = 0;
read_pending = false;
break;
....
Quote
While you're
at it, zip the cpp and header files and post those to the
attachment group.
Under which address can I find the attachment group?
~Roland
 

Re:InvalidWindowhandle after Close() or Application->Terminate()

"Roland" < XXXX@XXXXX.COM >wrote:
Quote

Under which address can I find the attachment group?
I presume that you're using the web interface (using a browser
to access the server). Here's a link to all of the cpp groups
(using the web interface):
newsgroups.borland.com/cgi-bin/dnewsweb?utag=&wild=cpp&cmd_grpsearch=Search&group=
To be clear, the attachments group can be accessed through the
web interface but you can not post attachments to that group
unless you use a news reader like Outlook Express. Here's a
link to all of the groups but this time, when you select a
group, you're default news reader will be launched:
info.borland.com/newsgroups/
Click Attachments/Binaries and that will open a new page
where the actual link is at the bottom of the page. Once
you configure the reader, all you have to do is launch it
and select which group you want to read.
~ JD