Multiple instance of application but run only one - c#

I have a unmanaged application which opens at runtime my managed application.
- Each time the unmanaged aplication is being executed , it opens a new instance of my application .
I have to somehow do this scenario:
-When the unmanaged application is being executed for the first time, my managed aplication should run fine,but if the user tries to open again the unmanaged application , those managed instances should be in "standby" mode and if the first managed application which is currently running is closed , one of the standby instances should be "resumed" .
As I've seen so far , I should be using mutex :
public Form1()
{
InitializeComponent();
if (!IsSingleInstance())
{
this.Close();
return;
}
}
private static Mutex _mutex;
private static bool IsSingleInstance()
{
_mutex = new Mutex(false, "MyApp");
GC.KeepAlive(_mutex);
try
{
return _mutex.WaitOne(0, false);
}
catch (AbandonedMutexException)
{
_mutex.ReleaseMutex();
return _mutex.WaitOne(0, false);
}
}
protected override void OnClosing(CancelEventArgs e)
{
if (_mutex != null)
{
_mutex.ReleaseMutex();
}
}
But ofcourse , the code only checks if another istance is running and if it does..then it will close it.
What can I do?
Thanks,

I'd rather put the lock in Main in Program.cs.
static void Main()
{
Mutex mutex = new Mutex(false, "MyApp");
if (mutex.WaitOne())
{
try
{
Application.Run(new Form1());
}
finally
{
mutex.ReleaseMutex();
}
}
}

Related

Why Single Instance Logic in Release Mode is failed?

Here is my code
I tried in Debug Mode. It works.
While in release does not why? Its a WPF application
This piece of code i put in Main Method for checking if a application is running or not. I want single instance to be running only. I copied this code from Stack Overflow only.
[STAThread]
static void Main()
{
const string MutexName = "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}";
try
{
Mutex mutex = new Mutex(true, MutexName);
if (mutex.WaitOne(TimeSpan.Zero, true))
{
mutex.ReleaseMutex();
//Here Application logic
}
else
{
MessageBox.Show("Application is alreadey running.");
Environment.Exit(1);
}
}
catch
{
Environment.Exit(1);
}
}
I don't know the exact reason. But this modification works
[STAThread]
static void Main()
{
const string MutexName = "8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F";
try
{
Mutex mutex;
if (!Mutex.TryOpenExisting(MutexName, out mutex))
{
mutex = new Mutex(true,MutexName);
var app = new App();
app.Run();
}
else
{
Environment.Exit(1);
}
}
catch
{
Environment.Exit(1);
}
}

Closing parent form from child thread

I've been scratching my head on this one for a while now and despite looking for solutions, im not quite understanding the implementations (several answers on stack overflow have already been looked at)
My program loads a splash page when it is opened, during which it checks for a database connection. If there is a connection, the splash page closes and the main form loads, otherwise it provides an error message then closes completely.
public partial class StartupSplash : Form
{
ThreadStart th;
Thread thread;
public StartupSplash()
{
InitializeComponent();
th = new ThreadStart(DbAvaliable);
thread = new Thread(th);
thread.Start();
}
private void DbAvaliable()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
if (result)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
else
{
MessageBox.Show("Unable to establish database connection. Please check your data connection and try again.");
}
}
}
I understand that I can't simply call this.Close() due to cross thread issues. I've read something about invoking methods, but im not too clear how to achieve the result above.
Initially I tried to use form load/shown events instead of alternate threads, but the image on the forms failed to load until after the messagebox had shown the error (rather than displaying, then running the connection check)
Could you set up an event to fire on Form2 with the results of the db check? Subscribe to the event on Form1 and tell it to close if the conditions warrant.
Not sure if it would work or not, but something like:
public Form2 : Form
{
public delegate void DbCheckHandler(object sender, DbEventArgs e);
public event DbCheckHandler DbCheckComplete;
//check the db
DbCheckComplete(this, new DbEventArgs { ShouldClose = true; });
}
public Form1 : Form
{
Form2 form2 = new Form2();
form2.DbCheckComplete += new DbCheckHandler(CheckDbResult);
form2.Show();
private void CheckDbResult(object sender, DbEventArgs e)
{
if(e.ShouldClose)
{
this.Close();
}
}
}
With some help from previous answers posted by Hans Passant (here and here), My solution was as follows:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new MyApp().Run(args);
}
class MyApp : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new StartupSplash();
}
protected override void OnCreateMainForm()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnectionString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
// pause not needed while checking for db connection as that takes its own amount of time to complete.
if (result)
{
System.Threading.Thread.Sleep(3000); //pause moved here to give the splash some time on screen if db connection available
this.MainForm = new MainWindow();
}
else
{
MessageBox.Show("Unable to connect to the database");
Environment.Exit(1); // shuts down the program if database connection not avaliable.
}
}
}

