Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/VCL/MDI Support    [ Add a report in this area ]  
Report #:  2112   Status: Need Feedback
MDIChild bug?
Project:  Delphi Build #:  6.240 Update 2
Version:    6.0 Submitted By:   Paul Stockton
Report Type:  Basic functionality failure Date Reported:  8/16/2002 1:45:06 AM
Severity:    Serious / Highly visible problem Last Updated: 1/4/2008 10:46:46 AM
Platform:    All versions Internal Tracking #:  
Resolution: Test Case Error (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: (4 Total Ratings)
2.75 out of 5
Total Votes: None
Description
I have two MDIChild forms which are identical apart from one has a TLabel on it, they are also being called in identical ways.
However, if I use the mouse to click the cancel button on the form which has the TLabel on I get an Access Violation.  I don't get the Access Violation if I use the ESCAPE key, the ENTER key (when the button is selected) or Alt+C (shortcut).

I have tried replacing the TLabel with other controls and some still cause the Violation, TMenu, however the TEdit control did not.
Steps to Reproduce:
****************
Click File, Form 2.
Click Ok.
Click Cancel.
Click Cancel.
Access Violation.

Click File, Form 4.
Click Ok.
Click Cancel.
Click Cancel.
No Access Violation.

Click File, Form 2.
ENTER.
ESCAPE.
ESCAPE.
No Access Violation.
****************
Workarounds
None
Attachment
Project1.zip
Comments

Peter Morris at 8/16/2002 4:45:45 AM -
I doubt that anyone will be able to reproduce this one.
Why not attach a demo project?

Petr Vones at 8/18/2002 10:36:04 AM -
In TForm.OnClose event change:

Action := caFree;

and do not call Release method

Paul Stockton at 8/20/2002 3:51:11 AM -
Thanks but we were already aware of that workaround - which changes the behaviour of the forms and doesn't give us the functionality that we require.

We would really like an explanation as to why we get this problem only on the form with the TLabel

Thanks.

Craig Stuntz at 8/19/2002 9:45:45 AM -
Petr, you should submit this as a Workaround.

Paul Stockton at 8/22/2002 1:56:44 AM -
Is there any way to UP the priority on this one - I really need an answer to this please :)

Kristofer Skaug at 8/22/2002 2:08:43 AM -
I can reproduce this (D6.2 Pro, WinXP Pro).
No idea why it happens though.

Paul Stockton at 8/22/2002 3:55:33 AM -
Thanks Kristofer, now we just need someone from Borland to explain it to us!!!

Please help Borland!!!

Joe White at 8/22/2002 8:48:28 AM -
Well, I'm not from Borland, but I figured a few things out:

   - The problem does not happen only with Form2 - I've gotten Form4 to crash as well.
   - You're freeing Form2 in the middle of processing a message.  That's why you're crashing.

Here's a rough outline of the sequence of events, with a lot of details left out (really):

1.  User clicks bCancel.  Windows sends several messages, including a WM_LBUTTONUP which, in turn, fires off a WM_COMMAND.
2.  TButton processes the WM_COMMAND and ends up calling Form2.bCancelClick.
3.  bCancelClick calls Close, which calls FormClose.
4.  FormClose calls Release, which posts a CM_RELEASE message to the form's message queue.  The form will be freed the next time Application.ProcessMessages is called.
5.  FormClose then calls ShowForm2.
6.  ShowForm2 calls ShowForm3.
7.  ShowForm3 calls TForm3.ShowModal.
8.  TForm3.ShowModal calls Application.ProcessMessages.

See the problem?  When ShowModal calls ProcessMessages, TForm2's CM_RELEASE message is processed, and TForm2 is freed.  But the call stack is still in the middle of a large number of nested methods of TForm2.

When TForm3.ShowModal returns, the stack steps backwards, and the TForm2 methods run to completion, which in some cases means calling other methods of Form2.  But Form2 has been freed already, so those method calls are likely to generate errors - sometimes.  Semi-non-deterministic; depends on exactly what sequence of events led to TForm2.FormClose being called, and what happens to get put in the slot of memory formerly occupied by Form2 after it's freed.

Moral:  Use Release with care.  When you have a button call Release, your button handler then needs to immediately return.  Don't even think about following a call to Release with anything that could process messages.

Paul Stockton at 8/23/2002 6:28:14 AM -
Thanks for the info.  Looks like you spent quite a bit time thinking of that one.  We came up with a similar idea but was wondering if anyone could explain the technical reasons why, as you seem to have.

Are you using an earlier version of Delphi?  We only managed to get form4 cause the error when it is compiled in Delphi4.  We just couldn't understand why it worked fine in Delphi6.

Any ideas why an extra label would cause the problem?  Thanks Paul.

Joe White at 8/23/2002 8:04:31 AM -
File | Form 2
(click OK on Form3)
File | Form 4
(click OK on Form3)
Cancel Form4 (with Form2 still open in the background)
(click OK on Form 3)

This consistently gives me an EAbstractError.  Delphi 6.02, Windows XP Professional.

(Yes, an EAbstractError.  Why not?  The object has been freed; its VMT is pointing into never-never land.)

As for why a label would make a difference - why does it matter?  You're accessing an object after it's freed.  You can expect Arbitrarily Bad Things (tm) to happen as a result.  Don't spend time worrying about why it crashes different ways when you do different things - just fix the code! <grin>

Paul Stockton at 8/27/2002 3:07:10 AM -
I received this reply from one of the forums and it does work, my only problem now is I want to pass parameters to my showform events.  PostMessage does allow for two integer parameters to be passed however I need to pass string variables and more than two.

I have attached a new project with this fix in.

<< in a common place, declare
<<
<< const
<<  WM_SHOWFORM2 = WM_USER + $0001;
<<
<< In main form, declare
<<
<<   procedure WMShowForm2( var Msg: TMessage ); message WM_SHOWFORM2;
<<
<< as
<<
<<     ShowForm2
<<
<< In TForm2.OnClose do
<<
<<    If FormStyle = fsMDIChild then
<<    begin
<<      Action := caFree;
<<      PostMessage( Application.MainForm.Handle, WM_SHOWFORM2, 0, 0 );
<<    end;

Server Response from: ETNACODE01