获取上一个活动窗口的句柄,在该窗口中,我的应用程序可能是托盘应用程序或不在焦点中



我需要获得桌面上当前/以前活动窗口的句柄。基本上,我正在开发一个可以拍摄屏幕截图的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()

最新更新