获取上一个活动窗口的句柄,在该窗口中,我的应用程序可能是托盘应用程序或不在焦点中
本文关键字:应用程序 窗口 焦点 上一个 活动 句柄 获取 我的 | 更新日期: 2023-09-27 18:27:56
我需要获得桌面上当前/以前活动窗口的句柄。基本上,我正在开发一个可以拍摄屏幕截图的c#Windows窗体应用程序。我正在使用GetForegroundWindow PInvoke来获取此句柄,但如果我从菜单单击中调用代码,活动窗口似乎被设置为菜单本身的窗口,因此生成的图像是一个黑色的小矩形。
该应用程序在带有上下文菜单的系统中运行。我还实现了全局热键,这些功能很好,但当我用鼠标使用上下文菜单时,就会出现上述情况。
如何跟踪以前活动的窗口句柄?请记住,我的应用程序以托盘图标的形式运行,因此重写wndproc永远不会启动。我也尝试过NativeForm和MessageOnly表单,但除非应用程序有焦点,否则它们永远不会启动。
我们是不是陷入了全局挂钩和外部dll?当然,必须有一个简单的方法来解决这个问题吗?(是的,我确实需要为特定的可用性场景实现菜单项和键盘快捷键
那么,如何从一个本身没有窗口且没有焦点的c#应用程序中跟踪桌面上当前/以前的活动窗口呢?
非常感谢您的帮助
我找到了一个简单得多的解决方案,虽然它有点像黑客,但它工作得漂亮、可靠,而且不需要任何成本。我所做的是,在菜单点击事件中,我显示一个窗体,然后立即隐藏该窗体。这可以将焦点从任务栏转移回桌面。我显示我的窗体,然后当我关闭它时,以前选择的窗口会重新获得焦点。然后我的GetForegroundWindow得到它的句柄。
我的应用程序实际上有一个状态表,可以在漫长的过程中更新用户,所以我可以用"捕获,请等待"的消息或其他什么来显示它。或者我可以简单地在屏幕上快速闪烁,以至于根本看不到它。然后我关闭它,线程睡眠(100)并继续屏幕捕获。像魅力一样工作
if (_runMode == RunMode.Tray)
{
FormStatus f = new FormStatus();
f.Show();
f.Close();
Thread.Sleep(100);
}
ScreenCapture.CaptureActiveWindow(filename);
假设您将ContextMenuStrip
用于托盘菜单:
IntPtr lastHandle;
public IntPtr GetForegroundWin(){
IntPtr hwnd = GetForegroundWindow();
if(hwnd != contextMenuStrip1.Handle) lastHandle = hwnd;
return lastHandle;
}
//Add a timer
Timer t = new Timer();
t.Interval = 1;
t.Tick += (s,e) => {
GetForegroundWin();
};//Then you can get the foreground Handle by lastHandle
t.Start();//this timer will run as long as your application runs.
好的,在不使用定时器的情况下,我们还有另一个使用SetWinEventHook
的选择。这个函数可以帮助您挂接一些回调来捕获一些事件,包括active window change
事件。以下是您了解更多信息的链接:在不轮询的情况下检测使用C#更改的活动窗口
以下是不使用定时器(轮询)的解决方案代码:
//Must add using System.Runtime.InteropServices;
public partial class Form1 : Form
{
[DllImport("user32")]
private static extern IntPtr SetWinEventHook(int minEvent, int maxEvent, IntPtr hModule, WinEventProcDelegate proc, int procId, int threadId, int flags);
private delegate void WinEventProcDelegate(IntPtr hHook, int ev, IntPtr hwnd, int objectId, int childId, int eventThread, int eventTime);
private void WinEventProc(IntPtr hHook, int ev, IntPtr hwnd, int objectId, int childId, int eventThread, int eventTime)
{
if(hwnd != contextMenuStrip1.Handle) lastHandle = hwnd;
}
public Form1()
{
InitializeComponent();
//EVENT_SYSTEM_FOREGROUND = 3
//WINEVENT_OUTOFCONTEXT = 0
SetWinEventHook(3, 3, IntPtr.Zero, WinEventProc, 0, 0, 0);
}
IntPtr lastHandle;
}
//You can access the lastHandle to get the current active/foreground window. This doesn't require GetForegroundWindow()