i have one problem with this ?!
i use this way for run only one instance of program.
it's do very good.but when i use this way in other app .
when i run one of them programs via shortcut from desktop , both programs invoke and show in desktop.
note : both programs run in windows system try .
static bool ok;
static Mutex mutex = new Mutex(true, "{123Newsoft-Cleaner Portable Program123}",out ok);
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
if (mutex.WaitOne(TimeSpan.Zero, true))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var mainForm = new Form1c();
try
{
mainForm.Visible = false;
mainForm.WindowState = FormWindowState.Normal;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Application.Run(mainForm);
}
else
{
NativeMethods.PostMessage((IntPtr)NativeMethods.HWND_BROADCAST, NativeMethods.WM_SHOWME, IntPtr.Zero, IntPtr.Zero);
}
//---------------- in main form
protected override void WndProc(ref Message M_C)
{
if (M_C.Msg == NativeMethods.WM_SHOWME)
{
ShowMe();
}
base.WndProc(ref M_C);
}
//*************
private void ShowMe()
{
if (WindowState == FormWindowState.Minimized)
{
Show();
WindowState = FormWindowState.Normal;
}
// get our current "TopMost" value (ours will always be false though)
bool top = TopMost;
// make our form jump to the top of everything
TopMost = true;
// set it back to whatever it was
TopMost = top;
}
This is already well supported by the .NET Framework. You want to use the WindowsFormsApplicationBase class. Set the IsSingleInstance property to true. You can override the OnStartupNextInstance method to do anything you like when another instance gets started. Like restoring the window of the first instance. Rewrite your Program.cs file to look like this:
using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices; // Add reference to Microsoft.VisualBasic
namespace WindowsFormsApplication1 {
class Program : WindowsFormsApplicationBase {
[STAThread]
static void Main(string[] args) {
var app = new Program();
app.Run(args);
}
public Program() {
this.IsSingleInstance = true;
this.EnableVisualStyles = true;
this.MainForm = new Form1();
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) {
if (this.MainForm.WindowState == FormWindowState.Minimized) this.MainForm.WindowState = FormWindowState.Normal;
this.MainForm.Activate();
}
}
}
To add to what Hans Passant wrote, I added an extra method on the main form that handles restoring the window and activating it. This was to wrap the invoke required condition of the form.
So the added method on the form is:
/// <summary>
/// Recovers this instance of the form.
/// </summary>
public void RestoreFromTray()
{
if(this.InvokeRequired)
{
this.Invoke(new Action(RestoreFromTray) );
return;
}
this.Visible = true;
this.WindowState = FormWindowState.Normal;
this.Activate();
}
Then in Hans' method, I changed the override to simply:
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
((formClassName)this.MainForm).RestoreFromTray();
}
Where formClassName is the class name of the form.
Related
I have a form that is run as a scheduled task. When it is run, nothing shows up, the program executes. I would also like the option of showing the form and manually executing the program with the different options that are available on the main form.
So, using parameters, I am able to run this and it works fine as a scheduled task. As a form, however, I am unable to get the form to show.
Here is my code:
******* MAIN PROGRAM
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length > 0)
{
Application.Run(new FileProcessor(true));
}
else
{
Application.Run(new FileProcessor(false));
}
}
******* INSIDE THE FORM
bool RunOnSchedule = true;
private bool setCore;
public FileProcessor(bool automatic = true)
{
RunOnSchedule = automatic;
if (RunOnSchedule)
{
setCore = true;
SetVisibleCore(false);
}
else
{
SetVisibleCore(true);
}
InitializeComponent();
if (!RunOnSchedule)
{
btnProcess.Visible = false;
}
if (RunOnSchedule)
{
object sender = new object();
EventArgs e = new EventArgs();
FileProcessor_Load(sender, e);
GetDefaultFiles();
BtnProcess_Click(sender, e);
}
}
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(setCore ? value : setCore);
}
If it doesn't run as a scheduled task, the form won't show up. I have tried using ShowDialog() instead of .Run() but it still doesn't work.
Any thoughts, ideas or help would be greatly appreciated.
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.
}
}
}
I have a windows form application which is supposed to show a splash screen with a label field that I want to update as the main form (called welcome.cs) loads in the background. The splash screen shows & hides just fine, but the label doesn't update.
I've done a lot of research but haven't quite found the solution.
Program.cs
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (new SingleGlobalInstance(1000))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashScreen splashscreen = new SplashScreen();
splashscreen.ShowSplashScreen();
Welcome welcome = new Welcome(splashscreen); //Takes some time to load
splashscreen.CloseForm();
Application.Run(welcome);
}
}
Splashscreen.cs
public partial class SplashScreen : Form
{
//Delegate for cross thread call to close
private delegate void CloseDelegate();
private delegate void UpdateStatusDelegate(string status);
private static SplashScreen splashScreen;
private Thread thread = null;
public SplashScreen()
{
InitializeComponent();
}
public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashScreen != null)
return;
thread = new Thread(ShowForm);
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
static private void ShowForm()
{
splashScreen = new SplashScreen();
Application.Run(splashScreen);
}
public void CloseForm()
{
splashScreen.Invoke(new CloseDelegate(CloseFormInternal));
}
static private void CloseFormInternal()
{
splashScreen.Close();
}
public void UpdateStatus(string status)
{
splashScreen.Invoke(new UpdateStatusDelegate(UpdateStatusInternal), status);
}
private void UpdateStatusInternal (string status)
{
if (splashScreen != null && splashScreen.IsHandleCreated)
{
lblStatus.Text = status;
}
}
}
Welcome.cs
public Welcome(Splashscreen splashscreen)
{
InitializeComponent();
//Code to log the user into the system
splashScreen.UpdateStatus("Logging in...");
//my expectation is that UpdateStatus call will update the label displayed on the splash screen but it doesn't.
//Do more stuff.....
}
Does it have something to do with multi-threading or is it because im creating a new instance of splashscreen in welcome.cs before calling UpdateStatus? How would I get around this?
You could do the following
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
// Creates the Splash
splash = new FrmSplash();
//Opens the Splash in a new Thread, this way any gifs, progress bars, lablels changes will work because the main thread isnt blocked
var t = Task.Factory.StartNew(() =>
{
splash.ShowDialog();
});
while (!splash.Created) // wait the splash screen form load process
System.Threading.Thread.Sleep(300);
UpdateSplashMessage("Loading the program... Please wait");
// Some slow initialization code.
// ...
//Close splash screen
CloseSplash();
Application.Run(args);
}
static void CloseSplash()
{
splash.Invoke(new MethodInvoker(() =>
{
splash.Close(); // Closes the splash that is running in the other thread
}));
}
static void UpdateSplashMessage(string msg)
{
splash.Invoke(new MethodInvoker(() =>
{
splash.AtualizarMensagem(msg);
}));
}
Note that you will need to create a method called AtualizarMensagem(string str) in your splash screen form, like this
public void AtualizarMensagem(string novaMsg)
{
lblCarregando.Text = novaMsg;
}
I have this code in my "useful snnipets" folder, it always works for me.
Hope this helps.
My Solution:
So I managed to find another tutorial http://www.codeproject.com/KB/dotnet/Yet_Another_Splash_Screen.aspx and the sourcecode seemed to make more sense to me. Here is the code i'm using now. Main() is left untouched.
Splash.cs
`
public partial class Frm_Splash : Form
{
delegate void ProgressDelegate(int percent);
delegate void SplashShowCloseDelegate();
/// <summary>
/// To ensure splash screen is closed using the API and not by keyboard or any other things
/// </summary>
bool CloseSplashScreenFlag = false;
/// <summary>
/// Base constructor
/// </summary>
///
public Frm_Splash()
{
InitializeComponent();
progress_Splash.Show();
this.ClientSize = this.BackgroundImage.Size;
}
public void ShowSplashScreen()
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new SplashShowCloseDelegate(ShowSplashScreen));
return;
}
this.Show();
Application.Run(this);
}
/// <summary>
/// Closes the SplashScreen
/// </summary>
public void CloseSplashScreen()
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new SplashShowCloseDelegate(CloseSplashScreen));
return;
}
CloseSplashScreenFlag = true;
this.Close();
}
/// <summary>
/// Update text in default green color of success message
/// </summary>
/// <param name="Text">Message</param>
public void Progress(int percent)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new ProgressDelegate(Progress), new object[] { percent });
return;
}
// Must be on the UI thread if we've got this far
progress_Splash.Value = percent;
// Fade in the splash screen - looks pro. :D
if (percent < 10)
this.Opacity = this.Opacity + .15;
}
/// <summary>
/// Prevents the closing of form other than by calling the CloseSplashScreen function
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SplashForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (CloseSplashScreenFlag == false)
e.Cancel = true;
}
}`
Form1.cs
public partial class Frm_Main : Form
{
Frm_Splash frm_Splash = new Frm_Splash();
public Frm_Main()
{
this.Hide();
Thread splashthread = new Thread(new ThreadStart(frm_Splash.ShowSplashScreen));
splashthread.IsBackground = true;
splashthread.Start();
InitializeComponent();
CenterToScreen();
}
private void Frm_Main_Load(object sender, EventArgs e)
{
if (PassedAll() == true)
FillMovieLB();
if (FillMovieProgress == 100)
{
//Throw in this sleep so the user can see the progress bar reach all the way to the end.
Thread.Sleep(1000);
this.Show();
frm_Splash.CloseSplashScreen();
this.Activate();
}
}
Original Question
G'day all,
I'm very new to programming in C# and i'm having a problem with the http://www.codeproject.com/KB/cs/prettygoodsplashscreen.aspx tutorial and implementing it within my application. I'm finding it a little difficult to understand what the problem is. I know there is alot of stuff about getting this splash screen to work but I can't get my head around it.
When I start the program, the Frm_Main will display, you can see the listbox being populated, because i've placed it in BackgroundWorker.DoWork(), and then afterwards my frm_Splash will show after the work is done. Obviously, the way it should be working is, frm_Splash will show during the work being done on Frm_Main, and the progress bar will show the progress of the loading (this part I haven't implemented yet).
Edit: I may not have been clear, but the question is: How can I get my splashscreen to display while the work is being done and before the main form is displayed?
Thanks everybody. :)
Here is my code:
static Frm_Splash frm_Splash = new Frm_Splash();
public delegate void ShowFormDelegate();
public void ShowForm()
{
frm_Splash.Show();
}
public Frm_Main()
{
InitializeComponent();
CenterToScreen();
if (PassedAll() == true)
{
back_loadprog.RunWorkerAsync();
}
}
private void back_loadprog_DoWork(object sender, DoWorkEventArgs e)
{
Invoke(new ShowFormDelegate(ShowForm));
Invoke(new FillMovieLBDelegate(FillMovieLB));
}
Here, have some code... Works for me.
Splash Form:
namespace Screens.Forms
{
public partial class Splash : DevExpress.XtraEditors.XtraForm
{
public Splash()
{
InitializeComponent();
}
string RandomLoadingMessage()
{
string[] lines ={
"Pripremam warp pogon",
"Moj drugi ekran za učitavanje je brži, probaj njega",
"Verzija programa koju imam u testiranju imala je smiješnije poruke"
};
return lines[new Random().Next(lines.Length)];
}
public void RandomizeText()
{
lblMessage.Text = RandomLoadingMessage();
}
private void Splash_Load(object sender, EventArgs e)
{
RandomizeText();
}
private static Splash _splash;
private static bool _shouldClose;
static void ThreadFunc()
{
_splash = new Splash();
_splash.Show();
while (!_shouldClose)
{
Application.DoEvents();
Thread.Sleep(100);
if (new Random().Next(1000) < 10)
{
_splash.Invoke(new MethodInvoker(_splash.RandomizeText));
}
}
for (int n = 0; n < 18; n++)
{
Application.DoEvents();
Thread.Sleep(60);
}
if (_splash != null)
{
_splash.Close();
_splash = null;
}
}
static public void ShowSplash()
{
_shouldClose = false;
Thread t = new Thread(ThreadFunc);
t.Priority = ThreadPriority.Lowest;
t.Start();
}
internal static void RemoveSplash()
{
_shouldClose = true;
}
internal static void ShowSplash(List<string> fromTwitterMessages)
{
ShowSplash();
}
}
}
Show it with:
Splash.ShowSplash();
Do the work you need, then when done:
Splash.RemoveSplash();
You need to take this a step further back to your Main() function of the application.
In general you could do this:
Create a ManualResetEvent or better ManualResetEventSlim if you are on .NET 4
Start a new thread displaying your SplashScreen, use Application.Run
In your SplashScreen you should create a time which polls the created ManualResetEvent
frequently, a nice animation could be placed here also
If the event is set you should close the form
Back in your Main() do your stuff like creating forms etc.
When finish set the event, so that the SplashScreen can be closed
To be sure that your MainForm is not shown before your SplashScreen is closed you can use another event
I have a program which only needs a NotifyIcon to work as intended. So I've been trying to get the main form to hide when the program starts.
In frmMain_Load, I tried both
this.Hide();
this.Visible = false;
without success.
They work in other methods, like in the NotifyIcon_MouseClick-method, but I want it to hide at Load.
I saw in another question here at SO where Matias suggested this:
BeginInvoke(new MethodInvoker(delegate
{
Hide();
}));
This works, but when I launch the program I can see the form flashing real fast. It's better than nothing, but I wonder if there is any better solution to this.
Thanks.
// In Your Program.cs Convert This
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
// To This
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 TheForm = new Form1();
Application.Run();
}
// Call Application.Exit() From Anywhere To Stop Application.Run() Message Pump and Exit Application
There is an easy way, if your program has the default Visual Studio generated Program.cs file:
[STAThread]
static void Main()
{
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault (false);
Application.Run (new MainForm ());
}
the simple fact of calling Run will, indeed make the form visible. Try doing the following in the properties of your form:
Set WindowState to Minimized
Set ShowInTaskbar to false
This should do the trick!
Don't call Show or ShowDialog on your form, you can have your Application.Run target a custom class that then instantiates a form and doesn't show or creates a NotifyIcon instance and handles everything from there.
You can also put this.hide = true in the form_shown event. I believe that event is fired once only and after the load event. You might see alittle flicker though if your form has a lot of controls and/or the computer is slow.
If your program doesn't require a form to run, then the best method is to not have a form at all.
Setup your NotifyIcon in the Program code, and enter a loop until you want to exit the program by setting some value, or calling some method.
In this example setting UserExitCalled to true (Program.UserExitCalled = true) will cause the program to quit.
Here is a brief example:
static class Program {
internal static Boolean UserExitCalled;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Setup your tray icon here
while (!UserExitCalled) {
Application.DoEvents(); // Process windows messages
Thread.Sleep(1);
}
return;
}
}
Here the full program class from one of my system tray applications as a working example.
// *********************************************************************
// [DCOM Productions .NET]
// [DPDN], [Visual Studio Launcher]
//
// THIS FILE IS PROVIDED "AS-IS" WITHOUT ANY WARRANTY OF ANY KIND. ANY
// MODIFICATIONS TO THIS FILE IN ANY WAY ARE YOUR SOLE RESPONSIBILITY.
//
// [Copyright (C) DCOM Productions .NET All rights reserved.]
// *********************************************************************
namespace VisualStudioLauncher
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
using VisualStudioLauncher.Common.Objects;
using VisualStudioLauncher.Forms;
using System.Drawing;
using VisualStudioLauncher.Common.Data;
using System.IO;
static class Program
{
#region Properties
private static ProjectLocationList m_ProjectLocationList;
/// <summary>
/// Gets or Sets the ProjectsLocationList
/// </summary>
public static ProjectLocationList ProjectLocationList
{
get
{
return m_ProjectLocationList;
}
set
{
m_ProjectLocationList = value;
}
}
private static ShellProcessList m_ShellProcessList = null;
/// <summary>
/// Gets or Sets the ShellProcessList
/// </summary>
public static ShellProcessList ShellProcessList
{
get
{
return m_ShellProcessList;
}
set
{
m_ShellProcessList = value;
}
}
private static NotifyIcon m_TrayIcon;
/// <summary>
/// Gets the programs tray application.
/// </summary>
public static NotifyIcon TrayIcon
{
get
{
return m_TrayIcon;
}
}
private static bool m_UserExitCalled;
/// <summary>
/// Gets a value indicating whether the user has called for an Application.Exit
/// </summary>
public static bool UserExitCalled
{
get
{
return m_UserExitCalled;
}
set
{
m_UserExitCalled = value;
}
}
// TODO: Finish implementation, then use this for real.
private static ApplicationConfiguration m_ApplicationConfiguration = null;
/// <summary>
/// Gets the application configuration
/// </summary>
public static ApplicationConfiguration ApplicationConfiguration
{
get
{
if (m_ApplicationConfiguration == null)
m_ApplicationConfiguration = ApplicationConfiguration.LoadConfigSection(#"./settings.config");
return m_ApplicationConfiguration;
}
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
if (args[0].ToLower() == "-rmvptr")
{
for (int i = 1; i < args.Length; i++) {
try {
if (File.Exists(Application.StartupPath + #"\\" + args[i])) {
File.Delete(Application.StartupPath + #"\\" + args[i]);
}
}
catch { /* this isn't critical, just convenient */ }
}
}
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
SplashForm splashForm = new SplashForm();
splashForm.Show();
while (!UserExitCalled)
{
Application.DoEvents();
Thread.Sleep(1);
}
if (m_TrayIcon != null)
{
m_TrayIcon.Icon = null;
m_TrayIcon.Visible = false;
m_TrayIcon.Dispose();
GC.Collect();
}
}
#region System Tray Management
public static void SetupTrayIcon()
{
m_TrayIcon = new NotifyIcon();
m_TrayIcon.Text = Resources.UserInterfaceStrings.ApplicationName;
m_TrayIcon.Visible = false; // This will be set visible when the context menu is generated
m_TrayIcon.MouseDoubleClick += new MouseEventHandler(m_TrayIcon_MouseDoubleClick);
if (Orcas.IsInstalled)
{
m_TrayIcon.Icon = Orcas.Icon;
}
else if (Whidbey.IsInstalled) {
m_TrayIcon.Icon = Whidbey.Icon;
}
else {
m_TrayIcon.Icon = SystemIcons.Warning;
m_TrayIcon.Text = "Visual Studio is not installed. VSL cannot run properly.";
}
}
static void m_TrayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
{
return;
}
SettingsForm settingsForm = new SettingsForm();
settingsForm.Show();
}
#endregion
}
}