Can a Dialog be made to "STAYONTOP"?

Technical support and scripting issues

Moderators: Dorian (MJT support), JRL

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Can a Dialog be made to "STAYONTOP"?

Post by jpuziano » Tue Mar 14, 2006 11:52 pm

Hi Marcus,

A Macro Scheduler Message Box can be made to always "Stay on Top"...

Code: Select all

Let>MSG_STAYONTOP=1
MessageModal>always on top
Can a Macro Scheduler Dialog be made to act the same way?

I am willing to resort to Win32 API calls. I found some helpful calls in your Change Border Style of Dialogs post in the Scripts and Tips forum.

I tried using -1 (HWND_TOPMOST) instead of -16 (GWL_STYLE) in the call to SetWindowLongA but that didn't do it. The more I read about it, the more I think it may be the SetWindowPos function that needs to be called, perhaps repeatedly? :?

If you (or anyone out there) could post the calls needed to do this, that would be great. I'm sure there are many Macro Scheduler users who would like to make a dialog "Stay on Top" if they only could.

Thanks in advance for any help or ideas...
Last edited by jpuziano on Tue Mar 21, 2006 7:53 am, edited 1 time in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
Marcus Tettmar
Site Admin
Posts: 7380
Joined: Thu Sep 19, 2002 3:00 pm
Location: Dorset, UK
Contact:

Post by Marcus Tettmar » Wed Mar 15, 2006 8:29 am

Hi,

Here's an example that has two non modal dialogs. One is set to stay on top - you'll note you can't focus the one behind, only the Stay On Top dialog:

Dialog>dlgMain
Caption=Main Dialog
Top=108
Width=451
Left=63
Height=250
Label=Main Dialog,64,16
EndDialog>dlgMain

Dialog>dlgStay
Caption=Stay On Top
Top=108
Width=267
Left=63
Height=143
Label=StayOnTop,32,16
Button=msButton1,24,72,75,25,2
EndDialog>dlgStay

Show>dlgMain
Show>dlgStay
Let>HWND_TOPMOST=-1
Let>HWND_NOTOPMOST=-2
Let>SWP_NOSIZE=1
Let>SWP_NOMOVE=2
Let>SWP_NOACTIVATE=16
Let>SWP_SHOWWINDOW=64
LibFunc>user32,FindWindowA,dhwnd,TForm,Stay On Top
Let>Flags={%SWP_NOACTIVATE% Or %SWP_SHOWWINDOW% Or %SWP_NOMOVE% Or %SWP_NOSIZE%}
LibFunc>User32,SetWindowPos,swpr,dhwnd,HWND_TOPMOST,0,0,0,0,Flags

Label>loop
GetDialogAction>dlgMain,r
if>r=2,exit
Goto>loop
Label>exit
Marcus Tettmar
http://mjtnet.com/blog/ | http://twitter.com/marcustettmar

Did you know we are now offering affordable monthly subscriptions for Macro Scheduler Standard?

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Wed Mar 15, 2006 11:21 pm

Hi Marcus,

Thanks for that, however please see further question...

:?: :?: :?: Can a Dialog be made "Impossible to Minimize"? :?: :?: :?:
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

Me_again
Automation Wizard
Posts: 1101
Joined: Fri Jan 07, 2005 5:55 pm
Location: Somewhere else on the planet

Post by Me_again » Tue Sep 19, 2006 1:53 pm

Hey, if that works well on top of Powerpoint you could probably sell it :lol:

OlgaFB
Pro Scripter
Posts: 58
Joined: Mon Nov 01, 2004 3:04 pm
Contact:

Post by OlgaFB » Mon Oct 09, 2006 6:35 pm

Hi all,

I didn't try this new example now, I just remember that all my trials to make a topmost dialog didn't succeed: it worked well when runnin an scp file, but didn't work when in was in an exe.

Please share if you find that it works. :)

Olga.

kpassaur
Automation Wizard
Posts: 696
Joined: Wed Jul 07, 2004 1:55 pm

Dialog Stay on Top

Post by kpassaur » Sat Oct 28, 2006 5:33 pm

Did anyone ever find out how to make a Dialog stay on top once compiled? I used the example above and it works great until I compile it. Once compiled it goes to the back.

I need it to display a message telling the user to launch their database application, and go to a specific record, then click on it. Any ideas?

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Re: Dialog Stay on Top

Post by jpuziano » Sat Oct 28, 2006 8:46 pm

kpassaur wrote:Did anyone ever find out how to make a Dialog stay on top once compiled? I used the example above and it works great until I compile it. Once compiled it goes to the back.
Hi kpassaur,

