Windows service - only one instance to allow at a time - c#

I tried with below code to restrict the second instance of the windows service, but below code is not working for me, can anyone help me out.
I have put time interval to run service, that is 5 mints, if first instance is started and running, after 5 mints second instance is starts even though first instance is not completed.
static class Program
{
[STAThread]
static void Main()
{
bool ok;
System.Threading.Mutex m = new System.Threading.Mutex(true, "ImageImportService", out ok);
if (!ok)
{
return;
}
GC.KeepAlive(m);
if (PriorProcess() != null)
{
return;
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ImageImportService()
};
ServiceBase.Run(ServicesToRun);
}
public static Process PriorProcess()
{
Process curr = Process.GetCurrentProcess();
Process[] procs = Process.GetProcessesByName(curr.ProcessName);
foreach (Process p in procs)
{
if ((p.Id != curr.Id) && (p.MainModule.FileName == curr.MainModule.FileName))
return p;
}
return null;
}
}

Service Control Manager, a component of Windows, does not allow starting a Windows service if it is already running. Just rely on it.
The main thing you need to do is to never launch your executable directly. Instead, use the ServiceController class, when starting the service from code, and Control Panel (services.msc) when starting/stopping it manually.
In some cases, you may need to take extra steps to make sure that the service does not keep any resources behind after it has been stopped, preventing its own subsequent startup until some lower level timeout. But nothing in your question indicates that you already ran into such issues (e.g., rebinding a TCP port).

Related

how to get PID of my app at runtime using C#

