【问题标题】:Windows.Forms: Activate an application that is already running in right FormWindowStateWindows.Forms:激活已在右 FormWindowState 中运行的应用程序
【发布时间】:2014-02-27 09:29:00
【问题描述】:

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

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

Microsoft.VisualBasic.Interaction.AppActivate(appIdentifier);

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

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

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

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

有人知道我该如何解决这个问题吗?有机会拿到最后一个windowState吗?

提前感谢您的帮助!

【问题讨论】:

标签: c# winforms single-instance


【解决方案1】:

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

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

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

在主程序中,如果实例已经在运行,我会调用

 NativeMethods.ActivateWindow(appIdentifier);

静态 NativeMethods- 类:

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 的帮助!我只调整了那里的解决方案,并在这里发布给其他有同样问题的人。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        这对我有用。请注意,我正在从不同的应用程序激活一个窗口,因此我无权访问 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;
            }
        

        【讨论】:

          猜你喜欢
          • 2012-05-17
          • 2012-03-15
          • 2020-05-07
          • 2011-01-14
          • 2011-07-24
          • 1970-01-01
          • 2010-12-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多