Keep Compiled Script's Window on Top

Started by MrLeadFoot, May 16, 2016, 03:24:54 PM

Previous topic - Next topic

MrLeadFoot

I know of IntControl 54's and WindowOnTop's ability to keep a DIFFERENT window on top, but is there a function that can tell a script/compiled .exe to keep ITSELF on top?

Thank you.

snowsnowsnow

Use "" as the "partial window title".

MrLeadFoot

That doesn't work. In fact, many of my scripts are made from a template that includes:

IntControl (54, "", 1, 0, 0)

even though it doesn't work.

For those times that I really need a window to stay in the foreground, years ago I resorted to making one .exe that runs a second .exe, and then the first .exe can have the function keep the 2nd .exe window on top. It's quite unwieldy to have to do that, and I was hoping by now that there was some new functionality in WB that is reliable in this regard, by now. But, I guess there still isn't. That's too bad.

Thanks for trying, though. I appreciate it.

td

As Snow++ pointed out using an empty string as a partial name will give the main window of the calling process the TOPMOST extended window style.  A window with the topmost style as described by MSFT will "be placed above all non-topmost windows and should stay above them, even when the window is deactivated." 
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

MrLeadFoot

OK, I should have been more clear. My bad. Sorry about that. Let me try this again, and put it another way, so maybe you can suggest a different perspective.

I have a script in which I use the AskFileName function. I want the Browse-for-file window that AskFileName brings up to stay on top. I thought that if I used the "" as the partial windowname parameter with IntControl 54 that any window that the script calls would stay on top, as well the script window, but realized early on that IntControl 54 really controls a window, not an app.

I tried putting IntControl 54 immediately prior to the AskFileName line in the script, but obviously that doesn't work because the Browse-for-file window does not exist at that moment. Hence why I went to the two .exe method.

So, I guess my question really should have been:

Is there a way to have the Browse-for-file window brought up by AskFileName stay on top?

Thanks for your patience.

snowsnowsnow

Quote from: MrLeadFoot on May 17, 2016, 02:55:10 PM
OK, I should have been more clear. My bad. Sorry about that. Let me try this again, and put it another way, so maybe you can suggest a different perspective.

Try this.  This uses a technique that I have used frequently.  It looks a little dirty/weird at first, but once you get the hang of it, you'll be glad you did.

Code (winbatch) Select

IntControl(50,0,0,0,0) ; Turn off Web Page Support

IF "%Param1%" == "-ontop"
    IntControl(54,WinIdGet(Param2),1,0,0)
    Exit
ENDIF

IF !IsDefined(Prog) THEN Prog = IntControl(1004,0,0,0,0)
RunHide(Prog,'-ontop SelectFile')
AskFilename("SelectFile",".","Text Files|*.txt|", "", 1)

MrLeadFoot

Thank you, SnowSnowSnow, for the snippet. While I have tried to figure out what's actually happening in the script, I'm stumped about a few things. For example, based on how substitution supposedly works in WB, according to the Help, I can't see how your use of %param1% doesn't cause the script to crash, as param1 is not a defined variable in the script before its being referred to. For that matter, what does that If branch up top actually do?

Then there's your implementation of the RunHide function. How is "-ontop SelectFile" a valid parameter? I don't see that verbiage in the Help for the RunHide function. And, since the Help says that IntControl 1004 "Returns the full path and file name of the current WinBatch program", RunHide seems to be calling the same script/.exe from which it's being run, again. ???

Where do I find out more regarding what you just sent me? I can't find info on any of what I mentioned above anywhere in the Help. If it's there somewhere, someone sure didn't want users to find it!  :o

Regardless, I sure appreciate you taking the time to help me out. ;)

MrLeadFoot

Saw the following in the new 2016b release notes. Does this mean that instead of SnowSnowSnow's solution that we can now use WindowOnTop before a function that brings up a window, like I described above, and the "brought-up" window will now stay on top?

QuoteAdded a third parameter to the "WindowOnTop" function.
      "Retry" - (Optional) Set to a @False (default) or @True value to indicate whether or not
                the function should use the current WIL retry timeout setting when a window
                name is provided in the function's first parameter. Set to @True to have the
                function use the current timeout setting. Set to @False or omit, to have
                the function immediately generate an error when the target window is not found.
                The parameter is ignored when the first parameter is a window id.
                Note that IntControl 46 can be used to change the current retry timeout setting
                (default is 9 seconds.)

