Process.Kill() is causing fatal error in Winform application - c#

today I want to open application inside of form, but it cause error.
if (File.Exists(ts3))
{
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);
}
foreach (var process in Process.GetProcessesByName(ts3check))
{
process.Kill();
}
Thread.Sleep(500);
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);
It should check, if this app is already openned, if it is, kill it and open new one inside of my form. But when I try to open process in form, it will cause fatal error and makes my form stopped working. I'm looking at it for like half a hour and I can't see it.
EDIT: app works if app is not already openned, but if it is, it will execute this part of code and make the error
foreach (var process in Process.GetProcessesByName(ts3check))
{
process.Kill();
}
Thread.Sleep(500);
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);

Try changing Thread.Sleep(2000) to p.WaitForInputIdle() and you might also want to take a look at Hosting EXE Applications in a WinForm project over at CodeProject; someone has created a control to do exactly what you're looking for.

Related

How to open "Microsoft Edge" from c# and wait for it to be closed?

I'm building a Windows Form application and I want to open "Microsoft Edge" through my app with a specific URL and wait until the user closes the Edge Window.
I tried it with this code:
using (Process p = Process.Start("microsoft-edge:www.mysite.com"))
{
p.WaitForExit();
}
When I execute this code, Edge is launching with the correct URL ... but got a null object reference. The "p" object that I'm getting from Process.Start is null.
I think it's related to the reuse of Windows application.
Does anyone have a workaround/have an idea how I can wait for the user to close Edge?
Finally I did managed to do so:
When you launch Edge (at least) two process get created:
MicrosoftEdge and MicrosoftEdgeCP.
MicrosoftEdgeCP - foreach tab. So we can "wait" on this new tab process that was just created.
//Edge process is "recycled", therefore no new process is returned.
Process.Start("microsoft-edge:www.mysite.com");
//We need to find the most recent MicrosoftEdgeCP process that is active
Process[] edgeProcessList = Process.GetProcessesByName("MicrosoftEdgeCP");
Process newestEdgeProcess = null;
foreach (Process theprocess in edgeProcessList)
{
if (newestEdgeProcess == null || theprocess.StartTime > newestEdgeProcess.StartTime)
{
newestEdgeProcess = theprocess;
}
}
newestEdgeProcess.WaitForExit();
From an older solution - use a WebBrowser control to load the HTML. Once you get the data back, use an ObjectForScripting to call a c# method to notify when done.
See http://www.codeproject.com/Tips/130267/Call-a-C-Method-From-JavaScript-Hosted-in-a-WebBrowser

Restart WPF application: wait untill new process is loaded before exiting the current process

Im working on a wpf application using blend 4.
under certain conditions, i need to restart the app.
Im currently using the following code:
System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
System.Threading.Thread.Sleep(1000);
Application.Current.Shutdown();
which works.
My problem is that the current instance closes before the new one is loaded, making it look like the program crashed. I used the thread.sleep to stall the shutdoen, but the timing is different.
Is there any way to wait for the new process to start before shutting down the current one?
something along the lines of:
System.Diagnostics.Process.Start(Application.ResourceAssembly.Location);
if (newProcess.IsLoaded == true)
{
Application.Current.Shutdown();
}
Edit:
The context of this being when settings are changed, i need to restart the application to apply the changes, and I would use a splash screen to say (applying new settings please wait) and this would display until the new process is loaded
What about that: Pass old process id as a start parameter to new instance and let new instance to kill old one when it's loaded.
Use Process.GetCurrentProcess method to read old instance pid. Pass the parameter to new instance using Arguments property in ProcessStartInfo. Then use Process.GetProcessById in new instance to get and kill old instance when the argument is passed.
Simply call WaitForInputIdle on the newly created Process:
Process p = Process.Start(...);
p.WaitForInputIdle();
Application.Current.MainWindow.Close(); // perhaps better than Shutdown
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Process[] myProcess = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
foreach (Process process in myProcess)
{
if (process.Id != Process.GetCurrentProcess().Id)
{
process.Kill();
}
}
}

Verify that another application is always running

I'm trying to make a console app in c# that will confirm that another application is always running. The other application periodically crashes, and I need to check every few minutes and relaunch it if it has stopped working.
There are many questions on SO that address making sure than no more than one instance of the application is running. I'm trying to confirm that one (no more or less) is running at all times.
Does anybody know how to even begin approaching this?
I would suggest using System.Diagnostics.Process.GetProcessesByName to see if your process is running and then, if not, using System.Diagnostics.Process.Start to start the process.
var processes = Process.GetProcessesByName("yourProcessName");
if(processes.Length == 0)
{
Process.Start(#"C:\Path\To\Your\Process.exe");
}
// Kill the extras
for(int i = 1; i < process.Length; i++)
{
processes[i].Kill();
}
These commands are useful to control processes:
// check for processes
Process[] processes = Process.GetProcessesByName("nameOfExecutable");
foreach (Process proc in processes)
{
// do stuff
}
// start process (need path)
Process.Start("pathToExecutable");
// close gui process gently (if needed)
bool status = proc.CloseMainWindow();
// wait for process to close gently
bool status = proc.WaitForExit(killTimeMS);
// force close (kill) process
proc.Kill();
If you implement a "no more than one" rule (which is well-documented, as you point out) and then implement the periodic crash-checker, that should be sufficient to ensure that one and only one copy is running.
In fact, the periodic process doesn't even have to check for a crash. It can just fire up an instance, which will immediately exit if another instance is already running, thanks to whatever "no more than one" mechanism you implement. This has the added benefit of avoiding a possible race-condition between detecting a dead process and starting a new one.
You have a few options. The first is checking for a running process using the Process class. I got this from a Microsoft site, but it looks like it works:
public bool IsProcessRunning(string name)
{
//here we're going to get a list of all running processes on
//the computer
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.StartsWith(name))
{
//process found so it's running so return true
return true;
}
}
//process not found, return false
return false;
}
You could also use interprocess communications. This is something we do in house. We have a watcher application that sends a message to a service being monitored. If the service doesn't return an ACK in a timeout period, we attempt to restart it.
I suggest you to check if your application is in the list of running processes:
System.Diagnostics.Process.GetProcesses();

