C# 捕捉活动窗口开关(也在同一应用程序中,例如Chrome选项卡)
我正在开发跟踪活动并将其记录到数据库的工具(稍后将添加,我目前正在TextBox中测试)。因此,它将读取活动窗口标题并计算在每个窗口上花费的时间 我知道有一个解决办法 但我注意到,如果谷歌浏览器被打开,我在标签之间切换,它不会做出反应。我必须点击其他窗口,然后点击Chrome选项卡,在这种情况下,检测到活动窗口开关 我在想,也许可以通过每X秒运行一次C# 捕捉活动窗口开关(也在同一应用程序中,例如Chrome选项卡),c#,windows,winapi,events,C#,Windows,Winapi,Events,我正在开发跟踪活动并将其记录到数据库的工具(稍后将添加,我目前正在TextBox中测试)。因此,它将读取活动窗口标题并计算在每个窗口上花费的时间 我知道有一个解决办法 但我注意到,如果谷歌浏览器被打开,我在标签之间切换,它不会做出反应。我必须点击其他窗口,然后点击Chrome选项卡,在这种情况下,检测到活动窗口开关 我在想,也许可以通过每X秒运行一次CheckForWindowTitle(),并与当前的GetActiveWindowTitle.GetActiveWindowTitleMethod
CheckForWindowTitle()
,并与当前的GetActiveWindowTitle.GetActiveWindowTitleMethod()
进行比较来解决这个问题,如果它们不匹配,则改为CheckForWindowTitle()
。有没有更好的解决办法
GetActiveWindowTitle.cs:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Activitytracker
{
class GetActiveWindowTitle
{
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
public const uint WINEVENT_OUTOFCONTEXT = 0;
public const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
public static string GetActiveWindowTitleMethod()
{
const int nChars = 256;
IntPtr handle = IntPtr.Zero;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
}
}
MainWindow.xaml.cs:
GetActiveWindowTitle.WinEventDelegate dele = null;
Stopwatch stopwatch = new Stopwatch();
public MainWindow()
{
InitializeComponent();
dele = new GetActiveWindowTitle.WinEventDelegate(WinEventProc);
IntPtr m_hhook = GetActiveWindowTitle.SetWinEventHook(GetActiveWindowTitle.EVENT_SYSTEM_FOREGROUND,
GetActiveWindowTitle.EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, GetActiveWindowTitle.WINEVENT_OUTOFCONTEXT);
//_ = CheckForWindowTitle();
}
public async Task CheckForWindowTitle()
{
while (true)
{
var delayTask = Task.Delay(100);
TextBoxMain.Text = GetActiveWindowTitle.GetActiveWindowTitleMethod();
await delayTask;
}
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject,
int idChild, uint dwEventThread, uint dwmsEventTime)
{
stopwatch.Stop();
var milliSeocnds = stopwatch.ElapsedMilliseconds;
var timeSpan = stopwatch.Elapsed;
var CurrentDate = DateTime.Now;
TextBoxMain.Text += GetActiveWindowTitle.GetActiveWindowTitleMethod() + " " + timeSpan + " " + CurrentDate + "\r\n";
stopwatch.Start();
}
编辑: 我不确定效率,但如果有人感兴趣,这里有一些进展(它也在跟踪Chrome和其他应用程序中的每个窗口):
编辑2: 我现在一直在尝试下面的答案中提供的工作方法。我需要分配变量,以便在以下情况下使用它:
dele = new GetActiveWindowTitle.WinEventDelegate(WinEventProc);
IntPtr m_hhook = GetActiveWindowTitle.SetWinEventHook(GetActiveWindowTitle.EVENT_OBJECT_FOCUS,
GetActiveWindowTitle.EVENT_OBJECT_FOCUS, IntPtr.Zero, dele, 0, 0, GetActiveWindowTitle.WINEVENT_OUTOFCONTEXT);
我试过:
public const uint EVENT_OBJECT_FOCUS = 3;
但这些都不起作用
方法如下:
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
GetActiveWindowTitle.stopwatch.Stop();
milliSeocnds = GetActiveWindowTitle.stopwatch.ElapsedMilliseconds;
timeSpan = GetActiveWindowTitle.stopwatch.Elapsed;
CurrentDate = DateTime.Now;
MainProcess.AddRecordToDatatable(GetActiveWindowTitle.GetActiveWindowTitleMethod(),
milliSeocnds / 1000, CurrentDate, MainProcess.AdminHoursCode, MainProcess.userName);
// Group DataTable records
MainProcess.OrganizeDataTable();
ActivityLogGrid.ItemsSource = MainProcess.ActivityLogGrouped.DefaultView;
GetActiveWindowTitle.stopwatch.Start();
}
经过一些测试,它应该是
public const uint EVENT_OBJECT_FOCUS = 0x8005;
但我注意到,如果谷歌浏览器被删除,它不会做出反应
打开,我在选项卡之间切换
在选项卡之间切换会导致焦点改变,因此您可以使用(另外)来涵盖这种情况。谢谢您的提示!我现在已经尝试过这种方法,但还没有成功。将
事件\系统\前景=3
更改为事件\对象\焦点=0x8005
。这是正确的方法吗?@哈曼这一行(C++中,<代码> StWiNeVeSooCK(EnvivObjutsFixFielk,EnvivObjutsFixCar,NULL,WEVEESTPROC,0, 0,Win事件,OutoFrEnter);<代码>当您单击Chrome的选项卡时,将为您获取EVENT\u OBJECT\u FOCUS
事件。@hatman您是否能够接收EVENT\u OBJECT\u FOCUS EVENT?我已经开始循环,但我认为正确的方法是使用您提供的上述解决方案。为了测试你的解决方案,我必须重写“两行”。我会在本周尝试这样做,并发布回复或接受答案。抱歉耽搁了。还没有时间继续此项目。看起来它应该是public consuint EVENT\u OBJECT\u FOCUS=0x8005代码>。这似乎是正确的变量。使用其他进程触发该方法。
public const uint EVENT_OBJECT_FOCUS = 0x8005;