JRL's solution from post: Can a Dialog be made "Impossible to Minimize"? was:
JRL wrote:In a non modal dialog the line:

WindowAction>0,[Dialog Title]

Inserted into the GetDialogAction> loop will prevent the dialog from staying minimised.

For a modal dialog a second script or an executable could be spawned to perform the same function.

A secondary script like this:

Label>start
WindowAction>0,[Dialog Title]
Wait>0.01
Goto>start

Hope this helps,
Dick
So... applying JRL's suggestion to the example Marcus provided earlier in this post would give us this:

Code: Select all

Dialog>dlgMain
   Caption=Main Dialog
   Top=108
   Width=451
   Left=63
   Height=250
   Label=Main Dialog,64,16
EndDialog>dlgMain

Dialog>dlgStay
   Caption=Stay On Top
   Top=108
   Width=267
   Left=63
   Height=143
   Label=StayOnTop,32,16
   Button=msButton1,24,72,75,25,2
EndDialog>dlgStay

Show>dlgMain
Show>dlgStay
Let>HWND_TOPMOST=-1
Let>HWND_NOTOPMOST=-2
Let>SWP_NOSIZE=1
Let>SWP_NOMOVE=2
Let>SWP_NOACTIVATE=16
Let>SWP_SHOWWINDOW=64
LibFunc>user32,FindWindowA,dhwnd,TForm,Stay On Top
Let>Flags={%SWP_NOACTIVATE% Or %SWP_SHOWWINDOW% Or %SWP_NOMOVE% Or %SWP_NOSIZE%}
LibFunc>User32,SetWindowPos,swpr,dhwnd,HWND_TOPMOST,0,0,0,0,Flags

Label>loop
  //JRL: next line continuously restores "Stay On Top" dialog
  WindowAction>0,Stay On Top
  //Wait added so script won't hog CPU cycles and slow PC down
  Wait>0.2
  GetDialogAction>dlgMain,r
  if>r=2,exit
Goto>loop

Label>exit
Don't forget a short Wait in the GetDialogAction> loop, see above.

I just tested this (using beta 9.0.031) in both compiled and non-compiled forms and the "Stay On Top" dialog cannot be minimized no matter what so this should work for you, however I did notice something curious...
  • - in the non-compiled version, tapping Windows Key-D will alternately minimize and restore the "Main Dialog" which is what I'd expect.
    - in the compiled version, tapping Windows Key-D minimizes the "Main Dialog" but tapping it again will not restore it (can be restored from the Taskbar however).
Marcus, shouldn't both uncompiled and compiled versions of this macro behave in the same way? Here's something else...

In the compiled version, when you run it, you'll notice an entry in the Taskbar right away... but nothing has been minimized yet. Hit Windows Key-D and the "Main Dialog" dissappears (minimizes I guess) but Taskbar still looks the same as it did when macro first ran.

Try it again, run compiled version only this time, click the minimize control on the "Main Dialog" window and see that it does minimize but not into the Taskbar, it creates a little mini-window just above the actual Taskbar. Can anyone explain what is actually happening here? Why doesn't it minimize to the Taskbar? Why does clicking the minimize control produce a different result than using Keyboard shortcuts for Windows such as Windows Key-D?
Last edited by jpuziano on Mon Oct 30, 2006 4:15 am, edited 2 times in total.
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
support
Automation Wizard
Posts: 1450
Joined: Sat Oct 19, 2002 4:38 pm
Location: London
Contact:

Post by support » Sun Oct 29, 2006 8:29 am