C#/.NET: Closing another process outside the main window

I just wanna ask your opinion/suggestion on how to 'terminate' a running application/process is C#
Right now, I do have the following codes:
Process myProcess;
private void btnOpen_Click(object sender, RoutedEventArgs e)
{
DirectoryInfo di = new DirectoryInfo(System.Environment.GetFolderPath(Environment.SpecialFolder.Programs));
myProcess = Process.Start(di + #"\Wosk\Wosk.appref-ms"); // opening a file coming for Startup Menu
}
private void btnClose_Click(object sender, RoutedEventArgs e)
{
myProcess.Kill(); // not working - Cannot process request because the process has exited
}
I also tried myProcess.Close(); but nothing's happening.
You should have a look at
Process.HasExited Property
A process can terminate independently
of your code. If you started the
process using this component, the
system updates the value of HasExited
automatically, even if the associated
process exits independently.
Based on your comment it looks like the Process instance has already exited when you hit the close button. This can happen at any time and it's something you need to guard against. The easiest way is to simply catch the exception that results from calling Kill on an already exited process.
try {
myProcess.Kill();
} catch ( InvalidOperationException ) {
// Process is already finished so nothing to do
}
You are starting a program that was installed with ClickOnce. The .appref-ms is executed by a helper program, rundll32.exe, that starts the process and quickly exits. To terminate the started process, you'll need to find the actual running .exe with Process.GetProcessesByName() and use the Kill method.
We can't tell you what the process name is, that's contained in the .appref-ms file. But it is easy for you to see with TaskMgr.exe.
Process[] islemler = Process.GetProcessesByName("osk");
foreach (Process islem in islemler)
islem.Kill();
First please replace:
di + #"\Wosk\Wosk.appref-ms"
with:
Path.Combine(di.FullName, #"Wosk\Wosk.appref-ms")
Now to the point: I don't know what Wosk.appref-ms is or how this process is started. If this is a file it will be opened with the default program associated with this file extension. The problem could be related to the fact that the process you start only starts another process and terminates immediately. That's why when you try to kill it it says that it has already exited, but the actual process it spawned is still running. In this case you will have to enumerate through the running processes with Process.GetProcesses(), find the process and stop it.

programmatically kill a process in vista/windows 7 in C#

I want to kill a process programmatically in vista/windows 7 (I'm not sure if there's significant problems in the implementation of the UAC between the two to make a difference).
Right now, my code looks like:
if(killProcess){
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
myProcess = System.Diagnostics.Process.Start(psi);
}
I have to do this because I need to make sure that if the user crashes the program or exits abruptly, this secondary process is restarted when the application is restarted, or if the user wants to change the parameters for this secondary process.
The code works fine in XP, but fails in Windows 7 (and I assume in Vista) with an 'access is denied' message. From what the Almighty Google has told me, I need to run my killing program as administrator to get around this problem, but that's just weak sauce. The other potential answer is to use LinkDemand, but I don't understand the msdn page for LinkDemand as it pertains to processes.
I could move the code into a thread, but that has a whole host of other difficulties inherent to it that I really don't want to discover.
You are correct in that it's because you don't have administrative priveleges. You can solve this by installing a service under the local system user and running a custom command against it as needed.
In your windows form app:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "SERVICE_NAME");
scp.Assert();
System.ServiceProcess.ServiceController serviceCon = new System.ServiceProcess.ServiceController("SERVICE_NAME", Environment.MachineName);
serviceCon.ExecuteCommand((int)SimpleServiceCustomCommands.KillProcess);
myProcess = System.Diagnostics.Process.Start(psi);
In your service:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
protected override void OnCustomCommand(int command)
{
switch (command)
{
case (int)SimpleServiceCustomCommands.KillProcess:
if(killProcess)
{
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
}
break;
default:
break;
}
}
I'll add the code for Simon Buchan's suggestion. It makes sense and should work as well, assuming your windows form is what launched the process in the first place.
Here's where you create the process. Notice the variable myProc. That's your handle on it:
System.Diagnostics.Process myProc = new System.Diagnostics.Process();
myProc.EnableRaisingEvents=false;
myProc.StartInfo.FileName="PATH_TO_EXE";
myProc.Start();
Later, just kill it with:
myProc.Kill();

Categories

Resources