snowsnowsnow

Quote from: MrLeadFoot on May 17, 2016, 08:48:03 PM
Thank you, SnowSnowSnow, for the snippet. While I have tried to figure out what's actually happening in the script, I'm stumped about a few things. For example, based on how substitution supposedly works in WB, according to the Help, I can't see how your use of %param1% doesn't cause the script to crash, as param1 is not a defined variable in the script before its being referred to.
No.  One of the nifty things about using % substitution is that it doesn't blow up the script if the variable is undefined.  That is, it works the same as the same basic construct does in ordinary DOS batch - an undefined variable substitutes as nothing.

Note that the usual WinBatch behavior - of aborting the script when an attempt is made to reference an undefined variable - is generally good and should be used most of the time.  This usage of % substitution, like all uses of % substitution should only be used when you a) Know what you are doing (and why) and b) Have thought through all the implications.

QuoteFor that matter, what does that If branch up top actually do?
When the program is invoked with Param1 containing the string "-ontop", it will expect Param2 to contain a partial window name, indicating the name of the window to be "on topped", and will go ahead and "ontop" that window.  After doing so, it exits the script.

QuoteThen there's your implementation of the RunHide function. How is "-ontop SelectFile" a valid parameter?
You can pass whatever you like when you invoke programs.  I think the answer you are seeking is that "-ontop" is syntax invented by me; it isn't defined by the WinBatch implementation.

QuoteI don't see that verbiage in the Help for the RunHide function.
It isn't.

QuoteAnd, since the Help says that IntControl 1004 "Returns the full path and file name of the current WinBatch program", RunHide seems to be calling the same script/.exe from which it's being run, again. ???
Correct.  The script invokes itself running in a separate process, concurrently with the original process.  The secondary process waits for the "SelectFile" window to appear, then "ontops" it.  Once it has done so, it exits.

Finally, note that the new feature you alluded to in a later post (about WindowOnTop() now having an additional optional parameter) is not germane to this discussion, except in one small way.  That is, the reason I use "WinIdGet()" in the IntControl(54) line is to allow the secondary script to wait (up to 9 seconds) for the SelectFile window to appear.  Had I not used WinIdGet(), the secondary script would almost certainly fail as the SelectFile window would not exist at the exact moment in which the secondary script tried to "ontop" it.

This is, in fact, a bug (well, not really a bug, more of an inconsistency) in IntControl(54) (aka, WindowOnTop) that I personally discovered and reported some time back.  It is nice that WWW noticed it and has provided a fix.  If you like, you can search this forum and find the thread that I started (sometime in the last month or two), that describes the problem and how using WinIdGet() provides a workaround.

MrLeadFoot

Sounds a lot like what I was doing with my 2-script method, except without having a 2nd script.

My script includes Boxes up functions, and I noticed with your method implemented what appeared to be blinking boxes, which in reality was really another box being  drawn when the script calls itself.

If the new WindowOnTop option to Retry (for 9 default seconds) won't work here, then what is that option for? I can't think of a reason for it to need to retry other than to check again for the existence/presence of a window it's looking to place on top.

snowsnowsnow

Quote from: MrLeadFoot on May 19, 2016, 01:48:53 PM
I can't think of a reason for it to need to retry other than to check again for the existence/presence of a window it's looking to place on top.

And you probably never will.

MrLeadFoot

So, then why did you say previously that it wasn't "germane" to the conversation? Shouldn't the new WindowOnTop Retry option work for what I want (and what you previously made your workaround for)? Or, am I missing something here? :P Like maybe it stays on that line in the script for 9 seconds, looking for the window, before going to the next line. I would think it continues looking for the window behind the scenes, which would be perfect for my application, because the very next line would create the window it's looking for.

snowsnowsnow

It doesn't mean that.  Trust me.  I am the one who discovered the problem that led to that feature being added, so trust me, I'm not making this up.

The basic fact is that WinBatch is a serial, single thread type language.  In fact, I think I read somewhere (long, long ago) that WB's reason-for-existence was to take the complex, multi-process, multi-thread, event-loop driven thing that is the Windows API and simplify it down to a simple, serial programming language (one suitable for beginners/non-programmers.

