I am trying to add to my time tracker window caption tracking using SetWindowsHookEx, but it is works only partially. Here is my code I using to provide subscribers with coresponding event:
public class Hooks
{
#region DllImport
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_SKIPOWNPROCESS = 2;
private const uint WINEVENT_SKIPOWNTHREAD = 1;
private const uint WINEVENT_OUTOFCONTEXT = 0;
private 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);
#endregion DllImport
public static event EventHandler<EventArgs<string>> WindowActivated;
public void Bind()
{
var listener = new WinEventDelegate(EventCallback);
var result = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
listener,
0,
0,
(WINEVENT_OUTOFCONTEXT));
}
private static void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd,
int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
System.Diagnostics.Debug.Write("EventCallback enter!");
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
var buffer = new StringBuilder(300);
var handle = GetForegroundWindow();
System.Diagnostics.Debug.Write(string.Format("EventCallback GetWindowText: {0}, '{1}'",
GetWindowText(handle, buffer, 300),
buffer));
if (GetWindowText(handle, buffer, 300) > 0 && WindowActivated != null)
{
System.Diagnostics.Debug.Write(string.Format(
"Calling handlers for WindowActivated with buffer='{0}'",
buffer));
WindowActivated(handle, new EventArgs<string>(buffer.ToString()));
}
}
System.Diagnostics.Debug.Write("EventCallback leave!");
}
}
I have main ui WPF application with single Textbox and I bind Hook's event to text box content. When I run it it looks work fine, until itself focused. I.e. if I clicked texbox of WPF window becomes active hook stops working for about 30-40 seconds. After that events capturing becomes work, but again - until main WPF windows becomes active.
Any ideas what is it and how to fix it?
I created a new WPF application using the standard Visual Studio template (VS2012; .NET 4.5). I then replaced the XAML and code-behind as follows:
MainWindow.xaml
<Window x:Class="stackoverflowtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<StackPanel VerticalAlignment="Top" Margin="15">
<TextBox x:Name="_tb" />
<Button Content="Does Nothing" HorizontalAlignment="Left" Margin="0,15" />
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace stackoverflowtest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_hooks = new Hooks(_tb);
_hooks.Bind();
}
readonly Hooks _hooks;
}
public class Hooks
{
public Hooks(TextBox textbox)
{
_listener = EventCallback;
_textbox = textbox;
}
readonly WinEventDelegate _listener;
readonly TextBox _textbox;
IntPtr _result;
public void Bind()
{
_result = SetWinEventHook(
EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero,
_listener,
0,
0,
WINEVENT_OUTOFCONTEXT
);
}
void EventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild,
uint dwEventThread, uint dwmsEventTime)
{
var windowTitle = new StringBuilder(300);
GetWindowText(hwnd, windowTitle, 300);
_textbox.Text = windowTitle.ToString();
}
#region P/Invoke
const uint WINEVENT_OUTOFCONTEXT = 0;
const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject,
int idChild, uint dwEventThread, uint dwmsEventTime);
#endregion
}
}
For me, this works fine. I can switch between different applications and their window titles are reflected in the textbox of the WPF app. There is no delay even when the textbox is focused. I added a do-nothing Button control just to prove that whether the texbox or the button is focused it does not change the behaviour.
I can only assume the problem you are having is related to something you are doing in your event handler, or failing that some kind of threading issue.
Probably the reason is that the delegate was garbage collected since it is assigned into a local variable. That's why it stopped to work after 30-40 sec.
Related
I need your guidance masters.
Bellow follow my code. I'm capturing the title of the window when the event 3 or 8 occur and creating a counter when the event 9 occur.
My code is working great, but, when I try to get the name of the owner of windows' exe with my function GetProcessName, I'm receiving the error "CallbackOnCollectedDelegate was detected". I already did and tried all I knowed, but nothing resolve the error. The error occur after some time of start the use of the application.
When I not call my function GetProcessName, the error not happen.
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
private const uint EVENT_SYSTEM_FOREGROUND = 3;
private const uint EVENT_SYSTEM_CAPTUREEND = 9;
private const uint EVENT_SYSTEM_CAPTURESTART = 8;
int counter = 0;
public Form1()
{
InitializeComponent();
IntPtr handle = IntPtr.Zero;
SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_CAPTUREEND, IntPtr.Zero, new WinEventDelegate(WinEventProc), 0, 0, 0);
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
try
{
if (eventType == EVENT_SYSTEM_FOREGROUND || eventType == EVENT_SYSTEM_CAPTURESTART && idObject == 0)
{
aux1 = GetActiveWindowTitle(hwnd);//A function tha get a name of the title of the window
if (aux1 != aux2 && string.IsNullOrEmpty(aux1) == false)
{
GetWindowThreadProcessId(hwnd, out pid);
pnomelast = GetProcessName((int)pid);//This is the function!!
aux2 = aux1;
aux1 = "";
}
}
else if (eventType == EVENT_SYSTEM_CAPTUREEND)
{
counter = counter + 1;
}
}
catch (Exception e)
{
};
}
public static string GetProcessName(int processId)
{
try
{
return Process.GetProcessById(processId).MainModule.FileName.ToString().Split('\\').Last();
}
catch (Exception)
{
return "";
}
}
Thanks a lot.
Your issue is that SetWinEventHook is creating a new delegate on the fly which has no reference. Since it is orphaned, it will be destroyed on the next garbage collection.
First create a new WinEventDelegate
private static winEventDelegate = new WinEventDelegate(WinEventProc);
Then change:
SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_CAPTUREEND, IntPtr.Zero, new WinEventDelegate(WinEventProc), 0, 0, 0);
TO:
SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_CAPTUREEND, IntPtr.Zero, winEventDelegate, 0, 0, 0);
I made a complete and compact version of the code, that represents the problem, the error happen when the Process.GetProcessById is called. Thanks.
namespace stackoverflow1 {
public partial class Form1 : Form {
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
private const uint EVENT_SYSTEM_FOREGROUND = 3;
private const uint EVENT_SYSTEM_CAPTURESTART = 8;
uint pid = 0;
string pnamelast = "";
public Form1()
{
InitializeComponent();
WinEventDelegate dele = new WinEventDelegate(WinEventProc);
SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_CAPTURESTART, IntPtr.Zero, dele, 0, 0, 0);
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
try
{
if (eventType == EVENT_SYSTEM_FOREGROUND || eventType == EVENT_SYSTEM_CAPTURESTART && idObject == 0)
{
GetWindowThreadProcessId(hwnd, out pid);
pnamelast = Process.GetProcessById((int)pid).MainModule.FileName.ToString().Split('\\').Last();
textBox1.AppendText(pnamelast + "\r\n");
}
}
catch
{
}
}
}
}
The goal
I developed a keyboard in Unity3D (C#) and want it to pop up when the users click on "EDIT" type control such as a address bar or an input field. Therefore, I need to detect when an "EDIT" control is clicked.
What I've tried
Currently I use SetWinEventHook and listen to event EVENT_OBJECT_FOCUS to get the handle of the object which gets the focus. After that, I use GetClassName to see if the focused object is an "EDIT" control which displays a flashing caret when clicked. However, take Google Chrome as an example, I always get Chrome_WidgetWin_1 whether I click the address bar or the plain text of the page. After doing some googling I found this blog post What makes RealGetWindowClass so much more real than GetClassName? saying that RealGetWindowClass can get the base class which I think it will be something like "EDIT" or "COMBOBOX" listed here. Things were not going so well. I tried using RealGetWindowClass and still get the same result Chrome_WidgetWin_1.
The problem
Why do GetClassName and RealGetWindowClass return the same value? How should I make RealGetWindowClass return the base class?
The code
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
[DllImport("user32.dll", SetLastError = true)]
private static extern int UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder pszType, uint cchType);
private delegate void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
private const int WINEVENT_SKIPOWNPROCESS = 2;
private IntPtr windowEventHook;
private const int EVENT_OBJECT_FOCUS = 0x8005;
private void Start()
{
if (windowEventHook == IntPtr.Zero)
{
windowEventHook = SetWinEventHook(
EVENT_OBJECT_FOCUS,
EVENT_OBJECT_FOCUS,
IntPtr.Zero,
WindowEventCallback,
0,
0,
WINEVENT_SKIPOWNPROCESS);
if (windowEventHook == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
private void OnDestroy()
{
UnhookWinEvent(windowEventHook);
}
private void WindowEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
UnityEngine.Debug.Log($"[EventType]: {(EventEnum)eventType} [Class Name]: {GetClassName(hWnd)} [Real Class]: {RealGetWindowClassM(hWnd)}");
// Will print out the same log whether I click an address bar or plain text.
// [EventType]: EVENT_OBJECT_FOCUS [Class Name]: Chrome_WidgetWin_1 [Real Class]: Chrome_WidgetWin_1
}
private string GetClassName(IntPtr hWnd)
{
StringBuilder className = new StringBuilder(256);
GetClassName(hWnd, className, className.Capacity);
return className.ToString();
}
private string RealGetWindowClassM(IntPtr hWnd)
{
StringBuilder className = new StringBuilder(256);
RealGetWindowClass(hWnd, className, (UInt32)className.Capacity);
return className.ToString();
}
I created a hook on a process to register when its Window moves.
I use the event constant EVENT_OBJECT_LOCATIONCHANGE, which per MSDN
An object has changed location, shape, or size. The system sends this event for the following user interface elements: caret and window objects. Server applications send this event for their accessible objects.
And it works, but it also triggers on simple mouse over of the application. Can anyone explain why?
Here is an example to reproduce it:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class NativeMethods
{
[DllImport("user32.dll")]
public static extern System.IntPtr SetWinEventHook(uint eventMin, uint eventMax, System.IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
public delegate void WinEventDelegate(System.IntPtr hWinEventHook, uint eventType, System.IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
}
public partial class Form1 : Form
{
private const uint WINEVENT_OUTOFCONTEXT = 0x0000;
private const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;
public Form1()
{
InitializeComponent();
int processId = Process.GetCurrentProcess().Id;
NativeMethods.SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, System.IntPtr.Zero, WinEventProc, (uint)processId, (uint)0, WINEVENT_OUTOFCONTEXT);
}
private void WinEventProc(System.IntPtr hWinEventHook, uint eventType, System.IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (hwnd == IntPtr.Zero)
{
Debug.WriteLine("Mouse moved");
}
else
{
Debug.WriteLine("Location changed");
}
}
}
}
The header file WinUser.h has this to say about EVENT_OBJECT_LOCATIONCHANGE:
* Note also that USER will generate LOCATIONCHANGE notifications for two
* non-window sys objects:
* (1) System caret
* (2) Cursor
This explains why the event fires when the cursor moves.
As Hans says in his comment, just filter the object ID by OBJID_CURSOR.
I have a problem in last two days i want to get processes of users which he clicked. like if a user clicks Notepad my program should tell me that user clicked Notepad. Notepad is opened. And if user clicks Calculator my program also tell that user clicked Calculator. Calcultor process is runing.
For this purpose i used this code. Hook manager which gives me mouse click events but not giving me the process.
I am only getting mouse intptr event.
private static void WindowEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Console.WriteLine("Event {0}", hwnd);// it is giving me mouse event
/*uint pid;
GetWindowThreadProcessId(hwnd, out pid);// it gives me process id
Process p = Process.GetProcessById((int)pid);// now here exception occured not in vs studio but when i run its exe then its gives me access violation exception
if (!my.ContainsKey(p.MainWindowTitle.ToString()))
{
my.Add(p.MainWindowTitle.ToString(), p.Id.ToString());
Console.WriteLine("\r\n");
Console.WriteLine("Status = Running");
Console.WriteLine("\r\n Window Title:" + p.MainWindowTitle.ToString());
Console.WriteLine("\r\n Process Name:" + p.ProcessName.ToString());
Console.WriteLine("\r\n Process Starting Time:" + p.StartTime.ToString());
}*/
}
the full code is
static void Main(string[] args)
{
HookManager.SubscribeToWindowEvents();
EventLoop.Run();
}
public static class HookManager
{
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
public static void SubscribeToWindowEvents()
{
if (windowEventHook == IntPtr.Zero)
{
windowEventHook = SetWinEventHook(
EVENT_SYSTEM_FOREGROUND, // eventMin
EVENT_SYSTEM_FOREGROUND, // eventMax
IntPtr.Zero, // hmodWinEventProc
WindowEventCallback, // lpfnWinEventProc
0, // idProcess
0, // idThread
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (windowEventHook == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
static Dictionary<string, string> my = new Dictionary<string, string>();
private static void WindowEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Console.WriteLine("Event {0}", hwnd);
/*uint pid;
GetWindowThreadProcessId(hwnd, out pid);
Process p = Process.GetProcessById((int)pid);
if (!my.ContainsKey(p.MainWindowTitle.ToString()))
{
my.Add(p.MainWindowTitle.ToString(), p.Id.ToString());
Console.WriteLine("\r\n");
Console.WriteLine("Status = Running");
Console.WriteLine("\r\n Window Title:" + p.MainWindowTitle.ToString());
Console.WriteLine("\r\n Process Name:" + p.ProcessName.ToString());
Console.WriteLine("\r\n Process Starting Time:" + p.StartTime.ToString());
}*/
}
}
private static IntPtr windowEventHook;
private delegate void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
[DllImport("user32.dll", SetLastError = true)]
private static extern int UnhookWinEvent(IntPtr hWinEventHook);
private const int WINEVENT_INCONTEXT = 4;
private const int WINEVENT_OUTOFCONTEXT = 0;
private const int WINEVENT_SKIPOWNPROCESS = 2;
private const int WINEVENT_SKIPOWNTHREAD = 1;
private const int EVENT_SYSTEM_FOREGROUND = 3;
public static class EventLoop
{
public static void Run()
{
MSG msg;
while (true)
{
if (PeekMessage(out msg, IntPtr.Zero, 0, 0, PM_REMOVE))
{
if (msg.Message == WM_QUIT)
break;
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
}
}
[StructLayout(LayoutKind.Sequential)]
private struct MSG
{
public IntPtr Hwnd;
public uint Message;
public IntPtr WParam;
public IntPtr LParam;
public uint Time;
}
const uint PM_NOREMOVE = 0;
const uint PM_REMOVE = 1;
const uint WM_QUIT = 0x0012;
[DllImport("user32.dll")]
private static extern bool PeekMessage(out MSG lpMsg, IntPtr hwnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
[DllImport("user32.dll")]
private static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll")]
private static extern IntPtr DispatchMessage(ref MSG lpMsg);
}
}
If you want to put your logic inside the mouse click handler you can simply call GetActiveWindow to get window handle (if you dont already have it). Then you can use GetWindowThreadProcessId to get process id from window handle.
Doing this with every mouse click looks like an overkill, however. You should probably think about hooking to active window change. Check this for details: Is there Windows system event on active window changed?
For example if the user is currently running VS2008 then I want the value VS2008.
I am assuming you want to get the name of the process owning the currently focused window. With some P/Invoke:
// The GetForegroundWindow function returns a handle to the foreground window
// (the window with which the user is currently working).
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
// The GetWindowThreadProcessId function retrieves the identifier of the thread
// that created the specified window and, optionally, the identifier of the
// process that created the window.
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// Returns the name of the process owning the foreground window.
private string GetForegroundProcessName()
{
IntPtr hwnd = GetForegroundWindow();
// The foreground window can be NULL in certain circumstances,
// such as when a window is losing activation.
if (hwnd == null)
return "Unknown";
uint pid;
GetWindowThreadProcessId(hwnd, out pid);
foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
{
if (p.Id == pid)
return p.ProcessName;
}
return "Unknown";
}
using System;
using System.Windows;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace FGHook
{
class ForegroundTracker
{
// Delegate and imports from pinvoke.net:
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
// Constants from winuser.h
const uint EVENT_SYSTEM_FOREGROUND = 3;
const uint WINEVENT_OUTOFCONTEXT = 0;
// Need to ensure delegate is not collected while we're using it,
// storing it in a class field is simplest way to do this.
static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);
public static void Main()
{
// Listen for foreground changes across all processes/threads on current desktop...
IntPtr hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
procDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);
// MessageBox provides the necessary mesage loop that SetWinEventHook requires.
MessageBox.Show("Tracking focus, close message box to exit.");
UnhookWinEvent(hhook);
}
static void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Console.WriteLine("Foreground changed to {0:x8}", hwnd.ToInt32());
//Console.WriteLine("ObjectID changed to {0:x8}", idObject);
//Console.WriteLine("ChildID changed to {0:x8}", idChild);
GetForegroundProcessName();
}
static void GetForegroundProcessName()
{
IntPtr hwnd = GetForegroundWindow();
// The foreground window can be NULL in certain circumstances,
// such as when a window is losing activation.
if (hwnd == null)
return;
uint pid;
GetWindowThreadProcessId(hwnd, out pid);
foreach (System.Diagnostics.Process p in System.Diagnostics.Process.GetProcesses())
{
if (p.Id == pid)
{
Console.WriteLine("Pid is: {0}",pid);
Console.WriteLine("Process name is {0}",p.ProcessName);
return;
}
//return;
}
Console.WriteLine("Unknown");
}
}
}