Link to home
Start Free TrialLog in
Avatar of ChrisJonesLycos
ChrisJonesLycos

asked on

ShowModal doesn't return to calling window

We have an app written in Delphi 7 that is used by about 1400 users. In a small number of cases (5 or 6) the program is not behaving properly when performing a ShowModal. We have the situation where the main form does
FormA.ShowModal;
then FormA does
FormB.ShowModal
then FormB does
FormC.ShowModal

You would expect then that when FormC does a Close, it should return to FormB. However what these users are getting is FormA is shown and FormB is buried underneath FormA.

Two questions then: Can anyone explain why this is happening on a limited number of machines?

Is there an easy way round it in the code? I've thought of putting Show for the calling form after every instance of AnotherForm.ShowModal but I'm not convinced this would work and as the overall project is more than a million lines long it would be a tedious task.

I believe in all cases the users concerned have Win XP Prof.
Avatar of Geert G
Geert G
Flag of Belgium image

this is a bug
i have never been able to pinpoint the exact cause

some workaround have been developed over the years
also some can be found here on EE:
https://www.experts-exchange.com/questions/26286057/Delphi-7-modal-form-hides-behind-window-on-a-Windows-7-box.html
https://www.experts-exchange.com/questions/23461413/Horrible-Modal-Form-Bug.html
Avatar of ChrisJonesLycos
ChrisJonesLycos

ASKER

Hi Geert. I think in theory your timer solution would work great. However I think what with the 100s of occurrences of ShowModal we have in the project it's a very big step to take. Also (like most developers) I'm a bit scared of rolling something like that to 1400 users (like 100 hours to roll it out) and then find that produces a different bug.

If I knew why Windows was doing this I could convince those specific users to change something in their system. Telling them it's a bug in Windows when all their colleagues don't have this problem is more than most of them are willing to believe.
I didn't say it's a bug in windows ... :)

i'm not exaclty sure where the bug is located
i know of other programs showing this problem written in Delphi (like toad from quest software)


as far as rollout and changing lots of forms is concerned ...
i share your anxiety to change for so many users.

a decade ago i started inheriting every form (shown to the end user) from a form class of my own
sort of a base form class
and providing ShowModal and procedures like such with a wrapper of my own

instead of having this:
type
  TFormXYZ = class(TForm)
    // etc
  end;

i have :
type
  TFormXYZ = class(TEndUserFormCategory)
  end;

I have only 4 or 5 different Categories
The work you have to do the first is indeed enormous.
But the time you save when a vendor introduces a new (not so nice) bug is also enormous

for instance: you have only 200 forms in your app X
you would have to check all 200 of those forms for the bug
I change 2, 3 maybe 4 of those base class forms

One other thing, if you have so many users, you need a better deployment system
Here we have some 400+ applications used among 3500 users
It takes us 1 click of a button to deploy a new version of a application
We used to do this manually until i was fed up with copying and created a deployment app

Every app starts with a shortcut
loader.exe %serverpath%\appname
>The loader looks for the app on the shared location,
>checks the size of the exe, checks the crc, if different, copies the new exe locally
>checks for any configuration changes for the registry
>starts the exe locally

only users restarting the app, will get the new version
> off course, later on we built in a messaging system to force a certain app to restart for all users

one other option is using a deployment tool, like LANDesk
I dont use Delphi, but I've had similar issues in other prog languages (with a Modal from a Modal from a Modal), and this is how I got around it:

When opening a Modal window, send it the hWnd of the calling window. Then when it's closed, simply set the calling hWnd as the Focussed window and bring to front

Only adds a couple of lines to the code
ASKER CERTIFIED SOLUTION
Avatar of Geert G
Geert G
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Oh, and just use the SetActiveWindow/SetFocus API calls to do the work for you
I think I'm going to go for Geert's timer solution as it's the simplest of all and probably the least risky in terms of introducing new bugs. Thanks.
I concur that this is a bug that happens with Delphi 5 & 7, pretty much the same kind of happens as in the expression "sh#t happens" ...

As far as I know, no-one ever found the reason, except maybe the guy who finally fixed it in Delphi code... Or they just got lucky and the problem disappeared by changing some other things.

If someone have leads on the reason, I'm interested.
Got to the party late; however, I will still add my $0.02. ;-)

This is why I use a slightly different approach from many (if not most) Delphi developers with regard to showing additional forms.  I put a completely public function (and, sometimes, overloaded it for slightly different circumstances) in the unit that contains the secondary function (i.e. the one being shown modally).  

By having that function in that unit:
I decouple the form from all other forms that may call it;
If I need to modify the code that performs the immediate actions of showing the form and then closing the form and returning to the calling form, I only have to do that in one place;
I only have to remember to Release the form in one place;
If I need to provide slightly different parameters for setting up the form, I can do so and I can make sure that it doesn't impact the rest of the calls to the form.

The major reason I started doing this was so that I could more readily reuse forms.  However, once I got started with it, I realized that decoupling the forms is important for even more reasons, one of which is in regard to rectifying the problem you site.
P.S. Most of my forms, I have also gotten in the habit of passing the identity of the calling form so that I can, among other things, execute a CallingForm.SetFRocus; and, if need be, a CallingForm.Show after the unit's form has been released..