What this all means is that in order to get multi-processing (other than with Dynamic dialogs, which are a whole 'nother kettle of fish), you have to run multiple processes - as I do in the example code.

So, as I said, the new feature added to WindowOnTop() is not germane to the issue of getting your AskFileName() window to be "on topped".  If you still don't understand this, all I can suggest is that you go back and re-read my previous (long) post, in which all is carefully revealed.

MrLeadFoot

I believe you, trust me, I really do. If that feature was derived from your report, or inconsistency, as you previously put it, then I am confident that you've already been down that road with the Retry, and I do not need to confirm that is does NOT do what we were hoping it would do.

If by "dynamic dialogs", you mean WIL Dialogs, I hear ya. While they can be unwieldly to script sometimes, I use them a lot with their Callback procedure. But, for what I would've thought would be something quite simple to do, bring up File and Folder dialogs (and have them stay on top), it would require a lot of code to create a WIL Dialog for something so seemingly simple (although it would be easy to use IC54 to keep that Wil Dialog on top). But, the interface would also be a bit weird because dialog controls don't have the same capabilities that native Windows File and Folder dialogs do. And, IIRC, there is no control for folder browsing, so a workaround would need to be done for Browse Folder-type abilities. All this to keep a File or Folder browse dialog on top is not worth it.

I will run with your workaround for now, and get rid of my 2-.exe method, just so I don't have to maintain 2 .EXEs for such a simple function, and replace it down the road with something else, if I ever decide I to want to spend more time on yet another workaround.  :P

td

The AskFileName dialog is a window owned by the WinBatch main Window and the Windows operation system will group an owned window in the z-order with its owner window.  Therefore, if you use WindowOnTop to give the WinBatch main window the the topmost style before calling AskFileName, the AskFileName dialog will also have that extended style when it is created by the function call.

From MSFT's documentation: "When a non-topmost window is made topmost, its owned windows are also made topmost."
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

snowsnowsnow

Quote from: td on May 20, 2016, 09:38:47 AM
From MSFT's documentation: "When a non-topmost window is made topmost, its owned windows are also made topmost."

Yes.  Just tested with this two-liner:

Code (winbatch) Select

IntControl(54,"",1,0,0)
AskFilename("SelectFile",".","Text Files|*.txt|", "", 1)


Which kind of brings us back to ...

Doe, a deer, a female deer, ...

However, that all said, the wording quoted above is interesting.  A lawyer might well argue that it means that while all owned windows extant at the moment of going on-top will also go on-top, it doesn't necessarily guarantee that subsequently created windows (such as our AskFilename() window) will be on-top.

Unlikely, but then again, lawyers have argued (successfully) for the "affluenza defense"...

MrLeadFoot

This does NOT work reliably. I have two different scripts using AskDirectory and AskFileName. Once I saw that it did not work with AskDirectory (and never has since I started using WB in 1994), I did not even bother trying it with AskFileName, assuming it would fail there, too (alas, more inconsistency!). I guess I should have specified AskDirectory in my original questions, not AskFileName. Try it yourself:

Code (winbatch) Select
IntControl(54,"",1,0,0)
AskDirectory("Select Folder...", "","", "",4)


Obviously, IC54 has an issue, which forces one to ALWAYS have to test for IC54 failure whenever it is attempted to be used, and I would prefer to be able to rely on functions. For this reason, like Snow's workaround, I always had to use 2 .EXEs whenever I needed a "called" window to stay on top, just to be safe. But, it sucks to have to maintain 2 .EXEs. With Snow's workaround, you have to be careful if you use Box commands, or you see weird "blinking" as the script calls itself.

td

Quote from: snowsnowsnow on May 20, 2016, 10:10:24 AM
Quote from: td on May 20, 2016, 09:38:47 AM
From MSFT's documentation: "When a non-topmost window is made topmost, its owned windows are also made topmost."
However, that all said, the wording quoted above is interesting.  A lawyer might well argue that it means that while all owned windows extant at the moment of going on-top will also go on-top, it doesn't necessarily guarantee that subsequently created windows (such as our AskFilename() window) will be on-top.

Unlikely, but then again, lawyers have argued (successfully) for the "affluenza defense"...

The sentence is structured as it is because of the context of the win32 function being documented and not because the topmost style will not be applied to owned windows created after the style is applied to the owner. 

An owned window receives the topmost style from its topmost owner when the owned window is created.  Lawyers, weasels and quibblers not withstanding.   The rational for this is, "Any window (for example, a dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner." 

Basically, MSFT dictates that a window owned by a topmost window must be made a topmost window in order to preserve the requirements of the owner-owned relationship. 

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

MrLeadFoot

Quote from: td on May 20, 2016, 10:59:45 AM"Any window (for example, a dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner."
I call BS on this. This is simply not true. In a script, put in the IC54, then throw in some BoxOpen statements, then AskDirectory. What will happen is that the WB script will open on top (as is evident by the Box you see), then the Browse For Folder dialog will open BEHIND the WB-generated Box.

I've never even bothered to check if this happens with WIL Dialogs, but I would guess the same thing happens, and if the WIL dialog is larger than the Browse for Folder window, you're in deep doo-doo, 'cause the user won't even see the Browse For Folder dialog! :o So, when I have to call AskDirectory from a WIL Dialog, I've always made sure NOT to use the IC54, and PRAY LIKE HECK a user doesn't click outside the Browse For Folder window! It may be a small one, but it's a nasty bug I wish would have gotten fixed at some point in the last 22 years. I would have reported it long ago had I known it was a bug, but I didn't, so I didn't.  ;)

MrLeadFoot

Snow, in case my last post gave you a slight heart murmur, I should mention that your workaround does indeed help with the AskDirectory window!  :)

