Why is a dialog box being displayed behind the main form? - delphi

Earlier today I went to open a file in a Delphi app I wrote. For some reason the connection to the file's network was down--reasons unimportant--and Windows created a dialog box alerting me to the problem. My app's main form, however, was on top of the newly created dialog (i.e., there was a form for my app, for the File Open dialog, and for the warning dialog box). The warning dialog was modal, and hidden behind the main form. Obviously, I had a problem.
Any idea what's going on, or how I can remedy the issue? The main form's position property is set to poDesigned, and I save/load the form's position on close/startup, I'm too much of a newbie to even know what info would help you diagnose the problem. To be clear, though, the issue was not the File Open dialog--that was displayed where it was supposed to be displayed--the issue was the warning dialog.
Thanks, as always --

I don't understand why is Windows creating a dialog in your app. Which API call resulted in that happening? Normal file operations don't show UI.
Most likely you were using an API function that can show UI, perhaps from the shell API. Any function that can show a modal dialog will request an owner HWND.
For example consider MessageBox(), a function that you know will show a modal dialog in your app. Its first parameter is called hWnd and is documented
A handle to the owner window of the
message box to be created. If this
parameter is NULL, the message box has
no owner window.
Raymond Chen has a whole series of articles on modality which explain why setting this is important.
I have a hunch that you are calling some Win32 API function that shows modal UI, and are not setting the owner HWND correctly. Of course, I could be completely wrong, but there's not more information to go on.

You can stop this by using SetErrorMode before trying to open the file on the network share:
var
OldErrorMode: Integer;
begin
OldErrorMode := SetErrorMode(SEM_NOOPENFILEERRORBOX);
try
if OpenDialog1.Execute then
begin
// ....
end;
finally
SetErrorMode(OldErrorMode);
end;
end;
Later versions of Delphi (IIRC, D2007 and higher) added an overloaded version of TOpenDialog.Execute that accepts a window handle as a parameter; this sets the TOpenDialog's parent and prevents the OpenDialog (and any error window it generates) from appearing behind the main window.
NOTE: You can get to the background dialog (from Windows) using Alt+Tab to cycle through until your application comes back up; this usually brings the hidden dialog forwaard on top of your form.

Related

Always on top like task manager

I am working on a project but I faced a problem in making a form stay always on top like task manager in delphi
I used this code but didn't work
SetWindowPos(Form1.Handle, HWND_TOPMOST, 0,0,0,0, SWP_NOACTIVATE+SWP_NOMOVE+SWP_NOSIZE);
Modern task manager uses internal private Windows functionality for its stay on top behaviour. The system does not make this available to user windows. The functionality that task manager uses simply isn't available to you.
Related question: Is Task Manager a special kind of 'Always on Top' window for windows 10?
Just use the Object Inspector at design time to set the form's FormStyle property to fsStayOnTop.
The code from the original post might work on a main form, but will not work on a secondary form. fsStayOnTop is only part of the solution for a secondary form. Below is an easy solution for making a secondary form stay on top while the main form is obscured by other applications - without resorting to showmodal or form creation hacks.
Put this in the "Form B" OnCreate event:
FormStyle:= fsStayOnTop;
but that alone won't do the trick...
Drag a TApplicationEvents onto your "Form B"
In the OnDeactivate event for ApplicationEvents1, add the following:
SetForegroundWindow(Handle);
I keep an eye on a small status window while my main form is crunching data out of site. Works beautifully!

Word ribbon disabled in ole container when second word instance running or activated

I am using a Delphi app with an olecontainer to load a word document "OleContainer1.CreateObjectFromFile('c:\test\hello.docx', false);".
The ribbon functions perfectly well in the opened document until I open a different word document or activate another already open word document. When I return to the document in the Ole container the ribbon is disabled. I am unable to click on any of the buttons or change ribbon tabs. Even if I close the other word document the ribbon in the ole document remains disabled.
I am working on windows 10 with Word 2016
The link provided by Cindy did in fact provide the answer with some tweaking. Many thanks. However, the link refers to Form activate and deactivate. If the ole application is in your main window then it needs to be handled in application events. If not in the main window then you need it in formActivate etc, but formActivate of a secondary form will not fire on application.activate so would need to also have code in application events which will tigger the formActivate of the secondary form. The following works for ole in main form and in Application onActivate
var
iO: IOleInPlaceActiveObject;
begin
if not VarIsClear(App) then begin
if Supports(OleContainer1.OleObject, IOleInPlaceActiveObject, io) then
IO.OnFrameWindowActivate(true);
end;
Same in application deactivate but pass false as the param for onFrameWindowActvate

