I face to a problem that my customer is already running the application appA. Then they go to desktop (not kill the appA), and upgrade the application with the version up by run appA.ps1 with PowerShell. After that, click on appA after installed -> get an exception. I guess the root cause is that have another instance is running.
My question is how can I check my application is already running? Can I kill it?
Additional, my application is windows 8 store, c#.
If you wand to keep your current instance running and kill all other instances of your application, you can do this:
using namespace System.Diagnostics;
...
// get current process
Process current = Process.GetCurrentProcess();
// get all the processes with currnent process name
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
//Ignore the current process
if (process.Id != current.Id)
{
process.Kill();
}
}
From Social MSDN:
All the Metro-style applications work in the highly sandboxed environment and there is no way to directly start an external application.
You cannot access windows app processes. Unfortunately, you aren't able to check for running windows apps.
I didn't find another way so far.
No Metro-style application
At first, you need the processes:
var processes = Process.GetProcessesByName("your application name")
To check whether your program is already running:
var isRunning = processes.Length > 1;
Then you loop through them and close the processes:
foreach (var process in processes)
{
process.CloseMainWindow();
// OR more aggressive:
process.Kill();
}
Related
I use ClikOnce for installation my application. But, when application is running and you try to delete it, ClickOnce says that application was deleted, but program is still running.
I know it will be deleted after reboot. But, my program can be autostarted. Therefore, it won't be deleted.
So, how can I force ClickOnce to close the application?
Try this one:
foreach (Process prog in Process.GetProcessesByName("MSACCESS")) {
if (prog.ProcessName == "MSACCESS") {
prog.Kill();
}
}
You need to change "MSACCESS" with your own application proccess name.
I have a windows service that I would like to be automatically and silently updated. I started using wyBuild to implement this, but have had some issues with it, and decided to try to build my own. I've written a standalone exe that can be called to do the update procedure: checks for a new zip file with the update, downloads it, unzips, stop the windows service, copy files from the zip, then restart the service. This exe works fine when I run it from the commandline and wasn't really difficult to write.
However, now I would like the service (the same one being updated) to shell out to the updater exe to update itself. I first tried Process.Start:
var proc = Process.Start(pathToUpdaterExe);
proc.WaitForExit(60000);
This called the updater, but when the updater stops the service, the process is killed and the update stops. I did some searching and it sounds like the solution is to use a separate AppDomain. This is what I have now:
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence objEvidence = new System.Security.Policy.Evidence(baseEvidence);
AppDomainSetup setup = new AppDomainSetup();
var updateDomain = AppDomain.CreateDomain("updateDomain", objEvidence, setup);
updateDomain.ExecuteAssembly(updater);
AppDomain.Unload(updateDomain);
However, now I get the error System.IO.IOException: "The process cannot access the file 'C:\Program Files (x86)\Company\Service\Service.dll' because it is being used by another process" when attempting to copy over the new Service.dll
Again, I've stopped the service at this point. I've confirmed this with logging. I can't imagine what would have Service.dll still locked, so I added code to check to see what is locking it:
public static IEnumerable<Process> GetProcessesLocking(string filePath)
{
var result = new List<Process>();
result.Clear();
var processes = Process.GetProcesses();
foreach (Process proc in processes)
{
try
{
if (proc.HasExited) continue;
foreach (ProcessModule module in proc.Modules)
{
if ((module.FileName.ToLower().CompareTo(filePath.ToLower()) == 0))
{
result.Add(proc);
break;
}
}
}
catch (Exception ex)
{
Log(ex.ToString());
Log("There was an error checking " + proc.ProcessName );
}
}
return result;
}
However this code indicates that nothing has a lock on the dll (result is empty and nothing is logged indicating an error).
I suspect I'm running afoul of some UAC issue that is the real cause of the IOException. The windows service runs as LocalSystem. All that to ask: How should I be running the update exe from the windows service such that it has rights to copy files in c:\Program Files?
Update
As the comments and answer suggest, Process.Start can work, but there is some nuance. You have to start cmd.exe and use it to start the updater. I also found I could not use a full path for the updater exe and that I needed to set UseShellExecute=false. This is my final working code that launches the updater from the .NET service:
var cmd = "/c start updater.exe";
var startInfo = new ProcessStartInfo("cmd.exe");
startInfo.Arguments = cmd;
startInfo.WorkingDirectory = AssemblyDirectory;
startInfo.UseShellExecute = false;
var proc = Process.Start(startInfo);
I did this exact thing - using a simpler (some might say kludgy) approach. The service:
Produces a batch command,
Downloads the new executables to a staging location,
Starts a process: cmd.exe which, in turn, runs the batch script w/o waiting for it to complete, and then
Immediately terminates itself.
The batch command:
Pings 127.0.0.1 five times,
Copies the executables to the final location and,
Restarts the service.
Works like clockwork. The ping is a reliable 5 second delay - lets the service shutdown before copying the files.
Edit:
Just for completeness - I realized that by batch cmd is pinging 127.0.0.1 not 128.0.0.1 and so I edited this answer to reflect that. I suppose either works - but 128.0.0.1 pings timeout, where 127.0.0.1 resolves to "me". Since I'm only using it as a poor-man's delay, it serves the purpose either way.
I am trying to print all running processes in C#, similarly to how tasklist or ps does. I tried it with the following code:
foreach(Process process in Process.GetProcesses()) {
if(!process.HasExited) {
Console.WriteLine(process.ProcessName);
}
}
But with it, I run into some issues on Windows (did not try it on Linux):
When I execute the above code with user-privileges, it only prints processes started by this user. If I run it as administrator, all processes are printed.
When I open a cmd window with user privileges and list the processes (i.e. execute tasklist), all processes are printed, even those started by the system / by an administrator account.
Is there a way to get all processes, even those started by a higher privileged user, without requiring the program to be run as administrator?
One solution came to my mind:
System.Diagnostics.Process.Start("CMD.exe", "tasklist > C:\file.txt");
String[] processes = File.ReadAllLines(#"C:\file.txt");
But this is really hacky and does not work on linux.
You can't. You can't let the same process run parts in elevated and in user mode. That's just the way they built it, mainly for security reasons. You can't just bypass it.
Enough about what you can't. What can you do? You could start a second (different) program that runs in elevated mode, or you could restart your current application when there is a section you need elevated privileges. You need Process.Start for this and you will have to set the ProcessStartInfo.Verb to "runas":
ProcessStartInfo startInfo = new ProcessStartInfo(exePath);
startInfo.Verb = "runas";
Process.Start(startInfo);
After some testing I found out, that administrator processes will show in the Process.GetProcesses() list but the boolean HasExited of admin privileged processes is always true (even if it hasn't closed)
So I just looped through the list without checking for process.HasExited
foreach(Process process in Process.GetProcesses()) {
if(!process.HasExited) { //running process with user privileges
//do some stuff here
}
else { //closed process or administrator process
//do some stuff here
}
}
And for the case that the process has actually stopped, I wrap it inside a try-catch block.
As this solution does not seem optimal to me, I am leaving this question open.
I am working on windows application. i have to run some window exe from my app, i am able to do the same but when i close my application these exe remains on running condition, i am not getting how can i close those exe. Please suggest some tips.
To run the Process
private void StartChildProcess(string fileName)
{
Process newProcess = new Process();
newProcess.StartInfo = new ProcessStartInfo(fileName); ;
newProcess.Start();
localProcess.Push(newProcess);
}
To close the process
private void CloseStartedProcesses()
{
while (localProcess.Count > 0)
{
Process process = localProcess.Pop();
if (process != null && !process.HasExited)
{
process.CloseMainWindow();
process.Close();
}
}
}
Some options:
Setup some communication system so the Main application can alert the other application to shutdown (read up on some WCF information or remoting)
Create a do.shutdown file and let the second application check if that file exists, simple but efficient.
Use the process.Kill options
Use Sendkey or equivalent to send a 'quit' key combination
Use Windows API - P/Invoke. FindWindow() or EnumWindows() to get the window handle. Then you can send WM_CLOSE or WM_QUIT to end the application via the SendMessage() function.
Note that if the application checks for user input on exiting (like a MessageBox asking weather the user really wants to quit) the only option might be to send WM_DESTROY which would be equivalent to Process.Kill (at least in respects to causing data loss - I am not certain it is the absolute equivalent).
Try this:
Process[] p = Process.GetProcessesByName("osk");
foreach (var item in p)
{
item.Kill();
}
The reason that the EXE you've ran from your application doesn't terminate once you close your application is probably because the 2nd application runs as a DIFFERENT, SEPARATE process.
If you run another process with System.Diagnostics.Process, it will remain in background until terminated manually or until it finishes it's job.
try this Process proc = Process.GetProcessesByName("processname");
proc.Kill();
I am looking for a way to block a user from opening new IE or firefox windows. Is there a way to do this using c#. I am looking at system.diagnostics
You could use a windows service since it runs on background and use this code to terminate a process (the code terminates a detected running internet explorer process)
while (true)
{
StartLoop:
try
{
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
if (process.ProcessName.ToUpperInvariant().Equals("IEXPLORE"))
process.Kill();
}
}
catch
{
goto StartLoop;
}
}
How about making a group policy for the "testing account" that excludes most of the start menu and the desktop. Make your program the only one that can run.
It won't guarantee that another process won't be started, but it will certainly make it more difficult.