Marcus, shouldn't both uncompiled and compiled versions of this macro behave in the same way?
They won't quite, because in one instance you have a visible main application form - the Macro Scheduler main form, and in another (compiled) the main form is a hidden control window.
In the compiled version, when you run it, you'll notice an entry in the Taskbar right away... but nothing has been minimized yet.
Of course you'll see an entry in the taskbar. Not sure why it has to be mininmized to see an entry in the task bar. If you run Notepad do you not see an entry for it in the taskbar? That's what happens when you run an application.
Hit Windows Key-D and the "Main Dialog" dissappears (minimizes I guess) but Taskbar still looks the same as it did when macro first ran.
Of course the main dialog disappears - you hit Windows-D which is to "show the desktop". Normally the main dialog would minimize to an icon above the task bar because it is a non-mdi child window. But Windows-D is "show desktop" so to show the desktop it has to hide that minimized icon.
Try it again, run compiled version only this time, click the minimize control on the "Main Dialog" window and see that it does minimize but not into the Taskbar, it creates a little mini-window just above the actual Taskbar. Can anyone explain what is actually happening here? Why doesn't it minimize to the Taskbar?
That is what is meant to happen. That's how Windows works. Child windows of non-MDI applications minimize to an icon above the taskbar.
Why does clicking the minimize control produce a different result than using Keyboard shortcuts for Windows such as Windows Key-D?
Well for starters when you click on an Application's minimize icon you are telling only it to minimize and it gets a special kind of message WM_CONTROL which it then responds to. When you hit windows key-d the system sends a WM_SHOWWINDOW message to ALL windows with a flag set to say it should minimize or maximize. Windows will also hide windows that would be in the way of the desktop because Windows-D is "show desktop". So there are two completely different types of processing going on. In the latter scenario Windows is manipulating the show state of the window before the application can respond to it - if the application does something different or needs to do some special processing it may be too late. Bear in mind that the main Macro Scheduler app (not compiled macros) , as do many other "system tray" apps, overrides the standard minimizing to HIDE the window. There's actually no such thing as "minimize to the system tray". The system tray just holds icons. So "minimize to the tray" is really "hiding" the window with the click on the icon "showing" it again.

The bottom line is you are not quite comparing like with like. Windows-D is "show desktop" so Windows does some extra processing to hide windows that would be in the way. The stay on top window isn't hidden because of it's stay on top, no hide status. Clicking a minimize button on a window does something completely different to pressing Windows-D.

Further to your previous message about Windows-D we've now added code to detect Windows-D so that the system tray icon knows the window is now hidden, so you won't have to click it twice.
MJT Net Support
[email protected]

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Mon Oct 30, 2006 6:04 am

support wrote:
jpuziano wrote:Marcus, shouldn't both uncompiled and compiled versions of this macro behave in the same way?
They won't quite, because in one instance you have a visible main application form - the Macro Scheduler main form, and in another (compiled) the main form is a hidden control window.
Fair enough.
support wrote:
jpuziano wrote:In the compiled version, when you run it, you'll notice an entry in the Taskbar right away... but nothing has been minimized yet.
Of course you'll see an entry in the taskbar. Not sure why it has to be minimized to see an entry in the task bar. If you run Notepad do you not see an entry for it in the taskbar? That's what happens when you run an application.
Of course, Taskbar entry is there while running, minimized or not; sorry, don't know what I was thinking. :oops:
support wrote:
jpuziano wrote:Hit Windows Key-D and the "Main Dialog" disappears (minimizes I guess) but Taskbar still looks the same as it did when macro first ran.
Of course the main dialog disappears - you hit Windows-D which is to "show the desktop". Normally the main dialog would minimize to an icon above the task bar because it is a non-mdi child window. But Windows-D is "show desktop" so to show the desktop it has to hide that minimized icon.
I'm used to seeing many windows on my machine and each one has a separate entry in the Taskbar. This compiled macro has two windows (dialogs) and each one will minimize to an icon "above the Taskbar" but there's only ever one entry in the Taskbar. I use Windows Key-D so often, I hardly ever see icons minimized "above" the Taskbar like that (because it hides them as you point out). Sorry for my confusion. :oops:
support wrote:
jpuziano wrote:Try it again, run compiled version only this time, click the minimize control on the "Main Dialog" window and see that it does minimize but not into the Taskbar, it creates a little mini-window just above the actual Taskbar. Can anyone explain what is actually happening here? Why doesn't it minimize to the Taskbar?
That is what is meant to happen. That's how Windows works. Child windows of non-MDI applications minimize to an icon above the taskbar.
Fair enough.
support wrote:
jpuziano wrote:Why does clicking the minimize control produce a different result than using Keyboard shortcuts for Windows such as Windows Key-D?
Well for starters when you click on an Application's minimize icon you are telling only it to minimize and it gets a special kind of message WM_CONTROL which it then responds to. When you hit windows key-d the system sends a WM_SHOWWINDOW message to ALL windows with a flag set to say it should minimize or maximize. Windows will also hide windows that would be in the way of the desktop because Windows-D is "show desktop". So there are two completely different types of processing going on. In the latter scenario Windows is manipulating the show state of the window before the application can respond to it - if the application does something different or needs to do some special processing it may be too late. Bear in mind that the main Macro Scheduler app (not compiled macros) , as do many other "system tray" apps, overrides the standard minimizing to HIDE the window. There's actually no such thing as "minimize to the system tray". The system tray just holds icons. So "minimize to the tray" is really "hiding" the window with the click on the icon "showing" it again.

