我想问你一个关于在Windows 10中将计算器窗口置于最前面的问题。我已经测试了很多代码,但实际上没有任何作用。我认为主要的问题是,计算器是“ ApplicationFrameHost”的一部分。 在我的应用程序(C#WinForm)中,如果系统计算器没有运行,我想启动它。如果它正在运行,则即使没有最小化窗口,也要将窗口置于最前面。
public static class WindowHelper
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_MINIMIZE = 0x06;
private const int SW_RESTORE = 0x09;
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// non-ApplicationFrameHost case
mWHandle = proc.MainWindowHandle;
if (appFH.Length > 0)
{
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
if ((app.MainWindowTitle == proc.MainWindowTitle) || (proc.MainWindowTitle.Length == 0))
mWHandle = app.MainWindowHandle;
}
}
// bring window to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
}
// calculator was not found, starts new one
System.Diagnostics.Process.Start("calc");
}
此代码也可以在Windows 7上运行,但对于没有英语本地化版本的10则不能。有一个问题,当最小化计算器时,将无法还原它。
正如我所说,我尝试了很多代码,例如:
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
// this was working to bring focus on already displayed window
WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
主要问题是,我没有找到解决方案,这可能会使非英语本地化窗口上的窗口最小化。
您有一些例子,如何处理? 谢谢。
编辑:
经过一些测试,我确定了为什么无法将此窗口置于最前面。带有en(可能与语言环境无关)的Win7和Win10仍然激活了Calculator,即使未最小化它也是如此。另一方面,将Win10最小化后,第二个Win10进程已暂停(请参阅图片附件)。 因此,现在的问题是,如何取消暂停。然后希望可以将窗口移到前面。
答案 0 :(得分:1)
如果您不是前台窗口,则无法强制使用前台窗口。实际上,有很多条件决定何时可以强制使用前台窗口。来自the docs :(底部适用于您)
系统限制可以设置前景窗口的进程。 仅当以下情况之一时,进程才能设置前台窗口 条件成立:
- 该过程是前台过程。
- 该过程由前台过程启动。
- 该进程收到了最后一个输入事件。
- 没有前台进程。
- 该进程正在调试中。
- 前台进程不是现代应用程序或“开始”屏幕。前景未锁定(请参见LockSetForegroundWindow)
- 前台锁定超时已到期(请参阅SystemParametersInfo中的SPI_GETFOREGROUNDLOCKTIMEOUT)。
- 没有菜单处于活动状态。
- 当用户处于活动状态时,应用程序无法将窗口强制到前台 与另一个窗口一起工作。相反,Windows会闪烁 通知用户的窗口。
答案 1 :(得分:0)
一段时间后(几乎没有其他项目占用),我找到了对我有用的解决方案。
public static class WindowHelper
{
public static Dictionary<IntPtr, String> appWins;
public static bool ThreadWindows(IntPtr handle, IntPtr param)
{
int size = WindowHelper.GetWindowTextLength(handle);
if (size > 0)
{
StringBuilder strbTitle = new StringBuilder(size + 1);
WindowHelper.GetWindowText(handle, strbTitle, strbTitle.Capacity);
if (strbTitle.Length > 0)
{
appWins.Add(handle, strbTitle.ToString());
return true;
}
}
return false;
}
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
//[DllImport("user32.dll")]
//private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_RESTORE = 0x09;
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// save first handle
mWHandle = proc.MainWindowHandle;
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
// calculator is already running
if (mWHandle == (IntPtr)0x00)
{
mWHandle = WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
} else
{
// create new windows dictionary
WindowHelper.appWins = new Dictionary<IntPtr, String>();
// enumerate all windows in all AFH threads
foreach (System.Diagnostics.ProcessThread thread in app.Threads)
WindowHelper.EnumThreadWindows(thread.Id, new WindowHelper.EnumThreadDelegate(WindowHelper.ThreadWindows), IntPtr.Zero);
// check if proc window was found
if (WindowHelper.appWins.ContainsValue(proc.MainWindowTitle))
{
IntPtr hwnd;
// get key from value
if ((hwnd = WindowHelper.appWins.First(x => x.Value == proc.MainWindowTitle).Key) != (IntPtr)0)
mWHandle = hwnd;
}
// clear list
WindowHelper.appWins.Clear();
}
}
if (mWHandle != (IntPtr)(0x00))
{
// bring already running calc to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
// do not search for other processes
break;
}
}
// start new calc instance
System.Diagnostics.Process.Start("calc");
}
此解决方案与语言环境无关。 感谢所有为我指出正确方向的人。