How do I 'warn' the Application that I closed the DLL it called?

Since I know you guys are exceptional people with awesome talents, maybe someone might be able to help me with this.
This is the situation:
I have an Application that calls a DLL. The catch here is that I'm opening the DLL in a TAdvPanel (it belongs to a TMS library, but I believe it works for the standard Panels too), and it works perfectly fine.
Whenever I close the tab, I can always call the DLL again and recreate its Form, but when I close the Form, the tab where the DLL was stays open, with no content inside of it.
Is there a way for me to "warn" the Application that the DLL was closed and that I can close the tab where the DLL was?
(Note: whenever I write Form, I mean the DLL's Form.)
This is how I call the DLL from inside the Application:
CallCompany(<Parameters..>,Panel.Handle);
And this code below belongs to the DLL:
library Company
uses
...,
U_Form in 'U_Form.pas' {Form}, Windows,
... ;
{$R *.res}
procedure CallCompany(<Parameters..>; ParentForm: THandle); export; stdcall;
var
...
begin
... <Preparing the form to open> ...
Form.Show;
Windows.SetParent(Form.Handle, ParentForm);
end;
exports
CallCompany;
I'm new with DLL's and the way they work. I know I could just not give the user the "Exit" button inside the DLL, forcing him to close the tab, but I wanted to give him that option too.
Ah, and I don't have any code for the OnClose event of the DLL's Form.
If you need any other information in order to help, just tell me and I'll post here whatever is needed.
BTW, I'm using Delphi XE7.
Thanks for the attention.
Complementing the Question:
I have a TAdvPageControl, in which I create TAdvTabSheets, and inside this TAdvTabSheets I put a TAdvPanel (set as alClient).
The DLL I call has a Form, does that categorize as "more that a DLL" ?
I'm posting an image so that might clear things a little bit. If it's still confusing, just say it and I'll drop the question.
When I close the form, the tab where the form was stays open, with no content inside of it.
Don't ever close the form without also closing the tab. That way this situation never arises.
As for specifics, I've got none to offer since the question has no real detail, no MCVE. But it's fairly obvious that the tab and the form that it hosts must be shown and hidden in unison.

Tab order in a console app with a single VCL form

I have a Windows console app created with Embarcadero XE 6 (in fact converted from a Borland C++Builder5 project). It has a single form with a few buttons and edit controls. All these controls have set TabStop=True and appropriate TabOrder's. However, pressing Tab in runtime when the form is shown does not do anything (it just produces a sound when a cursor/focus is in an Edit control and does nothing when a button is focused).
I have read in docs that Tab order would not work unless the Parent of the form is set. However, this is the only VCL form (the other windows are the console and the GLUT window), so there is no VCL parent AFAIK. I tried to set
Parent=Application->MainForm;
in the Form's constructor, but the Application->MainForm is also NULL. Any ideas?
Your problem is that you don't have a message loop. This is because console applications are not expected to have windows and do not come with message loops by default.
You can run a message loop by calling:
Application->Run();
However this will probably stop the console part of your application from working properly. How can your main thread service the console synchronously and the asynchronous GUI message loop at the same time?
I suspect you will need to have a more serious re-think of your application design.
Regarding your update, it seems that you do have a message loop, but it is the message loop for the GLUT framework. The VCL framework requires its message loop to handle dialog messages like TAB key presses.
It's plausible that running the VCL message loop in place of the GLUT message loop would give better results. But it's quite likely that would just break the GLUT part of the app.
Trying to run two incompatible GUI frameworks out of a single message loop is hard to get right. There's probably no quick fix here. You'll need to dig deeper. Perhaps it would be best to give up on the VCL and stick to the one GUI framework.

ShowMessage is hidden

I'm using Delphi XE3 in a complex application that has MDI forms, and forms that stays on top also.
Sometimes a simple ShowMessage('...') does not appear and stays behind the main application window.
Either people think that the application has crashed, or go to task manager and put back the application on top, and then showmessage windows come back on top.
This is occuring in XP, I haven't seen that under Win8 so far.
Any idea why?
You can try this:
Wrote your own myShowMSG function. In this function wrote the simple custom message form and some code to control - "Are this form are visible to user?" In control code write to error.log all tracelog information about this problem. Include the list of actually created forms and their states to .log
Replace all ShowMessage in your project to myShowMSG
Run all tests
Read your error.log's. Post it here to disquss

Resources