How to use SetWinEventHook() function to get Active Window changed message - c++

I have been working on a project which needs to detect current active window and get the active window title continuously.
Can anyone explain me how to use SetWinEventHook() function to get Active Window changed message.
[ i used GetForegroundWindow() function with a timer to get the active window. That approach is not very accurate because of the timer. So i need to use it with SetWinEventHook() function. can someone explain me how to do that? ]
hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND , EVENT_SYSTEM_FOREGROUND ,NULL,
WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
/* how to get active window message */
}

I have found the solution. EVENT_SYSTEM_FOREGROUND Event is the missing piece. The system sends this event even if the foreground window has changed to another window. We can use this event to get the current active window.
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
if (dwEvent == EVENT_SYSTEM_FOREGROUND)
{
/* do something */
}
}

Related

Make a event for a mouse button even if application is minimized

I want to make an application that responds to a mouse button so I done this:
case WM_LBUTTONDOWN:
MessageBox(
NULL,
(LPCWSTR)L"HALLOOOO",
(LPCWSTR)L"Worked",
MB_ICONASTERISK | MB_OK | MB_DEFBUTTON2
);
break;
but the problem is that this only works if the user clicks on the window and I want it to work even with the window minimized
this work even if the application is minimized
GetKeyState(VK_LBUTTON);
but if I put this in a loop if I press it once it will detect 1 million times because it will just check if the key is down and if I add delay using Sleep(250) it may work but sometimes it will not detect anything even if the user pressed the key
I want my app to be able to detect if a key is pressed even if it's minimized how can I do this?
Since you already have a window, call SetWindowsHookEx with WH_MOUSE_LL.
The API is documented here and the parameters are explained.
HHOOK SetWindowsHookExW(
[in] int idHook,
[in] HOOKPROC lpfn,
[in] HINSTANCE hmod,
[in] DWORD dwThreadId
);
The lpfn hook procedure can be defined as follows:
HWND hmain_window;
HHOOK hhook;
LRESULT CALLBACK mouse_proc(int code, WPARAM wparam, LPARAM lparam)
{
if (code == HC_ACTION && lparam)
{
if (wparam == WM_LBUTTONDOWN)
{
//MOUSEHOOKSTRUCT* mstruct = (MOUSEHOOKSTRUCT*)lparam;
static int i = 0;
std::wstring str = L"mouse down " + std::to_wstring(i++);
SetWindowText(hmain_window, str.c_str());
}
}
return CallNextHookEx(hhook, code, wparam, lparam);
}
int APIENTRY wWinMain(HINSTANCE hinst, HINSTANCE, LPWSTR, int)
{
...
RegisterClassEx(...);
hmain_window = CreateWindow(...);
hhook = SetWindowsHookEx(WH_MOUSE_LL, mouse_proc, hinst, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhook);
return 0;
}
You can try SetWindowsHookEx with parameter WH_MOUSE_LL or WH_MOUSE.
This article shows how to install a keyboard hook. You can replace WH_KEYBOARD with WH_MOUSE to install a mouse hook and use this document to handle the callback.

How to add event hook for mouse operations in c++ win32?

