恢复另一个应用程序的最小化窗口

Kei*_*thS 18 c# winapi interop windows-7

我正在向一个应用程序添加一些代码,如果它还没有运行,它将启动另一个应用程序,或者如果是,请将它带到前面.这需要少量的interop/WinAPI代码,我从其他网站获得了示例,但似乎无法在Win7中工作.

如果窗口处于某种可见状态,则API的SetForegroundWindow方法就像处理一样(这将是主要情况,根据公司策略,如果外部应用程序正在运行,则不应该最小化).但是,如果它被最小化(例外但很重要,因为我的应用程序在这种情况下似乎什么也不做),这个方法和ShowWindow/ShowWindowAsync实际上都不会从任务栏中恢复窗口; 所有方法都只是突出显示任务栏按钮.

这是代码; 大部分工作都很好,但是对ShowWindow()的调用(我也尝试过ShowWindowAsync),无论我发送的命令是什么,都不会做我想要的事情:

[DllImport("user32.dll")]
    private static extern int SetForegroundWindow(IntPtr hWnd);

    private const int SW_SHOWNORMAL = 1;
    private const int SW_SHOWMAXIMIZED = 3;
    private const int SW_RESTORE = 9;

    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

...

//The app is named uniquely enough that it can't be anything else,
//and is not normally launched except by this one.
//so this should normally return zero or one instance
var processes = Process.GetProcessesByName("ExternalApp.exe");

        if (processes.Any()) //a copy is already running
        {
            //I can't currently tell the window's state,
            //so I both restore and activate it
            var handle = processes.First().MainWindowHandle;
            ShowWindow(handle, SW_RESTORE); //GRR!!!
            SetForegroundWindow(handle);
            return true;
        }

        try
        {
            //If a copy is not running, start one.
            Process.Start(@"C:\Program Files (x86)\ExternalApp\ExternalApp.exe");
            return true;
        }
        catch (Exception)
        {
            //fallback for 32-bit OSes
            Process.Start(@"C:\Program Files\ExternalApp\ExternalApp.exe");
            return true;
        }
Run Code Online (Sandbox Code Playgroud)

我已经尝试过SHOWNORMAL(1),SHOWMAXIMIZED(3),RESTORE(9)以及其他几个大小调整命令,但似乎没有什么可以做到的.思考?

编辑:我发现一些我认为正在工作的其他代码的问题.对GetProcessesByName()的调用没有找到进程,因为我在寻找可执行文件名,而不是进程名.这导致我认为正在运行的代码并且实际上根本没有执行.我认为它有效,因为外部应用程序显然也会检测到副本已经在运行并尝试激活该当前实例.我从我搜索的进程名称中删除了".exe",现在代码执行了; 然而,这似乎是一个倒退,因为现在当我调用ShowWindow [Async]时,任务栏按钮甚至没有突出显示.所以,我现在知道我的应用程序和我正在调用的外部应用程序都不能在Win7中以编程方式更改不同实例的窗口状态.什么在这里?

Iva*_*nko 15

工作代码使用FindWindow方法:

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string className, string windowTitle);

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

[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);

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

private enum ShowWindowEnum
{
    Hide = 0,
    ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
    Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
    Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
    Restore = 9, ShowDefault = 10, ForceMinimized = 11
};

private struct Windowplacement
{
    public int length;
    public int flags;
    public int showCmd;
    public System.Drawing.Point ptMinPosition;
    public System.Drawing.Point ptMaxPosition;
    public System.Drawing.Rectangle rcNormalPosition;
}

private void BringWindowToFront()
{
    IntPtr wdwIntPtr = FindWindow(null, "Put_your_window_title_here");

    //get the hWnd of the process
    Windowplacement placement = new Windowplacement();
    GetWindowPlacement(wdwIntPtr, ref placement);

    // Check if window is minimized
    if (placement.showCmd == 2)
    {
        //the window is hidden so we restore it
        ShowWindow(wdwIntPtr, ShowWindowEnum.Restore);
    }

    //set user's focus to the window
    SetForegroundWindow(wdwIntPtr);
}
Run Code Online (Sandbox Code Playgroud)

你可以通过电话来使用它BringWindowToFront().

我总是有一个应用程序运行实例,所以如果你可以同时拥有几个打开的实例,你可能想稍微改变逻辑.

  • 只是一个说明... `IsIconic()` 和 `GetWindowPlacement()` 一样可以检查窗口是否被最小化......并且处理起来更简单一些。 (4认同)

Kei*_*thS 11

......显然你不能相信一个过程给你的信息.

Process.MainWindowHandle返回应用程序创建的第一个窗口的窗口句柄,该窗口通常是应用程序的主要顶级窗口.但是,在我的情况下,对FindWindow()的调用显示我想要恢复的实际窗口的句柄不是MainWindowHandle指向的.在这种情况下,Process的窗口句柄似乎是程序加载主窗体时显示的初始屏幕.

如果我在FindWindow返回的句柄上调用ShowWindow,它会完美地运行.

更不寻常的是,当窗口打开时,调用SetForegroundWindow(),当给定进程的MainWindowHandle(该窗口关闭时应该无效)时,可以正常工作.显然,句柄有一定的有效性,只是在窗口最小化时才有效.

总而言之,如果您发现自己处于困境,请调用FindWindow,将其传递给外部应用程序主窗口的已知名称,以获得所需的句柄.

  • [没有"主窗口"的概念](http://blogs.msdn.com/b/oldnewthing/archive/2008/02/20/7806911.aspx),该对象的作者只假设第一个是它.此外,[MSDN](http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v = vs.85).aspx)说"将创建指定窗口的线程带入前景" (3认同)

Ped*_*o77 10

我有同样的问题.我发现的最佳解决方案是ShowWindow使用标志调用SW_MINIMIZE,然后使用SW_RESTORE.:d

另一种可能的方案

// Code to display a window regardless of its current state
ShowWindow(hWnd, SW_SHOW);  // Make the window visible if it was hidden
ShowWindow(hWnd, SW_RESTORE);  // Next, restore it if it was minimized
SetForegroundWindow(hWnd);  // Finally, activate the window 
Run Code Online (Sandbox Code Playgroud)

来自的评论:http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx