C++ ignore events for x amount of seconds - c++

I got a bit of code off github that locks a laptop if the monitor goes to sleep or if the laptop lid is closed. The issue is, if the laptop is started up while the lid is already closed, such as when it's on a docking station for example. The second the code runs it sends the notification to lock the laptop. I have the complied program sitting in the startup folder so the behavior is such that when I login the program starts and then locks the pc immediately if it's closed.
I need to be able to ignore the GUID_LIDSWITCH_STATE_CHANGE and GUID_MONITOR_POWER_ON events for x amount of seconds once the program is started so that this behavior will stop, but I cannot figure out how to do this. From what I understand the bit of code to ignore all events for x seconds needs to be inserted under the "static LRESULT CALLBACK" portion of the code
Here is the code below:
#include <chrono>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <memory>
#include <sstream>
#include <windows.h>
namespace laplock {
namespace {
class LogLine {
public:
LogLine() {
if (!logfile) return;
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
tm localnow;
if (localtime_s(&localnow, &now) == 0) {
*logfile << std::put_time(&localnow, L"%F %T ");
}
}
~LogLine() {
if (!logfile) return;
*logfile << std::endl;
logfile->flush();
}
template <typename T> LogLine& operator<<(T value) {
if (!logfile) return *this;
*logfile << value;
return *this;
}
static std::unique_ptr<std::wofstream> logfile;
};
std::unique_ptr<std::wofstream> LogLine::logfile;
std::wostream& operator<<(std::wostream& stream, const GUID& guid) {
wchar_t str[128] = { 0 };
StringFromGUID2(guid, str, sizeof(str));
stream << str;
return stream;
}
static void systemError(wchar_t* what)
{
const DWORD error = GetLastError();
LogLine() << "Error " << error << " during: " << what;
static wchar_t buffer[1024];
const wchar_t* errorMessage = buffer;
if (!FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
error,
0,
buffer,
sizeof(buffer),
0
))
errorMessage = L"(cannot format error message)";
else
LogLine() << "System error message: " << errorMessage;
std::wstringstream message;
message << L"A system error occured within laplock." << std::endl;
message << L"Operation: " << what << std::endl;
message << L"System message: " << errorMessage;
MessageBox(NULL, message.str().c_str(), L"laplock error", MB_OK | MB_ICONERROR);
exit(EXIT_FAILURE);
}
static LRESULT CALLBACK windowProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE) {
LogLine() << "Window received irrelevant message";
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
if (GetSystemMetrics(SM_REMOTESESSION)) {
LogLine() << "Ignoring window message because session is currently remote";
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
const POWERBROADCAST_SETTING* setting = reinterpret_cast<const POWERBROADCAST_SETTING*>(lParam);
LogLine() << "Received POWERBROADCAST_SETTING " << setting->PowerSetting;
if (setting->PowerSetting != GUID_MONITOR_POWER_ON && setting->PowerSetting != GUID_LIDSWITCH_STATE_CHANGE) {
LogLine() << "Received irrelevant POWERBROADCAST_SETTING";
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
const DWORD* state = reinterpret_cast<const DWORD*>(&setting->Data);
LogLine() << "POWERBROADCAST_SETTING state: " << *state;
if (*state != 0) {
LogLine() << "Irrelevant POWERBROADCAST_SETTING state";
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LogLine() << "Locking";
if (LockWorkStation() == 0)
systemError(L"locking workstation");
else
LogLine() << "Locked";
return 0;
}
static void registerWindowClass(HINSTANCE instance)
{
LogLine() << "Registering window class";
WNDCLASSEX windowClass = { 0 };
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.lpfnWndProc = &windowProcedure;
windowClass.hInstance = instance;
windowClass.lpszClassName = L"laplock";
if (RegisterClassEx(&windowClass) == 0)
systemError(L"registering window class");
}
static HWND createWindow(HINSTANCE instance)
{
LogLine() << "Creating window";
HWND hWnd = CreateWindow(
L"laplock",
NULL,
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_MESSAGE,
NULL,
instance,
NULL
);
if (hWnd == NULL)
systemError(L"creating window");
return hWnd;
}
static void registerNotification(HWND window)
{
LogLine() << "Registering GUID_MONITOR_POWER_ON (GUID: " << GUID_MONITOR_POWER_ON << ")";
if (!RegisterPowerSettingNotification(window, &GUID_MONITOR_POWER_ON, DEVICE_NOTIFY_WINDOW_HANDLE))
systemError(L"cannot register GUID_MONITOR_POWER_ON power setting notification");
LogLine() << "Registering GUID_LIDSWITCH_STATE_CHANGE (GUID: " << GUID_LIDSWITCH_STATE_CHANGE << ")";
if (!RegisterPowerSettingNotification(window, &GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE))
systemError(L"cannot register GUID_LIDSWITCH_STATE_CHANGE power setting notification");
}
static WPARAM messageLoop()
{
for (;;)
{
LogLine() << "Awaiting next window message";
MSG message;
BOOL result = GetMessage(&message, NULL, 0, 0);
if (result == -1)
systemError(L"getting window message");
if (result == 0)
return message.wParam;
LogLine() << "Dispatching message";
DispatchMessage(&message);
}
}
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE, LPSTR commandLine, int)
{
if (*commandLine != 0)
LogLine::logfile.reset(new std::wofstream(commandLine, std::ios_base::app));
LogLine() << "laplock initializing";
registerWindowClass(instance);
HWND window = createWindow(instance);
registerNotification(window);
WPARAM result = messageLoop();
LogLine() << "laplock terminating";
return result;
}
}
}
int CALLBACK WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR commandLine, int cmdShow)
{
return laplock::WinMain(instance, prevInstance, commandLine, cmdShow);
}

