C# monitor external process state - c#

I am making a launcher app in C# on windows. However the process isn't directly started by my C# application but it uses a url to start it e.g "steam://rungameid/xxxxxxx"
I need it to monitor a process by name (say XYZ.exe) in the following fashion:
Receive an event when XYZ.exe starts
Receive an event when XYZ.exe exits
I just want to minimise and restore the my C# application's form when the application is running and not running respectively
thanks

Make a timer (with your preferred timer method) and poll every 'n' milliseconds (find what's best for you... I'd say for minimizing/restoring from a game, 500 milliseconds could be a good start, but experiment), then you can use something like:
bool processRunning = false;
void timerTickMethod()
{
var procIsRunning = Process.GetProcessesByName("xyz.exe").Any();
if(procIsRunning && !processRunning)
ProcessIsStartedEvent(); // or directly minimize your app
else if(!procIsRuning && processRunning)
ProcessIsEndedEvent(); // or directly restore your app
processRunning = procIsRunning;
}
If you want to make sure it's your xyz.exe that is running, you can pass in the full path to GetProcessesByName (so that if there's other xyz.exe in your system, it won't confuse your app)
Update
I was writing from memory, so maybe GetProcessesByName only work for friendly names (with no exe, or path).
If that's the case (I haven't tried), and you need the full path you could do it like:
var procIsRunning = Process.GetProcesses().Any(x => x.MainModule.Filename == #"c:\your\full\path.exe");

Related

C# Monitor launch of an executable and do operation before the user an use it

I am writing a test app to monitor another windows application(s) and perform operations before the user is allowed to use them.
Background
We have users that can access computers and launch applications. For some of these applications, we want the user to fill a little form and then they would be allowed to use the application. At the same time, we want to keep track of the total run time of the application (i.e. how long the user has used the application).
The application that a user can run is not all 3rd party apps and we have no control over their "quality".
Current solution
Using this Code Project article and WMI, I created a monitoring app that keep track of the opening and closing of an application displays the form to be filled.
The problem
I am testing the monitoring app using Calculator.exe as an example. The monitoring detects correctly the launch and the close of the executable and we can kill the app if the user cancel the form that pops up. We can also write a log with the data from the form and the start and end time.
Unfortunately, the executable is not "bound" in any way to the app and we cannot prevent the user from simply ignore the monitoring app form and use the application they launched.
Possible solutions
kill the launched application, display the form and re-launch the application if the user submit all the info.
This solution would work, but some of the applications may not be happy to be abruptly killed.
Suspend the thread of the launched application using the solution described in this answer.
My doubt here is about suspending the thread. As mentioned above, we do not know how well are the 3rd party application written. Is there a risk of deadlocks?
Also in this case, killing the process might present an issue with some of the 3rd party applications
Change tactic: instead of monitoring the launch of an application, make a launcher and edit the registry key for the application to start the launcher instead of the application. This strategy is what I am leaning toward, but I still don't know how to launch the application from the launcher if I change the registry key.
Is there a better solution we are not contemplating?
If not, which of the 3 would be the "go-to"?
Thanks!
Your best option is to use windows hooks.
Using a hook you can monitor the system for certain types of events. such as an application being executed or intercepting clicks an a lot more.
You may also use event tracing for monitoring the execution and termination of application in windows.
here's an example taken from the link I just gave:
using Diagnostics.Tracing;
using Diagnostics.Tracing.Parsers;
using System;
using System.Diagnostics;
using System.IO;
namespace ProcessMonitor
{
/// <summary>
/// The main program monitors processes (and image loads) using ETW.
/// </summary>
class Program
{
/// <summary>
/// This is a demo of using TraceEvent to activate a 'real time' provider that is listening to
/// the MyEventSource above. Normally this event source would be in a differnet process, but
/// it also works if this process generate the evnets and I do that here for simplicity.
/// </summary>
static int Main(string[] args)
{
// Today you have to be Admin to turn on ETW events (anyone can write ETW events).
if (!(TraceEventSession.IsElevated() ?? false))
{
Console.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process.");
return -1;
}
// As mentioned below, sessions can outlive the process that created them. Thus you need a way of
// naming the session so that you can 'reconnect' to it from another process. This is what the name
// is for. It can be anything, but it should be descriptive and unique. If you expect mulitple versions
// of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix)
var sessionName = "ProessMonitorSession";
using (var session = new TraceEventSession(sessionName, null)) // the null second parameter means 'real time session'
{
// Note that sessions create a OS object (a session) that lives beyond the lifetime of the process
// that created it (like Filles), thus you have to be more careful about always cleaning them up.
// An importanty way you can do this is to set the 'StopOnDispose' property which will cause the session to
// stop (and thus the OS object will die) when the TraceEventSession dies. Because we used a 'using'
// statement, this means that any exception in the code below will clean up the OS object.
session.StopOnDispose = true;
// By default, if you hit Ctrl-C your .NET objects may not be disposed, so force it to. It is OK if dispose is called twice.
Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); };
// prepare to read from the session, connect the ETWTraceEventSource to the session
using (var source = new ETWTraceEventSource(sessionName, TraceEventSourceType.Session))
{
Action<TraceEvent> action = delegate(TraceEvent data)
{
// Console.WriteLine("GOT EVENT: " + data.ToString());
var taskName = data.TaskName;
if (taskName == "ProcessStart" || taskName == "ProcessStop")
{
string exe = (string) data.PayloadByName("ImageName");
string exeName = Path.GetFileNameWithoutExtension(exe);
int processId = (int) data.PayloadByName("ProcessID");
if (taskName == "ProcessStart")
{
int parentProcessId = (int)data.PayloadByName("ParentProcessID");
Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} ParentID: {4}",
data.TimeStamp, taskName, exeName, processId, parentProcessId);
}
else
{
int exitCode = (int) data.PayloadByName("ExitCode");
long cpuCycles = (long) data.PayloadByName("CPUCycleCount");
Console.WriteLine("{0:HH:mm:ss.fff}: {1,-12}: {2} ID: {3} EXIT: {4} CPU Cycles: {5:n0}",
data.TimeStamp, taskName, exeName, processId, exitCode, cpuCycles);
}
}
};
// Hook up the parser that knows about Any EventSources regsitered with windows. (e.g. the OS ones.
var registeredParser = new RegisteredTraceEventParser(source);
registeredParser.All += action;
// You can also simply use 'logman query providers' to find out the GUID yourself and wire it in.
var processProviderGuid = TraceEventSession.GetProviderByName("Microsoft-Windows-Kernel-Process");
if (processProviderGuid == Guid.Empty)
{
Console.WriteLine("Error could not find Microsoft-Windows-Kernel-Process etw provider.");
return -1;
}
// Using logman query providers Microsoft-Windows-Kernel-Process I get
// 0x0000000000000010 WINEVENT_KEYWORD_PROCESS
// 0x0000000000000020 WINEVENT_KEYWORD_THREAD
// 0x0000000000000040 WINEVENT_KEYWORD_IMAGE
// 0x0000000000000080 WINEVENT_KEYWORD_CPU_PRIORITY
// 0x0000000000000100 WINEVENT_KEYWORD_OTHER_PRIORITY
// 0x0000000000000200 WINEVENT_KEYWORD_PROCESS_FREEZE
// 0x8000000000000000 Microsoft-Windows-Kernel-Process/Analytic
// So 0x10 is WINEVENT_KEYWORD_PROCESS
session.EnableProvider(processProviderGuid, TraceEventLevel.Informational, 0x10);
Console.WriteLine("Starting Listening for events");
// go into a loop processing events can calling the callbacks. Because this is live data (not from a file)
// processing never completes by itself, but only because someone called 'source.Close()'.
source.Process();
Console.WriteLine();
Console.WriteLine("Stopping Listening for events");
}
}
return 0;
}
}
}
Have I missed something? The simplest solution seems to be not to launch the application until they have filled in your form.

