Making Sure A ShowMessage Stays On Top - delphi

I have a few applications and I call a ShowMessage('Complete!'); at the end of a long operation.
Most of the time, this works great, but every once in awhile, the Message Dialog will show up behind the main form.
Is there any way for me to ensure the ShowMessage will always be on top?
Thanks!

Call the Windows MessageBox() API instead and pass in the handle to the active form. Actually, my code uses Application.MainFormHandle all the time which I am therefore sure is a reasonable and simple approach.
This will have the benefit of being the system native dialog rather than the home-grown Delphi version. It supports clipboard operations also.
If you want to get very fancy then you can use the Vista task dialog, but that's much more complex and you clearly don't need it for such a simple dialog.

Related

Cannot show a message during program load on iOS

During load of my application I am loading settings and other things, and want to be able to show a message to the user. However this does not work on my Delphi XE6 FireMonkey application targeting iOS (iOSSimulator).
When I call ShowMessage or MessageDlg during program load, it locks, and nothing is shown. It is probably entering the modal state, but since the message is not shown, it is not possible to continue.
Even in the main forms FormActivate, calling ShowMessage does not show anything.
How can I show a message while loading the application?
You can use loading symbol along with Message. It will serve your purpose. You can use "MBProgressHud", you not need to give any extra effort, just pass parameter and it will display loading image along with text. Enjoy!
I am surprised that no one have written about this before and that no Firemonkey users have answered my question.
That you are allowed to call Showmessage during program load, but the app locks if you do it, is not appropriate behavior. In a desktop app, it is quite normal to show a message during program load, in case something fails.
I am converting a 500k line project from VCL to FMX, and since I cannot show a message on iOS, I will have to restructure the create and load code.
The solution I plan to implement is to make failsafe solutions that will allow the app to load no matter what happens, then when the app is running, I can show whatever messages have come up during load (those that the user have to consider).
If anyone have more information or suggestions for a better solution, please comment.

Simulating Mouse Clicks within a minimized or inactive form

I'm having a hard time figuring out how to simulate mouse clicks and such in a window that is minimized or not currently active. In case it's not clear, I want my mouse to be able to click and stuff without actually using the mouse.
For example, while I'm browsing the web I would like my program to be able to be clicking inside of another application at the same time.
How can I accomplish this? All I can find is the same old movemouse and setcursorpos stuff... as we know that requires the use of your actual mouse/Cursor.
You are looking to automate applications. This is done not by faking input but by using an automation API. These days, the preferred one is UI Automation. This is perfectly accessible from Delphi: How to use MS UI Automation in Delphi 2009.

How to force Help and Printer Setup Dialogs to be displayed on the same monitor as the running application?

I know how to force forms to appear on the same monitor as the running application, but I do not see how to ask the Help or the Printer Setup dialogs to display on the same monitor. The Help displays where it displayed last time, but we want it to show up on the application monitor. The Printer Setup dialog always seems to appear on the primary monitor
Passing the parent form's Handle to TPrinterSetupDialog.Execute seems to do the trick.
if PrinterSetupDialog1.Execute(Self.Handle) then
//
Using Delphi 7 (where the TPrinterSetupDialog.Execute does not accept a parameter), you have two choices.
The easiest would be to create your own descendant of TPrinterSetupDialog. Execute is virtual in TCommonDialog, the ancestor of TPrinterSetupDialog, where it is overridden. You could override it in your own descendant, use the code in the TPrinterSetupDialog as a basis for your own Execute override, adding overload as well. Your overloaded Execute would accept a ParentHandle: HWND parameter, and set the PrintDlgRec.hWndOwner to that provided window handle.
I thought about trying to write this for you (or at least get it started), but there are additional things you'd have to copy from the Dialogs unit (functions that are defined in the implementation section that wrap some API calls, and the callback function that's used for the dialog's message loop), and I don't have D7 available where I'm at to even try to compile it.
The other alternative (as David Heffernan mentioned in his comment below) would be to call the Windows API PrintDlgEx directly yourself. This is discussed in MSDN, in the Print Dialog Box (Windows) topic. Once again, I don't have D7 available, so I can't really give you an example of using it from Delphi. (I checked, and don't have one tucked away anywhere.)
I'm not sure you can set the help window's position; I think that's done automatically by Windows based on the user's prior use. (I haven't been able to so so, anyway.)

Delphi, how to make independent windows

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.

How to Prevent ProcessMessages in Delphi

The Application.ProcessMessages command is well known and I use it in long processes to ensure my program will not tie up the computer.
But I have one fairly quick set of processing, where I am buffering a view into a file. During the buffering procedure, a few system messages may get sent off (e.g. redraw or scrollbar move or other events). I want to prevent these from getting handled by ProcessMessages until my buffering is complete.
Is there any way to either:
Prevent Application.ProcessMessages until my procedure is complete, or
Trap all messages generated during my procedure, and not release them until the end of the procedure.
Allowing the ProcessMessages to continue even if it sends messages you don't want should not be classed as problematic. With a bit of code refactoring, you could move the buffering method into a separate thread and go from there.
If you are attempting to copy the "visual contents" of a control into a file,
look at the WM_PRINT(xxx) message which allows child controls to paint themselves into bitmaps
try the LockWindowUpdate Win32 API method call which will turn off all painting messages to that control
override the WndProc/DefaultWndProc method on your control class or even the parent class if you need to and simply return "true" for each message sent
override specific control methods (such as "scroll bar moved", "OnPaint", "OnPaintBackground" etc) on the control class or even the parent and simply do nothing if your buffering is in progress
Overriding the WndProc or DefaultWndProc and simply returning true for each message essentially "turns off" ProcessMessages but it's not safe to do it this way because the control might need to process one or more messages to function correctly.
Turning off ProcessMessages is not possible (without rewriting the VCL code for message processing) because of the fact that it's part of how the VCL form's message loop has been constructed.
Trap all messages generated during my procedure, and not release them
until the end of the procedure.
There is a dirty hack you can do (only if you can not come up with a better way):
You can watch (trap) any messages by using Win32 Hooks.
Specifically, use SetWindowsHookEx with WH_CALLWNDPROC as the idHook value.
You can then record them in a list/queue and resend them when you want.
I learned way back in Windows 2 that windows messages will happen at times you don't expect them. Any part of a library can cause your app's message processing to happen. Rather than hold back the tide, make your code robust against the situation. This may be as simple as usinga a BeginUpdate/EndUpdate pair, or more complex (using a temporary and doing the final update at the end).
At a pedantic level, the way you "prevent" Application.ProcessMessages is to not call any code that
shows a modal dialog
calls SendMessage
runs its own local message loop
calls Application.ProcessMessages (which is a local message loop)
If you write a loop that does nothing but numerical calculations and file I/O, your UI will be frozen until you exit the loop because no messages are being processed.
If you want your UI to be responsive during some long-running operation of unknown arbitrary code (third party library) but you don't want certain kinds of actions to occur in your app during that time, that's a different problem - that's about preventing reentrancy. You want to prevent some parts of your code from being used while a particular activity is in progress. For example, modal dialogs prevent you from interacting with the app windows underneath the dialog by disabling all the app's top level windows except the modal dialog itself.

Resources