Related

WH_KEYBOARD_LL hook not called in UMDF driver, but works in example console app

I'm trying to detect all key presses and mouse events by registering WH_KEYBOARD_LL and WH_MOUSE_LL hooks. Apparently these low-level hooks don't require the hook procedure to reside in a separate DLL.
I have this working in the following example app (a console application).
#include <iostream>
#include <Windows.h>
#include <Winuser.h>
#include <thread>
#include <chrono>
#include <sstream>
#include <atomic>
#include <cassert>
LRESULT CALLBACK wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
std::cout << std::endl << "EVENT: " << hWnd << ", " << message << ", " << wParam << ", " << lParam << std::endl;
return 0;
}
LRESULT CALLBACK keyboardHook(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
std::cout << "Keyboard: " << nCode << ", " << wParam << ", " << lParam << std::endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK mouseHook(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
std::cout << "Mouse: " << nCode << ", " << wParam << ", " << lParam << std::endl;
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
const wchar_t pszClassName[] = L"MyMessageWindow";
auto hInstance = GetModuleHandle(NULL);
WNDCLASSEXW wcl;
ZeroMemory(&wcl, sizeof(WNDCLASSEXW));
wcl.cbSize = sizeof(WNDCLASSEXW);
wcl.hInstance = hInstance;
wcl.lpszClassName = pszClassName;
wcl.lpfnWndProc = wndProc;
assert(RegisterClassExW(&wcl) != 0);
auto hwnd = CreateWindowW(
pszClassName,
pszClassName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_MESSAGE,
NULL,
NULL,
NULL
);
auto threadId = 0;
std::thread t([hwnd, threadId]() {
auto keyboardHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHook, NULL, threadId);
auto mouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL, mouseHook, NULL, threadId);
while (true) {
MSG msg;
GetMessage(&msg, hwnd, 0, 0);
}
});
t.join();
return 0;
}
So this works, and I can see the keyboard and mouse events printed to the console regardless of what apps are in focus (if any), which is great.
However, when I do this inside a UMDF driver, the messages don't come through. The calls to SetWindowsHookEx appear to succeed without error.
I'm thinking of creating a minimal UMDF driver to test if it's possible, but thought I'd first ask here in case someone can tell me whether it's possible. If not, I have a few other approaches in mind.
Thanks

the WM_CLOSE event is never sent/received?

