Detect if there is a modal form showing - forms

Is there some method of detecting if there is a modal form showing in my VB6 application.
I want to show another form modally if there is a modal form showing and modeless if there isn't a modal form showing.
I know I can do some error handling to detect this and show modally if the error occurs:
Public Sub ShowFormModeless(frm As Form, Optional ownerForm As Form = Nothing)
On Error GoTo ShowModal
Call frm.Show(, ownerForm)
Exit Sub
ShowModal:
Call frm.Show(vbModal, ownerForm)
End Sub
But I want to be able to detect this without the error being thrown.

Try checking App.NonModalAllowed. Note that this property does not detect modal forms being shown from other (than current module) projects, i.e. if your application consists of main executable and several ActiveX dlls each of these projects will have a separate App object and Forms collection.
The result is that if a dll is showing a modal form only its own project's App.NonModalAllowed is flagged. So once again, App.NonModalAllowed is not a process-wide flag but a per project one.
Note that this flag tracks VB6 only forms, so if you are using API dialogs (open/save file, color picker, etc) this does not enter VB6 runtime's modal loop, so nothing is flagged.
If you application is a single exe then using this flag works as expected.

Related

In Delphi, how to restore a minimized modal form that is not the main form

In the project source, I detect a previous instance of my app, and open it then terminate the new instance.
Remember, I do this in the project source.
The application has a main form that can open a second modal form. If the second, modal, form is not open when the app is minimized (or the user switches to another application) it works fine.
The old main form is opened and the new instance is terminated. However, if the second modal form is minimized, its parent main form is also minimized. That's good UI behavior.
The problem exists when attempting to restore the modal form by a new instance. I can't seem to get the modal form to restore.
I can restore the main form, however the modal form still has focus, but is hidden.
This prevents any user action on the now visible main form. From the user's point of view, the app is hung.
The modal form's caption does not change, so it's easy to get its handle.
The app has a DataModule, which is created first. I do all the duplicate app testing in the project source after the DM is created, but before any other forms are, and well before Application.Run.
That assures that the handles I acquire come from the existing app.
I've tried:
PreviousHandle := FindWindow(nil, PAnsiChar('Form Editor'))
ShowWindow(PreviousHandle,SW_RESTORE);
ShowWindow(PreviousHandle,SW_NORMAL);
BringWindowToTop(PreviousHandle);
The best I've gotten out of variations of this is restoring the main form.
When the handle is for the modal form, it sometimes shows in the lower left as a minimized form.
I say sometimes because I've tried so many variations of the above that I don't remember exactly how this code sample behaved.
All I know is, whatever I've tried from the project source did not restore the modal form, so I tried sending a custom Windows Message to the modal form.
I know the message arrived and the message handler caught it. Example:
if not PostMessage(PreviousHandle,WM_RESTORE_FORM,PreviousHandle,0) then
ShowMessage('Can''t automatically show the Form program. '+
'Please click the taskbar icon.');
Here's what the message handler looks like. It is in the Modal Form. As you can see, I pass the form's handle as a Message param. I've verified that it arrives.
Here's the code in a TApplicationEvents OnMessage event:
procedure TfrmDisplayForm.ApplicationEvents1Message(var Msg: tagMSG;
var Handled: Boolean);
var
oldHwnd : THandle;
begin
if Msg.message = WM_RESTORE_ACORD then
begin
oldHwnd := Msg.lParam;
if ForceForegroundWindow(OldHwnd) then ShowMessage('true') else ShowMessage('False');
Handled := True;
end;
end;
Here's the function that is called. However, I've tried various ShowWindows(...) combinations with no luck. Actually, this function didn't do the trick either.
function TfrmDisplayForm.ForceForegroundWindow(hWnd: THandle): BOOL;
var
hCurWnd: THandle;
begin
{credit Peter Below}
hCurWnd := GetForegroundWindow;
AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, True);
Result := SetForegroundWindow(hWnd);
AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
GetCurrentThreadId, False);
end;
I've been working on this for a couple of days, and don't know what I'm doing wrong.
Question: How can I restore the modal form? It must be possible because it restores perfectly when the taskbar icon is clicked.
Don't try to restore individual forms instead use TApplication.Restore
Calling TApplication.Restore will restore all of the application windows to the state before the whole application was minimized same as clicking on TaskBar icon of the application.
PS: I also hope you are not allowing users to minimize individual Modal forms. Or you may also run into a problem where application seems to be stuck.

Multiple delphi forms