How to allow different login ID to be logged into the application for once in the same local computer

I've a window application which consists of splash screen, login window, and the main window. As what I've searched, most of the single instance application checking is at the application startup (App.xaml.cs):
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();
}
base.OnStartup(e);
}
}
For my case, I want to allow only one user with different login ID to be logged into the application for once in the same local computer. How can I implement the method above in Login.xaml.cs or MainWindow.xaml.cs, since the method above is done in App.xaml.cs?
By comparing process main title window:
public void SingleInstanceHandler()
{
Process[] procList = Process.GetProcesses();
foreach(Process proc in procList)
{
if (!string.IsNullOrEmpty(proc.MainWindowTitle))
{
if (proc.MainWindowTitle == windowTitle)
{
//Show relevant message
Application.Current.Shutdown();
}
}
}
}
This can be placed not only in App.xaml.cs, but also in Login.xaml.cs or MainWindow.xaml.cs

c# simple web server that launches a form on receiving a request

I have a C# application that acts as a web server to the local machine only.
I have used the example from this site as the base for my web server.
So, here is my problem, the main application spawns a listener thread to listen for and handle the response.
In Program.cs
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new SysTrayApp());
}
}
In SysTrayApp.cs:
public partial class SysTrayApp : Form
{
...
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
WebServer myWebServer = new WebServer(WebServer.Response, "http://localhost:8080/");
myWebServer.Run();
}
}
In WebServer.cs
...
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
var ctx = _listener.GetContext();
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}
}
catch { } // suppress any exceptions
});
}
When a request is received, I want to display a Windows Form to the local environment (not the HTTP response). The problem is that I am no longer in the main STAThread when I receive the request, so I can't open a form properly.
If I try open it in the listener thread, the form just freezes because the listener starts listening and blocks the thread. A similar thing happens if I open a threadpool thread.
public static string Response(HttpListenerRequest request)
{
Form form = new Form();
form.Show();
return "TEST!";
}
If I open it in a new normal Thread, the form pops up and then the thread closes and then the form closes again.
public static string Response(HttpListenerRequest request)
{
Thread thread = new Thread(startForm);
thread.Start();
return "TEST!";
}
public static void startForm()
{
Form form = new Form();
form.Show();
}
So, from what I can figure out, only forms in the main application/UI thread seem to work properly and also, you can't block the main thread, or else the forms freeze. So, from within the WebServer listener, how do I trigger the opening of a form on the main thread?
Should I create an event on the main form that launches the second form and try to trigger it from the listener thread?
Or is there a better way to do it?
P.S. I am a PHP/Python programmer that has had to venture into C# just for a single project, so I am not really sure what I am doing.
You can invoke a method of SysTrayApp in the worker thread as below
public class SysTrayApp : Form
{
public SysTrayApp()
{
Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning);
}
void ActualWork(DateTime dt)
{
this.Text = dt.ToString();
}
void Process()
{
while(true)
{
this.Invoke((Action)(() => ActualWork(DateTime.Now)));
Thread.Sleep(1000);
}
}
}
BTW: Don't use threads from threadpool for long running tasks. Why .net Threadpool is used only for short time span tasks?

