views:

56

answers:

2

Hi,

I have below scenario: WinForms app which allow only one instance of this app to be run (Mutex is in use here to check). App on start with some paramatere is runnig but hidden. When somebody will click on app again then Mutex will detect that app is already running and "unhide" the main form by call of native method (see method BringWindowToFront below).

Here is a code to find and show form window:

    public static class NativeMethods
{
    public enum ShowWindowOptions
    {
        FORCEMINIMIZE = 11,
        HIDE = 0,
        MAXIMIZE = 3,
        MINIMIZE = 6,
        RESTORE = 9,
        SHOW = 5,
        SHOWDEFAULT = 10,
        SHOWMAXIMIZED = 3,
        SHOWMINIMIZED = 2,
        SHOWMINNOACTIVE = 7,
        SHOWNA = 8,
        SHOWNOACTIVATE = 4,
        SHOWNORMAL = 1
    }

    [DllImport("user32.dll")]
    public static extern int ShowWindow(int hwnd, int cmdShow);

    [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
    public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

    [DllImport("USER32.DLL")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    public static void BringWindowToFront(string windowTitle)
    {
        // Get a handle to the application.
        IntPtr handle = FindWindow(null, windowTitle);

        // Verify that app is a running process.
        if (handle == IntPtr.Zero)
        {
            return;
        }

        // With this line you have changed window status from example, minimized to normal
        ShowWindow((int)handle, (int)ShowWindowOptions.SHOWDEFAULT);

        // Make app the foreground application
        SetForegroundWindow(handle);
    }
}

Everything is fine BUT I need one functionality yet. I would like to show another additional form when Main Form will unhide at 1st time. Normally I do it by form *_Shown* event. But when I use PInvoke methods to show window then this event is not fired up.

So basically I would like to show additional form when main form is shown (using ShowWindow PInvoke method)

Is this possible? Any other idea how to achieve it?

Thank you in advance.

+2  A: 

The Form.Shown event is only fired the first time the form is shown (i.e. after loading), doing any other action later on (for example, hiding and then re-showing) will not trigger the event. For more information see: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.shown.aspx

There are a couple of other events that may be useful in your case:

If none of these work, and you must use P/Invoke then I would go with SetActiveWindow which will send a WM_ACTIVATE message, which should force a Form.Activated.

Note that if that doesn't work (since SetActiveWindow sends a WM_ACTIVATE with a low order bit of 1, indicating that the window wasn't activated by a mouse, then you could work around this by sending a message directly to the window with your own WM_ACTIVATE message.

Oren
thx for this explanation
binball
+2  A: 

Writing single-instance apps is tricky. You don't have to, the .NET framework already supports them really well. Project + Add Reference, select Microsoft.VisualBasic. Open your project's Program.cs file and make it look like this:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic.ApplicationServices;

namespace WindowsFormsApplication1 {
    class Program : WindowsFormsApplicationBase {
        [STAThread]
        static void Main(string[] args) {
            var prg = new Program();
            prg.EnableVisualStyles = true;
            prg.IsSingleInstance = true;
            prg.MainForm = new Form1();
            prg.Run(args);
        }

        protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e) {
            var main = this.MainForm as Form1;
            main.WindowState = FormWindowState.Normal;
            main.BringToFront();
            // You could do something interesting with the command line arguments:
            //foreach (var arg in e.CommandLine) {
            //    main.OpenFile(arg);
            //}
        }
    }
}
Hans Passant
Scott Hanselman has a good post on this - http://www.hanselman.com/blog/CommentView.aspx?guid=d2f676ea-025b-4fd6-ae79-80b04a34f24c
ChrisF
Hans, thank you for this example. In my particular case this method for single-instance app is much better than Mutex.So I just add frmAnother frm = new frmAnother(); after main.BringToFront(); and it's work for me exactly as I want.Thx!
binball