Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I recently built an .exe that needs to stay open. (Or re-open after crashed) I have decided to make a watchdog program to restart it when it is closed/crashes. If I can create the watchdog program to work, how would I use a function like this to make my watchdog (which would be a windows service) able to start an executable in the session of the user logged on?
Edit:
Actually, if they don't do the same thing as a fork bomb, would having two vbs scripts doing something like this work?
Set WshShell = WScript.CreateObject("WScript.Shell")
Do
WshShell.Run "c:\somefolder\script1.vbs", 1, true
Loop
along with this script
Set WshShell = WScript.CreateObject("WScript.Shell")
Do
WshShell.Run "c:\somefolder\script2.vbs", 1, true
WshShell.Run "c:\somefolder\program.exe", 1, true
Loop
Okay. The two VBS scripts work really well. I have a question about VBS, but I'll ask that as its own question.
Also the reason people ask questions like yours is often because they don't like the console window.
This vbs script starts the console window hidden.
Set WshShell = WScript.CreateObject("WScript.Shell")
msgbox FormatNumber(WshShell.Run("cmd /k dir c:\windows\*.*", 0, false))
Also your batch file consumes much system resources incl battery life.
Try
:Start
c:\somefolder\program.exe
Goto Start
This starts your program, does nothing till it exits, then starts it.
That can be done in vbscript or vb6 (or vb.net by adding a couple of brackets).
Set WshShell = WScript.CreateObject("WScript.Shell")
Do
WshShell.Run "c:\somefolder\program.exe", 1, true
Loop
OR this which waits for an event.
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2")
Set objEvents = objWMIService.ExecNotificationQuery ("SELECT * FROM Win32_ProcessStopTrace")
Do
Set objReceivedEvent = objEvents.NextEvent
If lcase(objReceivedEvent.ProcessName) = lcase("Notepad.exe") then
Msgbox "Process exited with exit code " & objReceivedEvent.ExitStatus
WshShell.Run "c:\Windows\notepad.exe", 1, false
End If
Loop
In the run method. 0 is hidden and true/false is wait for program to exit.
EDIT
The WMI one may look like it's event driven, which it is. But WMI uses polling (appears to be 1 sec). So it has the same resource problems as the first batch file. All you do is move the blame from your program to WMI.
Edit 1
All my scripts I posted do what you want. You only need 1 script not 2. In the looping ones it waits for program to exit then continues. None of the scripts exit. They just keep waiting until your program stops running, then restarts it and waits till it stops again.
I would go the route of having a service process monitor for your primary application. And if it isn't running, then starts it in the desktop session of the current user.
See this msdn blog for some details about doing that.
You will also need to think about what the behavior should be when there isn't somebody logged on, or when multiple people are logged on.
Application Recovery and Restart.
Application Recovery and Restart
Applications have the opportunity to control what actions are taken on their behalf by the system when they fail.
If the application calls the RegisterApplicationRecoveryCallback function, the system executes the recovery callback on application failure. The application can attempt to recover documents. If the application has not registered for recovery, the system still attempts to diagnose and report the problem.
If the application calls the RegisterApplicationRestart function, the system restarts the application after the recovery or diagnosis is completed. If the application has not registered for restart, the system closes the application.
From Help.
Related
the Program entry point function is WinMain
and it doesn't create a Window so it runs in the background.
I want to get a notification when the program is closed like: by the user through task manager or through system shutdown so I can save some progress.
something like the windows messages WM_QUITE but I can't access that as far as I know cuz i don't create a window
If there is no window, you may consider modifying the program registration as a DLL service plug-in.
The service also has no window and executes in the background.
The process is closed. Only the kernel callback knows that a process is killed. There will be no event whether the R3 process is closed.
Unless you have another process intermittently scanning the process list continuously.
Registering as a service at least you can receive event callbacks when your service is stopped by others.
CreateServiceW
https://learn.microsoft.com/zh-cn/windows/win32/services/installing-a-service
Is the background program something that your own code started, using CreateProcess()? If so, you can use the process handle (hProcess in the PROCESS_INFORMATION structure) in functions like WaitForSingleObject() etc. to check if the process still runs.
So I have been working on a project to mess around with some of my coding friends. I am trying to make an AppleScript application that tells Chrome to go back a page when run and I want it to run all the time. I have had to base it off of whether or not chrome has an active window open or not, I managed to get it to work so far but when I put in the repeated "Go back" command it comes up with an error message saying can't get window 1.
This is the code I am using. I am using High Sierra if that makes a difference.
repeat
if application "Google Chrome" is running then
repeat
tell application "Google Chrome"
if exists (window 1 of application "Google Chrome") then
repeat while exists (window 1 of application "Google Chrome")
go back tab of window 1
end repeat
end if
end tell
end repeat
end if
end repeat
No. This is not how to implement a stay-open script. Doing endless repeat loops with no means of exiting them is just going to devour system resources and make Google Chrome unusable until the script is forced to quit.
Also, the code is horrific: lots of redundant statements and confusing syntax.
You would better achieve your aim by creating what is called a stay-open application script, which will use the idle handler to process commands every few seconds or so. As the name implies, the script will stay open and execute the commands until you tell it to quit.
Start by declaring a property that determines how often the idle handler is called. This is defined at the bottom, following a run handler, which executes upon running of the script and calls the idle handler.
property idleTime : 20 --seconds
on run
idle
end run
on idle
tell application "Google Chrome"
if it is not running then return idleTime
tell window 1 to if it exists then ¬
tell its active tab
if its URL contains "disney" then ¬
tell me to quit
set its URL to "chrome://newtab/"
end tell
end tell
return idleTime
end idle
I slightly modified the joke you're pulling on your friends, because go back will only work so many times before you reach the end of the history and there's no further back one can go. Instead, I told the tab to load up the New Tab starting page every 20 seconds, which I'm sure will be very confusing for the user.
In order to get it up and running properly, you need to save the script as an Application, and check the box that marks it as a stay open script. Then simply double click to run it.
There are two ways to terminate this script: ① Open Activity Monitor and terminate its process from the list of running processes; or ② Visit Disney.com (or any Disney website) in Chrome and wait 20 seconds.
Simply save this code as a stay open application.
on idle
tell application "Google Chrome"
if it is not running then return 10 -- seconds to wait before repeating
tell window 1 to if it exists then ¬
try
go back active tab
end try
end tell
return 10 -- seconds to wait before repeating
end idle
I have a program (runs as a background process) in which I installed a hook to capture EVENT_SYSTEM_FOREGROUND events (i.e - when the user switches between windows). The callback which is registered for the hook basically logs what application (process exe filename) the user has switched from and which they have switched to.
I want to add some code to check if the application they have switched from is still active (if not we assume they have closed it and that is what has brought a new window into the foreground). I am testing for it's existence by trying to create a handle to the previous PID using OpenProcess
//Check prev pid still exists - if not, assume the previous app has been closed
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
if (hPrevProc==NULL){
prevProcStillRunning=false;
}
else{
CloseHandle(hPrevProc);
}
Assumptions with the code above:
g_prevPid is populated with a PID - I have verified this
prevProcStillRunning has been initialized to true
The problem with the code above is that for some reason, even when the user has exited an app (say notepad.exe for example). For up to 10 seconds after they have exited, this test still passes (i.e - hPrevProc gets initialised). Even though I can see in the task manager that the Notepad.exe process has dissapeared (and yes I only have one instance of it opened), somehow, the OpenProcess line still can get a handle on that PID. I am guessing that somehow the PID actually still exists but it may be in a state where its terminating. I have found that if this code is called a few more times, eventually it will return null.
I would like to find out a better way I can test whether hPrevProc is still acitive.
I tried to test this using the GetExitCodeProcess function but this seems to just give me the PID and I'm not even sure if that's the right approach in any case.
Any help appreciated.
The process subsists in the system after it terminates at least while there is an open handle to it.
The only foolproof method to know whether a process is still active is:
make sure the process cannot exit with code STILL_ACTIVE (259)
try to open the process (OpenProcess)-> if you cannot is is terminated
read the exit process code (GetExitCodeProcess) -> if it is not STILL_ACTIVE the process is terminated.
You code could become:
//Check prev pid still exists - if not, assume the previous app has been closed
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
if (hPrevProc==NULL){
prevProcStillRunning=false;
}
else{
DWORD cr;
if ((GetExitCodeProcess(hPrevProc, &cr) == 0) || (cr != STILL_ACTIVE)) {
prevProcStillRunning=false;
}
CloseHandle(hPrevProc);
}
Anyway, closing a GUI application involves different steps:
the GUI elements are destroyed
the message loop ends
eventually the application could do background operations (save state to file, etc.)
the main procedure returns an exit code
the system knows that the application is terminated
The event will be sent as soon as the main window will be closed, which can happen some time before the application actually stops. A good example for that is Firefox. If you close the window and immediately try to start a new process, you will get an error because even if the UI is gone, the process is not still terminated. What is worse, is that you can find applications that simply go into background when you close the UI, and allow user to open UI again through an action on an icon in the status area of the taskbar (Shell_NotifyIcon and its callback). This is common for services of other application working in background (network servers, firewalls, etc.). In that case, the UI is gone but the process will not terminate.
TL/DR: the time between the disparition of the UI and the termination of the process owning it is variable and depends on the system load and the background activity of the process after closing the UI. You can try to use a delay for that but I cannon guarantee anything about it...
Probably some process (maybe yours?) still holds a valid handle to this process. Until CloseHandle was called on all handles, system maintains internal record which allow to access its process data. This is important because as you say it must be possible to call GetExitCodeProcess on closed process, also someone might want to wait for it to stop with WaitForSingleObject.
Also be carefull with PIDs, they can be reused - so in theory you might call OpenProcess on some other newly opened process.
As for checking if given process is not a zombie, you might try enumerating top level windows with EnumWindows, and checking if any of them is associated with given PID (to get window's PID use GetWindowThreadProcessID).
I've written a C application that grabs some sensor data and puts it into a string. This string gets passed to gammu-smsd-inject for transmission by SMSD. For reference, my application launches gammu-smsd-inject using fork() & wait(). The program waits for gammu-smsd-inject to terminate and then exits itself.
My program works just fine: if I run it manually from a bash prompt it grabs the sensor data, calls gammu-smsd-inject and quits. The sms appears in the database outbox and shortly after I receive an sms on my phone.
I've added the absolute path to my program into the runonreceive directive of SMSD. When I send a text to SMSD, it is received in the inbox and from the log file I can see the daemon running my program. The logfile then states that the process (my program) successfully exited (0), but I never receive any sms and nothing is added to the database's outbox or sentitems tables.
Any idea what might be going on? I haven't posted a code listing as it's quite long,but it is available.
The only think I could think of that might be happening is that gammu-smsd-inject is perhaps being terminated (by a parent process somewhere up the tree) BEFORE it gets a chance to do any SQL stuff. Wouldn't this create a non zero exit code though?
So the problem was which user was running the program. When I ran my application manually from bash, it launch it with my user ID, but when the SMSD daemon ran it, it was launched with a different ID which was causing issues for some reason. I thought it was a problem with the user ID being used to access the mysql database, but apparently not. In short, I don't actually know what the problem was, but by assigning my login's UID to the child process, everything suddenly worked.
Is it possible to create a windows service to create and maintain another process? Like I'm writing a program, and say a virus killed the process, could I have my window service running and basically 'watching' it? I already have the code for a regular application that stays running and executes a program if it's not currently running, to keep it running.
I've never written a service before, but would it be that hard to just write this simple program, which basically runs a check to see if the process is running, if not, it executes it and sleeps for a few minutes?
Thanks.
Yes, it is possible. It is not uncommon to see third-party apps have watchdog services to keep them running in case of crashes. A service can enumerate running processes using EnumProcesses(), and if the desired executable is not running then start a new copy of it using CreateProcessAsUser().
If the service is the one starting the executable process in the first place, or can find it after an enumeration, one optimization would be to keep an open handle to the process (returned by CreateProcess...(), or use OpenProcess() on the process ID an enumeration returns), and then use a wait function, like WaitForSingleObject(), to detect when the process stops running. That way, you don't have to enumerate processes to find out if the intended process is still running or not.