I'm learning DX12 and, in the process, learning "good old Win32".
i have trouble exiting the main loop and it seems related to the fact that i'm not receiving the WM_CLOSE message.
In C++, Windows 10, Console application.
#include <iostream>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <tchar.h>
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
std::cout << "Hello World!\n";
WNDCLASSEX wc = {
sizeof(WNDCLASSEX),
CS_CLASSDC,
WndProc,
0L, 0L,
GetModuleHandle(NULL),
NULL, NULL, NULL, NULL,
_T("ker engine"),
NULL
};
std::cout << "Registering Class\n";
::RegisterClassEx(&wc);
std::cout << "Creating Window\n";
HWND hwnd = ::CreateWindow(
wc.lpszClassName,
_T("Ker Engine DX12"),
WS_OVERLAPPEDWINDOW,
100, 100, 1280, 800, NULL, NULL,
wc.hInstance, NULL
);
std::cout << "Show Window\n";
::ShowWindow(hwnd, SW_SHOWDEFAULT);
std::cout << "Update Window\n";
::UpdateWindow(hwnd);
std::cout << "Entering main loop\n";
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != (WM_QUIT))
{
if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
std::cout << msg.message << std::endl;
switch (msg.message)
{
case WM_CLOSE:
std::cout << "close received\n";
::PostQuitMessage(0);
break;
}
continue;
}
}
std::cout << "leaving main loop\n";
std::cout << "Destroy Window\n";
::DestroyWindow(hwnd);
std::cout << "Unregister Class\n";
::UnregisterClass(wc.lpszClassName, wc.hInstance);
std::cout << "Bye\n";
return 0;
}
When i press the X (close) red window button, the window is closed but :
"closed received" isn't printed
"leaving main loop" isn't printed.
The output is :
Entering main loop
[a lot of message code, in decimal]
160 (a lot of it) (WM_NCMOUSEMOVE)
161 (WM_NCLBUTTONDOWN)
275 (WM_TIMER)
no more output printed, i have to close the console manually.
no WM_CLOSE,or WM_DESTROY, or WM_QUIT. Between BUTTONDOW and whatever TIMER is supposed to be, there should be an event related to the fact that the windows was closed, doesn't it ?
I'm a beginner at this. I tried to search google and stackoverflow but i didn't understand if the context applied to me, or it was too specific/unrelated. it's probably a duplicate but i can't find it.
Am i losing/skiping message perhaps ? that's all i can think of.
Thanks to Simon Mourier comment and link to a tutorial, the problem was solved.
The message handling had to be done in WndProc, not in the "main loop".
I'm reposting the modified, cleaned, working, code :
#include <iostream>
#include <d3d12.h>
#include <dxgi1_4.h>
#include <tchar.h>
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
std::cout << "close received\n";
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hWnd, msg, wParam, lParam);
}
int main()
{
WNDCLASSEX wc = {
sizeof(WNDCLASSEX),
CS_CLASSDC,
WndProc,
0L, 0L,
GetModuleHandle(NULL),
NULL, NULL, NULL, NULL,
_T("ker engine"),
NULL
};
::RegisterClassEx(&wc);
HWND hwnd = ::CreateWindow(
wc.lpszClassName,
_T("Ker Engine DX12"),
WS_OVERLAPPEDWINDOW,
100, 100, 1280, 800, NULL, NULL,
wc.hInstance, NULL
);
::ShowWindow(hwnd, SW_SHOWDEFAULT);
::UpdateWindow(hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (msg.message != (WM_QUIT))
{
if (::PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
::DestroyWindow(hwnd);
::UnregisterClass(wc.lpszClassName, wc.hInstance);
return 0;
}

Cannot receive WM_CLIPBOARDUPDATE messages

I am trying to use Clipboard Format Listener for my C++ Console Application. The goal is to monitor every change in the clipboard. I create MessageOnly window, successfully call AddClipboardFormatListener in WM_CREATE, but never get WM_CLIPBOARDUPDATE message in WindowProc function.
#include <iostream>
#include "windows.h"
using namespace std;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
if (AddClipboardFormatListener(hwnd))
cout << " Listener started" << endl;
else
cout << " Start listener failed" << endl;
break;
case WM_DESTROY:
if (RemoveClipboardFormatListener(hwnd))
cout << " Listener stopped" << endl;
else
cout << " Stop listener failed" << endl;
break;
case WM_CLIPBOARDUPDATE:
// Clipboard content has changed
cout << " Clipboard updated" << endl;
break;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int main(int argc, char* argv[])
{
HWND hWindow = nullptr;
static const wchar_t* className = L"ClipboardListener";
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = WindowProc;
wx.hInstance = GetModuleHandle(NULL);
wx.lpszClassName = className;
if (!RegisterClassEx(&wx)) {
cout << "Cannot register class" << endl;
}
else
{
hWindow = CreateWindowEx(
0,
className,
L"ClipboardListener",
0, 0, 0, 0, 0,
HWND_MESSAGE,
NULL, NULL, NULL);
}
if (!hWindow)
{
cout << "Cannot create window" << endl;
}
else
{
while (true)
{
// Peek for a WM_CLIPBOARDUPDATE message
MSG message = { 0 };
PeekMessage(&message, hWindow, WM_CLIPBOARDUPDATE, WM_CLIPBOARDUPDATE, PM_REMOVE);
if (message.message == WM_CLIPBOARDUPDATE)
{
cout << "Sample window received WM_CLIPBOARDUPDATE message" << endl;
}
}
}
cin.get();
DestroyWindow(hWindow);
return 0;
}
PeekMessage works well, but I don't want to use loop to receive messages.
If I delete PeekMessage or replace PM_REMOVE with PM_NOREMOVE, nothing changes.
Your message loop is wrong.
CreateWindowEx() sends a WM_CREATE message before exiting, which is why your WindowProc() receives that message.
However, PeekMessage() does not dispatch messages to windows, which is why your WindowProc() does not receive the WM_CLIPBOARDUPDATE messages. Your message loop needs to call DispatchMessage() for that. You should also be using GetMessage() instead of PeekMessage(), so that the loop makes the calling thread sleep when there are no messages to process.
A standard message loop looks more like this:
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}

WH_KEYBOARD_LL not working for regular letters and digits

I'm using SetWindowsHookExA(WH_KEYBOARD_LL, HookCallback, GetModuleHandleA(NULL), 0); to set a global hook for capturing the keystrokes, but the result is strange.
The callback function can be executed when I press the "special" keys such as "Enter", "Tab", "Shift", "Ctrl" and other keys having a Virtual Key Code, while it fails to capture the keystrokes when I press the regular letters and digits.
I am confused about it and could anyone tell me the reason?
#include <Windows.h>
#include <iostream>
using namespace std;
HHOOK keyboardHook = 0;
LRESULT CALLBACK HookCallback(int code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *ks = (KBDLLHOOKSTRUCT*)lParam;
cout<< "[TEST] " << ks->vkCode << endl;
return CallNextHookEx(0, code, wParam, lParam);
}
int main()
{
keyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, HookCallback, GetModuleHandleA(NULL), 0);
if (keyboardHook == 0)
{
cout << "failed" << endl;
return -1;
}
cout << "ok" << endl;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(keyboardHook);
return 0;
}

list of programs with interface and processes with enumwindows

I need to find all the open Window with graphic interfaces and their processes and I don't really know how to do it. I've written some code but I just succeeded in finding open windows:
HWND hwnd = GetForegroundWindow(); // get handle of currently active window
GetWindowText(hwnd, wnd_title, sizeof(wnd_title));
cout << "Window with focus: " << wnd_title << endl << endl;
EnumWindows(EnumWindowsProc, 0);
EnumWindowsProc is defined like this:
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char class_name[80];
char title[80];
if (IsWindowVisible(hwnd)) {
GetClassName(hwnd, class_name, sizeof(class_name));
GetWindowText(hwnd, title, sizeof(title));
cout << "Window title: " << title << endl;
cout << "Class name: " << class_name << endl << endl;
}
return TRUE;
}
Someone can help me?
I would recommend you not to check if IsWindowVisible because of
If the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style, the return value is nonzero. Otherwise, the return value is zero.
Because the return value specifies whether the window has the WS_VISIBLE style, it may be nonzero even if the window is totally obscured by other windows.
While enumerating windows you can use DWORD WINAPI GetWindowThreadProcessId(_In_ HWND hWnd, _Out_opt_ LPDWORD lpdwProcessId); to retrieve process id correlated with that particular HWND.
example :
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char class_name[80];
char title[80];
DWORD dwProcessId;
GetClassName(hwnd,class_name, sizeof(class_name));
GetWindowText(hwnd,title,sizeof(title));
// get process id based on hwnd
GetWindowThreadProcessId(hwnd, &dwProcessId);
std::cout << "Window title: "<< title << std::endl;
std::cout << "Class name: "<< class_name << std::endl
// display process id based on hwnd
std::cout << "Process Id: " << dwProcessId << std::endl;
return TRUE;
}