How to Unhook windows hooks - c++

I have a program (not a DLL) that creates a thread, and in this thread I create a hook using SetWindowsHookExW() to get keyboard events. I also have a global variable that I can use to turn off this thread.
The thing is that I don't know how to release the hooks and continue the function/thread, because it also does some cleanup. When I use UnhookWindowsHookEx() and place breakpoints in the following lines, the breakpoints are never reached.
The example on MSDN is "broken", because it needs an app.h; Also, every tutorial on the Internet, either input systems, keylogger, etc, they talk about DLLs, that I'm not using, and some of them implement a wrapper Unhook function but they never use it.
What I've been trying:
#include <Windows.h>
bool bContinue;
wchar_t vkTecla;
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
if (bContinue)
{
UnhookWindowsHookEx(hHook);
return 0;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
// I tested these 3 cases
/*************/
while(GetMessageW(&msg, 0, 0, 0));
// Or
GetMessageW(&msg, 0, 0, 0);
/*************/
while(GetMessageW(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/*************/
while (bContinue)
{
// PeekMessage(...);
GetMessageW(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// In this example I would remove the other Unhook function
UnhookWindowsHookEx(hHook);
/*************/
CloseHandle(hfile);
}
If I do the first example, the:
while(GetMessageW(&msg, 0, 0, 0));
and check bContinue inside of the callback function;
or use the third one:
while (bContinue)
{
GetMessageW(&msg, 0, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hHook);
And place a breakpoint in CloseHandle(hArquivo);, when I make the bContinue = false, this line never gets executed.
So the question is:
Where do I place UnhookWindowsHookEx()? Is it inside the Callback function, or somewhere else?
When I release the hook, will the thread continue? Because at the moment, I don't get the program to stop at breakpoints past the unhooking that have some cleanup.

GetMessage() is a blocking function. It will not exit until the message queue of the calling thread has a message available for the caller to process.
But, you are running this code in a worker thread that has no UI of its own. And, although hooks do use messaging internally, they are private to the hook implementation and the caller of (Peek|Get)Message() will never see them. So, unless the other threads in your app are posting messages to this worker thread via PostThreadMessage(), there are simply no messages for GetMessage() to return to your code. That is why your loop doesn't break.
So, you need to either:
use PeekMessage() instead of GetMessage() so you can monitor your bContinue variable in between polls of the message queue:
#include <Windows.h>
bool bContinue = TRUE;
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
wchar_t vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
HHOOK hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
while (bContinue)
{
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
Sleep(10);
}
UnhookWindowsHookEx(hHook);
CloseHandle(hfile);
}
...
// to stop the thread:
bContinue = FALSE;
change bContinue to be a HANDLE returned by CreateEvent(), and then use MsgWaitForMultipleObjects() in a loop to monitor that event and the message queue at the same time, calling (Get|Peek)Message() only when it reports the message queue has messages to process. Then you can use SetEvent() when you want to trigger the loop to end.
#include <Windows.h>
HANDLE hStop = CreateEvent(NULL, TRUE, FALSE, NULL);
LRESULT CALLBACK KeyboardCallBack(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
wchar_t vkTecla = ((KBDLLHOOKSTRUCT*)lParam)->vkCode;
if (wParam == WM_KEYDOWN)
{
// Do stuff here
}
// ...
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
void MainThread(HANDLE hfile)
{
HHOOK hHook = SetWindowsHookExW(WH_KEYBOARD_LL, KeyboardCallBack, 0, 0);
MSG msg;
while (MsgWaitForMultipleObjects(1, &hStop, FALSE, INFINITE, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1))
{
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
UnhookWindowsHookEx(hHook);
CloseHandle(hfile);
}
...
// to stop the thread:
SetEvent(hStop);

Related

Handle message from another thread in Win32 windows

I created a window with Win32s, I wish it could handle incoming messages from another thread in addition to typical windows messages.
I'm using this piece of code:
while (dataAvailable || GetMessage(&msg, nullptr, 0, 0))
{
// if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
if (dataAvailable == true)
{
cout << "My thread message/signal!" << endl;
dataAvailable = false;
}
else
{
//Windows message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
the "DataAvailable" is an atomic bool that I set when I would like pass a my own message to win32 app/windows.
This don't work well.
It is possible to do this?
I suggest you to use standard messages. Register your own new message and use PostMessage from another thread to your main window thread.
I base my example code on standard windows sample code: https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/begin/LearnWin32/HelloWorld/cpp/main.cpp
In this code I add a standard std::thread :
// ...
auto th1 = std::thread([=] {
const UINT WM_EX_SOME_SPECIALINTERNALMESSAGE = ::RegisterWindowMessage(L"SomeSpecialInternalMessage");
for (int n = 0; n < 10; ++n) {
PostMessage(hwnd, WM_EX_SOME_SPECIALINTERNALMESSAGE, 0, 0);
Sleep(1000);
}
});
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
th1.join();
As you see in this code, WM_EX_SOME_SPECIALINTERNALMESSAGE is a custom windows message. Its posted every second to you main window proc: WindowProc. To receive it modify WindowProc:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
const UINT WM_EX_SOME_SPECIALINTERNALMESSAGE = ::RegisterWindowMessage(L"SomeSpecialInternalMessage");
if(uMsg == WM_EX_SOME_SPECIALINTERNALMESSAGE) {
OutputDebugStringW(L"WM_EX_SOME_SPECIALINTERNALMESSAGE\n");
}
// ...

Properly using AddClipboardFormatListener and subscribing to WM_CLIPBOARDUPDATE message

I am currently attempting to use the Windows clipboard and its notifications in my application. Specifically, I am attempting to subscribe to the WM_CLIPBOARDUPDATE window message by using the AddClipboardFormatListener() function. Previously, I had been using the SetClipboardViewer() function in order to add my window directly into the clipboard viewer chain. This had worked just fine, and I had received the relevant messages WM_DRAWCLIPBOARD and WM_DESTROYCLIPBOARD when expected. However, I would like to avoid continuing to use the clipboard chain because of how volatile it can be.
My understanding was that I would be perfectly able to receive WM_CLIPBOARDUPDATE after calling AddClipboardFormatListener(). Is there another step here that I am missing? What do I need to do to make sure that I receive this message properly? As it stands currently, I am not receiving it when performing a copy operation.
Here is an abridged example of what my code looks like:
WNDPROC override:
LRESULT CALLBACK ClipboardService::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
switch ( pMsg->message )
{
case WM_DRAWCLIPBOARD:
// Handle clipboard available event and forward message
break;
case WM_CLIPBOARDUPDATE:
// This is never triggered
break;
case WM_DESTROYCLIPBOARD:
// Handle clipboard cleared event and forward message
break;
}
return ::CallNextHookEx( g_Hook, nCode, wParam, lParam );
}
Called by Constructor:
HRESULT ClipboardService::SetOrRefreshWindowsHook()
{
HRESULT hr = S_OK;
try
{
if (!m_bHookSet)
{
g_hwndCurrent = ::CreateWindowEx(0, "Message", "ClipboardMessageWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
m_dwThreadID = ::GetWindowThreadProcessId(g_hwndCurrent, &m_dwProcessID);
_Module.Lock();
SetLastError(0);
g_Hook = ::SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, 0, m_dwThreadID);
//g_hwndNext = ::SetClipboardViewer(g_hwndCurrent); old way to subscribe
// This is what I expect should subscribe me to WM_CLIPBOARDUPDATE messages
if (!::AddClipboardFormatListener(g_hwndCurrent))
hr_exit(E_UNEXPECTED);
DWORD dwLastError = ::GetLastError();
g_This = this;
m_bHookSet = true;
}
}
catch (...)
{
hr_exit(E_UNEXPECTED);
}
wrapup:
return hr;
}
This is a COM interface that is called by a .NET wrapper, but I don't think that either of those two things are relevant to my problem in this case (figured I would add just in case).
You should not be using SetWindowsHookEx(WH_CALLWNDPROC) to receive messages to your own window. Use RegisterClass/Ex() instead to register your own custom window class that has your WndProc assigned to it, and then CreateWindowEx() can create an instance of that window class. No hooking needed.
HINSTANCE g_hThisInst = NULL;
HWND g_hwndCurrent = NULL;
//HWND g_hwndNext = NULL;
bool g_AddedListener = false;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
g_hThisInst = hinstDLL;
return TRUE;
}
LRESULT CALLBACK ClipboardService::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
//g_hwndNext = ::SetClipboardViewer(hwnd);
g_AddedListener = ::AddClipboardFormatListener(hwnd);
return g_AddedListener ? 0 : -1;
case WM_DESTROY:
/*
ChangeClipboardChain(hwnd, g_hwndNext);
g_hwndNext = NULL;
*/
if (g_AddedListener)
{
RemoveClipboardFormatListener(hwnd);
g_AddedListener = false;
}
return 0;
/*
case WM_CHANGECBCHAIN:
if (g_hwndNext == (HWND)wParam)
g_hwndNext = (HWND)lParam;
else if (g_hwndNext)
SendMessage(g_hwndNext, uMsg, wParam, lParam);
break;
case WM_DRAWCLIPBOARD:
// Handle clipboard available event
if (g_hwndNext)
SendMessage(g_hwndNext, uMsg, wParam, lParam);
break;
*/
case WM_CLIPBOARDUPDATE:
// Handle clipboard updated event
return 0;
case WM_DESTROYCLIPBOARD:
// Handle clipboard cleared event and forward message
break;
}
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HRESULT ClipboardService::SetOrRefreshWindowsHook()
{
try
{
if (!g_hwndCurrent)
{
WNDCLASS wndClass = {};
wndClass.lpfnWndProc = &ClipboardService::WndProc;
wndClass.hInstance = g_hThisInst;
wndClass.lpszClassName = TEXT("ClipboardMessageWindow");
if (!::RegisterClass(&wndClass))
{
DWORD dwLastError = ::GetLastError();
if (dwLastError != ERROR_CLASS_ALREADY_EXISTS)
return HRESULT_FROM_WIN32(dwLastError);
}
g_hwndCurrent = ::CreateWindowEx(0, wndClass.lpszClassName, "", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, g_hThisInst, NULL);
if (!g_hwndCurrent)
{
DWORD dwLastError = ::GetLastError();
return HRESULT_FROM_WIN32(dwLastError);
}
g_This = this;
}
}
catch (...)
{
return E_UNEXPECTED;
}
return S_OK;
}

Closing a window completely in Visual Studio, terminating the VS-debugger as well

I am trying to close my window after creating it and everything works well except one tiny detail: the debugger in the Visual Studio is still open. This means that there's still something not closed entirely I guess (a COM object?).
This is part of the code within my WinMain():
MSG msg;
while (TRUE)
{
if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
}
else
{
// RUN GAME CODE
// ...
}
}
return msg.wParam;
} // end of WinMain()
I placed a breakpoint just within the if and on running, I find that the if condition never resolves to true even when I close my window. What should I be doing to ensure that the window closes completely.
Below is my WinProc();
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}

Control OS mouse clicks

I can't seem to find what I am looking for which is a way to alter the OS's mouse clicks. To specify this would be on Windows.
The goal is to limit the number of mouse clicks a user can register within a period of time.
I think the function that you are looking for is SetWindowsHookEx. Here is a quick example.
#include <windows.h>
const DWORD desireddelay = 10;
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
static DWORD previoustimestamp = 0;
if ((nCode == 0) && (wParam == WM_RBUTTONDOWN))
{
if ((((MSLLHOOKSTRUCT*)lParam)->time - previoustimestamp) < desireddelay)
{
return 1; //Non-Zero Swallows the keystroke. 0 Allows it. Always CallNextHookEx if you are not swallowing it.
}
else
{
previoustimestamp = ((MSLLHOOKSTRUCT*)lParam)->time;
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(NULL), NULL);
MSG msg;
bool done = false;
while (GetMessage(&msg, NULL, NULL, NULL)) {}
UnhookWindowsHookEx(hook);
return 0;
}

Get Notified about Windows is Going to Sleep/Waking up in C++

I am working on an App which has Multiple Threads waiting for different inputs from DLLs and Serial Ports.
I want to add a functionality that before machine going to Sleep, I have to unload certain DLL and On waking up have to Re-load the DLL.
For this, I need to get notified on Sleep and Wake up.
I found many files about doing in C# but I want to do this in C++.
I tried using this code Project but could not capture any event. I removed everything related to Window Paint and All that as I do not need it's GUI and kept only main message loop (The While loop in the main)
EDIT:-
I am using this as my main loop:-
// Start the message loop.
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
To be frank I have copied this from CodeProject, and Made only one Modification i.e. Checked GetMessage(..) != 0 from a MSDN Article.
Am I missing something?
Or anyother Solution??
I am using VS2010 and programming in C++
Thanks in Advance!
Try handling the WM_POWERBROADCAST message
Here's sample code that should work. Apparently you do need to create a window otherwise you don't receive the messages. The sample creates a hidden window to achieve this.
static long FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_POWERBROADCAST)
{
//Do something
return TRUE;
}
else
return DefWindowProc(hWnd, message, wParam, lParam);
}
int _tmain(int argc, _TCHAR* argv[])
{
WNDCLASS wc = {0};
// Set up and register window class
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = _T("SomeNameYouInvented");
RegisterClass(&wc);
HWND hWin = CreateWindow(_T("SomeNameYouInvented"), _T(""), 0, 0, 0, 0, 0, NULL, NULL, NULL, 0);
BOOL bRet;
MSG msg;
while( (bRet = GetMessage( &msg, hWin, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}