恢复另一个应用程序的最小化窗口
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了恢复另一个应用程序的最小化窗口相关的知识,希望对你有一定的参考价值。
我正在向一个应用程序添加一些代码,如果它还没有运行,它将启动另一个应用程序,或者如果是,请将它带到前面。这需要少量的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;
}
我已经尝试过SHOWNORMAL(1),SHOWMAXIMIZED(3),RESTORE(9)以及其他几个大小调整命令,但似乎没有什么可以做到的。思考?
编辑:我发现一些我认为正在工作的其他代码的问题。对GetProcessesByName()的调用没有找到进程,因为我在寻找可执行文件名,而不是进程名。这导致我认为正在运行的代码并且实际上根本没有执行。我认为它有效,因为外部应用程序显然也会检测到副本已经在运行并尝试激活该当前实例。我从我搜索的进程名称中删除了“.exe”,现在代码执行了;然而,这似乎是一个倒退,因为现在当我调用ShowWindow [Async]时,任务栏按钮甚至没有突出显示。所以,我现在知道我的应用程序和我正在调用的外部应用程序都不能在Win7中以编程方式更改不同实例的窗口状态。什么在这里?
使用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);
}
你可以通过调用BringWindowToFront()
来使用它。
我总是有一个应用程序运行实例,所以如果你可以同时拥有几个打开的实例,你可能想稍微改变逻辑。
......显然你不能相信一个过程给你的信息。
Process.MainWindowHandle返回应用程序创建的第一个窗口的窗口句柄,该窗口通常是应用程序的主要顶级窗口。但是,在我的情况下,对FindWindow()的调用显示我想要恢复的实际窗口的句柄不是MainWindowHandle指向的。在这种情况下,Process的窗口句柄似乎是程序加载主窗体时显示的初始屏幕。
如果我在FindWindow返回的句柄上调用ShowWindow,它会完美地运行。
更不寻常的是,当窗口打开时,调用SetForegroundWindow(),当给定进程的MainWindowHandle(该窗口关闭时应该无效)时,可以正常工作。显然,句柄有一定的有效性,只是在窗口最小化时才有效。
总而言之,如果您发现自己处于困境,请调用FindWindow,将其传递给外部应用程序主窗口的已知名称,以获得所需的句柄。
我有同样的问题。我找到的最好的解决方案是用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
来自评论:http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx
托盘调用ShowWindow(handle,SW_RESTORE);在SetForegroundWindow(句柄)之后;
这可能会解决您的问题。
听起来你正在尝试执行一个与alt-tabbing具有相同结果的动作,如果窗口被最小化则会返回窗口,而如果它被最大化则“记住”窗口。
NativeMethods.cs:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
// Specify your namespace here
namespace <your.namespace>
{
static class NativeMethods
{
// This is the Interop/WinAPI that will be used
[DllImport("user32.dll")]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fUnknown);
}
}
主要代码:
// Under normal circumstances, only one process with one window exists
Process[] processes = Process.GetProcessesByName("ExternalApp.exe");
if (processes.Length > 0 && processes[0].MainWindowHandle != IntPtr.Zero)
{
// Since this simulates alt-tab, it restores minimized windows to their previous state
SwitchToThisWindow(process.MainWindowHandle, true);
return true;
}
// Multiple things are happening here
// First, the ProgramFilesX86 variable automatically accounts for 32-bit or 64-bit systems and returns the correct folder
// Secondly, $-strings are the C# shortcut for string.format() (It automatically calls .ToString() on each variable contained in { })
// Thirdly, if the process was able to start, the return value is not null
try { if (Process.Start($"{System.Environment.SpecialFolder.ProgramFilesX86}\\ExternalApp\\ExternalApp.exe") != null) return true; }
catch
{
// Code for handling an exception (probably FileNotFoundException)
// ...
return false;
}
// Code for when the external app was unable to start without producing an exception
// ...
return false;
我希望这提供了一个更简单的解决方案。
(一般规则:如果一个字符串值是序数,即它属于某个东西而不仅仅是一个值,那么最好以编程方式获得它。在更改东西时你会省去很多麻烦。在这种情况下,我假设安装位置可以转换为全局常量,并且可以通过编程方式找到.exe名称。)
以上是关于恢复另一个应用程序的最小化窗口的主要内容,如果未能解决你的问题,请参考以下文章