Windows.Forms:激活已在正确的FormWindowState中运行的应用程序

时间:2012-03-22 14:43:23

标签: c# winforms single-instance

我们的应用程序具有以下要求:如果应用程序正在运行并且我再次启动应用程序,则必须激活第一个实例,而不是打开新实例。

为了实现这一点,在主例程中我检查是否已经有一个正在运行的实例。如果是,我使用以下命令将第一个实例带到前面:

Microsoft.VisualBasic.Interaction.AppActivate(appIdentifier);

到目前为止,所有工作都按预期进行。 此解决方案的唯一问题是,在第一个实例最小化的情况下,通过再次启动应用程序,第一个实例将处于活动状态,但不可见(仍然最小化)

这是我的问题。如何通过激活实例返回到最后一个WindowState。 我的解决方案是,订阅Form.Activated事件并在eventhandler方法中执行以下代码:

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

但是使用这个解决方案我遇到了问题,如果应用程序在最小化应用程序之前处于最大化状态,则在激活它之后不会返回到它。

有人知道如何解决这个问题吗?有没有机会获得最后一个windowState?

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:2)

首先,非常感谢Steve和StevenP。现在,我根据您的两种解决方案为我的案例找到了一种方法。

我没有采用“stevenP”解决方案的原因:除非在一个案例中,否则一切正常。如果应用程序处于正常大小状态,然后我再次启动应用程序而不最小化第一个实例,则第一个实例将以最大化大小而不是正常大小打开。

现在我的解决方案看起来像这样(就像我说的,这是两个解决方案的合并:-)):

在已经运行实例的情况下的主例程中,我调用

 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,
}

正如我在开始时所说:非常感谢Steve和StevenP的帮助!我只是在那里修改了解决方案并将其发布给其他有同样问题的人。

答案 1 :(得分:1)

从最小化恢复到以前的状态,你必须知道上一个状态是什么。

这是Form的扩展方法,如果您单击任务栏中的窗口,它将向Windows询问它将使用的还原状态。也就是说,正常或最大化。

        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);

答案 2 :(得分:0)

一点PInvoke可以解决您的问题:

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);

答案 3 :(得分:0)

这对我有用。请注意,我正在从其他应用程序激活窗口,因此我无法访问Form对象。我也在使用WPF而不是WinForms,尽管它对我使用的解决方案并不重要:

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

这就是我调用ActivateWindow方法(减去我的日志代码)的方法:

    private bool GiveFocusToAnotherProcess(Process runningProcess)
    {
        try
        {
            NativeMethods.ActivateWindow(runningProcess.MainWindowHandle);
        }
        catch (Exception ex)
        {
            return false;
        }
        return true;
    }