Windows 8 taskmanager app history in C#

I am trying to access application history from C#. I would like to present same information as in task manager, but I cannot find api/example. Of course I implement a desktop application.
To specify problem: I am not interested on CPU/RAM. The only thing I would like to get is Time.
UPDATE
To exactly show what I am talking about look at this screen:
There is no supported way to get this information. Sorry.
The description of the questions lacks details that you are talking about Metro Apps. The solution would be an equivalent of Process.TotalProcessorTime but for Metro Apps.
Unfortunately, you cannot get that information because as you stated the applications are running within another process (WWAHost.exe). The design of Metro is a bit more like the phone - you can't directly manipulate the system in the same way. There isn't a directly "Process" in the Windows Runtime (see here), which in turn means the Process class wouldn't make sense to port...
I assume by The only thing I would like to get is Time. you mean the start and end time of each process
The best way will be that you will have to build that history your self. If you need the history only when your application is running then you just implement the code bellow otherwise if you wish to build the history for a certain period even when your application is down then try to create a Windows service that does the job for you. Following are the steps you need to do assuming you know how to create a windows service project, compile and install it:
Getting running processes info :
using System;
using System.Diagnostics;
public static class ProcessStart
{
Process[] runningProcesses;
var processesStartTimes = new Dictionary<int, Datetime>();
var processesExitTimes = new Dictionary<int, Datetime>();
static ProcessStart()
{
// This will get current running processes
runningProcesses = Process.GetProcesses();
foreach (var p in processes)
{
p.Exited += new EventHandler(ProcessExited);
processesStartTimes.Add(p.Id, p.StartTime);
}
}
private void ProcessExited(object sender, System.EventArgs e)
{
var p = (Process)sender;
processesExitTimes.Add(p.Id, p.ExitTime);
}
}
Getting new started processes
You need to create a new Timer object and run it every second checking for new created processes. I copied the code above and extended it :
public static class ProcessStart
{
Process[] runningProcesses;
var processesStartTimes = new Dictionary<int, Datetime>();
var processesExitTimes = new Dictionary<int, Datetime>();
var updateTimer = new Timer(1000);
static ProcessStart()
{
// This will get current running processes
runningProcesses = Process.GetProcesses();
foreach (var p in processes)
{
p.Exited += new EventHandler(ProcessExited);
processesStartTimes.Add(p.Id, p.StartTime);
}
updateTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
private void ProcessExited(object sender, System.EventArgs e)
{
var p = (Process)sender;
processesExitTimes.Add(p.Id, p.ExitTime);
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
runningProcesses = Process.GetProcesses();
foreach (var p in processes)
{
// This will only add the processes that are not added yet
if (!processesStartTimes.Keys.Contains(p.Id))
{
p.Exited += new EventHandler(ProcessExited);
processesStartTimes.Add(p.Id, p.StartTime);
}
}
}
}
Finally :
You just then need to play with the System.Diagnostics.Process class. That should be your best way for getting all information you need about windows processes. It will grant you access to a wide range of properties and methods. Here is the official MSDN lik for it:
Process Class
EDIT :
As I can see from your comment, you are interested in the time the CPU have spent running a specific process. The same System.Diagnostics.Process class contains that info as well. That can be found using the Process.PrivilegedProcessorTime property. The MSDN description for this property is :
A TimeSpan that indicates the amount of time that the process has spent running code inside the operating system core.
More information Here
EDIT 2:
The following 2 Properties could also give you probably what you need:
Process.UserProcessorTime : Here
A TimeSpan that indicates the amount of time that the associated process has spent running code inside the application portion of the process (not inside the operating system core).
Process.TotalProcessorTime : Here
A TimeSpan that indicates the amount of time that the associated process has spent utilizing the CPU. This value is the sum of the UserProcessorTime and the PrivilegedProcessorTime.
I've done some research on this, because I found it to be interesting how the metro apps integrate into the existing process structure.
As other people have pointed out here, it is not possible in a beautiful supported API way to get the info you want.
However, every app is launched as a different process and for processes there are known ways to get run time, cpu time etc.
If you find the correspondig process to your windows 8 app, you will be able to get the info you need.
Some apps are really easy to spot. They are just a executable like any other desktop application with a proper processname and description.
For example in this picture "Map", "Windows Reader" and "Microsoft Camera Application":
Some other apps are a bit harder to spot. They are hosted in a process that is launched by the wwahost.exe executabe. I could only spot the app name by looking at the module list.
This is the Bing app:
To enumerate the modules and mapped files from a process you can use the WinAPIs VirtualQueryEx and GetMappedFileName.
Then you want to look for files that are located at %programfiles%\WindowsApps. This is the folder where windows saves all the application files for it's apps.
Every app has a .pri file. This file contains binary metadata of the application. You could use it to find the name of the app from the process that is hosting it. In the same folder with the .pri file there is a AppxManifest.xml in which you could find all kinds of additional information about the app.
I will try to summarize my writing a bit:
enumerate processes with WinAPI and get all infos you need (run time, cpu time, etc).
enumerate mapped files of each process and look for ressources.pri. The directory where this file is located has the app name in it.
as bonus read the AppxManifest.xml file for additional info on the app. You might need Administrator privilege or additional privileges to read this file.

Don't display wait cursor when console app is launching

I've developed a small console application that essentially pings a url, records the result, restarts the phone if required and then schedules itself to run again.
The client is complaining about the "washing machine" icon being displayed (albeit for less than a second) every time the application launches.
I'm hiding the wait cursor in the first line of my main method but is there any way of preventing the wait cursor from displaying at all?
static void Main()
{
//Hide cursor
IntPtr hOldCursor = SetCursor(IntPtr.Zero);
//Ensure EventLog table is ready
PrepareDatabase();
tapi = new Tapi();
tapi.TAPI_Open();
//Ping specified URL and restart phone if required.
PingRestart();
tapi.TAPI_Close();
//Set the application to run again after the ping interval has passed
SystemTime systemTime = new SystemTime(DateTime.Now.AddMilliseconds(RegistryAccess.PingInterval));
CeRunAppAtTime(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase, ref systemTime);
}
There is no way to disable the wait cursor, as it appears before the application runs so the application can't block it.
The only way is to code it in C or Assembly, as those languages start up very fast in comparison to .NET executables. But still, an AntiVirus program could block it for a while before it executes.

Execute process/program silently

I am creating a wpf application that needs a prerequisite. If that prerequisites is not met then I ask the user if he will like to install the prerequisite that happens to be: Microsoft Visual C++ 2010 SP1 Redistributable Package.
So if the user chose to install the prerequisite I will execute vcredist_x86.exe (that is the file that get's downloaded from the first link that I provided).
Then on my application I will be able to tell when the installation is complete by doing something like:
ProcessStartInfo psi = new ProcessStartInfo(#"vcredist_x86.exe");
var p = new Process(); p.StartInfo = psi;
p.Start(); //start the process
p.WaitForExit(); // wait for the installation to finish
// installation should be done now
Ok everything works great so far. The problem is that I have a progress bar in my wpf application and I will like to show the progress in there.
I have been able to show the progress of the installation by doing the following:
There is a program called AutoIt that it is great for automating simple tasks. For example I can easily detect if a window exists with autoit by using something like:
I could then compile that script and create a very small executable. In that executable I will return 1 if the specified window exists or 0 otherwise.
When the user moves to the next window my script might return 2 because that is a different window. AutoIt can also see the progress of a progress bar of a window!!! so if that script returns 80 for example then I will update my progress to 80% for instance.
I do that by doing something like:
// start the autoitExecutable....
// wait for executable to exit usually takes 10 miliseconds it is fast
if (autoitProcess.ExitCode == 1)
{
// do somthing
}else if(autoitProcess.ExitCode == 2)
{
// do something else
} //etc....
As you can see I have to execute that script every 1 second to detect what changes have been done in order to update my progress bar in WPF. That works but every time I execute that executable with c# I get the:
cursor for about 500 milliseconds then on the next second it appears again. That becomes annoying even though no windows show up. It will be nice if I could get rid of that cursor and execute that executable silently somehow. when I execute the autoit executable there are no windows that show up nor nothing else.
P.S.
I know I could use c# to check for the existance of a window and maybe see the value of other window's handler's just like autoit is able to do it but it is so simple to create those programs with AutoIt and it will be nice if I could use AutoIt instead of C# for this kind of taks
I saw this behavior when the exe was set to "windows application" rather than "console application".
Changing the type to console no longer gives a busy cursor at launch.
You could add an event handler as well for example
System.Diagnostics.ProcessStartInfo p = new
System.Diagnostics.ProcessStartInfo(#"vcredist_x86.exe") ;
p.Arguments="-RunForever";
proc = new System.Diagnostics.Process();
proc.StartInfo = p;
proc.EnableRaisingEvents = true;
proc.Exited += new EventHandler(myProcess_Exited);
proc.Start();
inside the event if I wanted to do something like this
// Inside the form class:
private System.Diagnostics.Process proc;
private void myProcess_Exited(object sender, System.EventArgs e)
{
button3.BackColor=Color.LightGreen; //success indicator
}
if you wanted to do this in a While Loop you could also do something like this for example
but you would have to change the params to fit your case
example code you can utilize
while(!autoitProcess.WaitForExit(someTimeout))
{
if(ShouldCancel)
{
break;
}
}
does this make sense or help out...?

How to programmatically detect when the OS (Windows) is waking up or going to sleep

Background
My son likes to use his laptop when he's not supposed to and I just thought it would be handy if I could write an application that would email me whenever he opened / closed his laptop.
(I'd even settle for something that notified me when there was network traffic on the machine)
Question
How do you programmatically detect when an OS is waking up or going to sleep? I found this link from this related post. But that covers OS X. I'm looking for the same thing for Windows 7.
(I'd like to do this in Java, if possible, but I'd settle for C#/C++)
Easiest way is not to write any code at all, even though this is stack overflow. Click Start, type Schedule and choose Scheduled Tasks. Set one up (click Create Task) and set a Trigger when the machine is unlocked. For the Action, have it send you an email.
Repeat for startup and when a user logs in, if you want. Done.
You're going to want to create a window and watch for the WM_POWERBROADCAST message (http://msdn.microsoft.com/en-us/library/aa373248%28v=vs.85%29.aspx) and check the wParam for your desired action. For example, your window should receive a WM_POWERBROADCAST with PBT_APMSUSPEND as the wParam when the system is about to enter a suspended state (i.e. closing a laptop). Resuming seems to have a few different wParam values: PBT_APMRESUMESUSPEND, PBT_APMRESUMECRITICAL and PBT_APMRESUMEAUTOMATIC
I search for a long time and found that this was the best way, the 'Sleep'-event was never working before:
private ManagementEventWatcher managementEventWatcher;
private readonly Dictionary<string, string> powerValues = new Dictionary<string, string>
{
{"4", "Entering Suspend"},
{"7", "Resume from Suspend"},
{"10", "Power Status Change"},
{"11", "OEM Event"},
{"18", "Resume Automatic"}
};
public void InitPowerEvents()
{
var q = new WqlEventQuery();
var scope = new ManagementScope("root\\CIMV2");
q.EventClassName = "Win32_PowerManagementEvent";
managementEventWatcher = new ManagementEventWatcher(scope, q);
managementEventWatcher.EventArrived += PowerEventArrive;
managementEventWatcher.Start();
}
private void PowerEventArrive(object sender, EventArrivedEventArgs e)
{
foreach (PropertyData pd in e.NewEvent.Properties)
{
if (pd == null || pd.Value == null) continue;
var name = powerValues.ContainsKey(pd.Value.ToString())
? powerValues[pd.Value.ToString()]
: pd.Value.ToString();
Console.WriteLine("PowerEvent:"+name);
}
}
public void Stop()
{
managementEventWatcher.Stop();
}
A very simple, perhaps crude, but effective way may be to have a program with a timer firing every minute. If the timer fires and it's been, say, 5 minutes of real time since its last execution then you can likely assume that the computer was sleeping since it's unlikely that your thread was unable to be scheduled for so long.
The other reason for the difference may be a clock adjustment, like DST or a manual change, but that kind of "noise" should be very low, in your scenario.
You could write a simple app and register it as a Windows service, to be started automatically at system startup. This app could then do whatever you want when it starts. And if it's a proper Windows app, it can register to get notification about impending system shutdown too (I don't remember the details but I implemented this in a C++ MFC app many years ago).
If you prefer Java, you could register your app as a service via a suitable service wrapper like Tanuki (it seems they have a free Community License option). Although this might be overkill. And it may be possible to get notification about the JVM shutting down when the system is closing (but I have no concrete experience with this).
http://www.pinvoke.net/default.aspx/powrprof.CallNtPowerInformation - Check out the link. It has almost all win32api for all windows function. You can call power management feature directly in your windows 7 laptop. For that create a Windows Service , that will use these specific api to notify the machine state.

Categories

Resources