To demonstrate the problem I created a simple application that consists of 4 blank forms. One of them (Form1) is the main and shows automatically. Showing other forms I put in the code project:
…
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.CreateForm(TForm3, Form3);
Application.CreateForm(TForm4, Form4);
Form2.Show;
Form3.Show;
Form4.Show;
Application.Run;
end.
On the second form (or any other) Form2 I put a button that, when clicked, synchronously executes long (>5 seconds) SQL query (any, I open the stored procedure). Is it synchronous, that is, the app hangs for at least 10 seconds. At this time triggers the windows ghosting. Windows creates Windows Ghost for all Windows stale apps that you can minimize, move and close. After executing a query, the application resumes processing messages and everything returns to its original state.
It must be so, but for me it is not. In fact, after defrosting program Z-order of the Windows is changed, the order of the Windows mixed. Moreover, the top (or bottom) can get out of any window, I have not noticed any pattern. It seems that Windows does not correctly restore the Z-order when cancelling the ghosting.
This behavior is also found in Delphi 2007. Note that under the Delphi debugger mode ghosting is disabled and you will not see this behavior. Run the application without debugger to see this behaviour.
After disabling mode ghosting with DisableProcessWindowsGhosting - everything works correctly.
But I don't want to completely disable this mode, the program often hangs for more than 5 seconds, and this mode is useful: the user is still nicer to look at Windows that somehow redrawn than not redrawn at all. To rewrite half the program code for asynchronous execution of queries is very long and time-consuming task, I'm afraid we don't have enough resources, although it is undoubtedly the right approach.
MainFormOnTaskBar property has nothing to do with my question, there is no such property in delphi 7.
Does this effect anyone else besides me? If not – where did I go wrong? How to force Windows to properly reconstruct the sequence of Windows?
There is exactly one way to avoid your application becoming unresponsive. Don't block the main thread.
You are asking how to block the main thread, and keep the application responsive. The only way for an application to remain responsive is for it to process its message queue in a timely fashion. You simply cannot have it both ways. You can't both process messages and not process messages.
Probably the z-order gets changed because your application is not able to process the various clicks you make while the application is not processing messages. And then processes them when the application starts processing messages again.
Conclusion: if you want your application to remain responsive, arrange for the long running tasks to run asynchronously with respect to the main thread.
Disable the windows ghosting "feature" completely and it will fix the z-order issue (and other annoyances of this feature).
The Windows API function to call is named DisableProcessWindowsGhosting, in user32.dll: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-disableprocesswindowsghosting
Allen Bauer, former Delphi architect, described why this z-order issue happens. The page is not available anymore, but WayBackMachine comes to the rescue:
https://web.archive.org/web/20161128155906/https://community.embarcadero.com/blogs/entry/popupmode-and-popupparent-295
This function is not imported in Winapi.Windows.pas (at least not up to Delphi 10.2), so you need to do it yourself. Declare a procedure that imports user32.dll's DisableProcessWindowsGhosting function dynamically and call it before your application starts, like this:
procedure DisableProcessWindowsGhosting;
var
DisableProcessWindowsGhostingProc: procedure;
begin
DisableProcessWindowsGhostingProc := GetProcAddress(GetModuleHandle('user32.dll'), 'DisableProcessWindowsGhosting');
if Assigned(DisableProcessWindowsGhostingProc) then
DisableProcessWindowsGhostingProc;
end;
begin
// Disable windows ghosting feature (XP and newer)
DisableProcessWindowsGhosting;
Application.Initialize;
...
end.
Related
The Application.Run procedure calls an infinite loop that handles windows messages:
repeat
try
HandleMessage;
except
HandleException(Self);
end;
until Terminated;
The Terminated property can be set to true only through Application.Terminate procedure, which sends PostQuitMesage.
I would like to change the message handling loop so that I can directly stop it using the global variable (without using messages queue):
var MyTerminated:Boolean
....
repeat
try
HandleMessage;
except
HandleException(Self);
end;
until Terminated or MyTerminated;
The question is, is it possible to make the program use your own version of Application.Run?
"Terminated" property is read-only. However it is a direct getter of the FTerminated field, therefore Application.Terminated directly reads from the boolean field. While the language disallows setting Application.Terminated, you can set the boolean value at that address using a pointer:
PBoolean(#Application.Terminated)^ := True;
You may also consider using Halt, which will pass over the message loop completely, for a more abrupt but less hacky solution.
Yes, you can make your application use own version of Application run, but this practice is discouraged, because it changes normal program flow, designed by the architects of Delphi.
Directly stopping Application.Run signifies that there is a need to restart Application.Run later, for example, after some action that is wanted to be done from the main thread. This makes the program puzzled, harder to understand by peer programmers and more error prone as a whole.
The program design should be simple and straightforward. If an application is big, for example two million lines of code, the overall design of the execution flow should be simple anyway:
If you need to do some longer actions, do them from the worker threads;
If you need to do an instant actions, do them from your main form or from the other forms.
So a Delphi application main loop should only be exited on the overall application exit, which is done by the PostQuitMessage. We don't have to avoid this message.
The reason why PostQuitMessage is wanted to be avoided, is probably an instantaneous exit. This is not how VCL applications are supposed to run. If one doesn't need forms (for example for a Windows Service application), just don't use the TApplication class an don't run forms, just make your own message loop based on MsgWaitForMultipleObjects.
I am using TTimer in my software and it supposed to run forever 24/7. Nowhere in my software is that timer disabled or stopped from running. It's main function is to update table's value. It is started as soon as the software is run and from that point on TTimer should not stop. However, after running for over a month, that TTimer mysteriously stops running. The software is run on Windows 7 and the software is developed on Delphi 2010 XE. I've searched my code to see what might be causing it, but I can't figure out what.
Timer1.Enabled:=true;
That's how the timer is started.
UPDATE:
After doing some investigation, I found out that the TTimer never stopped, but there is another issue. My TStringGrid table on a TForm just simply don't show any values being updated. Further, I also found out that my TList List I am using to store list of data item is being destroyed somehow that the list becomes empty. But the data items in the list are not deleted anywhere in the code once they are loaded only when the program is started.
Everytime I update the TStringGrid on the form, I run through my TList items from 0 to count-1 location. So, if there is no item in the TList in the memory, my code simply skips
over the display part and thus nothing gets updated on the TStringGrid.
Something like:
If (List.count>0) then
begin
//Display values in TStringGrid;
end;
But while the software is still running, I was able to reload my list of items from a file
back into TList list and my software started to work like it supposed.
I hate to say the ugliest word programmers hate the most. I am afraid I may have a memory leak. Anyone think so?
Any help will be greatly appreciated. Thanks.
I bet it stops 49 days after reboot. When Windows GetTickCount wraps around. Sure you're not doing a check that would fail based on this?
TTimer is just a wrapper around the Windows SetTimer() API which I believe will run forever.
I suspect that the timer still runs, but the event handler that it fires is failing to operate as desired.
I'm not sure why it's stopping after a month; I'd suspect (as Erik said) you have something using GetTickCount() that's failing after the wraparound at ~49 days.
As a general rule, though, it's better to stop/start the timer to prevent a delay from causing a timer message to be dropped:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
try
// Do whatever on timer event firing
finally
Timer1.Enabled := True;
end;
end;
You might try this instead of just allowing it to run constantly; if it is a bug in the TTimer code (I don't see anything after a quick scan of XE's TTimer implementation), stopping and starting may reset things to prevent the failure.
You should free memory allocated after the job is done:
Timer1.FreeOnRelease() or .Free();
I have an application that uses tabs like the Chrome browser. Now I want to be able to open more forms and not be limited to only one form. These forms should act the same but if I close main form all forms are closed. How can I make all forms be equal, so no matter which form I close it only closes that form and not exit application before all forms are closed? Any ideas?
Image of my explorer
Kind Regards
Roy M Klever
It's not too hard to do this, though it starts getting complicated quickly depending on how complete you want it to be. Getting multiple modal dialogs to work independently is a ton of effort.
To start, you need to avoid Application.MainForm entirely. Always use Form := TMyForm.Create(Application) instead of Application.CreateForm(TMyForm, Form). The later sets MainForm and you never want that to happen.
To make things shut down properly you'll need to do something like this in your form's OnClose event handler:
if Screen.FormCount = 1 then
Application.Terminate;
CloseAction := caFree;
Application.Run relies on MainForm being assigned, so in your DPR replace that line with this loop:
repeat
try
Application.HandleMessage;
except
Application.HandleException(Application);
end;
until Application.Terminated;
There are a couple of ways to handle the taskbar entry.
Single taskbar entry: Set Application.MainFormOnTaskbar := False; and the hidden TApplication handle will be used. Clicking on the taskbar entry will bring all of the windows to the front. You'll need to override Application.OnMessage or add a TApplicationEvents component, and watch for WM_CLOSE with the Msg.Handle = Application.Handle`. In that case the user has right-clicked on the taskbar and selected Close, so you should close all the windows.
Multiple taskbar entries: Set Application.MainFormOntaskbar := True. Override your form's CreateParams method and set Params.WndParent := 0;. Each taskbar entry will control that form.
There are probably a few other gotchas, but that's the basics.
As I said, making ShowModal and TOpenDialog/TSaveDialog working independently, so it only affects its parent form and so multiple dialogs can be open at once, is a ton of work, and I can't really recommend it. If you're a masochist, here's the general steps:
Replace TCustomForm.ShowModal with a custom version. Among other things, that routine disables all the other windows in the application, so you need to replace the DisableTaskWindows/EnableTaskWindows calls with EnableWindow(Owner.Handle, False/True) to just disable the parent form. At this point you can open multiple dialogs, but they can only be closed in last-in, first-out order, because the calls end up being recursive. If that's fine, stop here.
There are two ways to work around that:
Rather than making ShowModal blocking, have StartModal and EndModal routines that have the first bit and last bit of ShowModal's code and call an OnShowModalDone event when the dialog is closed. This is kind of a pain to use, but is relatively easy to code and easy to make stable.
Use the Windows fiber routines to swap out the stack and start a new message loop. This approach is easy to use, because ShowModal is blocking, so you call it like normal. This is the approach we used in Beyond Compare. Don't do it. It's complicated to write, there will be stability issues for non-trivial applications because of incompatibilities with third party code (Windows global message hooks, TWebBrowser, .NET in shell extensions loaded by the browse dialog, etc), and if it's a cross-platform project, the Unix ucontext functions aren't safe to use either.
The common dialogs (TOpenDialog, TColorDialog, etc), have similar restrictions. To make them only disable the parent form you need to override TCommonDialog.TaskModalDialog and replace the DisableTaskWindows/EnableTaskWindows calls there too. They can't be made asynchronous like the regular Delphi dialogs above though, since they're blocking functions provided by Windows (GetOpenFileName, ChooseColor, etc). The only way to allow those to close in any order is to have each dialog run in a dedicated thread. Windows can handle most of the synchronization to do that, as long as you're careful about accessing the VCL objects, but it basically involves rewriting large portions of Dialogs.pas.
If you really want that,
1) use a small, maybe hidden, MainForm and launch just the first childform at startup.
2) launch separate applications instead of Windows in the same process. This is what later Office version use.
Here is a similar StackOverflow question:
Multiple app windows activation not working correctly
In my case I don't try to avoid the MainForm like Craig describes. Instead, I hide the main window and all of my real windows are other non-modal forms. I have been happy with how my application works, but Craig's approach may be simpler.
See my answer on the above question to see code samples for my approach and a few links with good background information.
The first form created in a Delphi application is treated as the main form and the application terminates when this form gets closed. The obvious solution is to have a first form that is not one that gets closed by the user but rather one that is not visible to the user and gets closed only when all other forms have been closed.
I have not tried this, but it should work.
This is too late to be an answer but I bumped into the same problem. The solution I opted for is to extract Application.ExeName and pass it to a function like createProcess or even shellExecute. So, now I have independent applications at the OS Level. I also needed different taskbar buttons for the different instances.
What is TApplication.Handle?
Where does it come from?
Why does it exist?
And most importantly: why do all forms have it as their parent window handle?
The Delphi help says:
TApplication.Handle
Provides access to the window handle
of the main form (window) of the
application.
property Handle: HWND;
Description
Use Handle when calling Windows API
functions that require a parent window
handle. For example, a DLL that
displays its own top-level pop-up
windows needs a parent window to
display its windows in the
application. Using the Handle property
makes such windows part of the
application, so that they are
minimized, restored, enabled and
disabled with the application.
If I focus on the words "the window handle of the main form of the application", and I take that to mean the window handle of the main form of the application, then I can compare:
"the window handle of the main form of the application", with
the window handle of the MainForm of the Application
but they are not the same:
Application.MainForm.Handle: 11473728
Application.Handle: 11079574
So what is Application.Handle?
Where does it come from?
What Windows® window handle is it?
If it is the Windows® window handle of the Application's MainForm, then why don't they match?
If it's not the window handle of the Application's MainForm, then what is it?
More importantly: Why is it the ultimate parent owner of every form?
And most important: Why does everything go haywire if i try to have a form be unparented unowned (so i it can appear on the TaskBar), or try to use something like IProgressDialog?
Really what I'm asking is: What is the design rationale that makes Application.Handle exist? If I can understand the why, the how should become obvious.
Understanding through a game of twenty questions:
In talking about the solution of making a window appear on the taskbar by making its owner null, Peter Below in 2000 said:
This can cause some problems with modal forms shown from
secondary forms.
If the user switches away from the app while a modal
form is up, and then back to the form that showed it, the modal form may
hide beneath the form. It is possible to deal with this by making sure
the modal form is parented [sic; he meant owned] to the form that showed it (using
params.WndParent as above)
But this is not possible with the standard
dialogs from the Dialogs unit and exceptions, which need more effort to
get them to work right (basically handling Application.OnActivate,
looking for modal forms parented to Application via GetLastActivePopup
and bringing them to the top of the Z-order via SetWindowPos).
Why does a modal form end up stuck behind other forms?
What mechanism normally brings a modal form to the front, and why is it not functional here?
Windows® is responsible for showing windows stacked. What has gone wrong that Windows® isn't showing the right windows?
He also talked about using the new Windows extended style that forces a window to appear on the taskbar (when the normal rules of making it un-owned is insufficient, impractical, or undesirable), by adding the WS_EX_APPWINDOW extended style:
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams( params );
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;
But then he cautions:
If you click on a secondary forms taskbar button while another app is
active this will still bring all the applications forms to front. If you
do not want that there is option
Who is bringing all the forms to the front when the form's owner is still Application.Handle. Is Application doing this? Why is it doing this? Rather than doing this, shouldn't it not be doing this? What is the downside of not doing this; I see the downside of doing it (system menu's don't work property, taskbar button thumbnails are inaccurate, Windows® shell cannot minimize windows.
In another post dealing with the Application, Mike Edenfield says that the parent window sends other window's their minimize, maximize and restore messages:
This will add the taskbar button for your form, but there are a few other minor details to
handle. Most obviously, your form still receives minimize/maximize that get sent to the parent
form (the main form of the application). In order to avoid this, you can install a message
handler for WM_SYSCOMMAND by adding a line such as:
procedure WMSysCommand(var Msg: TMessage); WM_SYSCOMMAND;
procedure TParentForm.WMSysCommand(var Msg: TMessage);
begin
if Msg.wParam = SC_MINIMIZE then
begin
// Send child windows message, don't
// send to windows with a taskbar button.
end;
end;
Note that this handler goes in the PARENT form of the one you want to behave independently of > the rest of the application, so as to avoid passing on the minimize message. You can add similar > code for SC_MAXIMIZE, SC_RESTORE, etc.
How is it that minimize/maximize/restore messages for my Windows® windows are not going to my window? Is this because messages destined for a window are sent, by Windows® to the window's owner? And in this case all the forms in a Delphi application are "owned" by Application? Does that not mean that making the owner null:
procedure TForm2.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := 0; //NULL
end;
will remove Application and it's window Handle from interfering with my form, and Windows should once again send me my minimize/maximize/restore messages?
Perhaps if we compared and contrasted now a "normal" Windows application does things, with how Borland initially designed Delphi applications to do things - with respect to this Application object and it's main loop.
what solution was the Application object solving?
What change was made with later versions of Delphi so that these same issues don't exist?
Did the change in later versions of Delphi not introduce other problems, that the initial Application design tried so hard to solve?
How can those newer applications still function without Application interfering with them?
Obviously Borland realized the flaw in their initial design. What was their initial design, what problem was it solving, what is the flaw, what was the re-design, and how does it solve the problem?
The reason for the application window has a bit of a sordid history. When developing Delphi 1, we knew we wanted to use "SDI" (windows scattered all over the desktop) ui model for the IDE. We also knew that Windows sucked (and still does) at that model. However we also noticed that Visual Basic at that time employed that model and it seemed to work well. Upon further examination, we found that VB used a special "hidden" parking window which was used as the "owner" (Windows blurs the notion of parent and owner at times, but the distinction is similar to VCL) for all the other visible windows.
This is how we solved the "problem" where the windows containing the main menu was rarely ever focused so processing Alt-F for the File menu simply wouldn't work. By using this central parking window as an intermediary, we could more easily keep track of and route messages to the appropriate windows.
This arrangement also solved another issue where normally multiple top level windows were entirely independent. By making the application handle the "owner" of all these windows, they would all behave in concert. For instance, you may have noticed that when you select any of the application windows, all the application windows move to the front and retain their z-order relative to each other. This would also make the application minimize and restore as a functional grouping.
That is a consequence of using this model. We could have manually done all this work to keep things straight, but the design philosophy was to not re-invent Windows, but to leverage it where we could. That is also why a TButton or a TEdit is really a Windows "User" BUTTON and EDIT window class and style, respectively.
As Windows evolved, that "SDI" model began to fall out of favor. In fact Windows itself began to become "hostile" to that style of application. Starting with Windows Vista and continuing to 7, the user shell doesn't seem to work well with an application using a parking window. So, we set out to shuffle things around in VCL to eliminate the parking window and move its function into the main form. This presented several "chicken and egg" problems whereby we need to have the parking window available early enough in the application initialization so that other windows can "attach" to it, but the main form itself may not be constructed soon enough. TApplication has to jump through a few hoops to get this to work, and there have been a few subtle edge cases that have caused issue, but most of the problems have been worked out. However, for any application you move forward, it will remain using the older parking window model.
All VCL apps have a "hidden" top level window called Application. This is created automatically on application startup. Amongst other things it is the main windows message handler for VCL - hence Application.ProcessMessages.
Having the apps top level window hidden does cause some strange things, noticeably the incomplete system menu that shows in the task bar, and incorrect thumb nail windows in Vista. Later versions of Delphi correct this.
However, not all windows must have it as a parent, Windows just tends to work better if it is.
However, any form created with Application.CreateForm will have it as the parent, and it will also be owned by the Application object. As they are owned, they will be freed once Application is freed. This happen behind the scenes in Forms.DoneApplication
From looking at the source in forms.pas (Delphi 2009), it appears that they create a "master" window in win32 GUI apps to allow calls to
TApplication.Minimize
TApplication.Restore
etc
It appears that messages passed to the Application.Handle are forwarded as appropriate to the MainForm, if it exists. This would allow the app to respond to minimize, etc if the main window has not been created. By modifying the project source you can create a Delphi app without a main window.
In this case, the TApplication methods will still work, even if you haven't created a main window. Not sure if I'm grasping all of the purposes, but I don't have time to go through all of the TApplication code.
Per your questions:
Where does it come from? It is the handle of a window created in TApplication.Create
What windows handle is it? a fake window that every GUI Delphi app requires as part of the TApplication abstraction
Is it the windows handle of the application's main form No
If its not the handle of application's main form then what is it? See above
more importantly: why is it the ultimate parent of every form? assuming you're right that its the ultimate parent, i assume that it is so because it makes it easy to find all of forms in your application (enumerating the children of this "master" form).
and most important: why does everything go haywire if i try to have a form be unparented I think because the hidden "master" form is getting system messages that it should pass on to its children and/or the main form, but can't find the unparented form.
Anyway, that's my take on it. You can probably learn more by looking at the TApplication declaration and code in forms.pas. The bottom line from what i see is it is a convenient abstraction.
When we created our program, it closed properly under XP, but under Vista, even though the program is closed, the process is often still running until I open task manager and manually kill the process.
Any suggestions on how to make sure this is closed when we close the program? What a pain.
Mark Gundy
www.magchat.com
The debugger will be your friend here. Step through the shutdown until you get stuck. That'll be the best bet.
But... assuming for some reason the debugger is affecting the behaviour, or can't be used for some other reason:
A few earlier replies suggest using FastMM. This has been the default memory manager for delphi since D2006. You can try flipping on the options to report memory leaks... but that'll only work after you've finished shutting down the process, which is what isn't working. :) So I doubt it will help you much in this case. The full version of FastMM, as opposed to the standard one packaged with delphi, might have some other helpful features... But I can't recall any that would help here.
To inspect your app while it's stuck, you could try the sysinternals tools, like Process Explorer & Process Monitor. Process Monitor may show you if it's choking on any ACCESS_DENIED errors, etc, and the stack trace at the time of the error. Process Explorer could be especially useful, by listing all the handles your process is still holding open, and allowing you to view the stack of all its living threads. A familiar function or two, in the stack traces of any hung threads, may send you hunting in the right area.
Are you using multiple threads? If one of them can't terminate for some reason, it'll hang the cleanup process.
The short answer is that you have a bug in your application. So, have you tried debugging it?
If you have the Delphi IDE installed on Vista, run the app from the IDE and break it when it 'hangs'. Chances are that you'll have a thread that hasn't terminated itself, and the VCL is waiting for it to finish.
If you don't have the IDE installed on vista, you can probably use the remote debugger, but I'm not familiar with this.
What do you call to close your program? Try using
Application.Terminate;
To force all forms to close and the process to exit.
It probably means you have some memory leak - some resource is not released.
If your application instantiates COM objects, check that you properly close them.
If you use older version of Delphi, you can try to locate possible memory leaks with FastMM
Edit, examples as requested:
I had two situations where application sometimes would stay resident in memory after exit. Both applications would disappear from taskbar, but they would be still active - visible in task manager. Both applications were created with Delphi 7.
First application has one main window with panel in which ather forms are embedded. Each form is standard TForm. Each form is created first time user requests it. Everything worked without problems in test environment, but users reported that from time to time, application would remain in memory, usually after longer usage - when user displayed almost all of the forms in application. I could not replicate this behavior while testing. That was first time I found out about FastMM. When I first run application with FastMM, it reported that some of forms embedded in main form were not released. This version was tested at user site and it turned out that 2 forms that have lots of data aware components would hang up and prevent application from exiting. When I added code that makes sure that all created forms are released before main form, application never hung up on exit.
Second example is application that uses COM to activate GIS editor (Geomedia) to manipulate some map data. I imported type libraries and created Delphi wrapper object. Some of created objects were not freed when application ends. Application icon disappeared from task bar, but application and GIS editor were still active and visible in task manager. Again, it did not happen every time application run. I included FastMM in application and it reported that some objects were not freed. I made sure that every created object gets freed and after that application did not hang on exit any more.
... and if you need to close single form, then use:
Form.Close;
GUI AND HANDLER DELETED. Reference and some parts of memory is left to provide access to variables, constants, etc.
If you need to hide ( something like Minimize, only GUI is cleared ) form, then:
Form.Hide;
GUI is cleared, leaving internal resources untoauched ( reference, handler, memory )
If form is dynamic ( created at runetime ), then use:
Form.Destroy;
ALL RESOURCES WILL BE CLEARED FROM MEMORY, leaving reference and handlers attached so you could access its location in memory.
If form is dynamic and you will not use it for the same interface, then:
Form.Free;
ALL RESOURCES, REFERENCES, HANDLERS ARE DELETED. I recommend to use this to VCL TComponent class, not for TForm class.
Also, there is Form.FreeAndNill, but my guess that it deleted all memory and loaded handlers, only allowing to use same memory space in the same interface again... (I might be wrong though).
P.S. I hope I am not writing wrong things as the last time I read the theory was a long, long time ago... and it was about Destructor DESTROY in general ...
P.P.S ALSO PLEASE BE CAREFUL if you're writing a Vista-ready app - that it includes UAC Handling with manifests / runtime code and SuperBar compatibility requirement. Also Aero requires some additional megabytes to output file due its Aero feature ... :P