td

Quote from: MrLeadFoot on May 20, 2016, 11:05:25 AM
Quote from: td on May 20, 2016, 10:59:45 AM"Any window (for example, a dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner."
I call BS on this. This is simply not true. In a script, put in the IC54, then throw in some BoxOpen statements, then AskDirectory. What will happen is that the WB script will open on top (as is evident by the Box you see), then the Browse For Folder dialog will open BEHIND the WB-generated Box.

I've never even bothered to check if this happens with WIL Dialogs, but I would guess the same thing happens, and if the WIL dialog is larger than the Browse for Folder window, you're in deep doo-doo, 'cause the user won't even see the Browse For Folder dialog! :o So, when I have to call AskDirectory from a WIL Dialog, I've always made sure NOT to use the IC54, and PRAY LIKE HECK a user doesn't click outside the Browse For Folder window! It may be a small one, but it's a nasty bug I wish would have gotten fixed at some point in the last 22 years. I would have reported it long ago had I known it was a bug, but I didn't, so I didn't.  ;)

It is clear that you don't understand the MSFT terminology used in the statement nor the differences between owner, owned, child, parent, and sibling windows as defined by them.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

MrLeadFoot

Seriously? Why are you always so condescending in your posts to me? Their statement is pretty clearly defined:

QuoteAny window (for example, a dialog box) owned by a topmost window is itself made a topmost window, to ensure that all owned windows stay above their owner."

I don't know how much clearer that can be. They specifically state that ANY window, including a dialog box, should stay above their "owner's" window, if the owned window is a topmost window. That means that if IC54 is used to tell a WB script window to be topmost, then any windows generated by that WB script should stay ABOVE the WB script window. As written, there is no ambiguity to their statement, and other way to interpret it.

Not trying to start an argument, but AskFileName works as described by their statement, so why doesn't AskDirectory? I don't see any reason why it shouldn't. Did you try it, and see that it indeed does not stay on top like AskFileName does? Why doesn't it? Is there a reason AskFileName does, while AskDirectory was made not to stay on top?




snowsnowsnow

I could say more, but, for now, I'll just say:

https://en.wikipedia.org/wiki/Duane_Gish#Debates

And, specifically, refer to "The Gish Gallop".

MrLeadFoot


gibberish

I also have been frustrated by this problem, and this was the thread that best addressed the problem.

I noticed something in my own situation: when run directly from Winbatch Studio, the WindowOnTop / IntControl(54) methods worked. But once I ran either the .wbt file outside of WinBatch studio, it no longer worked.

Found this solution, which made it work:
From Article ID:   W13250
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/Hiding-Disabling~Apps~to~Prevent~User~Intervention+Cover~the~Screen~to~Keep~Users~Out.txt

Place these lines at the top of your script:

