windows 从桌面快捷方式的快捷键运行 C# 程序时,GetForegroundWindow 不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2684562/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GetForegroundWindow not working when C# program is run from a shortcut key of a desktop shortcut
提问by Alex Vang
I'm trying to get a handle to the foreground window in C#/Net 2.0/WinForms by calling the native GetForegroundWindow WinAPI function, in my app's form's constructor.
我正在尝试通过在我的应用程序窗体的构造函数中调用本机 GetForegroundWindow WinAPI 函数来获取 C#/Net 2.0/WinForms 中前景窗口的句柄。
When I run the program directly from Windows Explorer or Total Commander, it correctly identifies the Windows Explorer or Total Commander window.
当我直接从 Windows 资源管理器或 Total Commander 运行该程序时,它正确识别了 Windows 资源管理器或 Total Commander 窗口。
However, if I create a shortcut to my program on desktop and set a shortcut key for the shortcut (let's say Ctrl+Alt+X), when I'm running my program using the shortcut, the foreground window is identified as the "Shell_TrayWnd window" (Handle 0x00010064), and not the actual window. (Let's say I'm running Firefox on top, when I press Ctrl+Alt+X my program starts and says that the foreground window is not Firefox, as it should, it says it's the taskbar - Shell_TrayWnd.)
但是,如果我在桌面上为我的程序创建一个快捷方式并为该快捷方式设置一个快捷键(比如 Ctrl+Alt+X),当我使用该快捷方式运行我的程序时,前台窗口被标识为“Shell_TrayWnd窗口”(句柄 0x00010064),而不是实际的窗口。(假设我在顶部运行 Firefox,当我按 Ctrl+Alt+X 时,我的程序启动并说前台窗口不是 Firefox,正如它应该的那样,它说它是任务栏 - Shell_TrayWnd。)
public MainForm()
{
this.InitializeComponent();
IntPtr handle = WinAPI.GetForegroundWindow();
this.Text = handle.ToString();
StringBuilder title = new StringBuilder(255);
if (WinAPI.GetWindowText(handle, title, 255) > 0)
{
this.Text += title.ToString();
}
}
How can I get the real foreground window? Should I (also) use other functions like GetWindow?
我怎样才能得到真正的前景窗口?我应该(也)使用 GetWindow 等其他函数吗?
Thank you
谢谢
回答by OregonGhost
Note that the task bar may bethe real foreground window at the time you call GetForegroundWindow, simply because it's Explorer who's handling the shortcut press, and the task bar belongs to Explorer (Shell_TrayWnd is the window class of the task bar).
注意,在调用GetForegroundWindow 时,任务栏可能是真正的前台窗口,因为它是Explorer 在处理快捷键,而任务栏属于Explorer(Shell_TrayWnd 是任务栏的窗口类)。
If you want to do something with the global active window, you may be better off by starting your application and letting it wait in the background. Then you can handle key presses while your application is running, so Explorer won't interfere.
如果您想对全局活动窗口执行某些操作,最好启动您的应用程序并让它在后台等待。然后,您可以在应用程序运行时处理按键操作,这样 Explorer 就不会受到干扰。
Somehow, this reminds me of an article by Raymond Chen.
不知怎的,这让我想起了Raymond Chen的一篇文章。
回答by harpo
I think you're trying to do the same thing as I am — open a shell from Explorer at the current path.
我认为您正在尝试做与我相同的事情 - 在当前路径上从资源管理器打开一个 shell。
I ran into exactly the same problem. Here's a program that's working for me. It uses EnumWindows
to search through all visiblewindows until it finds one whose title is a real path.
我遇到了完全相同的问题。这是一个对我有用的程序。它用于EnumWindows
搜索所有可见窗口,直到找到标题为真实路径的窗口。
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
public class ShellHere
{
// Thanks to pinvoke.net for the WinAPI stuff
[DllImport("user32.dll")]
private static extern int EnumWindows(CallBackPtr callPtr, int lPar);
[DllImport("user32.dll")]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
[DllImport("user32.dll", EntryPoint="GetWindowLong")]
private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, GWL nIndex);
[DllImport("user32.dll", EntryPoint="GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex);
public delegate bool CallBackPtr(int hwnd, int lParam);
private static CallBackPtr _callBackPtr;
// This static method is required because Win32 does not support
// GetWindowLongPtr directly
public static IntPtr GetWindowLongPtr(IntPtr hWnd, GWL nIndex)
{
if (IntPtr.Size == 8)
return GetWindowLongPtr64(hWnd, nIndex);
else
return GetWindowLongPtr32(hWnd, nIndex);
}
public static bool FindPathInTitle( int hwnd, int lparams )
{
const int nChars = 256;
StringBuilder buffer = new StringBuilder( nChars );
IntPtr result = GetWindowLongPtr( new IntPtr(hwnd), GWL.GWL_STYLE );
// ignore invisible windows
if ( (result.ToInt64() & WS_VISIBLE) != 0 )
{
if ( GetWindowText( hwnd, buffer, nChars ) > 0 )
{
string title = buffer.ToString();
// ignore the taskbar
if ( title.ToLower() != "start" && Directory.Exists( title ) )
{
_folder = title;
return false;
}
}
}
return true;
}
private static string _folder;
public static void Main()
{
_callBackPtr = new CallBackPtr( FindPathInTitle );
EnumWindows( _callBackPtr, 0 );
Process shell = new Process();
shell.StartInfo.FileName = "cmd.exe";
if ( !string.IsNullOrEmpty( _folder ) )
shell.StartInfo.WorkingDirectory = _folder;
shell.Start();
}
public enum GWL
{
GWL_WNDPROC = (-4),
GWL_HINSTANCE = (-6),
GWL_HWNDPARENT = (-8),
GWL_STYLE = (-16),
GWL_EXSTYLE = (-20),
GWL_USERDATA = (-21),
GWL_ID = (-12)
}
// Window Styles
const UInt32 WS_VISIBLE = 0x10000000;
}
It's working for me so far (Win7-64). Note that you don't have to be directly on the Explorer window for it to work — it'll use the next one in the tab order.
到目前为止,它对我有用(Win7-64)。请注意,您不必直接在资源管理器窗口上即可使用它 — 它将使用 Tab 键顺序中的下一个。
回答by peterchen
I'm not sure what you need the foreground window for, so this might or might not help:
我不确定您需要前景窗口做什么,所以这可能有帮助,也可能无济于事:
You probably can detect that you were started through a shortcut by:
您可能可以通过以下方式检测到您是通过快捷方式启动的:
- calling GetStartupInfo
- checking
dwFlags
forSTARTF_TITLEISLINKNAME
- 调用GetStartupInfo
- 检查
dwFlags
的STARTF_TITLEISLINKNAME
In that case you might try to get the window that's previous in Z order, or on top on the Desktop window.
在这种情况下,您可能会尝试获取 Z 顺序中的前一个窗口,或桌面窗口的顶部。