The bottom line is you are not quite comparing like with like. Windows-D is "show desktop" so Windows does some extra processing to hide windows that would be in the way. The stay on top window isn't hidden because of it's stay on top, no hide status. Clicking a minimize button on a window does something completely different to pressing Windows-D.
Thanks support for your patience and detailed reply, its appreciated. I have a better understanding of what's going on now. :)
support wrote:Further to your previous message about Windows-D we've now added code to detect Windows-D so that the system tray icon knows the window is now hidden, so you won't have to click it twice.
So in the next version, with MS Main form visible, you hit Windows Key-D, everything minimizes, right-clicking the MS tray icon would now offer "Show" and double clicking it would now open the MS Main form. That's great news, thanks.

Will the code you've added also handle these situations?:

- A second press of Windows Key-D will restore the MS Main form. Would right-clicking the MS tray icon then offer "Hide" and would double clicking it hide the MS Main form?

- Does it also handle Windows Key-M (minimize all windows) and its reverse, SHIFT-Windows Key-M? :D
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Mon Oct 30, 2006 5:30 pm

jpuziano wrote:So in the next version, with MS Main form visible, you hit Windows Key-D, everything minimizes, right-clicking the MS tray icon would now offer "Show" and double clicking it would now open the MS Main form. That's great news, thanks.

Will the code you've added also handle these situations?:

- A second press of Windows Key-D will restore the MS Main form. Would right-clicking the MS tray icon then offer "Hide" and would double clicking it hide the MS Main form?

- Does it also handle Windows Key-M (minimize all windows) and its reverse, SHIFT-Windows Key-M? :D
I just tested 9.0.032, your fix takes care of all the above, thanks! :)
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

kpassaur
Automation Wizard
Posts: 696
Joined: Wed Jul 07, 2004 1:55 pm

Stay on top with Drop Down List

Post by kpassaur » Tue Oct 31, 2006 9:58 pm

Thank all you you for your help. It works great on just about all the Dialogs. What it dosn't work on is one where there is a combobox.

What happens naturally, is when it cycles it puts the dialog box on top of the list that has already dropped down, blocking some of the choices.

I now understand why, and am curious as to if anyone knows of a solution.

User avatar
JRL
Automation Wizard
Posts: 3501
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Tue Oct 31, 2006 11:08 pm

One possibility would be to create a safe zone using the cursor position. If the cursor is in a specific position relative to the combo box the WindowAction>3 function is inactive.

Here's a modified version of the above script: This is meant as a quick and dirty sample and therefore I did not take into account the cursor's "Y" position. But if the mouse cursor "X" position is anywhere within the zone defined by the combo box size and position the WindowAction>3 will not occur and the combo box menu will not be interfered with.

Code: Select all

Dialog>dlgMain
   Caption=Main Dialog
   Top=108
   Width=451
   Left=63
   Height=250
   Label=Main Dialog,64,16
EndDialog>dlgMain

Dialog>dlgStay
   Caption=Stay On Top
   Width=267
   Height=143
   Top=108
   Left=63
   Label=StayOnTop,32,16
   Button=msButton1,24,72,75,25,2
   ComboBox=msComboBox1,98,24,145,item1%CRLF%item2%CRLF%item3%CRLF%item4%CRLF%
EndDialog>dlgStay

Show>dlgMain
Show>dlgStay

Let>HWND_TOPMOST=-1
Let>HWND_NOTOPMOST=-2
Let>SWP_NOSIZE=1
Let>SWP_NOMOVE=2
Let>SWP_NOACTIVATE=16
Let>SWP_SHOWWINDOW=64
LibFunc>user32,FindWindowA,dhwnd,TForm,Stay On Top
Let>Flags={%SWP_NOACTIVATE% Or %SWP_SHOWWINDOW% Or %SWP_NOMOVE% Or %SWP_NOSIZE%}
LibFunc>User32,SetWindowPos,swpr,dhwnd,HWND_TOPMOST,0,0,0,0,Flags

Label>loop
  GetWindowPos>Stay On Top,wX,wY
  GetCursorPos>cX,cY
  Let>Xmin=%wX%+98
  Let>Xmax=%Xmin%+145
  //JRL: next line continuously restores "Stay On Top" dialog
  If>{(%cX%>%Xmin%)and(%cX%<%Xmax%)}
    //do nothing
  Else
    WindowAction>0,Stay On Top
  EndIf
  //Wait added so script won't hog CPU cycles and slow PC down
  Wait>0.2
  GetDialogAction>dlgMain,r
  if>r=2,exit
Goto>loop

Label>exit