thisWin=WinName()
;IntControl(54, thisWin, 1, 0, 0)
WindowOnTop( thisWin, 1 )

MrLeadFoot

The 2nd line has a semi-colon in front of it, which comments out that line. Was that a typo?

stanl

Quote from: MrLeadFoot on June 30, 2018, 08:53:02 PM
The 2nd line has a semi-colon in front of it, which comments out that line. Was that a typo?

No. The IntControl 46 only allows setting the default wait time. So if commented out/or not used defaults to 9 seconds.

....IFICantBYTE

Been a long time since I posted anything, but just my 2 cents worth after looking at this discussion... and forgive me if I'm wrong, but I think you guys are expecting that all windows created by a script (compiled or otherwise) are "owned" by the first window and then any subsequent window that the script displays to own the next etc. etc... and I guess that could be a fair assumption. However, I don't think that it necessarily works that way in WB or any windows application. I think that Tony was trying to say that created windows can have their own hierarchy of ownership and can even be "owned" by perhaps a window such as the "desktop" rather than the running script's main window or dialog or any other window that was created by the very same running script... ownership or sibling/child relationship or message procedure handling can even be changed after creation. That said, it would also presumably be possible for a change to be made to WB so that it works the way you want it to.
I don't think Tony meant to be condescending to you... he is very helpful really, it's just his style and he likes to make you work things out for yourself .. we probably benefit more from this than being spoon fed with complete answers in the long run anyway.
Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

MrLeadFoot

Quote from: stanl on July 01, 2018, 07:49:20 AM
Quote from: MrLeadFoot on June 30, 2018, 08:53:02 PM
The 2nd line has a semi-colon in front of it, which comments out that line. Was that a typo?

No. The IntControl 46 only allows setting the default wait time. So if commented out/or not used defaults to 9 seconds.
Your snippet displayed 54, not 46. Was THAT a typo?  ;)

stanl

Quote from: MrLeadFoot on July 03, 2018, 08:11:37 AM
Your snippet displayed 54, not 46. Was THAT a typo?  ;)

Actually my 'snippet' displayed 46, but as a great contributor IFICanByte suggested this is a forum for solving problems, not silly semantics.

td

I would imagine that the commented ;IntControl(54, OurWnd, 1, 0, 0) was placed in the Tech Database script to assist users with older versions of WinBatch as older versions of WinBatch only have IntControl 54 and not its replacement - the "WindowOnTop" function
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

MrLeadFoot

Quote from: stanl on July 03, 2018, 09:22:02 AM
Quote from: MrLeadFoot on July 03, 2018, 08:11:37 AM
Your snippet displayed 54, not 46. Was THAT a typo?  ;)

Actually my 'snippet' displayed 46, but as a great contributor IFICanByte suggested this is a forum for solving problems, not silly semantics.
I wasn't referring to what you posted, but what Gibberish posted. He posted some lines of code that included IntControl 54, but then referred to IntControl 46, which was NOT in his original post thus was a bit confusing, so I was trying to get clarification.

MrLeadFoot

Quote from: td on July 03, 2018, 09:35:12 AM
I would imagine that the commented ;IntControl(54, OurWnd, 1, 0, 0) was placed in the Tech Database script to assist users with older versions of WinBatch as older versions of WinBatch only have IntControl 54 and not its replacement - the "WindowOnTop" function
I see what you mean. It's basically showing someone how to use WindowOnTop it in place of IntControl 54. Thanks for that clarification.

MrLeadFoot

Quote from: gibberish on June 30, 2018, 08:06:30 PM
I also have been frustrated by this problem, and this was the thread that best addressed the problem.

I noticed something in my own situation: when run directly from Winbatch Studio, the WindowOnTop / IntControl(54) methods worked. But once I ran either the .wbt file outside of WinBatch studio, it no longer worked.

Found this solution, which made it work:
From Article ID:   W13250
http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/nftechsupt.web+WinBatch/Hiding-Disabling~Apps~to~Prevent~User~Intervention+Cover~the~Screen~to~Keep~Users~Out.txt

Place these lines at the top of your script:

thisWin=WinName()
;IntControl(54, thisWin, 1, 0, 0)
WindowOnTop( thisWin, 1 )

Just so you know, this does not work with the Browse For Folder window that's generated by the AskDirectory function, which was why this initial thread was started. Thanks for trying, though! :-)