1

我需要获取桌面上当前/以前活动窗口的句柄。基本上,我正在开发可以截屏的 ac# Windows Forms 应用程序。我正在使用 GetForegroundWindow PInvoke 来获取此句柄,但如果我通过单击菜单调用我的代码,则活动窗口似乎设置为菜单本身的窗口,因此生成的图像是一个黑色的小矩形。

该应用程序在带有上下文菜单的系统托盘中运行。我也实现了全局热键并且这些工作正常,但是当我使用鼠标使用上下文菜单时,会发生上述情况。

如何跟踪以前活动的窗口句柄?请记住,我的应用程序作为托盘图标运行,因此覆盖 wndproc 永远不会触发。我也尝试过 NativeForm 和 MessageOnly 表单,但除非应用程序具有焦点,否则它们永远不会触发。

我们是全局挂钩和外部 dll 吗?当然必须有一个简单的方法来解决这个问题?(是的,我确实需要为特定的可用性场景实现菜单项和键盘快捷键。

那么,如何从没有窗口本身且没有焦点的 ac# 应用程序跟踪桌面上当前/上一个活动窗口?

非常感谢您的帮助

4

2 回答 2

0

我找到了一个更简单的解决方案,虽然它有点像 hack,但它运行良好、可靠且不花钱。我所做的是,从我的菜单单击事件中,我显示一个表单,然后立即隐藏该表单。这具有将焦点从任务栏移回桌面的效果。我显示我的表单,然后当我关闭它时,之前选择的窗口重新获得焦点。然后我的 GetForegroundWindow 得到它的句柄。

我的应用程序实际上有一个状态表单,可以在漫长的过程中更新用户,所以我可以用“正在捕获,请稍候”消息或其他东西来显示它。或者我可以简单地在屏幕上快速闪现它,以至于根本看不到它。然后我关闭它,线程 sleep(100) 并继续屏幕截图。奇迹般有效

        if (_runMode == RunMode.Tray)
        {
            FormStatus f = new FormStatus();
            f.Show();
            f.Close();
            Thread.Sleep(100);
        }

        ScreenCapture.CaptureActiveWindow(filename);
于 2013-08-16T21:56:17.050 回答
0

假设您使用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事件。这是您了解更多信息的链接:Detect active window changed using C# without polling

这是不使用计时器(轮询)的解决方案的代码:

//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()
于 2013-08-16T19:52:03.837 回答