WPF mutex for single app instance not working

I'm trying to use the mutex method for only allowing one instance of my app to run. That is - I only want a max of one instance for all users on a machine. I've read through the various other threads on this issue and the solution seems straightforward enough but in testing I can't get my second instance to not run. Here is my code...
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// check that there is only one instance of the control panel running...
bool createdNew = true;
using (Mutex instanceMutex = new Mutex(true, #"Global\ControlPanel", out createdNew))
{
if (!createdNew)
{
Application.Current.Shutdown();
return;
}
}
base.OnStartup(e);
}
}
You're also disposing the mutex in the same method, so the mutex only lives for the duration of the method. Store the mutex in a static field, and keep it alive for the duration of your application.
Here is my new code which has the answer provided by #Willem van Rumpt (and #OJ)...
public partial class App : Application
{
private Mutex _instanceMutex = null;
protected override void OnStartup(StartupEventArgs e)
{
// check that there is only one instance of the control panel running...
bool createdNew;
_instanceMutex = new Mutex(true, #"Global\ControlPanel", out createdNew);
if (!createdNew)
{
_instanceMutex = null;
Application.Current.Shutdown();
return;
}
base.OnStartup(e);
}
protected override void OnExit(ExitEventArgs e)
{
if(_instanceMutex != null)
_instanceMutex.ReleaseMutex();
base.OnExit(e);
}
}
You're destroying the Mutex immediately after you've created it and tested it. You need to keep the Mutex reference alive for lifetime of your application.
Make the Mutex a member/field of your Application class.
Release the mutex when your application shuts down.
As extension sample:
public static class Extension
{
private static Mutex mutex;
public static bool IsOneTimeLaunch(this Application application, string uniqueName = null)
{
var applicationName = Path.GetFileName(Assembly.GetEntryAssembly().GetName().Name);
uniqueName = uniqueName ?? string.Format("{0}_{1}_{2}",
Environment.MachineName,
Environment.UserName,
applicationName);
application.Exit += (sender, e) => mutex.Dispose();
bool isOneTimeLaunch;
mutex = new Mutex(true, uniqueName, out isOneTimeLaunch);
return isOneTimeLaunch;
}
}
App Class:
protected override void OnStartup(StartupEventArgs e)
{
if (this.IsOneTimeLaunch())
{
base.OnStartup(e);
}
else
{
this.Shutdown();
}
}
I can suggest a much cleaner approach that also introduce the useful concept of overriding the Main method in WPF application. Also, if using your solution you take a look at the task manager, you will notice that the new instance actually reach the execution state (you can see a new process created in the list of task) and then suddenly close. The approach proposed in the post that follows will avoid this drawback too.
http://blog.clauskonrad.net/2011/04/wpf-how-to-make-your-application-single.html
I was told to implement this mutex approach on an already developed WPF application that we had. The work around to the problem with using override of the OnStart() that I found was in
App.g.cs
This file is located in
obj\x86\debug\
and contains the main() function, so you just simply put this piece of code in your main function.
bool isOnlyInstance = false;
Mutex m = new Mutex(true, #"WpfSingleInstanceApplication", out isOnlyInstance);
if (!isOnlyInstance)
{
MessageBox.Show("Another Instance of the application is already running.",
"Alert",
MessageBoxButton.OK,
MessageBoxImage.Exclamation);
return;
}
GC.KeepAlive(m);
but for this you need to keep the BUILD ACTION of your app.xaml set to ApplicationDefinition
NOTE: This might not be the best way, since I'm a beginner. (please tell me if there's something I should change)
I did this from this link just add the given class and a single line in you App.Xaml.cs
http://wpfsingleinstance.codeplex.com/
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
WpfSingleInstance.Make(); //added this is the function of that class
base.OnStartup(e);
}
}

Categories

Resources