I wanted to add a system foreground event hook to track the active window and track mouse clicks(right-click) within the active window. I add eventHook for EVENT_SYSTEM_FOREGROUND, which is working as expected, my hook:
HWINEVENTHOOK hHook = SetWinEventHook (EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND,
NULL, MyEventHandler, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
where MyEventHandler is
void CALLBACK MyEventHandler (
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD idEventThread,
DWORD dwmsEventTime
)
{ ... }
How to add a mouse event handler to track mouse operations like right click?

How do I handle win32 events from another thread? [duplicate]

Using the Win32 APIs, is it possible to create a Window or Dialog in one thread then collect events for it from another thread?
Are HWNDs tied to threads?
Trying the contrived example below I never see GetMessage() fire.
HWND g_hWnd;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
But here, I do.
HWND g_hWnd;
HINSTANCE g_hInstance;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
Can somebody explain what I'm seeing?
No.
GetMessage returns messages on the current thread's input queue. The HWND parameter is a filter, so that GetMessage only returns messages in the current thread's input queue intended for that window.
Windows have thread affinity - messages intended for a window get handled on the thread that created and therefore owns the window.
From the MSDN:
The GetMessage function retrieves a
message from the calling thread's
message queue
So no, what you describe is not directly possible.
In your first example the Dialog and GetMessage are in separate threads. And the documentation says:
The GetMessage function retrieves a message from the calling thread's message queue.
The second example works since the calling thread (for GetMessage) also owns the Dialog.
Use AttachThreadInput.
In your example programm finish after create window.
But anyway in win32 all threads have own message queue.
And all message queues get messages for windows created in this thread.
see:
http://msdn.microsoft.com/en-us/library/ms644928(VS.85).aspx (Using Messages and Message Queues)
http://msdn.microsoft.com/en-us/library/ms644936(VS.85).aspx (GetMessage Function)
You can of course change the window procedure that handles messages for any window. Check the SetWindowLong function - http://msdn.microsoft.com/en-us/library/ms633591(VS.85).aspx - there are some rules as to what address space the new proc is. I suggest using a dll. Another way is to sub class the window message queue.
Of course you can !
Just use remote code injection ! (very classic !)

external variable is not available to thread until blocking call is made...

I have two code files, one contains my WinMain() function, and all functions related to my main dialog window. The other contains a thread callback and variable functions related to my program. I have defined HWND hWnd = NULL as a global variable in MainDlg.cpp and defined extern HWND hWnd in Other.cpp (which contains the thread callback). The thread is created when the WM_INITDIALOG message is sent to the window. Inside the thread callback, the hWnd variable is null until long operation is performed, then after that it becomes available.
MainDlg.cpp
HWND hWnd = NULL;
HANDLE hListenThread = NULL;
DWORD WINAPI ListenThread( LPVOID lpvParam );
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
/* ... */
if( NULL == (hWnd=CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)WndProc)) )
{
MessageBox( NULL, "Error creating the main dialog!", NULL, MB_OK | MB_ICONERROR );
return -1;
}
MSG msg;
while( GetMessage(&msg,NULL,0,0) && IsWindow(hWnd) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
BOOL CALLBACK WndProc(HWND hWndDlg, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:
{
DWORD dwListenThreadId = NULL;
/* referencing hWnd here works fine... */
/* ... */
hListenThread = CreateThread(
NULL,
0,
ListenThread,
hWndDlg,
0,
&dwListenThreadId);
/* ... */
} break;
}
return false;
}
Other.cpp
extern HWND hWnd;
DWORD WINAPI ListenThread( LPVOID lpvParam )
{
if( hWnd == NULL )
MessageBox( NULL, "hWnd == NULL", NULL, MB_OK | MB_SYSTEMMODAL );
if( hWnd != NULL )
MessageBox( NULL, "hWnd != NULL", NULL, MB_OK | MB_SYSTEMMODAL );
return 0;
}
Both Message Boxes in the ListenThread callback are displayed when the application is launched. Can someone please tell me why this is happening? Is there something I can do to fix this besides doing while( hWnd == NULL ); at the beginning of my ListenThread ?
The WM_INITDIALOG message occurs before CreateDialog returns and hWnd isn't set until CreateDialog returns. So the thread starts running before CreateDialog returns and sets the global hWnd variable.
So you could fix this by moving your thread creation from the WM_INITDIALOG message to just after the return of CreateDialog.
But you don't need to do that because you code doesn't required the global hWnd variable. You are already passing your dialogs window handle as the parameter to the thread start procedure. So just cast the lpvParam to an HWND and use that. That will let you get rid of your global variable, which is bad practice to use.
Other.cpp
DWORD WINAPI ListenThread( LPVOID lpvParam )
{
HWND hWnd= (HWND)lpvParam;
if( hWnd == NULL )
MessageBox( NULL, "hWnd == NULL", NULL, MB_OK | MB_SYSTEMMODAL );
if( hWnd != NULL )
MessageBox( NULL, "hWnd != NULL", NULL, MB_OK | MB_SYSTEMMODAL );
return 0;
}
The WM_INITDIALOG message is issued to WndProc() from inside of CreateDialog() itself, not by DispatchMessage(). This is stated as much in the CreateDialog() documentation. Your hWnd variable is not assigned until after CreateDialog() exits. If your thread starts running before CreateDialog() exits (depending on task scheduling, that is not a guarantee), your first MessageBox() gets called. While the MessageBox() is running, CreateDialog() has time to exit and assign the variable, which is why the second MessageBox() gets called after you dismiss the first MessageBox().
You don't need to use the hWnd variable in your thread at all. You are passing the dialog HWND to the lpParameter parameter of CreateThread(), so it will appear in the lpvParam parameter of ListenThread(), eg:
DWORD WINAPI ListenThread( LPVOID lpvParam )
{
HWND hWnd = (HWND) lpvParam;
...
return 0;
}

Can the HWND from CreateWindow/CreateDialog be GetMessage'd from another thread?

Using the Win32 APIs, is it possible to create a Window or Dialog in one thread then collect events for it from another thread?
Are HWNDs tied to threads?
Trying the contrived example below I never see GetMessage() fire.
HWND g_hWnd;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
But here, I do.
HWND g_hWnd;
HINSTANCE g_hInstance;
DWORD WINAPI myThreadProc(LPVOID lpParam)
{
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), 0, myDlgProc);
while(GetMessage(&msg, hWnd, 0, 0) > 0)
{
...
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
g_hInstance = hInstance;
CreateThread(NULL, 0 myThreadProc, NULL, 0, NULL);
...
}
Can somebody explain what I'm seeing?
No.
GetMessage returns messages on the current thread's input queue. The HWND parameter is a filter, so that GetMessage only returns messages in the current thread's input queue intended for that window.
Windows have thread affinity - messages intended for a window get handled on the thread that created and therefore owns the window.
From the MSDN:
The GetMessage function retrieves a
message from the calling thread's
message queue
So no, what you describe is not directly possible.
In your first example the Dialog and GetMessage are in separate threads. And the documentation says:
The GetMessage function retrieves a message from the calling thread's message queue.
The second example works since the calling thread (for GetMessage) also owns the Dialog.
Use AttachThreadInput.
In your example programm finish after create window.
But anyway in win32 all threads have own message queue.
And all message queues get messages for windows created in this thread.
see:
http://msdn.microsoft.com/en-us/library/ms644928(VS.85).aspx (Using Messages and Message Queues)
http://msdn.microsoft.com/en-us/library/ms644936(VS.85).aspx (GetMessage Function)
You can of course change the window procedure that handles messages for any window. Check the SetWindowLong function - http://msdn.microsoft.com/en-us/library/ms633591(VS.85).aspx - there are some rules as to what address space the new proc is. I suggest using a dll. Another way is to sub class the window message queue.
Of course you can !
Just use remote code injection ! (very classic !)