Question

Our application has the following requirement: If the application is running and I start the application again, the first instance has to be activated instead to open a new instance.

To realize this, in the main routine I check if there is already a running instance. If yes I use following command to bring in front the first instance:

Microsoft.VisualBasic.Interaction.AppActivate(appIdentifier);

Until now all works as expected. The only problem with this solution is that in case of the first instance is minimized, by start the application again the first instance will be active, but not visible (still minimized)

And this is my question. How can I go back to the last WindowState by activating the instance. My solution was, to subscribe for the Form.Activated event and execute following code in the eventhandler method:

if (MyForm.WindowState == FormWindowState.Minimized)
     {
        MyForm.WindowState = FormWindowState.Normal;
     }

But with this solution I have the problem, that if the application was in maximized-state before minimizing the application do not goes back to it after activate it.

Has anybody an idea how I can solve this? is there a chance to get the last windowState?

Thanks in advance for your help!

Was it helpful?

Solution

First, thanks a lot to Steve and StevenP. Now I found a way for my case based on your both solutions.

The reason why I didn't took the "stevenP" solution: with this, all works fine unless in one case. If the application is in normal size state and then I start the application again without minimize the first instance the first instance will open in maximized size instead of normal size.

Now my solution looks like this (like I said, it's a merge of the two solutions :-) ):

In main routine in case that already an instance is running I call

 NativeMethods.ActivateWindow(appIdentifier);

static NativeMethods- class:

public static void ActivateWindow(string appIdentifier)
{
   var process = Process.GetProcesses().
           FirstOrDefault(actual => actual.MainWindowTitle == appIdentifier);
   if (process == null)
   {
      return;
   }

   var mainWin = process.MainWindowHandle;
   var placement = new WindowPlacement();
   placement.Length = Marshal.SizeOf(placement);
   GetWindowPlacement(mainWin, ref placement);

   if (placement.ShowCmd == SW_SHOWMINIMIZED)
   {
      ShowWindow(mainWin, (uint)WindowShowStyle.Restore);
   }
   else
   {
      Interaction.AppActivate(appIdentifier);
   }
}

internal struct WindowPlacement
{
   internal int Length;
   internal int Flags;
   internal int ShowCmd;
   internal Point MinPosition;
   internal Point MaxPosition;
   internal Rectangle NormalPosition;
}

internal enum WindowShowStyle : uint
{
   Hide = 0,
   ShowNormal = 1,
   ShowMinimized = 2,
   ShowMaximized = 3,
   Restore = 9,
}

As I said at the beginning: Thanks a lot to Steve and StevenP for the help! I only adapted there solution and post it here for others with the same problem.

OTHER TIPS

Do restore to the previous state from minimized, you have to know what the rprevious state was.

Here is an extension method to Form, which will ask Windows for the restore state that it would use, if you were to click on the window in the taskbar. That is, Normal or Maximized.

        public static void Restore(this Form form)
        {
            if (form.WindowState == FormWindowState.Minimized)
            {
                var placement = new WindowPlacement();
                placement.length = Marshal.SizeOf(placement);
                NativeMethods.GetWindowPlacement(form.Handle, ref placement);

                if ((placement.flags & RESTORETOMAXIMIZED) == RESTORETOMAXIMIZED)
                    form.WindowState = FormWindowState.Maximized;
                else
                    form.WindowState = FormWindowState.Normal;
            }

            form.Show();
        }

 public struct WindowPlacement
        {
            public int length;
            public int flags;
            public int showCmd;
            public Point ptMinPosition;
            public Point ptMaxPosition;
            public Rectangle rcNormalPosition;
        }

        public const int RESTORETOMAXIMIZED = 0x2;

 [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl);

A bit of PInvoke could resolve your issue:

DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

/// <summary>
/// Enumeration of the different ways of showing a window using 
/// ShowWindow</summary>
private enum WindowShowStyle : uint
{
    Hide = 0,
    ShowNormal = 1,
    ShowMinimized = 2,
    ShowMaximized = 3,
    // Many more, but this one seems to be the one required
    /// <summary>
    /// Activates and displays the window. If the window is 
    /// minimized or maximized, the system restores it to its original size 
    /// and position. An application should specify this flag when restoring 
    /// a minimized window.
    /// </summary>
    /// <remarks>See SW_RESTORE</remarks>
    Restore = 9

}

IntPtr mainWin = Process.GetProcessByID(appIdentifier).MainWindowHandle;
ShowWindow(mainWin, WindowShowStyle.Restore);

Here's what worked for me. Note that I'm activating a window from a different application so I don't have access to the Form object. I'm also working with WPF rather than WinForms, though it doesn't really matter with the solution I used:

internal static class NativeMethods
{
    public static void ActivateWindow(IntPtr windowHandle)
    {
        var placement = new WindowPlacement();
        placement.Length = Marshal.SizeOf(placement);
        GetWindowPlacement(windowHandle, ref placement);
        if (placement.ShowCmd == (uint)WindowShowStyle.ShowMinimized)
        {
            ShowWindow(windowHandle, (uint)WindowShowStyle.Restore);
        }
        else
        {
            ShowWindow(windowHandle, placement.ShowCmd);
        }

        SetForegroundWindow(windowHandle);
    }

    private struct WindowPlacement
    {
        internal int Length;
        internal int Flags;
        internal uint ShowCmd;
        internal Point MinPosition;
        internal Point MaxPosition;
        internal Rectangle NormalPosition;
    }

    private enum WindowShowStyle : uint
    {
        Hide = 0,
        ShowNormal = 1,
        ShowMinimized = 2,
        ShowMaximized = 3,
        Restore = 9,
    }

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetWindowPlacement(IntPtr hWnd, ref WindowPlacement lpwndpl);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

    [DllImport("User32.dll")]
    private static extern IntPtr SetForegroundWindow(IntPtr hWnd);
}

And this is how I'm calling the ActivateWindow method (minus my logging code):

    private bool GiveFocusToAnotherProcess(Process runningProcess)
    {
        try
        {
            NativeMethods.ActivateWindow(runningProcess.MainWindowHandle);
        }
        catch (Exception ex)
        {
            return false;
        }
        return true;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top