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!

How reliable is WSH AppActivate()? I'm looking for experience and/or people willing to experiment...

Status
Not open for further replies.

Olaf Doschke

Programmer
Oct 13, 2004
14,847
DE
We all know and use methods to prevent double starts. I maintain an application that already implmented the usual FindWindow/SetForeGroundWindows method.

A customer's suspicion is, this still doesn't work. I found a possible flaw in the logic, and while I am at rewriting this I remembered WMI queries fro win32_process can also show you whether a process of an exe runs in a separate Windows session.

So my new code works on that basis and I end up with a ProcessIds instead of Hwnd. And I found an easy way to activate a process by that instead of SetForeGroundWindow via this:
Code:
oWSSH = CreateObject("WScript.Shell")
oWSSH.AppActivate(Processid)

My first tests are all successful, but here's the thing I can't explain: The result value of the AppActivate() call should tell, whether the activation succeeded. But mostly it returns .F., even when the app activation does work.

OK, that's lamenting over a detail, which isn't really a problem, as long as it works it's totally sufficient, but I ask myself: "how reliable is it?"
Does anybody already use WScript.Shell AppActivate? Or are you willing to experiment with it and see whether it works reliable for you, too?

You don't even need any more code to find out a process ID, if you experiment with several Foxpro sessions started one can activate the other once you know the _vfp.processid of the session you want to activate. I'd also be interested in whether this works on WinXP,7 and 8, too.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Olaf,

I have only ever used oWSSH.AppActivate by passing the name of the application to be activated, rather than the process ID. I have found that it works reliably, but it is often necessary to insert a delay of a few hundred milliseconds between instantiating "WScript.Shell" (or launching an app with oWSSH.Run) and invoking oWSSH.AppActivate.

I don't know any way of determining if the activation is successful, other than the usual FindWindow method, which takes you back to where you started.

I've done this mainly with VFP 9 under Windows XP. When I get a moment, I'll experiment with Windows 7.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thanks, Mike!

The timing is the lesser problem, but it's a good idea to start-up WScript.Shell proactively even when it's later not used to activate an already running process.

The reason the ProcessId is a better qualifier for me is how WMI enables us to see processes across several Windows sessions. I do these two WMI queries:
Code:
Select ProcessId, SessionId, CreationDate, Name From Win32_Process where ProcessId = <<_vfp.ProcessId>>
Select ProcessId, SessionId, CreationDate From Win32_process where Name='<<the name from the first query>' And ProcessId <> <<_vfp.ProcessId>>

If a process is found in another SessionId the user gets a notice to change Windows sessions and I quit.

And in the case of a double start in the same Windows session, I get an overview of the own process and what I'd call sibling processes. Usually only one, obviously, once that mechanism is established, but I can decide a winner by earliest CreationDate, which WMI gives with microsecond precision.

In case I switch, I would like to be sure that activation worked. Otherwise, it would seem to the user the software broke and instead it's just a case of a minimized process not maximizing again, for example. Or whatever else doesn't work.

Another reason I'd like to work on the principle of ProcessIds is, they are the earliest handle I can think of. In a startup time of the runtime, there may be no Window handle, judging already running processes by any action the main.prg start code does is already later than that, no matter if you open some file exclusive or create a semaphore.

So testing efforts are welcome. If that turns out nice, I'd judge it as a very stable and unbeatable mechanism, unless someone tells me WMI might only see a process "long" (=a few microseconds) after it was created. But I'll test that, too, intentionally starting an EXE 2 or more times.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I think I found out the circumstances when oWSSH.AppActivate(Processid) returns .f.

1. The documentation of AppActivate says the value is false when the activated process can't get focus, meaning SetFocus() to the main window doesn't work
2. I got this when I start an old VFP process which I kept open for hours or even from last day.

I assume it works more reliable when the already running process is active or - as in the critical case I want to prevent - also just started.

And my tests about multiple starts all ran well, only one process remains. With one exception. After several tests one of the starts judged foxuser.dbf as corrupt ans asked whether I want to overwrite it with a new resource file. And since that happens before main.prg it's a process that stayed open, too, it never started the routine to find out it's a secondary sibling process.

But the solution for that is obvious, I include a config.fpw with RESOURCE=OFF, so that dbf never is in the way.

I'd still like to hear how that works in Win8, Win7 or XP.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Thanks, Tom, for the concern.

I thought of that, but
1. In my case, that's under my control. The software is the major deal on the workstations of the users and the system will be adapted as necessary.
2. I don't RUN /N wscript scriptname of JS or VBS scripts.
3. I remember this discussion, WScript.Shell isn't WSH, it's a COM Helper object. Like other things, eg Scripting.FilesystemObject, it works independently of settings.
4. I'm well aware of other solutions, but nothing in the Fox Wikis shows processes in further Windows sessions!

I just checked once more, whether turning off WSH influences Wscript.Shell usage. It only disables running JS or VBS script files, but nothing more, nothing less, Wscript.Shell doesn't get disabled. What you also can't do is use Wscript.Shell.Run() to run vbs scripts. So the security aspect isn't undermined, too.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Also note: You can use WMI to make the WMI queries with a normal account. I found out, that you need an elevated process to get at some win32_process properties, eg the ExecutablePath is NULL for processes of another SessionId, but you can give your EXE a very specific name with which it appears in the win32_process.name property.

Besides, you can combine that, look for a semaphore or mutex, but everything you do is after process entry already exists. You can CreateMutex() and CreateSemaphore(), but that needs at least one DECLARE and a call while you only need to be the same EXE name and nothing else to be seen by a process list query. Semaphore/Mutex can be a valid add on in case you don't trust another process by name just being sabotage to hinder your EXE from running. Users will look for yourapp.exe in the Task Manager, find and kill it, though. So that's not a very clever attack.

Even though you and only you know what further Semaphore or Mutex identifies a sibling process, it's not there in the first split second. You can check whether CraationDate of another process is old enough, so you can be sure this unique identifier is established by the other process before you look for it. I don't know, though, whether Semaphore/Mutex is per system or per session. Yes, those are the things you only need to worry about for split seconds, but that is my concern about the corner case of starting an EXE twice directly and the other corner case is - in my case - only allowing an app to run in one session.

Sure, in many cases you want to be able to start in multiple sessions, ie when the computer is a terminal server you want to enable that app to run once per session. Then simply only query for processes in the same SessionId.

The only thing I don't figure out is why a long-running VFP session actually activates with Wscript.Shell.AppActivate(), but that still returns .F. I looked into how complex a VFP9.EXE process actually is windows wise. Even when you close all windows except _SCREEN you have already a lot of windows handles of some hidden windows, some for IME (Japanese keyboard input), that always exist. I assume the complex windows structure makes AppActivate fail in the aspect of putting the keyboard focus to the VFP IDE. But it does get it anyway. It's most likely nothing to worry about when you only need this to work for the _SCREEN of a compiled VFP project, not VFP itself.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top