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?
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 tried get current active application name (or process name) but in some application like Microsoft Edge is result ApplicationFrameHost. Is there way to get application name such as in Task manager?
My actual code:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
private string GetActiveProcess()
{
const int nChars = 256;
uint processId;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
GetWindowThreadProcessId(handle, out processId);
return Process.GetProcessById((int)processId).ProcessName;
}
return null;
}
This solution looks functional for me in form application:
//aktivneOknoProces
string aktivneOknoProces = GetActiveProcess();
private Process _realProcess;
private string GetActiveProcess()
{
string app = "";
var foregroundProcess = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(WinAPIFunctions.GetforegroundWindow()));
if (foregroundProcess.ProcessName == "ApplicationFrameHost")
{
foregroundProcess = GetRealProcess(foregroundProcess);
}
if(foregroundProcess != null)
{
app = foregroundProcess.ProcessName;
}
return app;
}
private Process GetRealProcess(Process foregroundProcess)
{
WinAPIFunctions.EnumChildWindows(foregroundProcess.MainWindowHandle, ChildWindowCallback, IntPtr.Zero);
return _realProcess;
}
private bool ChildWindowCallback(IntPtr hwnd, IntPtr lparam)
{
var process = Process.GetProcessById(WinAPIFunctions.GetWindowProcessId(hwnd));
if (process.ProcessName != "ApplicationFrameHost")
{
_realProcess = process;
}
return true;
}
public class WinAPIFunctions
{
//Used to get Handle for Foreground Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetForegroundWindow();
//Used to get ID of any Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
public delegate bool WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc callback, IntPtr lParam);
public static int GetWindowProcessId(IntPtr hwnd)
{
int pid;
GetWindowThreadProcessId(hwnd, out pid);
return pid;
}
public static IntPtr GetforegroundWindow()
{
return GetForegroundWindow();
}
}
I believe what you are looking for is this:
Process.GetCurrentProcess().ProcessName
GetCurrentProcess
ProcessName
That should give you the name of the curent process
I'm writing an application in c# and I need to know when the for the ground window has changed
I used SetWindowsHookEx but I don't get the call back when I switch between windows
my code:
private const int WH_CALLWNDPROC = 4;
private delegate IntPtr windowName(int nCode, IntPtr wParam, IntPtr lParam);
private static windowName _name = HookCallback;
private static IntPtr _hook = IntPtr.Zero;
public static void start()
{
_hook = SetHook(_name);
Application.Run();
UnhookWindowsHookEx(_hook);
}
private static IntPtr SetHook(windowName proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_CALLWNDPROC, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
browser = GetActiveWindow();
Console.WriteLine(browser);
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
ok i have an answer
public static void start()
{
WinEventDelegate dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
string window = GetActiveWindowTitle();
Console.WriteLine(window);
while (true)
{
if (window != GetActiveWindowTitle())
{
window = GetActiveWindowTitle();
Console.WriteLine(window);
}
}
}
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
private static string GetActiveWindowTitle()
{
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;
}
public static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Console.WriteLine(GetActiveWindowTitle());
}
#region imports
[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_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
its a bit messy but it works
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");
}
}
}