Search code examples
c#winformspinvokewinforms-interop

Show Form with PInvoke


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?


Solution

  • 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);
                //}
            }
        }
    }