Good news,
If you aiim for using a separate VFP built EXE as background process, without or even with a form diplaysing, here's the solution to that not taking away the foreground process and foeground form state of the app using this background process. Here's just the main.prg of a project you compile as an EXE, say background.exe:
Code:
* Compile as EXE and use as OLE public COM server
* Direct start of the EXE will do nothing and end immediately.
Define Class Process as Session Olepublic
Procedure Init()
Public goApp
goApp = This
This.AddProperty("Self",JustFname(_vfp.ServerName))
This.Main()
* usually here goes a READ EVENTS, but
* it's not possible to read events here, as we need to
* return to the session starting and using this OLEpublic
* COM server class, so we let a timer call read events
* after we returned:
CreateAnyonymousPublicObject('AsyncCommand',['goApp.Readevents()'])
EndProc
Procedure Main()
* just for example:
* -------------------------------------------------------------
* -------------------------------------------------------------
* +++ ATTENTION +++
*
* "Batteries not included". This is just an example,
* Code of backgroundmain.scx is not included.
*
* +++ ATTENTION +++
* -------------------------------------------------------------
* -------------------------------------------------------------
Do Form backgroundmain.scx
* Requirements of backgroundmain.scx are:
* -non-modal form
* -top level form.
*
* An in-screen form is possible but is in-screen of a new _Screen,
* which can be shown by _Screen.visble = .T.
* Just notice this form is not part of the forms of the calling
* application, the COM server is its own new process!
*
* DON'T INCLUDE READ EVENTS here!
* don't include read events or any code after it.
* There's the ReadEvents() method and the Destroy() for that.
* The Init() will care to both return from Init() and yet run
* the read events of the new OLE process
EndProc
Procedure ReadEvents()
Read Events
EndProc
Procedure Quit()
Release This
EndProc
Procedure Destroy()
Clear Events
Quit
EndProc
EndDefine
Define Class AsyncCommand as Timer
Interval = 1
cCommand = ''
Procedure Init(tcCommand)
This.cCommand = tcCommand
Endproc
Procedure Timer()
Local lcCommand
lcCommand = This.cCommand
This.Enabled = .F.
* self release:
Release This
* This will still execute as last line of code
* of this timer method, as the release just hits
* when nothing remains on the callstack, i.e.
* after the current method ends:
&lcCommand
EndProc
EndDefine
Procedure CreateAnyonymousPublicObject(tcClass, tcParams)
_Screen.AddObject(Sys(2015), tcClass, &tcParams)
EndProc
See comments, you need to add a backgroundmain.scx or change the Main() method to whatever else. Just note: If that takes long in itself, it won't be good. The Init needs to end and return quick or else it will not feel like it's doing what it mainly should do in the background. The Junction is done by the timer, that does it's command - calling the ReadEvents method, after Main returned to Init() and Init() returns to the CreateObject call.
When this code is saved as the main.prg of a new background.pjx and is compiled as EXE with administrative elevation of the VFP9.exe you don't just get background.exe but also background.tlb and background.vbr, as it's a COM server.
Usage of this is not by Shellexecute or run, but - giving the name of the exe is background.exe and the class is named Process, create it by CREATEOBJECT("Background.Process").
For sake of testing just do an empty top level non-modal backgroundmain.scx form and you'll see the Background.Process will start and show (as long as what stores the object reference doesn't release). While the ReadEvents() method keeps the form and the COM object from ending, too, releasing the object you create by CREATEOBJECT("Background.Process") causes the Destroy() and thus the CLEAR EVENTS and QUIT. You may now do more with the form code, you can also add something to the ReadEvents method before the READ EVENTS line or instead of it. It will be executed really in parallel to who- or whatever creates this object and when the ReadEvents method ends by calling This.Quit() instead of doing READ EVENTS it would also work as a shoot off process that, for example sends a list of mails and then ends.
It's surely not beginner material and if you found this thread to start a form behind another simply in z-order, there are much easier ways without a separate EXE, this is not intended for you.
I'm still looking into starting any other EXE and keeping foreground process state, as this just solves the case the background process is your own VPF creation. It's also not easy to understand and extend.
Chriss