I have trouble with checking if a process is still running.
I created a small program that should keep 2 programs up and running.
For this example I use Notepad and windows calculator.
The Code below will launch both applications, but its failing on checking their running state by their process.checkalive propert also hasexited fails.
Notice that the sample program uses a class Apprunner to handle multiple applications. After launching both applications it crashes with:
System.InvalidOperationException:
'Process has exited, so the requested information is not available.'
Despite that both programs Notepad.exe and Calc.exe are running.
Code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace watchdog
{
class AppRunner
{
public Process Program;
public AppRunner(ProcessStartInfo processrunner)
{
this.Program = new Process();
this.Program.StartInfo = processrunner;
StartExecute();
}
public void StartExecute()
{
this.Program.Start();
}
public bool checkAlive()
{
this.Program.Refresh();
return (bool)this.Program.Responding;
//fails
// also failing as true => return this.Program.HasExited;
//(its not true app still runs)
}
public void KeepEmRunning()
{
if (!checkAlive())
{
StartExecute();
}
}
}
//-----------main prog - - - - -
class Program
{
static void Main(string[] args)
{
List<AppRunner> programs = new List<AppRunner>();
ProcessStartInfo prog = new ProcessStartInfo();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"C:\Windows\system32\Notepad.exe";
programs.Add(new AppRunner(startInfo));
startInfo.FileName = #"C:\Windows\system32\Calc.exe";
programs.Add(new AppRunner(startInfo));
string s;
do
{
System.Threading.Thread.Sleep(1000);// wait for start.
Console.WriteLine("Notepad" + programs[0].checkAlive());
Console.WriteLine("Calc" + programs[1].checkAlive());
Console.WriteLine("press X for exit other key for update");
s = Console.ReadLine().ToUpper();
} while (s != "X");
}
}
}
Code running on Windows 10, and vs2017 its a .net 4.6 console app.
Process.Responding throws an exception if the process has already exited. I guess Responding's purpose is to check if the process is dead-locked or still working, but doesn't work if the process is gone already.
Calc.exe indeed immediatly returns, after starting Calculator.exe (see TaskManager). So the result you observe is correct: the process you started for calc.exe has already exited, although you still see a calculator window.
Related
I have an application that is both gui and console.
Console: It executes from a windows schedule to do some automated tasks, so its called with an argument
GUI: Used for entering config parameters, a much nicer way for the user to do this than console.
All this works great. its primarily a console app, the console is hidden if its opened with no arguments and the configuration form is shown.
Problem:
If I open it FROM the console with NO arguments, the console is hidden and the form is shown.
how can i detect what or where i opened the app from, if it was opened from windows then hide the console, if it was opened from console then leave the console shown.
If you really want to know "where" your application has been started you have to know what is your parent process. In order to know your parent process you can read the solution of How to get parent process in .NET in managed way
Then you can for example check if your parent process name is explorer(windows) to open your application as a GUI.
sample code based on the solution provided in How to get parent process in .NET in managed way
namespace ConsoleApp1
{
public static class ProcessExtensions
{
private static string FindIndexedProcessName(int pid)
{
var processName = Process.GetProcessById(pid).ProcessName;
var processesByName = Process.GetProcessesByName(processName);
string processIndexdName = null;
for (var index = 0; index < processesByName.Length; index++)
{
processIndexdName = index == 0 ? processName : processName + "#" + index;
var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
if ((int)processId.NextValue() == pid)
{
return processIndexdName;
}
}
return processIndexdName;
}
private static Process FindPidFromIndexedProcessName(string indexedProcessName)
{
var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
return Process.GetProcessById((int)parentId.NextValue());
}
public static Process Parent(this Process process)
{
return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Process.GetCurrentProcess().Parent().ProcessName);
Console.ReadKey();
}
}
}
This code will outputs:
debug in visual studio: devenv
start from windows: explorer
start from cmd: cmd
start from powershell console: powershell
...
One way to do this is to separate your cli version and gui version into 2 executable (like 7z do with 7z.exe a command line tool and 7zG the Gui version)
You could have 3 projects in visual studio:
MyApp.Console (console app)
MyApp.WindowsGui (winform/wpf app)
MyApp.Logic (all the logic)
Console and WindowsGui have a reference to your Logic project
This will give you cleaner code as each "Frontend" project will handle only their purpose (handling GUI or console stuff) and your Logic are callable by both frontends
I am unclear as to what you're trying to achieve. From my understanding, the application will launch as a console application regardless of having arguments or not. To prevent it from disappearing, you can utilize a Boolean to prevent the window from closing while the user is inputting configuration. For example (syntax may not be 100% at DialogResult):
using System;
using System.Windows.Forms;
// Allows you to access the static objects of Console
// without having to repeatedly type Console.Something.
using static System.Console;
static bool configured = false;
static bool showForm = false;
static void Main(string[] args) {
showForm = args.Length < 1;
if (showForm) {
WriteLine("The application needs to be configured.");
using (ConfigForm config = new ConfigForm()) {
if (config.ShowDialog() == DialogResult.OK) {
showForm = false;
configured = true;
// Set your configured arguments here.
}
}
}
// Prevents the console from closing.
while (showForm)
ReadKey();
// Do your processing in this condition.
if (!showForm && configured)
WriteLine("Thanks for playing. Press any key to exit.");
else // Retry or exit in this one.
WriteLine("An error occurred. Press any key to exit.");
ReadKey();
}
If your application is set as a console application then it will launch the console window by default. Now, if you need to show and hide your console at different times, you can look into this post where the accepted answer provides a proper way to utilize Windows API to achieve this without having to perform some shady logic to find the window by title or identity.
using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
var handle = GetConsoleWindow();
// Hide
ShowWindow(handle, SW_HIDE);
// Show
ShowWindow(handle, SW_SHOW);
If this doesn't solve what you need, feel free to be more thorough in your post and include some code to give more definition to your issue. I am unable to comment and ask questions so I gave a basic solution. If you have any questions, feel free to ask.
This might help:
using System;
using System.Diagnostics;
static class IsRanFromConsole
{
private static readonly string[] consoleNames = {
"cmd", "bash", "ash", "dash", "ksh", "zsh", "csh",
"tcsh", "ch", "eshell", "fish", "psh", "pwsh", "rc",
"sash", "scsh", "powershell", "tcc"
};
private static bool isCache = false;
private static bool isConsole;
public static bool IsConsole()
{
if (!isCache)
{
string parentProc = Process.GetCurrentProcess().Parent().ProcessName;
isConsole = Array.IndexOf(consoleNames, parentProc) > -1;
}
return isConsole;
}
}
Usage:
Console.WriteLine(IsRanFromConsole.IsConsole());
For the .Parent() function, you need to add this code.
I have some unit tests that use Azure Storage. When running these locally, I want them to use the Azure Storage emulator which is part of the Azure SDK v1.5. If the emulator isn't running, I want it to be started.
To start the emulator from the command line, I can use this:
"C:\Program Files\Windows Azure SDK\v1.5\bin\csrun" /devstore
This works fine.
When I try to start it using this C# code, it crashes:
using System.IO;
using System.Diagnostics;
...
ProcessStartInfo processToStart = new ProcessStartInfo()
{
FileName = Path.Combine(SDKDirectory, "csrun"),
Arguments = "/devstore"
};
Process.Start(processToStart);
I've tried fiddling with a number of ProcessStartInfo settings, but nothing seems to work. Is anybody else having this problem?
I've checked the Application Event Log and found the following two entries:
Event ID: 1023
.NET Runtime version 2.0.50727.5446 - Fatal Execution Engine Error (000007FEF46B40D2) (80131506)
Event ID: 1000
Faulting application name: DSService.exe, version: 6.0.6002.18312, time stamp: 0x4e5d8cf3
Faulting module name: mscorwks.dll, version: 2.0.50727.5446, time stamp: 0x4d8cdb54
Exception code: 0xc0000005
Fault offset: 0x00000000001de8d4
Faulting process id: 0x%9
Faulting application start time: 0x%10
Faulting application path: %11
Faulting module path: %12
Report Id: %13
Updated 7/12/2022:
If you are running Visual Studio 2022, azurite.exe is the replacement for the now-deprecated AzureStorageEmulator.exe which can be found here:
C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Extensions\Microsoft\Azure Storage Emulator\azurite.exe
NB: if you are running Professional (or another) Edition, you'll need to replace Community with Professional (or the appropriate edition name) in the path.
Updated 1/19/2015:
After doing more testing (i.e., running several builds), I've discovered that WAStorageEmulator.exe's status API is actually broken in a couple of significant ways (which may or may not have impact on how you use it).
The status reports False even when an existing process is running if the user differs between the existing running process and the user used to launch the status process. This incorrect status report will lead to a failure to launch the process that looks like this:
C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator>WAStorageEmulator.exe status
Windows Azure Storage Emulator 3.4.0.0 command line tool
IsRunning: False
BlobEndpoint: http://127.0.0.1:10000/
QueueEndpoint: http://127.0.0.1:10001/
TableEndpoint: http://127.0.0.1:10002/
C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator>WAStorageEmulator.exe start
Windows Azure Storage Emulator 3.4.0.0 command line tool
Error: Port conflict with existing application.
Additionally, the status command appears only to report the endpoints specified in WAStorageEmulator.exe.config, not those of the existing running process. I.e., if you start the emulator, then make a change to the config file, and then call status, it will report the endpoints listed in the config.
Given all of these caveats, it may, in fact, simply be better to use the original implementation as it appears to be more reliable.
I will leave both so others can choose whichever solution works for them.
Updated 1/18/2015:
I have fully rewritten this code to properly leverage WAStorageEmulator.exe's status API per #RobertKoritnik's request.
public static class AzureStorageEmulatorManager
{
public static bool IsProcessRunning()
{
bool status;
using (Process process = Process.Start(StorageEmulatorProcessFactory.Create(ProcessCommand.Status)))
{
if (process == null)
{
throw new InvalidOperationException("Unable to start process.");
}
status = GetStatus(process);
process.WaitForExit();
}
return status;
}
public static void StartStorageEmulator()
{
if (!IsProcessRunning())
{
ExecuteProcess(ProcessCommand.Start);
}
}
public static void StopStorageEmulator()
{
if (IsProcessRunning())
{
ExecuteProcess(ProcessCommand.Stop);
}
}
private static void ExecuteProcess(ProcessCommand command)
{
string error;
using (Process process = Process.Start(StorageEmulatorProcessFactory.Create(command)))
{
if (process == null)
{
throw new InvalidOperationException("Unable to start process.");
}
error = GetError(process);
process.WaitForExit();
}
if (!String.IsNullOrEmpty(error))
{
throw new InvalidOperationException(error);
}
}
private static class StorageEmulatorProcessFactory
{
public static ProcessStartInfo Create(ProcessCommand command)
{
return new ProcessStartInfo
{
FileName = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\WAStorageEmulator.exe",
Arguments = command.ToString().ToLower(),
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
}
}
private enum ProcessCommand
{
Start,
Stop,
Status
}
private static bool GetStatus(Process process)
{
string output = process.StandardOutput.ReadToEnd();
string isRunningLine = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).SingleOrDefault(line => line.StartsWith("IsRunning"));
if (isRunningLine == null)
{
return false;
}
return Boolean.Parse(isRunningLine.Split(':').Select(part => part.Trim()).Last());
}
private static string GetError(Process process)
{
string output = process.StandardError.ReadToEnd();
return output.Split(':').Select(part => part.Trim()).Last();
}
}
And the corresponding tests:
[TestFixture]
public class When_starting_process
{
[Test]
public void Should_return_started_status()
{
if (AzureStorageEmulatorManager.IsProcessRunning())
{
AzureStorageEmulatorManager.StopStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.False);
}
AzureStorageEmulatorManager.StartStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.True);
}
}
[TestFixture]
public class When_stopping_process
{
[Test]
public void Should_return_stopped_status()
{
if (!AzureStorageEmulatorManager.IsProcessRunning())
{
AzureStorageEmulatorManager.StartStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.True);
}
AzureStorageEmulatorManager.StopStorageEmulator();
Assert.That(AzureStorageEmulatorManager.IsProcessRunning(), Is.False);
}
}
Original post:
I took Doug Clutter's and Smarx's code one step further and created a utility class:
The code below has been updated to work on both Windows 7 and 8 and now points at the new storage emulator path as of SDK 2.4.**
public static class AzureStorageEmulatorManager
{
private const string _windowsAzureStorageEmulatorPath = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\WAStorageEmulator.exe";
private const string _win7ProcessName = "WAStorageEmulator";
private const string _win8ProcessName = "WASTOR~1";
private static readonly ProcessStartInfo startStorageEmulator = new ProcessStartInfo
{
FileName = _windowsAzureStorageEmulatorPath,
Arguments = "start",
};
private static readonly ProcessStartInfo stopStorageEmulator = new ProcessStartInfo
{
FileName = _windowsAzureStorageEmulatorPath,
Arguments = "stop",
};
private static Process GetProcess()
{
return Process.GetProcessesByName(_win7ProcessName).FirstOrDefault() ?? Process.GetProcessesByName(_win8ProcessName).FirstOrDefault();
}
public static bool IsProcessStarted()
{
return GetProcess() != null;
}
public static void StartStorageEmulator()
{
if (!IsProcessStarted())
{
using (Process process = Process.Start(startStorageEmulator))
{
process.WaitForExit();
}
}
}
public static void StopStorageEmulator()
{
using (Process process = Process.Start(stopStorageEmulator))
{
process.WaitForExit();
}
}
}
This program worked fine for me. Give it a try, and if it works for you too, work backwards from there. (What about your app is different from this?)
using System.Diagnostics;
public class Program
{
public static void Main() {
Process.Start(#"c:\program files\windows azure sdk\v1.5\bin\csrun", "/devstore").WaitForExit();
}
}
The file name in v4.6 is "AzureStorageEmulator.exe". The full path is: "C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe"
For Windows Azure Storage Emulator v5.2, the following helper class can be used to start the emulator:
using System.Diagnostics;
public static class StorageEmulatorHelper {
/* Usage:
* ======
AzureStorageEmulator.exe init : Initialize the emulator database and configuration.
AzureStorageEmulator.exe start : Start the emulator.
AzureStorageEmulator.exe stop : Stop the emulator.
AzureStorageEmulator.exe status : Get current emulator status.
AzureStorageEmulator.exe clear : Delete all data in the emulator.
AzureStorageEmulator.exe help [command] : Show general or command-specific help.
*/
public enum StorageEmulatorCommand {
Init,
Start,
Stop,
Status,
Clear
}
public static int StartStorageEmulator() {
return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Start);
}
public static int StopStorageEmulator() {
return ExecuteStorageEmulatorCommand(StorageEmulatorCommand.Stop);
}
public static int ExecuteStorageEmulatorCommand(StorageEmulatorCommand command) {
var start = new ProcessStartInfo {
Arguments = command.ToString(),
FileName = #"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe"
};
var exitCode = executeProcess(start);
return exitCode;
}
private static int executeProcess(ProcessStartInfo startInfo) {
int exitCode = -1;
try {
using (var proc = new Process {StartInfo = startInfo}) {
proc.Start();
proc.WaitForExit();
exitCode = proc.ExitCode;
}
}
catch {
//
}
return exitCode;
}
}
[Thanks to huha for the boilerplate code to execute a shell command.]
FYI - The 1.6 default location is C:\Program Files\Windows Azure Emulator\emulator as stated on the MSDN docs.
We are running into the same issue. We have the concept of a "smoke test" which runs between groups of tests, and which ensure the environment is in a good state before the next group starts. We have a .cmd file that kicks off the smoke tests, and it works just fine starting the devfabric emulator, but the devstore emulator only runs as long as the .cmd process runs.
Apparently the implementation of the DSServiceSQL.exe is different than DFService.exe. DFService seems to run like a windows service - kick it off, and it keeps running. DSServiceSQL dies as soon as the process that started it dies.
I uninstalled all of the Windows Azure bits:
WA SDK v1.5.20830.1814
WA Tools for Visual Studio: v1.5.40909.1602
WA AppFabric: v1.5.37
WA AppFabric: v2.0.224
Then, I downloaded and installed everything using the unified installer. Everything came back except the AppFabric v2. All the version numbers are the same. Reran my tests and still having a problem.
And then...(this is weird)...it would work every now and then. Rebooted the machine and now it works. Have shutdown and rebooted a number of times now...and it just works. (sigh)
Thanks to everyone who provided feedback and/or ideas!
The final code is:
static void StartAzureStorageEmulator()
{
ProcessStartInfo processStartInfo = new ProcessStartInfo()
{
FileName = Path.Combine(SDKDirectory, "csrun.exe"),
Arguments = "/devstore",
};
using (Process process = Process.Start(processStartInfo))
{
process.WaitForExit();
}
}
maybe caused by file not found?
try this
FileName = Path.Combine(SDKDirectory, "csrun.exe")
Here we go: Pass the string "start" to the method ExecuteWAStorageEmulator().
The NUnit.Framework is used for the Assert only.
using System.Diagnostics;
using NUnit.Framework;
private static void ExecuteWAStorageEmulator(string argument)
{
var start = new ProcessStartInfo
{
Arguments = argument,
FileName = #"c:\Program Files (x86)\Microsoft SDKs\Windows Azure\Storage Emulator\WAStorageEmulator.exe"
};
var exitCode = ExecuteProcess(start);
Assert.AreEqual(exitCode, 0, "Error {0} executing {1} {2}", exitCode, start.FileName, start.Arguments);
}
private static int ExecuteProcess(ProcessStartInfo start)
{
int exitCode;
using (var proc = new Process { StartInfo = start })
{
proc.Start();
proc.WaitForExit();
exitCode = proc.ExitCode;
}
return exitCode;
}
See also my new self-answered question
There's now a neat little NuGet package to assist with starting/stopping the Azure Storage Emulator programmatically: RimDev.Automation.StorageEmulator.
The source code is available in this GitHub repository, but you can essentially do things like this:
if(!AzureStorageEmulatorAutomation.IsEmulatorRunning())
{
AzureStorageEmulatorAutomation emulator = new AzureStorageEmulatorAutomation();
emulator.Start();
// Even clear some things
emulator.ClearBlobs();
emulator.ClearTables();
emulator.ClearQueues();
emulator.Stop();
}
It feels like the cleanest option to me.
I am actually able to delete the files, but the system restores them almost immediately. I have been unsuccessful in using sysocmgr.exe to remove games from systems and would like to do it via code (I can get sysocmgr.exe to run and remove the games if I run it manually, but it does not work for me in a login script - it gets executed and just sits there. If I do a shutdown, the files do not get removed, but if I open task manager and end the task, the files get removed)...
My uninstall batch file looks like:
copy sysoc.txt "%windir%\temp\sysoc.txt" /y
sysocmgr /i:"%windir%\inf\sysoc.inf" /u:"%windir%\temp\sysoc.txt" /q /r
sysoc.txt looks like:
[Components]
pinball = off
Solitaire = off
freecell = off
hearts = off
minesweeper = off
spider = off
zonegames = off
anyone have any suggestions???
You can try using PowerShell script to remove programs (not sure if you can remove XP Games as they are part of Windows Components but worth a shot): How can I uninstall an application using PowerShell?
Also, found this tool that talks about removing games: http://www.systemtools.com/board/Forum8/HTML/000065.html
Also, note that logon scripts run in the security context of the logged in user, so if they are not Admins this is almost certain to fail. A startup script might be more successful.
This is how I got it to work (this is being executed as "SYSTEM"):
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
namespace XPGameRemoval
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
string WinDir = Environment.GetEnvironmentVariable("WinDir");
FileStream cStream = new FileStream(
WinDir + "\\Temp\\SysOC.txt",
FileMode.Create,
FileAccess.ReadWrite,
FileShare.ReadWrite);
StreamWriter cWriter = new StreamWriter(cStream);
cWriter.WriteLine("[Components]");
cWriter.WriteLine("pinball = off");
cWriter.WriteLine("Solitaire = off");
cWriter.WriteLine("freecell = off");
cWriter.WriteLine("hearts = off");
cWriter.WriteLine("minesweeper = off");
cWriter.WriteLine("spider = off");
cWriter.WriteLine("zonegames = off");
cWriter.Close();
cStream.Close();
Process P = Process.Start(WinDir+"\\System32\\SysOCMgr.exe","/i:\""+WinDir+"\\Inf\\SysOC.Inf\" /u:\""+WinDir+"\\Temp\\SysOC.txt\" /q /r");
int Timeout = 15;
System.Threading.Thread.Sleep(5000);
while (File.Exists(WinDir+"\\System32\\SOL.EXE") && Timeout>0 && !P.HasExited)
{
System.Threading.Thread.Sleep(59000); // wait a little under 15 minutes
Timeout--;
}
if (!P.HasExited)
P.Kill();
if (P.ExitCode != 0) // SysOCMgr errored out, return error
Environment.Exit(P.ExitCode);
if (File.Exists(WinDir + "\\System32\\SOL.EXE")) // something went wrong, return generic error...
Environment.Exit(80);
}
}
}
Let's say I have a windows service called "MyService" and an executable called "MyEXE"
Is it possible (from within "MyService") to start several instances of "MyEXE" running in seperate application domains in parallel?
I would apprecaiate if some one can also provide a small sample using .net.
As long as it is a managed program then, yes, you can run it in its own AppDomain. You'll need a thread to run the code, AppDomain.ExecuteAssembly() is the handy one that automatically starts running the Main() method of that program. Here's an example that uses two console mode applications:
using System;
using System.Threading;
using System.IO;
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
string exePath = #"c:\projects\consoleapplication2\bin\debug\consoleapplication2.exe";
for (int ix = 0; ix < 10; ++ix) {
var setup = new AppDomainSetup();
setup.ApplicationBase = Path.GetDirectoryName(exePath);
var ad = AppDomain.CreateDomain(string.Format("Domain #{0}", ix + 1), null, setup);
var t = new Thread(() => {
ad.ExecuteAssembly(exePath);
AppDomain.Unload(ad);
});
t.Start();
}
Console.ReadLine();
}
}
}
And the one that's ran 10 times:
using System;
namespace ConsoleApplication2 {
class Program {
static void Main(string[] args) {
Console.WriteLine("Hello from {0}", AppDomain.CurrentDomain.FriendlyName);
}
}
}
One thing I didn't count on and stuck under a table a bit, the AppDomainSetup.ApplicationBase property didn't work as I expected. I had to pass the full path of the EXE to ExecuteAssembly() instead of just passing "consoleapplication2.exe". That was odd.
I wrote a program in c#
now I would like to know what is the proper way to prevent the program from starting if it is already running?
so if it is already running, and double-click on the program it will not start because it is already running.
I can do that, but I was thinking of a standard and proper way.
The recommended way to do this is with a system mutex.
bool createdNew;
using(var mutex = new System.Threading.Mutex(true, "MyAppName", out createdNew))
{
if (createdNew)
// first instance
Application.Run();
else
MessageBox.Show("There is already an instace running");
}
The first parameter to the Mutex ctor tells it to give create a system wide mutex for this thread. If the Mutex already exists it will return out false through the 3rd parameter.
Update
Where to put this?
I'd put this in program.cs. If you put it in form_load you'll need to keep the mutex for the life time of the application (have the mutex as a member on the form), and manually release it in the form unload.
The earlier you call this the better, before the other app opens DB connections etc. and before resources are put created for forms / controlls etc.
Quick way I did in one of the applications .. You can look at the list of running processes to see whether the current application is already running and not start the application again.
Process[] lprcTestApp = Process.GetProcessesByName("TestApplication");
if (lprcTestApp.Length > 0)
{
// The TestApplication is already running, don't run it again
}
I think enumerating the process list could potentially be slow. You could also create a Mutex using the System.Threading.Mutex class and check to see if it's already created when the process starts. However, this would require calling into Win32 system code so wouldn't be completely platform agnostic.
Take a look at Scotts blog post and don't be foolished by the assembly name. It's just a file name of a standard file in the .Net framework.
Here are more informations direct out of MSDN for the WindowsFormsApplicationBase.
You can use a system-wide Semaphore, using the Semaphore Constructor (Int32, Int32, String, Boolean%) constructor and a fairly unique name.
Cheers, Matthias
If your application produces/consumes files, then you're better registering a system wide communication mechanism (e.g. a remoting or WCF endpoint, or even a socket). Then, if the second instance of the application is being launched from double clicking one of your files, you can send the file information across to the running instance.
Otherwise, if it's a standalone program, then as others have said, a Mutex or Semaphore would server equally well.
solution in Windows form application Prohibit again run application(reopen application).
1- first add Class RunAlready.cs
2-Call method processIsRunning() with Name Process from RunAlready.cs in Program.cs
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Tirage.MainStand
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
PublicClass.Class.RunAlready RunAPP = new PublicClass.Class.RunAlready();
string outApp = RunAPP.processIsRunning("Tirage.MainStand");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainStand_FrmLogin fLogin = new MainStand_FrmLogin();
if (outApp.Length == 0)
{
if (fLogin.ShowDialog() == DialogResult.OK)
{
Application.Run(new MainStand_masterFrm());
}
}
else MessageBox.Show( "Instance already running");
}
}
}
class RunAlready:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PublicClass.Class
{
public class RunAlready
{
public string processIsRunning(string process)
{
string xdescription = "";
System.Diagnostics.Process[] processes =
System.Diagnostics.Process.GetProcessesByName(process);
foreach (System.Diagnostics.Process proc in processes)
{
var iddd = System.Diagnostics.Process.GetCurrentProcess().Id;
if (proc.Id != System.Diagnostics.Process.GetCurrentProcess().Id)
{
xdescription = "Application Run At time:" + proc.StartTime.ToString() + System.Environment.NewLine;
xdescription += "Current physical memory : " + proc.WorkingSet64.ToString() + System.Environment.NewLine;
xdescription += "Total processor time : " + proc.TotalProcessorTime.ToString() + System.Environment.NewLine;
xdescription += "Virtual memory size : " + proc.VirtualMemorySize64.ToString() + System.Environment.NewLine;
}
}
return xdescription;
}
}
}