Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Automate Windows Explorer Behind Foxpro (VFP9)? 2

Status
Not open for further replies.

mydocpro

Technical User
Mar 13, 2016
48
US
DECLARE INTEGER ShellExecute IN shell32.dll INTEGER hndWin,STRING cAction,STRING cFileName,STRING cParams,STRING cDir,INTEGER nShowWin
ShellExecute(0,"open","notepad",null,"",4) && works OK to send Notepad 'behind' (non-active window)
ShellExecute(0,"open","explorer","C:\","",4) && fails to send Explorer behind foxpro

Any thoughts to get the Explorer window(s) behind (as non-active window) VFP (apps)?

Utmost thanks and blessings in advance!
Philip M Traynor
 
Try passing 2 (instead of 4) as your last parameter to ShellExecute(). That will launch Explorer in a minimised window, and the VFP window will remain in front.

If you want Explorer to be in a normal window (not minimised) with VFP in front, then pass 1 as the last parameter; in your VFP application, set focus to your active form.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks Mike,

But I still am missing something. Explorer takes over once it's active.

But, I wonder if a timer with your BringWindowToTop(_SCREEN.hWnd) idea might work to (re-)activate the VFP app to top level.

(I've got to rest ... but look forward to experimenting more in the morrow)

Utmost thanks and blessings!
Philip M. Traynor
 
I think the problem is that it takes a few milliseconds for Explorer to load, and by the time it has done so, VFP has already executed the code that brings itself to the front.

So, yes, a timer would solve that. But it would be easier for VFP simply to pause for a short period, while Explorer is loading. You can achieve that as follows:

Code:
DECARE INTEGER Sleep
ShellExecute( .... etc.)
Sleep(1000)    && experiment with this figure to get the optimum sleep time
BrintWindowToTop(... etc.)

By the way, with all the code posted here, you only need to execute the DECLARE commands once - not every time you call the corresponding function. You could put the DECLAREs at the start of your main program, for example.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
On my Windows 10 the inverse happens, Notepad comes to front and the Explorer stays behind the _screen.
_SCREEN.AlwaysOnTop=.T. works for me.

The cleanest solution would be to bind the _screen.Deactivate event to a eventhandler object with bindevent. In its event it will bring _screen back to front and then unbind.

Bye, Olaf.

 
Thanks Olaf,

I'm always very happy when you (and Mike) reply ... as the solution(s) become promising.

I'll experiment with your _SCREEN.AlwaysOnTop=.T. command (again) ... which fails to activate the vfp screen 'on top'.
... and _screen.Deactivate event (if I can figure how to do that in the 'form' properties, etc.) ... using Mike's code.

... and/or timer (with Mike's code)

I'll report as things solve.

Utmost blessings,
Philip M Traynor
 
Regarding _SCREEN.Deactivate: It's not a method. You don't call it in order to deactivate the window. Rather, it is an event - one that occurs when the window becomes deactivated. But, unlike events for forms and other controls, you can't write code in _SCREEN.Deactivate. Olaf's point was that you use it with BINDEVENTS(). If you haven't used BINDEVENTS() before, you might find the concept a bit challenging (but don't let me put you off).

Regarding _SCREEN.AlwaysOnTop: I'm not sure if that would work. You don't want the VFP window to always stay on top. You just want it to appear in front of WindowsExplorer for this particular case. Still, it might be worth experimenting.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
The idea is to set AlwaysOnTop=.T. before Shellexecute (that alone works), then set it back to .F. after the Explorer started. You might end up with AlwaysOnTop=.F., before the Explorer Window shows up, but it would be the simplest solution needing no API. There are other places you could set AlwaysOnTop to .F., especially in Deactivate again, or via Bindevents to it.

Bye, Olaf.

 
Resolved:

Thanks so much Mike and Olaf for enabling me to think!! Here's an 'unpolished' work-around solution using the Timer (until I grasp your ideas better) ... I may edit/append if significant

1. Add a Timer object to the Form: (i.e., tmrScreenToForeground) ... whose interval is set to 7 mSec (arbitrary)
2. DECLARE INTEGER ShellExecute IN shell32.dll INTEGER hndWin,STRING cAction,STRING cFileName,STRING cParams,STRING cDir,INTEGER nShowWin
DECLARE INTEGER SetForegroundWindow IN user32 INTEGER hwnd && in main.prg once
3. _screen.AlwaysOnTop = .T.
ShellExecute(0,cAction,cFileName,cPath,"",1) && "4" might be used to replace "1"
_screen.ActiveForm.tmrScreenToForeground.enabled = .T. && trigger SetForegroundWindow(_SCREEN.hWnd) 7 mSec interval
4. In the tmrScreenToForeground.Timer Event:
WAIT WINDOW "" TIMEOUT 0.5 && put the brakes on Foxpro else it fails
SetForegroundWindow(_SCREEN.hWnd)
this.Enabled = .F. && else it loops
_screen.AlwaysOnTop = .F.
 
If the Timeout 0.5 helps, just set the timer interval to 500 (ms).

Since the behaviour will differ from PC to PC it would be best to react on the deactivation, therefore the event driven solution would be better.

Bye, Olaf.
 
In regard of nShowWindow paremeter of ShellExecute, you can experiment a little with an own EXEcutable you create wth VFP

Default behviour of applications is to restart their main window in the size, position and state it was when you last exited from them. That happens, when you doubleclick it. That should also happen when using 5.

4 means the active should stay the active window, that doesn't say anything about the z-order, the active window can still be overlayed with the new (Explorer) window.

That already indicates you should handle either the new or your own apps window as aftermath.

What adds to this is, that the code inside an EXE may override what the OS does with the main window, in the anner as VFP code can set _SCREEN.WindowState. Simply test with an own EXE and have the code _SCREEN.WindowState=2, that will maximise the _SCREEN, no matter how Windows sets the size and position, also if you set the _SCREEN to normal size and resized and repositioned before your last exit.

I'm unsure what happens in which order, so you may get quirky behaviour anyway. If your application window actually is kept active, but still the Explorer Window draws in front of it, this will also not casue the deactivate event, so one further thing is becoming handy, or should I say handly? If the return value of ShellExecute is no error code (<=32) but a larger number (>32) it's the hwnd handle for the new main window, so you can act both on _screen and the main Window of the application you started.

Besides SetForegroundWindow you also have BringWindowToTop and SetWindowPos, which handles the Z-Order and x,y positions. I haven't experimented with this myself, though.

Bye, Olaf.
 
Philip,

It's good that you've found a solution. But the steps you have adopted look a bit like overkill, for a couple reasons.

First, I don't see why you need to use both SetForegroundWindow() and _SCREEN.AlwaysOnTop. These are alternative ways of solving the same problem. Also, using a timer seems much more complicated than simply calling Sleep(), as per my original suggestion. And, given that you are using a timer, there is no point in also doing a WAIT TIMEOUT.

That said, if the solution you have adopted is working for you, by all means leave it at that.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike and Olaf,
Mike
_SCREEN.AlwaysOnTop = .T.:
1) ... fails to activate the frontmost window (Windows 8.1/VFP-9), BringWindowToTop(_SCREEN.hWnd) also fails (in the same manner). (By some miracle of God's grace, I stumbled into SetForegroundWindow(_SCREEN.hWnd) which does activate the VFP program on top
2) (Olaf's) _SCREEN.AlwaysOnTop = .T. is necessary to prevent File-Explorer from 'blinking' through the frontmost Form (caused by ShellExecute(0,cAction,cFileName,cPath,"",4) (1 or 4). ShellExecute both activates and bringson-top (on my machine).
3) Mike: Sleep() failed for me 2-fold (n my machine) (both before the timer and within the timer event) (on this machine)
4) Mike and Olaf: Wait window "" timeout 0.5 ... works well. Setting the timer.interval to 500 (mSec) fails: --> 'Blinking' (Explorer bleeding through the VFP form) (as above). Honestly, I don't know why Wait window "" timeout 0.5 has become the reasonable work-around (I can't explain it).

File-Explorer is tricky but required for today's regulated medical EMRs ... JPGs and PDFs being the legal stuff. I've also automated (via refresh) Explorer to 'terminate' after each record change(s):
BringWindowToTop(m.lnHWND)
SendMessage(lnHWND,0x0010,0,0)
_screen.AlwaysOnTop = .F.
... etc. so File Explorer folders (linked to each record number) continuously open/close in the background ... as the user advances to different records. (tested OK on 2 machines so far)

Olaf, I have read your excellent post several times to digest your inspiring thoughts. I need to read it a few more times as there remain your pearls I don't understand (yet). Win8+ File-Explorer 'remembers much'. Event-binding is new for me and I may try to learn it and the EXE pearls. You always encourage me to do best.

Again, thanks so much Mike and Olaf for inspiring me to the uttermost!

Philip M. Traynor
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top