User avatar
jpuziano
Automation Wizard
Posts: 1085
Joined: Sat Oct 30, 2004 12:00 am

Post by jpuziano » Sat Feb 19, 2011 8:34 pm

Hi all,

I am re-posting this here for completeness... and for future reference for anyone searching for a way to make a Dialog StayOnTop when you are running your MS macro compiled - check out this post: http://www.mjtnet.com/forum/viewtopic.php?t=6773

...and in particular, JRL's info shown below. All we needed to do is... "Get its location and move it to the location it is already in". JRL how did you discover or come up with that? :shock: I wish I would have known that back in 2006. As far as I know, that little gem isn't in the Help File or documented anywhere (until now, in these forums).

Marcus: Should this technique to making a Dialog StayOnTop (even if compiled) be in the Help File somewhere, maybe as a code example? Or better yet, could you make use of this technique internally and add a property to the new v12 Dialogs called StayOnTop: Y/N
That way, we could just get/set the property and it could take care of the details for us and just work, compiled or not. I believe this is already on the Official Wish List but if not, please consider adding it.


Take care and thanks again JRL for sharing this gem.
JRL wrote:I think I stated this before but if not sorry cause I've known it since this was first discussed. All you need do to keep the dialog on top when compiled is move the dialog. Get its location and move it to the location it is already in. In the sample above, put a line in the loop that moves the dialog to 10,10 and it will stay on top when compiled.

Code: Select all

Dialog>Dialog1
object Dialog1: TForm
  Left = 475
  Top = 174
  HelpContext = 5000
  BorderIcons = []
  Caption = 'Progress'
  ClientHeight = 20
  ClientWidth = 400
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = False
  PixelsPerInch = 96
  TextHeight = 13
  object ProgressBar1: TProgressBar
    Left = 0
    Top = 0
    Width = 400
    Height = 20
    TabOrder = 0
  end
end
EndDialog>Dialog1
Show>dialog1

LibFunc>User32,SetWindowPos,swpr,dialog1.handle,-1,0,0,0,0,83

MoveWindow>Progress,10,10
Let>percent=0

Label>Loop
  Wait>0.5
  Add>percent,5
  SetDialogProperty>Dialog1,Progressbar1,Position,percent
  If>percent=100
    Wait>2
    Exit>0
  EndIf
  MoveWindow>Progress,10,10
Goto>Loop
jpuziano

Note: If anyone else on the planet would find the following useful...
[Open] PlayWav command that plays from embedded script data
...then please add your thoughts/support at the above post - :-)

User avatar
Rain
Automation Wizard
Posts: 550
Joined: Tue Aug 09, 2005 5:02 pm
Contact:

Post by Rain » Mon Feb 21, 2011 1:42 pm

Marcus: Should this technique to making a Dialog StayOnTop (even if compiled) be in the Help File somewhere, maybe as a code example? Or better yet, could you make use of this technique internally and add a property to the new v12 Dialogs called StayOnTop: Y/N
That way, we could just get/set the property and it could take care of the details for us and just work, compiled or not. I believe this is already on the Official Wish List but if not, please consider adding it.
It's already part of the dialog designer in v12.

1. Set the FormStyle to fsStayOnTop
2. Set OnTaskbar to True

Code: Select all

Dialog>Dialog1
object Dialog1: TForm
  Left = 297
  Top = 105
  HelpContext = 5000
  BorderIcons = [biSystemMenu]
  Caption = 'Dialog Stay On Top Example'
  ClientHeight = 71
  ClientWidth = 243
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  FormStyle = fsStayOnTop
  OldCreateOrder = True
  ShowHint = True
  OnTaskBar = True
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 8
    Top = 8
    Width = 172
    Height = 26
    Caption = 
      '1. Set the FormStyle to fsStayOnTop'#13#10'2. Set OnTaskbar to Tru' +
      'e'
  end
end
EndDialog>Dialog1

AddDialogHandler>Dialog1,,OnClose,Exit
Show>Dialog1

Label>Loop
wait>.1
Goto>Loop

SRT>Exit
  Exit>1
END>Exit



User avatar
JRL
Automation Wizard
Posts: 3501
Joined: Mon Jan 10, 2005 6:22 pm
Location: Iowa

Post by JRL » Mon Feb 21, 2011 7:03 pm

Rain,
Thanks for that. Much easier to follow and implement.

Do you need to set OnTaskbar to True for fsStayOnTop to work? I tried your sample without OnTaskbar set to True and it seemed to work.

Post Reply
Sign up to our newsletter for free automation tips, tricks & discounts