1

I have a utility WinForm application that generally runs minimized. It is used on a PC in a manufacturing plant. I would like to have the application become not visible when minimized to prevent accidently closing the form or playing with some of the settings. Not meant to be foolproof, just a bit of caution.

However I cannot get the application’s main and only form to reappear sending it a WM_SYSCOMMAND, SC_RESTORE message from another instance of the same application.

I have the Resize_Event set up to set Visible back to true when not minimized.

I’ve tried SendMessage and PostMessage. If I allow the form to minimize or maximize without setting form’s Visible property to false, the call works as expected and the target form resizes.

Is the form’s message pump is not running in this state so it ignores the message?

Should I create another thread that checks a message queue every so often? How is that done?

Sample code in the app that is restoring the form:

...
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName("MyApp")) { //current.ProcessName)) {
  if (process.Id != current.Id) {
    SendMessage(process.MainWindowHandle, WM_SYSCOMMAND, (IntPtr)SC_RESTORE, (IntPtr)0);
    Interaction.AppActivate(process.Id); //Most reliable way to focus target
    SetForegroundWindow(process.MainWindowHandle);
    break;
  }
}
...

Code in target form that restores visibility.

  // If form is minimized then hide it
  if (WindowState == FormWindowState.Minimized) {
    this.Visible = false;
  }
  else {
    this.Visible = true;
  }
Rich Shealer
  • 3,362
  • 1
  • 34
  • 59
  • 1
    Probably better to create a tray icon when minimizing rather than having the user try to restart the application just to show it again. When doing that you'll be staying within the same process, and don't need to deal with any of the IPC mess. – Servy Jan 14 '14 at 22:19
  • That was another thought that I had considered. Not as obvious to reopen there. – Rich Shealer Jan 14 '14 at 22:39
  • possible duplicate of [Run one instance of program](http://stackoverflow.com/questions/11923785/run-one-instance-of-program) – Hans Passant Jan 14 '14 at 22:53
  • @HansPassant - yes it is based on that, but the quirk is that I can't get the hidden forms handle this way. – Rich Shealer Jan 15 '14 at 15:09
  • That answer explicitly shows you how to restore the window. It doesn't need a "handle", the event handler runs in the first instance of the process so there's no need for any kind of process interop. .NET takes care of it. I can't possibly guess what the "quirk" might be. – Hans Passant Jan 15 '14 at 15:15
  • @HansPassant - Sorry I had just looked at another option and confused it with your suggestion. Using this code I was able to get it to work. – Rich Shealer Jan 15 '14 at 20:03

3 Answers3

2

What I generally do is override the Form.OnClosing method and then proceed to set e.Cancel = true. Then instead invoke the Hide() method so that it is still running in the background.

To get the application back I then used named events to create a single instance application. You can also use a Mutex. See this SO anwser: How to run one instance of a c# WinForm application?

Edit Named events will also help you open this from another application. Just when you received some sort of show event, you just tell your form to Show().

Community
  • 1
  • 1
deloreyk
  • 1,248
  • 15
  • 24
0

This is not fool-proof, but it is simple to implement.

  • Add a Boolean value like m_closePrompt that you set to true when your program first loads.
  • Wire up an Event Handler for the FormClosing event.

screen shot

private void MdiForm_Closing(object sender, FormClosingEventArgs e) {
  if (m_closePrompt) {
    string ask = "Really Close this Application?";
    if (MessageBox.Show(ask, "Confirmation",  MessageBoxButtons.YesNo, MessageBoxIcon.Question, 0) != DialogResult.Yes) {
      e.Cancel = true;
    } else {
      m_closePrompt = false;
    }
  }
}

That should at least pop-up the system dialog box.

If you have other methods you wish to close your application (like an unhandled exception), then set m_closePrompt = false in the error handling routine before closing your application.

  • Whoops. I missed the part about "from another application". If this does not help you at all, let me know and I will just delete it. I want to give you a chance to see it first, just in case. –  Jan 14 '14 at 22:36
  • This one was close for a workaround but Hans got me in the correct direction. – Rich Shealer Jan 15 '14 at 20:04
0

Hans Passant pointed me in the proper direction with his comment to my question referring to this question.

My final code looked like this.

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;   // Add reference to Microsoft.VisualBasic

namespace MyApp
{
  class Program : WindowsFormsApplicationBase 
  {
     /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
      var app = new Program();
      app.Run(args);
    }
    public Program()
    {
      this.IsSingleInstance = true;
      this.EnableVisualStyles = true;
      this.MainForm = new fMain();
    }
    protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
    {
      if (this.MainForm.WindowState == FormWindowState.Minimized) {
        this.MainForm.Show();     // Unhide if hidden
        this.MainForm.WindowState = FormWindowState.Normal; //Restore
      }
      this.MainForm.Activate();
    }
  }

}
Community
  • 1
  • 1
Rich Shealer
  • 3,362
  • 1
  • 34
  • 59