My app checks at startup if any other instance of the same is running already, if yes then it will close all other instances. For this I tried using Process.GetProcessByName("AppName") function and store all the process with AppName in processes[] array. Now i want to find the PID of current instance so that i can close all other instances of my app (which obviously have same name but different PIDs). But i am unable to find that even after lot of googling. Also how can i find the PID of an instance of my app which i have created with Process.Start("AppName.exe") function called from inside AppName.exe
OK, given problems with my other solution, see the following
In order to hook in between processes, you need some form of IPC. To use the simplicty of shared handles between EventWaitHandles, you could make each program listen for a cancellation flag.
public static EventWaitHAndle CancellationEvent =
new EventWaitHandle(
false,
EventResetMode.AutoReset,
"MyAppCancel");
private object lockObject = new object();
And later...
Task.Run(() =>
{
while(true)
{
CancellationEvent.WaitOne();
lock(lockObject)
if(!thisIsCalling) // static bool to prevent this program from ending itself
Environment.Exit(0);
}
}
And then call the cancellation like so
lock(lockObject)
{
thisIsCalling = true;
CancellationEvent.Set();
thisIsCalling = false;
}
Why don't you just check equality with your current process?
var processes = Process.GetProcessByName("AppName");
foreach (var p in processes)
{
if (p != Process.GetCurrentProcess())
p.CloseMainWindow();
}
If you're interested in closing other instances of your app, why not do the opposite and prevent multiple instances from opening in the first place? Using EventWaitHandle can do this thusly:
bool created;
var eve = new System.Threading.EventWaitHandle(
false,
EventResetMode.AutoReset,
"MyAppHandle",
out created);
if(!created)
{
eve.Set();
Environment.Exit(-1); // Always use an exit error code if you're expecting to call from the console!
}
The handle parameter, "MyAppHandle" in this case, will be shared across the entire system, thus meaning not only will the out created paramete be false on secondary instaces, but you can use eve.Set() to cause the handle to fire acorss application. Set up a listening thread and this can allow a message loop to display a message when you attempt to open second instance.
Task.Run(() =>
{
while(true)
{
eve.WaitOne();
// Display an error here
}
}

Cannot evaluate expression because a native frame is on top of the call stack

I'm creating a simple window service and when I go to debug I get the error, "Cannot evaluate expression because a native frame is on top of the call stack.". Also, when I build the service in Release and run it just hangs.
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
Thats all that is in the Program.cs file, where it normally gets hung on the ServiceBase.Run(ServicesToRun) line.
Everything I've been able to find only relates to the expression not being evaluated because the code is optimized or having to deal with asp.net and response.redirect.
Code for the Service.
public TruckRateClearService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
tmrProcess.Enabled = true;
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 129)
{
OnStart(null);
}
}
protected override void OnStop()
{
tmrProcess.Enabled = false;
}
private void tmrProcess_Tick(object sender, EventArgs e)
{
tmrProcess.Enabled = false;
try
{
eventLog.WriteEntry("Clearing Truck Rates Start" + DateTime.Now.ToString());
TruckRateClearingAgent.Process();
eventLog.WriteEntry("Clearing Truck Rates Finished" + DateTime.Now.ToString());
}
catch (Exception ex)
{
eventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
}
tmrProcess.Enabled = true;
}
internal void Run()
{
tmrProcess_Tick(tmrProcess, null);
}
The Internal Void Run() was added just recent on the suggestion in the comments by Eren Ersönmez. His idea has been very helpful for helping debug my logic until I can figure the rest out.
I was able to get the into the Native call stack and it sits on one location, 76F17094 ret. Now I have no idea what this is but maybe someone else will.
Also, when I start the service and look into attaching it to VS I'm noticing two instances of it. One is the normal .exe and another is a .vshost.exe. When I start other services I only see the .exe file in the Attach to process part of the debugger. Could this be because one is on the v4 Framework ( .vshost .exe service ) and another on the v2 ( single .exe service ) Framework?
I believe I got it working. It seems that the problem lied with the timer I was using. The original timer I was using was a System.Windows.Forms timer. I switched it to System.Timers.Timers and everything started working again. Still cant attach VS to it but I can debug it still by using the Internal Run() method. Thanks for all the help n.n
Your main problem is that you're trying to directly run a windows service exe. Windows services can only be started via Service Control Manager (SCM). In order to be able to debug in VS, I'd recommend something like this:
static void Main()
{
if (Environment.UserInteractive)
{
new MyService1().Run();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(new ServiceBase[] { new MyService1() });
}
}
You'd create a MyService1.Run method which spawns a new thread that runs the service loop. Also, you'd call the same Run method from within the MyService1.Onstart.
This scheme runs it as a service when being started by SCM, but treats it like a normal exe when being debugged in VS (or being run directly as an exe outside VS).
The problem
This notification means that the thread is currently executing unmanaged code, and therefore cannot be used to evaluate the expression.
In some situations, you could wait for the call to return to managed code before evaluating the expression. Unfortunately, in this situation, that won't happen until you shut down the service.
An Alternative
You might consider overriding the ServiceBase.OnCustomCommand method and putting a breakpoint there so you can evaluate your expression.
protected override void OnCustomCommand(int command)
{
//Debugger.Break() <- or just put a breakpoint in here.
}
You can invoke the custom command as follows:
c:\>sc control YourServiceName 129
The exception you're seeing means that unmanaged code is throwing an exception, so the .NET debugger can't show you the usual useful details.
What are you doing in MyService1() ? Can you post the code inside it?
Also are you trying to debug the service by just starting it from the environment. That might not work.
I usually write something like this:
static void Main(params string[] args)
{
if (args.Length > 0 && args[0] == "/console")
{
// Run whatever your service calls here
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
}
Then in the project properties under the Debug tab enter /console as the command line arguments. You should be able to step into the application and debug it. You can only debug a service by installing it first: http://msdn.microsoft.com/en-us/library/7a50syb3(v=vs.80).aspx

Restrict multiple instances of an application

Okay, so i've created my c# application, created an installer for it and have it working installed on my machine.
The problem is, when the user opens the application exe twice, there will be two instances of the application running. I only ever want one instance of the application to be running at any time, how do I go about doing this?
Thanks for your help,
The common technique for this is to create a named Mutex and check for its presence on application start.
See this or this.
Code from DDJ:
class App : Form
{
Mutex mutex;
App()
{
Text = "Single Instance!";
mutex = new Mutex(false, "SINGLE_INSTANCE_MUTEX");
if (!mutex.WaitOne(0, false))
{
mutex.Close();
mutex = null;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
mutex.ReleaseMutex();
base.Dispose(disposing);
}
static void Main()
{
App app = new App();
if (app.mutex != null) Application.Run(app);
else MessageBox.Show("Instance already running");
}
}
i solved this problem by this
[STAThread]
static void Main()
{
Process[] result = Process.GetProcessesByName("ApplicationName");
if (result.Length > 1)
{
MessageBox.Show("There is already a instance running.", "Information");
System.Environment.Exit(0);
}
// here normal start
}
it is simple, but i had hardly time to check for better solutions.
With thanks to Messrs. Allen and Powell:
static void Main()
{
using (Mutex mutex = new Mutex(false, #"Global\" + appGuid)) {
if (!mutex.WaitOne(0, false)) {
string processName = GetProcessName();
BringOldInstanceToFront(processName);
}
else {
GC.Collect();
Application.Run(new Voting());
}
}
}
private static void BringOldInstanceToFront(string processName) {
Process[] RunningProcesses = Process.GetProcessesByName(processName);
if (RunningProcesses.Length > 0) {
Process runningProcess = RunningProcesses[0];
if (runningProcess != null) {
IntPtr mainWindowHandle = runningProcess.MainWindowHandle;
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_SHOWMINIMIZED);
NativeMethods.ShowWindowAsync(mainWindowHandle, (int) WindowConstants.ShowWindowConstants.SW_RESTORE);
}
}
}
I don't know the environment that you are operating in, but something to keep in mind about 'single-instance applications' is how you define single-instance. If the application can be run on multiple workstations at the same time, using a common datasource, is that an issue? Likewise, what about a terminal-services situation (or a "run as" situation) where more than one user is logged into the same computer, do you want to restrict the application in such a way that only one instance per-user, per-computer? Or are you okay with it simply being one instance per user?
The answer to these might lead you in one direction over another. For example, we have a 'single-instance' application with the scope being a group of computers. Only one user is allowed on within that group of workstations. We managed this by have a table in our shared data-source that tracked currently connected users. This is a maintenance issue as you need to be sure that table is 100% accurate all the time. Handling things like unexpected power outages on the workstation, leaving "bogus" records in that table took some careful handling.

Single instance windows forms application and how to get reference on it?

I have a Windows Forms application that allows only one instance to be running at the time. I have implemented Singleton by using Mutex. The Application must be startable from commandline (with or without parameters). Application is started and exited by script. User can not take any action on it.
So, application purpose is simple "indicator" application that will just display some visual and graphical information for the enduser. End user can not do anything with it, just see it. It is windows forms application because then visual and graphical appearance is relatively easy implement (you can get it topmost, borderless, etc.).
To put it simply:
How can I exit the current running application when someone tries to run same application with exit commandline parameter?
bool quit = (args.Length > 0 && args[0] == "quit") ? true : false;
using (Mutex mutex = new Mutex(false, sExeName))
{
if (!mutex.WaitOne(0, true))
{
if (quit)
{
// This is the tricky part?
// How can I get reference to "previous" launced
// Windows Forms application and call it's Exit() method.
}
}
else
{
if (!quit)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
The .NET framework offers a very good generic solution for this. Check the bottom of this MSDN magazine article. Use the StartupNextInstanceHandler() event handler to pass arbitrary commands to the running instance, like "quit".
Is this not over complicating things ? Rather than closing the existing instance and starting a new one, can you not just re-activate the existing instance? Either way round the code below should give you some ideas on how to go about it...?
Process thisProcess = Process.GetCurrentProcess();
Process[] allProcesses = Process.GetProcessesByName(thisProcess.ProcessName);
Process otherProcess = null;
foreach (Process p in allProcesses )
{
if ((p.Id != thisProcess.Id) && (p.MainModule.FileName == thisProcess.MainModule.FileName))
{
otherProcess = p;
break;
}
}
if (otherProcess != null)
{
//note IntPtr expected by API calls.
IntPtr hWnd = otherProcess.MainWindowHandle;
//restore if minimized
ShowWindow(hWnd ,1);
//bring to the front
SetForegroundWindow (hWnd);
}
else
{
//run your app here
}
There is another question about this here
This is a somewhat quick-and-dirty solution which you would probably want to refine:
[STAThread]
static void Main()
{
var me = Process.GetCurrentProcess();
var otherMe = Process.GetProcessesByName(me.ProcessName).Where(p => p.Id != me.Id).FirstOrDefault();
if (otherMe != null)
{
otherMe.Kill();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
If an instance of the app is already started, that process is killed; otherwise the app starts normally.
I think the easiest way is the following
see the link
http://codenicely.blogspot.com/2010/04/creating-forms-object.html

Prevent multiple instances of a given app in .NET?

In .NET, what's the best way to prevent multiple instances of an app from running at the same time? And if there's no "best" technique, what are some of the caveats to consider with each solution?
Use Mutex. One of the examples above using GetProcessByName has many caveats. Here is a good article on the subject:
http://odetocode.com/Blogs/scott/archive/2004/08/20/401.aspx
[STAThread]
static void Main()
{
using(Mutex mutex = new Mutex(false, "Global\\" + appGuid))
{
if(!mutex.WaitOne(0, false))
{
MessageBox.Show("Instance already running");
return;
}
Application.Run(new Form1());
}
}
private static string appGuid = "c0a76b5a-12ab-45c5-b9d9-d693faa6e7b9";
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
{
AppLog.Write("Application XXXX already running. Only one instance of this application is allowed", AppLog.LogMessageType.Warn);
return;
}
Here is the code you need to ensure that only one instance is running. This is the method of using a named mutex.
public class Program
{
static System.Threading.Mutex singleton = new Mutex(true, "My App Name");
static void Main(string[] args)
{
if (!singleton.WaitOne(TimeSpan.Zero, true))
{
//there is already another instance running!
Application.Exit();
}
}
}
Hanselman has a post on using the WinFormsApplicationBase class from the Microsoft.VisualBasic assembly to do this.
1 - Create a reference in program.cs ->
using System.Diagnostics;
2 - Put into void Main() as the first line of code ->
if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length >1)
return;
That's it.
After trying multiple solutions i the question. I ended up using the example for WPF here: http://www.c-sharpcorner.com/UploadFile/f9f215/how-to-restrict-the-application-to-just-one-instance/
public partial class App : Application
{
private static Mutex _mutex = null;
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "MyAppName";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
//app is already running! Exiting the application
Application.Current.Shutdown();
}
}
}
In App.xaml:
x:Class="*YourNameSpace*.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
It sounds like there are 3 fundamental techniques that have been suggested so far.
Derive from the Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class and set the IsSingleInstance property to true. (I believe a caveat here is that this won't work with WPF applications, will it?)
Use a named mutex and check if it's already been created.
Get a list of running processes and compare the names of the processes. (This has the caveat of requiring your process name to be unique relative to any other processes running on a given user's machine.)
Any caveats I've missed?
i tried all the solutions here and nothing worked in my C# .net 4.0 project. Hoping to help someone here the solution that worked for me:
As main class variables:
private static string appGuid = "WRITE AN UNIQUE GUID HERE";
private static Mutex mutex;
When you need to check if app is already running:
bool mutexCreated;
mutex = new Mutex(true, "Global\\" + appGuid, out mutexCreated);
if (mutexCreated)
mutex.ReleaseMutex();
if (!mutexCreated)
{
//App is already running, close this!
Environment.Exit(0); //i used this because its a console app
}
I needed to close other istances only with some conditions, this worked well for my purpose
Using Visual Studio 2005 or 2008 when you create a project for an executable, on the properties windows inside the "Application" panel there is a check box named “Make single instance application” that you can activate to convert the application on a single instance application.
Here is a capture of the window I'm talking of:
This is a Visual Studio 2008 windows application project.
http://en.csharp-online.net/Application_Architecture_in_Windows_Forms_2.0—Single-Instance_Detection_and_Management
This is the code for VB.Net
Private Shared Sub Main()
Using mutex As New Mutex(False, appGuid)
If Not mutex.WaitOne(0, False) Then
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error)
Return
End If
Application.Run(New Form1())
End Using
End Sub
This is the code for C#
private static void Main()
{
using (Mutex mutex = new Mutex(false, appGuid)) {
if (!mutex.WaitOne(0, false)) {
MessageBox.Show("Instance already running", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Application.Run(new Form1());
}
}
Use VB.NET!
No: really ;)
using Microsoft.VisualBasic.ApplicationServices;
The WindowsFormsApplicationBase from VB.Net provides you with a "SingleInstace" Property, which determines other Instances and let only one Instance run.
[STAThread]
static void Main() // args are OK here, of course
{
bool ok;
m = new System.Threading.Mutex(true, "YourNameHere", out ok);
if (! ok)
{
MessageBox.Show("Another instance is already running.");
return;
}
Application.Run(new Form1()); // or whatever was there
GC.KeepAlive(m); // important!
}
From: Ensuring a single instance of .NET Application
and: Single Instance Application Mutex
Same answer as #Smink and #Imjustpondering with a twist:
Jon Skeet's FAQ on C# to find out why GC.KeepAlive matters
This article simply explains how you can create a windows application with control on the number of its instances or run only single instance. This is very typical need of a business application. There are already lots of other possible solutions to control this.
https://web.archive.org/web/20090205153420/http://www.openwinforms.com/single_instance_application.html
http://www.codeproject.com/KB/cs/SingleInstancingWithIpc.aspx
You have to use System.Diagnostics.Process.
Check out: http://www.devx.com/tips/Tip/20044
(Note: this is a fun-solution! It works but uses bad GDI+ design to achieve this.)
Put an image in with your app and load it on startup. Hold it until the app exits. The user wont be able to start a 2nd instance. (Of course the mutex solution is much cleaner)
private static Bitmap randomName = new Bitmap("my_image.jpg");
Simply using a StreamWriter, how about this?
System.IO.File.StreamWriter OpenFlag = null; //globally
and
try
{
OpenFlag = new StreamWriter(Path.GetTempPath() + "OpenedIfRunning");
}
catch (System.IO.IOException) //file in use
{
Environment.Exit(0);
}
Normally it's done with a named Mutex (use new Mutex( "your app name", true ) and check the return value), but there's also some support classes in Microsoft.VisualBasic.dll that can do it for you.
This worked for me in pure C#. the try/catch is when possibly a process in the list exits during your loop.
using System.Diagnostics;
....
[STAThread]
static void Main()
{
...
int procCount = 0;
foreach (Process pp in Process.GetProcesses())
{
try
{
if (String.Compare(pp.MainModule.FileName, Application.ExecutablePath, true) == 0)
{
procCount++;
if(procCount > 1) {
Application.Exit();
return;
}
}
}
catch { }
}
Application.Run(new Form1());
}
Be sure to consider security when restricting an application to a single instance:
Full article:
https://blogs.msdn.microsoft.com/oldnewthing/20060620-13/?p=30813
We are using a named mutex with a fixed name in order to detect
whether another copy of the program is running. But that also means an
attacker can create the mutex first, thereby preventing our program
from running at all! How can I prevent this type of denial of service
attack?
...
If the attacker is running in the same security context as your
program is (or would be) running in, then there is nothing you can do.
Whatever "secret handshake" you come up with to determine whether
another copy of your program is running, the attacker can mimic it.
Since it is running in the correct security context, it can do
anything that the "real" program can do.
...
Clearly you can't protect yourself from an attacker running at the
same security privilege, but you can still protect yourself against
unprivileged attackers running at other security privileges.
Try setting a DACL on your mutex, here's the .NET way:
https://msdn.microsoft.com/en-us/library/system.security.accesscontrol.mutexsecurity(v=vs.110).aspx
None of this answers worked for me because I needed this to work under Linux using monodevelop. This works great for me:
Call this method passing it a unique ID
public static void PreventMultipleInstance(string applicationId)
{
// Under Windows this is:
// C:\Users\SomeUser\AppData\Local\Temp\
// Linux this is:
// /tmp/
var temporaryDirectory = Path.GetTempPath();
// Application ID (Make sure this guid is different accross your different applications!
var applicationGuid = applicationId + ".process-lock";
// file that will serve as our lock
var fileFulePath = Path.Combine(temporaryDirectory, applicationGuid);
try
{
// Prevents other processes from reading from or writing to this file
var _InstanceLock = new FileStream(fileFulePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_InstanceLock.Lock(0, 0);
MonoApp.Logger.LogToDisk(LogType.Notification, "04ZH-EQP0", "Aquired Lock", fileFulePath);
// todo investigate why we need a reference to file stream. Without this GC releases the lock!
System.Timers.Timer t = new System.Timers.Timer()
{
Interval = 500000,
Enabled = true,
};
t.Elapsed += (a, b) =>
{
try
{
_InstanceLock.Lock(0, 0);
}
catch
{
MonoApp.Logger.Log(LogType.Error, "AOI7-QMCT", "Unable to lock file");
}
};
t.Start();
}
catch
{
// Terminate application because another instance with this ID is running
Environment.Exit(102534);
}
}

Categories

Resources