|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Make Single Instance in C#In the Visual Studio documentation for VISUAL BASIC ONLY, there seems to be
the ability to mark an application as "Single Instance" so that it will run only once. How do implement this same functionality in a Windows Forms C# application? Alex internal void ProcessImport(bool IsInteractive, ProcessMode processMode,
System.ComponentModel.ISynchronizeInvoke synchronizer) { _IsInteractive = IsInteractive; /* Use mutex to allow only one running instance of application */ bool gotMutex = false; if (_mutex == null) { _mutex = new Mutex(true, "MLXListingImport", out _ownsMutex); if (_ownsMutex) { gotMutex = true; } } /* Didn't get it */ if (!gotMutex) { _log.Warn("Attempted to start second running instance of program."); if (IsInteractive) { MessageBox.Show( "Import processing is currently running in an other instance of this program.", "Import Request Cancelled",MessageBoxButtons.OK,MessageBoxIcon.Information); } OnImportComplete(); } } /* ProcessImport() */ Show quote "Alex Maghen" <AlexMaghen@newsgroup.nospam> wrote in message news:66BDC47E-B37F-4D4C-A61E-0142D2F94140@microsoft.com... > In the Visual Studio documentation for VISUAL BASIC ONLY, there seems to > be > the ability to mark an application as "Single Instance" so that it will > run > only once. How do implement this same functionality in a Windows Forms C# > application? > > Alex Jim -
Thanks for this and forgive but... I'm not quite sure what I would do with this. What do I do with the "internal void ProcessImport()" function? Where does it go? Do I call it from somewhere? Alex Show quote "Jim Rand" wrote: > internal void ProcessImport(bool IsInteractive, ProcessMode processMode, > System.ComponentModel.ISynchronizeInvoke > synchronizer) > { > _IsInteractive = IsInteractive; > > /* Use mutex to allow only one running instance of application */ > bool gotMutex = false; > if (_mutex == null) > { > _mutex = new Mutex(true, "MLXListingImport", out _ownsMutex); > if (_ownsMutex) > > { > gotMutex = true; > } > } > > /* Didn't get it */ > if (!gotMutex) > { > _log.Warn("Attempted to start second running instance of program."); > if (IsInteractive) > { > MessageBox.Show( > "Import processing is currently running in an other instance of this > program.", > "Import Request > Cancelled",MessageBoxButtons.OK,MessageBoxIcon.Information); > } > OnImportComplete(); > } > > } /* ProcessImport() */ > > "Alex Maghen" <AlexMaghen@newsgroup.nospam> wrote in message > news:66BDC47E-B37F-4D4C-A61E-0142D2F94140@microsoft.com... > > In the Visual Studio documentation for VISUAL BASIC ONLY, there seems to > > be > > the ability to mark an application as "Single Instance" so that it will > > run > > only once. How do implement this same functionality in a Windows Forms C# > > application? > > > > Alex > > > Alex Maghen <AlexMaghen@newsgroup.nospam> wrote:
> Thanks for this and forgive but... I'm not quite sure what I would do with The example was a bit confusing IMO, as it didn't show the other > this. What do I do with the "internal void ProcessImport()" function? Where > does it go? Do I call it from somewhere? variables involved etc. Have a look at http://pobox.com/~skeet/csharp/faq/#one.application.instance and see if that helps. You'll want to insert the sample code (using an appropriate unique name) early on, eg as the first thing Main does. -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too It's funny - I just today had to do this for an application that we offer.
There was one additional key - if the application was already started, the new instance should cause the old instance to Activate, then the new instance should just disappear. This means (to the user) that if they launch the application, they get to use the application. I ran into a surprisingly ugly scenario, where the application was minimized to the system tray (not the task bar), and the Process class would return "0" as the Main Window Handle for the process. This made ShowWindow() very unhappy. I found code to work around this at: http://www.myjavaserver.com/~walthari/SpecialServices.cs His implemention of FindMainWindow(int processId) makes use of EnumWindows in a way I wouldn't have thought of - and more importantly, it worked. Everything worked great after that. (I didn't use any of his other code, as I rolled my own implementation using a Named Mutex. This is easy enough to do, and I have some weird custom requirements based on user settings and configuration options...) -- Show quoteChris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP http://www.coversant.com/blogs/cmullins "Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message news:MPG.208764a9654d270098dabb@msnews.microsoft.com... > Alex Maghen <AlexMaghen@newsgroup.nospam> wrote: >> Thanks for this and forgive but... I'm not quite sure what I would do >> with >> this. What do I do with the "internal void ProcessImport()" function? >> Where >> does it go? Do I call it from somewhere? > > The example was a bit confusing IMO, as it didn't show the other > variables involved etc. > > Have a look at > http://pobox.com/~skeet/csharp/faq/#one.application.instance > and see if that helps. > > You'll want to insert the sample code (using an appropriate unique > name) early on, eg as the first thing Main does. > > -- > Jon Skeet - <sk***@pobox.com> > http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet > If replying to the group, please do not mail me too Chris Mullins [MVP] <cmull***@yahoo.com> wrote:
> It's funny - I just today had to do this for an application that we offer. <snip>> There was one additional key - if the application was already started, the > new instance should cause the old instance to Activate, then the new > instance should just disappear. This means (to the user) that if they launch > the application, they get to use the application. Yup, that's a pretty common scenario. Time to update the FAQ to include that link, I suspect... -- Jon Skeet - <sk***@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet If replying to the group, please do not mail me too This was just a quick example of using a Mutex to stop a second instance
from running. Hi Alex,
Yes, a WinForms application written in VB.NEThave a specific application framework, with which we could config a VB.NET application a single instance application. Unfortunately, a WinForms application written in C# doesn't have such a application framework. A common way to make a application written in C# single instance is to make use of Mutex, as Jon has suggested. You may add the following code to the static Main method of the application. using System.Threading; [STAThread] static void Main() { bool firstInstance; Mutex mutex = new Mutex(false, "Local\\" +someUniqueName, out firstInstance); if (firstInstance) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } else { MessageBox.Show("An instance has already been run!"); } } If you're using VS05, you have another option, that is to use Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class. We could derive a class from WindowsFormsApplicationBase class and set the IsSingleInstance property to true. The following is a sample. It requires that you add a reference to 'Microsoft.VisualBasic' to your C# project. using System.Windows.Forms; using Microsoft.VisualBasic.ApplicationServices; class Program:WindowsFormsApplicationBase { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Program prog = new Program(); prog.EnableVisualStyles = true; prog.MainForm = new Form1(); prog.Run(new string[] { ""}); } public Program() { this.IsSingleInstance = true; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { MessageBox.Show("another instance has been run!"); base.OnStartupNextInstance(eventArgs); } } Hope this helps. If you have anything unclear, please feel free to let me know. Sincerely, Linda Liu Microsoft Online Community Support ================================================== Get notification to my posts through email? Please refer to http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif ications. Note: The MSDN Managed Newsgroup support offering is for non-urgent issues where an initial response from the community or a Microsoft Support Engineer within 1 business day is acceptable. Please note that each follow up response may take approximately 2 business days as the support professional working with you may need further investigation to reach the most efficient resolution. The offering is not appropriate for situations that require urgent, real-time or phone-based interactions or complex project analysis and dump analysis issues. Issues of this nature are best handled working with a dedicated Microsoft Support Engineer by contacting Microsoft Customer Support Services (CSS) at http://msdn.microsoft.com/subscriptions/support/default.aspx. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights. Linda -
This is very helpful. Just one question about your C# sample (the top one): In the case where it's NOT the first instance, how do I get access to the information about how this attempt at running the app ocurred (things like command line parameters)? Alex Show quote "Linda Liu [MSFT]" wrote: > Hi Alex, > > Yes, a WinForms application written in VB.NEThave a specific application > framework, with which we could config a VB.NET application a single > instance application. Unfortunately, a WinForms application written in C# > doesn't have such a application framework. > > A common way to make a application written in C# single instance is to make > use of Mutex, as Jon has suggested. You may add the following code to the > static Main method of the application. > > using System.Threading; > > [STAThread] > static void Main() > { > bool firstInstance; > Mutex mutex = new Mutex(false, "Local\\" +someUniqueName, out > firstInstance); > > if (firstInstance) > { > Application.EnableVisualStyles(); > Application.SetCompatibleTextRenderingDefault(false); > Application.Run(new Form1()); > } > else > { > MessageBox.Show("An instance has already been run!"); > } > } > > If you're using VS05, you have another option, that is to use > Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase > class. We could derive a class from WindowsFormsApplicationBase class and > set the IsSingleInstance property to true. > > The following is a sample. It requires that you add a reference to > 'Microsoft.VisualBasic' to your C# project. > > using System.Windows.Forms; > using Microsoft.VisualBasic.ApplicationServices; > > class Program:WindowsFormsApplicationBase > { > /// <summary> > /// The main entry point for the application. > /// </summary> > [STAThread] > static void Main() > { > Program prog = new Program(); > prog.EnableVisualStyles = true; > prog.MainForm = new Form1(); > prog.Run(new string[] { ""}); > > } > public Program() > { > this.IsSingleInstance = true; > } > > protected override void > OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) > { > MessageBox.Show("another instance has been run!"); > base.OnStartupNextInstance(eventArgs); > } > } > > Hope this helps. > If you have anything unclear, please feel free to let me know. > > Sincerely, > Linda Liu > Microsoft Online Community Support > > ================================================== > Get notification to my posts through email? Please refer to > http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif > ications. > > Note: The MSDN Managed Newsgroup support offering is for non-urgent issues > where an initial response from the community or a Microsoft Support > Engineer within 1 business day is acceptable. Please note that each follow > up response may take approximately 2 business days as the support > professional working with you may need further investigation to reach the > most efficient resolution. The offering is not appropriate for situations > that require urgent, real-time or phone-based interactions or complex > project analysis and dump analysis issues. Issues of this nature are best > handled working with a dedicated Microsoft Support Engineer by contacting > Microsoft Customer Support Services (CSS) at > http://msdn.microsoft.com/subscriptions/support/default.aspx. > ================================================== > > This posting is provided "AS IS" with no warranties, and confers no rights. > > Linda -
One more question about this - What happens when the application is run for a second time and, instead of running it that second time, in my Main() I want to be able to call a function inside the main form of the original instance. How do I get a reference to that Form object here? Alex Show quote "Linda Liu [MSFT]" wrote: > Hi Alex, > > Yes, a WinForms application written in VB.NEThave a specific application > framework, with which we could config a VB.NET application a single > instance application. Unfortunately, a WinForms application written in C# > doesn't have such a application framework. > > A common way to make a application written in C# single instance is to make > use of Mutex, as Jon has suggested. You may add the following code to the > static Main method of the application. > > using System.Threading; > > [STAThread] > static void Main() > { > bool firstInstance; > Mutex mutex = new Mutex(false, "Local\\" +someUniqueName, out > firstInstance); > > if (firstInstance) > { > Application.EnableVisualStyles(); > Application.SetCompatibleTextRenderingDefault(false); > Application.Run(new Form1()); > } > else > { > MessageBox.Show("An instance has already been run!"); > } > } > > If you're using VS05, you have another option, that is to use > Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase > class. We could derive a class from WindowsFormsApplicationBase class and > set the IsSingleInstance property to true. > > The following is a sample. It requires that you add a reference to > 'Microsoft.VisualBasic' to your C# project. > > using System.Windows.Forms; > using Microsoft.VisualBasic.ApplicationServices; > > class Program:WindowsFormsApplicationBase > { > /// <summary> > /// The main entry point for the application. > /// </summary> > [STAThread] > static void Main() > { > Program prog = new Program(); > prog.EnableVisualStyles = true; > prog.MainForm = new Form1(); > prog.Run(new string[] { ""}); > > } > public Program() > { > this.IsSingleInstance = true; > } > > protected override void > OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) > { > MessageBox.Show("another instance has been run!"); > base.OnStartupNextInstance(eventArgs); > } > } > > Hope this helps. > If you have anything unclear, please feel free to let me know. > > Sincerely, > Linda Liu > Microsoft Online Community Support > > ================================================== > Get notification to my posts through email? Please refer to > http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif > ications. > > Note: The MSDN Managed Newsgroup support offering is for non-urgent issues > where an initial response from the community or a Microsoft Support > Engineer within 1 business day is acceptable. Please note that each follow > up response may take approximately 2 business days as the support > professional working with you may need further investigation to reach the > most efficient resolution. The offering is not appropriate for situations > that require urgent, real-time or phone-based interactions or complex > project analysis and dump analysis issues. Issues of this nature are best > handled working with a dedicated Microsoft Support Engineer by contacting > Microsoft Customer Support Services (CSS) at > http://msdn.microsoft.com/subscriptions/support/default.aspx. > ================================================== > > This posting is provided "AS IS" with no warranties, and confers no rights. > > Hi Alex,
Thank you for your reply. As for the option of using mutex, we could use ChannelServices to register a channel for the main form when the application is run for the first time. When the application is run for the second time, we could create a proxy for the previous instance using RemotingServices. Pass the command line parameters of the second instance or call a function inside the main form of the original instance, and then exit the second instance. The following is a sample. It requires that you add a reference to System.Runtime.Remoting in your application. using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Threading; static class Program { [STAThread] static void Main(string[] args) { bool firstInstance = false; string safeName = Application.UserAppDataPath.Replace(@"\", "_"); Mutex mutex = new Mutex(true, safeName, out firstInstance); if(!firstInstance) { string formUrl = "tcp://localhost:1313/form1"; Form1 otherMainfrm = (Form1)RemotingServices.Connect(typeof(Form1), formUrl); otherMainfrm.Method1(args); return; } ChannelServices.RegisterChannel(new TcpChannel(1313),false); RemotingServices.Marshal(form1, "form1"); Application.Run(form1); } static Form1 form1 = new Form1(); } public partial class Form1 : Form { public Form1() { InitializeComponent(); } delegate void MethodCallback(string[] args); public void Method1(string[] args) { // Note that it is not allowed for non-UI thread to access controls on the form, instead, we should use the Invoke method of the form to execute a delegate on the UI thread that own's the control's underlying windows handle. if(this.InvokeRequired) { MethodCallback callback = new MethodCallback(Method1); this.Invoke(callback, new object[] { args }); return; } string command = ""; for(int i =0;i<args.Length; i++) { command += args[i] + " "; } this.textBox1.Text = command; } } As the option of using WindowsFormsApplicationBase, it's easy and straight forward to do this. The following is a sample. using System.Windows.Forms; using Microsoft.VisualBasic.ApplicationServices; class Program:WindowsFormsApplicationBase { [STAThread] static void Main(string[] commandline) { Program prog = new Program(); mainform = new Form1(); prog.MainForm = mainform; prog.Run(commandline); } static Form1 mainform = null; public Program() { this.IsSingleInstance = true; } protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) { string command = ""; for(int i =0 ; i<eventArgs.CommandLine.Count; i++) { command += eventArgs.CommandLine[i] + " "; } MessageBox.Show("this is the second instance! " + eventArgs.CommandLine.Count.ToString() + " " + command); base.OnStartupNextInstance(eventArgs); mainform.Method1(); } } Hope this helps. If you have any question, please feel free to let me know. Sincerely, Linda Liu Microsoft Online Community Support |
|||||||||||||||||||||||