I have managed to find the following code from StackOverflow:
using Microsoft.VisualBasic.ApplicationServices;
using System.Windows.Forms;
namespace ExciteEngine2.MainApplication {
public class SingleInstanceController: WindowsFormsApplicationBase {
public delegate Form CreateMainForm();
public delegate void StartNextInstanceDelegate(Form mainWindow);
private readonly CreateMainForm formCreation;
private readonly StartNextInstanceDelegate onStartNextInstance;
public SingleInstanceController() {
}
public SingleInstanceController(AuthenticationMode authenticationMode)
: base(authenticationMode) {
}
public SingleInstanceController(CreateMainForm formCreation, StartNextInstanceDelegate onStartNextInstance) {
// Set whether the application is single instance
this.formCreation = formCreation;
this.onStartNextInstance = onStartNextInstance;
IsSingleInstance = true;
StartupNextInstance += this_StartupNextInstance;
}
private void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e) {
if (onStartNextInstance != null) {
onStartNextInstance(MainForm);
// This code will be executed when the user tries to start the running program again,
// for example, by clicking on the exe file.
// This code can determine how to re-activate the existing main window of the running application.
}
}
protected override void OnCreateMainForm() {
// Instantiate your main application form
MainForm = formCreation();
}
//public void Run() {
// string[] commandLine = new string[0];
// base.Run(commandLine);
//}
protected override void OnRun() {
base.OnRun();
}
}
}
And I have this in my Program.cs:
private static Form CreateForm() {
return new AppMDIRibbon();
}
private static void OnStartNextInstance(Form mainWindow)
{
// When the user tries to restart the application again, the main window is activated again.
mainWindow.WindowState = FormWindowState.Maximized;
}
[STAThread]
static void Main(string[] args) {
SingleInstanceController ApplicationSingleInstanceController = new SingleInstanceController(CreateForm, OnStartNextInstance);
ApplicationSingleInstanceController.Run(args);
#region Application Logic
#endregion
}
Now, I have a lot of application logic that I need BEFORE the Run():
#region Application Logic
//Uninstall
foreach (string arg in args) {
if (arg.Split('=')[0] == "/u") {
ApplicationLogger.Info("Uninstallation command received.");
Process.Start(new ProcessStartInfo(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\msiexec.exe", "/x " + arg.Split('=')[1]));
return;
}
}
SetupXPO();
SetupLogging();
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += Application_ThreadException;
try {
ApplicationLogger.Info("Setting Telerik Theme: " + ConfigurationManager.AppSettings["ThemeToUse"]);
ThemeResolutionService.ApplicationThemeName = ConfigurationManager.AppSettings["ThemeToUse"];
}
catch (Exception ex) {
ApplicationLogger.Error("Exception while setting Telerik Theme.", ex);
ThemeResolutionService.ApplicationThemeName = "ControlDefault";
}
DevExpress.UserSkins.OfficeSkins.Register();
DevExpress.UserSkins.BonusSkins.Register();
DevExpress.Skins.SkinManager.EnableFormSkins();
DevExpress.Skins.SkinManager.EnableMdiFormSkins();
if (args.Contains("/dx")) {
Application.Run(new AppMDIRibbonDX());
ApplicationLogger.Info("Application (DX) started.");
}
else {
Application.Run(new AppMDIRibbon());
ApplicationLogger.Info("Application started.");
}
#endregion
How can I setup this logic? I'm using a commandline argument to actually start an alternate form. I'm using a commandline argument to cause an uninstallation and also calling some method to setup DB and logging. Similarly, I'm setting up culture and themes too. All this before the actual application run. Can anyone suggest?
If you simplify the Visual Basic-derived class you linked, you can just replace your current call to Application.Run(). This does depend on how you want to handle subsequent instances.
With the version below, just change you calls of: Application.Run(myForm) to SingleInstanceApplication.Run(myForm);
public sealed class SingleInstanceApplication : WindowsFormsApplicationBase
{
private static SingleInstanceApplication _application;
private SingleInstanceApplication()
{
base.IsSingleInstance = true;
}
public static void Run(Form form)
{
_application = new SingleInstanceApplication {MainForm = form};
_application.StartupNextInstance += NextInstanceHandler;
_application.Run(Environment.GetCommandLineArgs());
}
static void NextInstanceHandler(object sender, StartupNextInstanceEventArgs e)
{
// Do whatever you want to do when the user launches subsequent instances
// like when the user tries to restart the application again, the main window is activated again.
_application.MainWindow.WindowState = FormWindowState.Maximized;
}
}
Then your Main() method contains your "Application Logic"
[STAThread]
static void Main(string[] args) {
#region Application Logic
//Uninstall
foreach (string arg in args) {
if (arg.Split('=')[0] == "/u") {
ApplicationLogger.Info("Uninstallation command received.");
Process.Start(new ProcessStartInfo(Environment.GetFolderPath(Environment.SpecialFolder.System) + "\\msiexec.exe", "/x " + arg.Split('=')[1]));
return;
}
}
SetupXPO();
SetupLogging();
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-GB");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += Application_ThreadException;
try {
ApplicationLogger.Info("Setting Telerik Theme: " + ConfigurationManager.AppSettings["ThemeToUse"]);
ThemeResolutionService.ApplicationThemeName = ConfigurationManager.AppSettings["ThemeToUse"];
}
catch (Exception ex) {
ApplicationLogger.Error("Exception while setting Telerik Theme.", ex);
ThemeResolutionService.ApplicationThemeName = "ControlDefault";
}
DevExpress.UserSkins.OfficeSkins.Register();
DevExpress.UserSkins.BonusSkins.Register();
DevExpress.Skins.SkinManager.EnableFormSkins();
DevExpress.Skins.SkinManager.EnableMdiFormSkins();
if (args.Contains("/dx")) {
SingleInstanceApplication.Run(new AppMDIRibbonDX());
ApplicationLogger.Info("Application (DX) started.");
}
else {
SingleInstanceApplication.Run(new AppMDIRibbon());
ApplicationLogger.Info("Application started.");
}
#endregion
}
Related
I have created simple MutexManager:
public static class MutexManager
{
private static string mutexName
{
get
{
return "MyAppName" + System.Security.Principal.WindowsIdentity.GetCurrent().User.AccountDomainSid;
}
}
public static bool CreateApplicationMutex()
{
bool createdNew;
var mutex = new Mutex(false, mutexName, out createdNew);
return createdNew;
}
}
The problem is that CreateApplicationMutex always returns true on new application instance startup. As long as I had exactly same code in app.cs everything was correct, but after I moved it to MutexManager createdNew is always true. What am I doing wrong?
The following works as expected for me, and returns false on second instance
public static class MutexManager
{
private static string mutexName => "MyAppName" + System.Security.Principal.WindowsIdentity.GetCurrent()
.User?.AccountDomainSid;
public static bool CreateApplicationMutex()
{
new Mutex(false, mutexName, out var createdNew);
return createdNew;
}
}
private static void Main(string[] args)
{
Console.WriteLine(MutexManager.CreateApplicationMutex());
Console.ReadKey();
}
Output
true
false
Make sure you debug your app, and check the mutex name
Update
Winforms
MessageBox.Show(
MutexManager.CreateApplicationMutex()
.ToString());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
WPF
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
MessageBox.Show(
MutexManager.CreateApplicationMutex()
.ToString());
base.OnStartup(e);
}
}
Once again it works as expected, and cant be reproduced
I had a similar problem, the reason was life time of mutex variable. Following code works fine by me in debug version, but always returns true for created_new in release version:
using System;
static class Program
{
[STAThread]
static void Main(string[] args)
{
string mutex_name = "MyApplicationName_SingleInstanceMutex";
bool created_new = false;
System.Threading.Mutex mutex = new System.Threading.Mutex(false, mutex_name, out created_new);
if (!created_new)
{
System.Windows.Forms.MessageBox.Show("Application is already started!");
return;
}
/* Create & run mainForm here */
}
}
Making mutex static solves the problem:
using System;
static class Program
{
static System.Threading.Mutex mutex = null;
[STAThread]
static void Main(string[] args)
{
string mutex_name = "MyApplicationName_SingleInstanceMutex";
bool created_new = false;
mutex = new System.Threading.Mutex(false, mutex_name, out created_new);
if (!created_new)
{
System.Windows.Forms.MessageBox.Show("Application is already started!");
return;
}
/* Create & run mainForm here */
}
}
i'm really struggeling with OOP. I would like to start a process in my additional class. The process is a shell and I need to access this shell from severel forms and classes to write the commands and to receive the output. I use events to get the data. Here is my class for the process.
My class for the
public class ADBShell
{
public static string output = String.Empty;
public static Process adbshell = new Process();
public void Start_ADBShell()
{
if (adbshell != null && !adbshell.HasExited)
return;
adbshell = new Process();
adbshell.StartInfo.UseShellExecute = false;
adbshell.StartInfo.FileName = #"D:\adb\adb.exe";
adbshell.StartInfo.Arguments = "shell";
adbshell.StartInfo.RedirectStandardOutput = true;
adbshell.StartInfo.RedirectStandardInput = true;
//adb.StartInfo.RedirectStandardError = true;
adbshell.EnableRaisingEvents = true;
adbshell.StartInfo.CreateNoWindow = true;
//adb.ErrorDataReceived += new DataReceivedEventHandler(adb_ErrorDataReceived);
adbshell.OutputDataReceived += new DataReceivedEventHandler(adbshell_OutputDataReceived);
try { var started = adbshell.Start(); }
catch (Exception ex)
{
Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
}
//adb.BeginErrorReadLine();
adbshell.BeginOutputReadLine();
}
void adbshell_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
output += (e.Data) + Environment.NewLine;
}
public void press_touch(string x, string y)
{
adbshell.StandardInput.WriteLine("input tap " + String.Format("{0} {1}", x, y));
Debug.WriteLine("pressed");
}
}
My Form class looks like
public partial class Form1 : Form
{
private bool _record;
private bool _selecting;
private Rectangle _selection;
//---------------------------------------------------------------------
public Form1()
{
InitializeComponent();
}
//---------------------------------------------------------------------
private void Form1_Load(object sender, System.EventArgs e)
{
ADBShell adbshell = new ADBShell();
adbshell.Start_ADBShell();
}
Everytime I have to make a new object in my methods, but i dont want to create everytime a new object. I would like make one time the object and access everytime to the same object. I do not want to make servel processes. I need only proccess and send and receive everytime the data to this process.
Do I have to make a static class?
How I can dispose and close my process after I'm quit my Form Class?
1: You do not want a static class. You want a SINGLETON - that is a class that has only one instance. This is normally accessed using a static property. At the easiest way this works like this:
public class A () {
private A () {}
public static A Instance {get; } = new A();
}
Access is via:
A.Instance
2: You do not. Processes do not get disposed. You exit the last thread that is not a background thread then the process ends. Otherwise you kill it, if that has to be done "In force" from the outside.
Move the ADBShell intialization in constructor of Form class. So this object will live till Form is not exited and to release resources by process make sure you call Process.close() in ADBShell class (Either in destructor or implement a IDisposable)
public partial class Form1 : Form
{
private bool _record;
private bool _selecting;
ADBShell adbshell;
private Rectangle _selection;
//---------------------------------------------------------------------
public Form1()
{
InitializeComponent();
adbshell = new ADBShell();
}
//---------------------------------------------------------------------
private void Form1_Load(object sender, System.EventArgs e)
{
adbshell.Start_ADBShell();
}
Dipose Process like this by adding Destructor
~ADBShell()
{
process.Close();
}
or implement Dispose method of IDisposable
Class ABDShell : IDisposable
{
...
...
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
process.Close();
}
}
}
Updated singleton class
sealed class ADBShell
{
public static string output = String.Empty;
private ABDShell _instance;
private Process _processInstance;
// Note: constructor is 'private'
private ADBShell()
{
}
public Process ProcessInstance
{
if(_processInstance==null)
_processInstance = new Process();
get _processInstance ;
}
public static ADBShell Instance
{
get
{
if (_instance == null)
{
_instance = new ABDShell();
}
return _instance;
}
}
}
Now from your Form just do this
Process process = ABDShell.Instance.ProcessInstance;
// Sealed class makes sure it is not inherited. If inheritance required, go to Abstract Pattern.
class ADBShell
{
//public static property used to expose Singleton instance.
public static ADBShell Instance;
// private constructor
private ADBShell() { }
public static ADBShell getInstance()
{
if (Instance == null)
{
Instance = new Process;
}
}
}
Update
Thank you with your helps I solved my problems and now the ADB runs much faster instead of start everytime a new process.
public class ADBShell
{
private static ADBShell instance;
//private List<Employee> employeeList = null;
private Process shell = null;
private StreamWriter myWriter = null;
private static readonly object syncRoot = new object();
private ADBShell()
{
if (shell == null)
{
shell = new Process();
shell.StartInfo.FileName = (#"D:\ADB\ADB.exe");
shell.StartInfo.Arguments = "shell";
shell.StartInfo.RedirectStandardInput = true;
shell.StartInfo.UseShellExecute = false;
shell.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
shell.StartInfo.RedirectStandardOutput = true;
shell.StartInfo.CreateNoWindow = true;
shell.EnableRaisingEvents = true;
shell.OutputDataReceived += (sender, a) => Console.WriteLine(a.Data);
shell.Start();
myWriter = shell.StandardInput;
shell.BeginOutputReadLine();
}
}
public static ADBShell Instance()
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new ADBShell();
}
}
}
return instance;
}
public void tap(int x, int y)
{
myWriter.WriteLine("input tap {0} {1}", x.ToString(), y.ToString());
Thread.Sleep(10);
}
public void tap(string x, string y)
{
myWriter.WriteLine("input tap {0} {1}", x, y);
Thread.Sleep(10);
}
public void exit()
{
myWriter.WriteLine("exit");
}
public void Close()
{
myWriter.WriteLine("exit");
shell.WaitForExit();
if (!shell.HasExited)
{
shell.Kill();
}
shell.Close();
shell.Dispose();
myWriter.Close();
myWriter.Dispose();
}
}
I'm new at C# programming and i'm lost with a thing that could be simple.
Executing a console application, at a moment i need to call a Windows Form that will show statics of the execution but when i call the form1.ShowDialog(); this stop the console runtime.
How do i keep my console execution alive while i show a Windows form screen ?
class Program
{
static Form1 form = new Form1();
public static bool run = true;
static void Main(string[] args)
{
work();
}
public static void work()
{
form.Show();
while (run)
{
Console.WriteLine("Console still running");
}
}
}
try this it work on me
using System.Windows.Forms;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public static bool run = true;
static void Main(string[] args)
{
Startthread();
Application.Run(new Form1());
Console.ReadLine();
}
private static void Startthread()
{
var thread = new Thread(() =>
{
while (run)
{
Console.WriteLine("console is running...");
Thread.Sleep(1000);
}
});
thread.Start();
}
}
}
Threading is like "process inside a process" in my own understanding.
See this question. You have to use Form1.Show() because Form1.ShowDialog() pauses execution until the form is closed.
Update This seems to be working (with Application.Run):-
public static Form1 form = new Form1();
public static bool run = true;
[MTAThread]
static void Main(string[] args)
{
new Thread(() => Application.Run(form)).Start();
new Thread(work).Start();
}
public static void work()
{
while (run)
{
Console.WriteLine("Console Running");
}
}
I am working on converting a console application into a windowed format and as someone who knows little about it but has had experience with a similar application already in window format in the past I figured it wouldn't be too hard.
So I created a form and added a textbox to it just to get the logging information to start with.
This console app used to run in a single thread, I have since added a second thread to allow the form to run side by side with the console for testing. (it runs fine in a single thread strangely now too).
This is the code I am using to write text to the form except that I am not getting ANYTHING at all on the form.
static Form1 f = new Form1();
delegate void SetTextCallback(string s);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
I can confirm that there is text entering the "text" variable but it is not getting to the form.
Any help would be appreciated.
This is the full file:
using System;
using System.Windows.Forms;
using Chraft.Properties;
using System.IO;
using Chraft.Plugins.Events.Args;
using Chraft.Plugins.Events;
namespace Chraft
{
public class Logger
{
private StreamWriter WriteLog;
private Server Server;
internal Logger(Server server, string file)
{
Server = server;
try
{
WriteLog = new StreamWriter(file, true);
WriteLog.AutoFlush = true;
}
catch
{
WriteLog = null;
}
}
~Logger()
{
try
{
WriteLog.Close();
}
catch
{
}
}
public void Log(LogLevel level, string format, params object[] arguments)
{
Log(level, string.Format(format, arguments));
}
public void Log(LogLevel level, string message)
{
//Event
LoggerEventArgs e = new LoggerEventArgs(this, level, message);
Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
if (e.EventCanceled) return;
level = e.LogLevel;
message = e.LogMessage;
//End Event
LogToConsole(level, message);
LogToForm(level, message);
LogToFile(level, message);
}
private void LogToConsole(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
Console.WriteLine(Settings.Default.LogConsoleFormat, DateTime.Now, level.ToString().ToUpper(), message);
}
}
static Form1 f = new Form1();
delegate void SetTextCallback(string s);
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
private void LogToForm(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
SetText(DateTime.Now + level.ToString().ToUpper() + message);
}
}
private void LogToFile(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogFileLevel && WriteLog != null)
WriteLog.WriteLine(Settings.Default.LogFileFormat, DateTime.Now, level.ToString().ToUpper(), message);
}
public void Log(Exception ex)
{
//Event
LoggerEventArgs e = new LoggerEventArgs(this, LogLevel.Debug, ex.ToString(), ex);
Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
if (e.EventCanceled) return;
//End Event
Log(LogLevel.Debug, ex.ToString());
}
public enum LogLevel : int
{
Trivial = -1,
Debug = 0,
Info = 1,
Warning = 2,
Caution = 3,
Notice = 4,
Error = 5,
Fatal = 6
}
}
}
The problem is that you are creating two Form objects. One that is created in your Program.cs file:
Application.Run(new Form1());
And the one you created in your logger class
Form f = new Form1();
The one passed to Application.Run is the one that the user is interacting with. It has become visible and responds to user interaction because of the Application.Run call.
The one you created on your logger class just sits there in memory. Its TextBox is happily adding the text you ask it to, but that one isn't visible anywhere.
There are many ways to handle this situation. You could gain access to the correct Form object through Application.OpenForms, but a more appropriate way to handle it would be to add an event on the logger that the form can subscribe to and it can handle updating the TextBox in response to the event.
Updated
class LoggerLogEventArgs : EventArgs
{
public LoggerLogEventArgs(string message)
{
this.message = message;
}
private string message;
public string Message { get { return message; } }
}
class Logger
{
public event EventHandler<LoggerLogEventArgs> Logged;
protected virtual void OnLogged(LoggerLogEventArgs e)
{
EventHandler<LoggerLogEventArgs> handler = Logged;
if (handler != null)
handler(this, e);
}
// I would change this method name to LogToEvent
private void LogToForm(LogLevel level, string message)
{
if ((int)level >= Settings.Default.LogConsoleLevel)
{
OnLogged(new LoggerLogEventArgs(message));
}
}
}
class Form1 : Form
{
// Subscribe to the logger only when we are ready to display text
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
GetLog().Logged += new EventHandler<LoggerLogEventArgs>(logger_Logged);
}
// Unsubscribe from the logger before we are no longer ready to display text
protected override void OnHandleDestroyed(EventArgs e)
{
GetLog().Logged -= new EventHandler<LoggerLogEventArgs>(logger_Logged);
base.OnHandleDestroyed(e);
}
private void logger_Logged(object sender, LoggerLogEventArgs e)
{
if (InvokeRequired)
BeginInvoke(new EventHandler<LoggerLogEventArgs>(logger_Logged), e);
else
textBox1.AppendText(e.Message);
}
}
hello i try this it works ( I make a console application and I add a windows form)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;
using System.Windows.Forms;
namespace ConsoleApplication6
{
class Program
{
delegate void SetTextCallback(string s);
static Form1 f;
static void Main(string[] args)
{
f = new Form1();
f.Show();
SetText("test");
Console.ReadLine();
}
private static void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (f.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
f.textBox1.Invoke(d, new object[] { text });
}
else
{
f.textBox1.AppendText(text);
}
}
}
}
I got the following code to run the application at windows startup:
private void SetStartup(string AppName, bool enable)
{
string runKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
Microsoft.Win32.RegistryKey startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey);
if (enable)
{
if (startupKey.GetValue(AppName) == null)
{
startupKey.Close();
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
startupKey.SetValue(AppName, Application.ExecutablePath.ToString());
startupKey.Close();
}
}
else
{
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
startupKey.DeleteValue(AppName, false);
startupKey.Close();
}
}
It works. but I want the program to start minimized (at windows startup only).
I didnt find a working code / good explanation how to do it.
Can you help me please?
thanks.
Have you tried
this.WindowState = FormWindowState.Minimized;
If you want to start minimized at windows startup only you can add extra argument to command line, like myapp.exe --start-minimized, then you can parse this parameter and detect whether you need to start minimized or not.
Since this is only adding a registry key to SOFTWARE\Microsoft\Windows\CurrentVersion\Run which causes the OS to start the app at startup there isn't a lot you can do unless the application you want to startup accepts a command line parameter to start minimized (You could then add the parameter to the executable path of the key).
If this is a necessary function and you can't modify the program to accept a parameter to minimize the only thing I can think of doing would be to write a program that would minimize these apps after the OS has started them.
Don't normally revive old threads but one Easy way including minimize to system tray, for WPF like this:
public class EntryPoint
{
[STAThread]
public static void Main(string[] args)
{
SingleInstanceManager manager = new SingleInstanceManager();
manager.Run(args);
}
}
public class SingleInstanceManager : WindowsFormsApplicationBase
{
SingleInstanceApplication app;
public SingleInstanceManager()
{
this.IsSingleInstance = true;
}
protected override bool OnStartup(Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new SingleInstanceApplication();
app.Run();
return false;
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
base.OnStartupNextInstance(eventArgs);
app.Activate();
}
}
public class SingleInstanceApplication : Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
bool startMinimized = false;
for (int i = 0; i != e.Args.Length; ++i)
{
if (e.Args[i] == "/StartMinimized")
{
startMinimized = true;
}
}
MainWindow mainWindow = new MainWindow();
if (startMinimized)
{
mainWindow.WindowState = WindowState.Minimized;
}
mainWindow.Show();
}
public void Activate()
{
this.MainWindow.Activate();
this.MainWindow.WindowState = WindowState.Normal;
}
}
}
Your Window class:
public partial class MainWindow : Window
{
private Window _window;
public MainWindow()
{
InitializeComponent();
SetStartup("AppName", true);
}
private void SetStartup(string AppName, bool enable)
{
string runKey = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
Microsoft.Win32.RegistryKey startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey);
if (enable)
{
if (startupKey.GetValue(AppName) == null)
{
startupKey.Close();
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
startupKey.SetValue(AppName, Assembly.GetExecutingAssembly().Location + " /StartMinimized");
startupKey.Close();
}
}
else
{
startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
startupKey.DeleteValue(AppName, false);
startupKey.Close();
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (this.WindowState == System.Windows.WindowState.Minimized)
{
var minimized = (_window.WindowState == WindowState.Minimized);
_window.ShowInTaskbar = !minimized;
}
else
ShowInTaskbar = true;
}
Worked first time so had to post. I'm using WPF notifyicon, hence why i needed it to go to system tray on windows startup.
Had a really hard time finding a good answer to this, finally found it in a really old book. On my Forms application, just opened the program.cs and changed
Application.Run(new Form1());
to
Form1 f = new Form1();
f.WindowState = FormWindowState.Minimized;
f.ShowInTaskbar = false;
Application.Run(f);
and it opens without a flicker directly to the tray. This app was more just a service, so set it to just have a notify icon and exit button when right clicked. Hope this helps!!
I have strugled with the same issue, and found a working solution:
In your program.cs, handle the parameter, and then pass that parameter to Form1:
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length != 0){
Application.Run(new Form1(args[0]));
}
else
{
Application.Run(new Form1("normalState"));
}
}
In your Form1.cs, you can call a function with the passed parameter and minimize the app:
public Form1(string parameter)
{
InitializeComponent();
MinimizeApp(parameter);
}
For example, with this function i used, if you start the application with the -minimized parameter, then it will start minimized, a notifyicon pops up in the taskbar and a bubble saying the app is started and running in the background.
public void MinimizeApp(string parameter)
{
if (parameter == "-minimized")
{
this.WindowState = FormWindowState.Minimized;
notifyIcon1.Visible = true;
notifyIcon1.BalloonTipText = "Program is started and running in the background...";
notifyIcon1.ShowBalloonTip(500);
Hide();
}
}