I have two delphi forms; frmHome and frmStats. There is a button on the main form (frmHome) and when you click on it it takes you to frmStats.
On btn click in frmHome:
frmStats.ShowModal;
Hide;
This works fine but on frmStats there is also a button that I would like to take the user back to the main form when clicked on. The problem is I get error messages.
If I make reference to the form like this I get the error message "cannot make visable window modal"
implementation
uses frmHome_u;
However if I make reference like this, then i get the message "circular unit reference"
interface
uses {a bunch of uses} , frmHome_u;
On btn click in frmStats:
frmHome.ShowModal;
Hide;
How do I do this?
Modal forms have owners. These owning forms are disabled when the modal form is shown. A form is always shown above its owner.
You are trying to make form1 be the owner of form2 and then in turn have form2 own form1. That circular ownership is not allowed. It would imply that both windows would be disabled, and each window on top of the other.
What you need to do is to close the modal form. Replace
frmHome.ShowModal;
Hide;
with
ModalResult := mrOK;
If you want both forms to be visible and enabled at the same time, then you must not show them modally.
If I understand what you are trying to do then this should work just fine.
frmStats.Enabled := True;
frmStats.Show;
Enabled := False;
Hide;
And you have the reciprocal code in the other form.
Because the other form is disabled, it can not be brought into focus until you enable it.
EDIT
If the users closes FrmStats and FrmHome is the mainform then you must enable it in the onclose event.

How to hook GWT navigation from a userscript?

I'm writing a userscript for a GWT-based site.
My script uses URL of the page as input. It should be update each page of the site with additional information.
Unfortunately, as view changes in GWT are implemented via rerendering (only location anchor in browser address-bar is being changed), clicks on internal links are not recognized as page loads and Greasemonkey does not invoke my script, leaving new views unmodified.
Is there a way to hook in GWT-based navigation from an userscript? I need a way to modify each "change" Gerrit navigates to.
Complete workflow should look like:
User scans through the list of issues
User clicks on a link . (Address bar will assume a location of a change being clicked, for example https://git.eclipse.org/r/#/c/38781/)
Page is modified by userscript to contain information about new view (in our case /c/38781/)
Greasemonkey is only invoked at the first step of this workflow, and I don't know ho to detect second one to be able to trigger the third.
I've tried to observe DOM changes on the page, but my listeners are never called probably due to the fact GWT renders some parts via innerHTML property, without explicit child manipulation.

Is there a property that tells if a form is deactivated by other form `ShowModal` procedure?

Is there a property that tells if a form is deactivated by other form ShowModal procedure ?
EDIT :
My program has a tray icon that brings to front the main form when it's clicked. I want to disable this when another window is shown in modal state. Because not doing so the main form (which is disable) will cover the modal form and completly block my program.
This behaviour is to be expected. When a modal form is shown, the other forms are disabled. You don't need to disable anything at all, the framework already handles it all for you. The beep is sounding because you are attempting to interact with a disabled form.
If you want to be notified when your window has been disabled, for any reason, not just because a modal form has been shown, listen to the WM_ENABLE message. To test whether or not your main form has been disabled. Do that by calling the IsWindowEnabled Win32 function.
Having said that I feel that it is likely you've not diagnosed the issue correctly. It sounds like you might be suffering from window ownership problems, which are common in Delphi 6. Or perhaps you are attempting to restore the application incorrectly from your notification icon code. Use Application.BringToFront for that.
The VCL's handling of modal dialogs seem very mixed up. When you show a system provided modal dialog, e.g. MessageBox, windows are disabled whether or not they are visible. However, the VCL only disables visible windows when ShowModal is called. What's more, you cannot use Enabled to test whether or not the window is disabled, you must use the IsWindowEnabled Win32 function.
You can test Application.ModalLevel at any point in time to find out if there's a modal form. E.g.:
if Application.ModalLevel = 0 then
MainForm.Visible := True;
Note that non-TCustomForm descendants will not set modal level, API dialogs like a file open dialog or MessageBox for instance. If there's a possibility of such a thing, you might surround code that runs those dialogs with ModalStarted and ModalFinished.
It doesn't seem necessary in your case, but if you somehow need to be notified that a form/dialog is going modal, you can attach a handler to Application.OnModalBegin and Application.OnModalEnd events. You can use an TApplicationEvents component for that.

How to close all open durandaljs modal dialogs

Currently I am working on a project that relies heavily on modal dialogs. I'm using durandal's dialog plugin. The problem I have is that within a modal, a user can click an element which displays its details in another modal.
What I would like to do is to close all open modals before I open a new modal. Can anyone give me a good idea of how I can ensure only a single dialog is open at any given time in durandaljs?
Why not use Durandal's pub/sub, or a client-side message bus such as postal.js (which is what we use)? We close all modals by sending a close message over the channel 'app' and the topic 'app/modals'. Instead of holding a reference to an observable (which could have memory implications), we just hold a reference to the message channel (which is a string). Much cleaner way to go.
Ok so the issue I was facing was that I have various Modals, where one modal could be opened from within another modal. However I wanted the modals to close when another would open. The tricky part was that I am using widgets and click events to open the modals.
Since my project is an SPA it occurred to me to simply create a ko.observable - currentModal - on my global object and each new Modal closes the previous, then replaces the old with the new in currentModal(this);
I went even further and am now using the route objects to fire the Modals open as well. Durandal is fun.