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);
}
Related
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;
}
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);
}
I'm trying to make an application that just detects if the left mouse button is held down. In trying to do this, as well as learn mouse hooks, I copy-pasted a hook from an example source (https://cboard.cprogramming.com/windows-programming/119909-setwindowshookex-lowlevelmouseproc.html) just to see what it would do. The problem is that it lags my computer. Why is this, and how can I fix it?
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <iostream>
#include <cstdio>
using namespace std;
HHOOK g_Hook;
HANDLE g_evExit;
LRESULT CALLBACK LowLevelMouseProc (int code, WPARAM wParam, LPARAM lParam)
{
if (code == HC_ACTION)
{
const char *msg;
char msg_buff[128];
switch (wParam)
{
case WM_LBUTTONDOWN: msg = "WM_LBUTTONDOWN"; break;
case WM_LBUTTONUP: msg = "WM_LBUTTONUP"; break;
case WM_RBUTTONDOWN: msg = "WM_RBUTTONDOWN"; break;
case WM_RBUTTONUP: msg = "WM_RBUTTONUP"; break;
default:
sprintf(msg_buff, "Unknown msg: %u", wParam);
msg = msg_buff;
break;
}//switch
const MSLLHOOKSTRUCT *p =
reinterpret_cast<const MSLLHOOKSTRUCT*>(lParam);
cout << msg << " - [" << p->pt.x << ',' << p->pt.y << ']' << endl;
static bool left_down = false;
static bool right_down = false;
switch (wParam)
{
case WM_LBUTTONDOWN: left_down = true; break;
case WM_LBUTTONUP: left_down = false; break;
case WM_RBUTTONDOWN: right_down = true; break;
case WM_RBUTTONUP: right_down = false; break;
}//switch
if (left_down && right_down)
SetEvent(g_evExit);
}//if
return CallNextHookEx(g_Hook, code, wParam, lParam);
}//LowLevelMouseProc
int main()
{
g_evExit = CreateEvent(0, TRUE, FALSE, 0);
if (!g_evExit)
{
cerr << "CreateEvent failed, le = " << GetLastError() << endl;
return 1;
}//if
g_Hook = SetWindowsHookEx(WH_MOUSE_LL, &LowLevelMouseProc,
GetModuleHandle(0), 0);
if (!g_Hook)
{
cerr << "SetWindowsHookEx() failed, le = " << GetLastError() << endl;
return 1;
}//if
cout << "Press both left and right mouse buttons to exit..." << endl;
MSG msg;
DWORD status;
while (1)
{
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
DispatchMessage(&msg);
status = MsgWaitForMultipleObjects(1, &g_evExit, FALSE,
INFINITE, QS_ALLINPUT);
if (status == (WAIT_OBJECT_0 + 1))
{
// there are messages to process, eat em up
continue;
}//if
else
{
// assume g_evExit is signaled
break;
}//else
}//while
cout << "Exiting..." << endl;
UnhookWindowsHookEx(g_Hook);
CloseHandle(g_evExit);
return 0;
}//main
You need a message pump. The code you posted uses PeekMessage in combination with MsgWaitForMultipleObjects, but it's probably a better idea to use GetMessage along with TranslateMessage and DispatchMessage, as showcased in How to manually run message pump in C++:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 1) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
With this loop, I was able to set up a WH_MOUSE_LL hook with SetWindowsHookExA without having the mouse input lag, and correctly receiving all events.
Make sure the hook is installed on the same thread that will pump the messages.
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;
}
When, I open some of the software applications I have to wait 2-3 seconds until window will show on desktop. I have to use Sleep(2000); and then call method set always on top. I'm trying to replace Sleep in my code. I would like to get signal from opened window and after this, call a method, which allows opened window be always on top.
Here's my code:
BOOL CALLBACK EnumWindowsProc(HWND windowHandle, LPARAM lParam)
{
DWORD searchedProcessId = (DWORD)lParam;
DWORD windowProcessId = 0;
GetWindowThreadProcessId(windowHandle, &windowProcessId);
cout << "Process id: " << windowProcessId << endl;
if(searchedProcessId == windowProcessId) {
HWND hwnd = windowHandle;
Sleep(2000);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
cout << "Process ID found!" << endl;
return TRUE;
}
return TRUE;
}
void AlwaysOnTop(int processId)
{
EnumWindows(&EnumWindowsProc, (LPARAM)processId);
}
void AlwaysOnTop(char *name)
{
cout << "String: " << name << endl;
Sleep(2000);
HWND h = FindWindow(NULL, (LPCSTR) name);
SetActiveWindow(h);
SetForegroundWindow(h);
SetWindowPos(h, HWND_TOPMOST, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
}
int main()
{
char s[] = {"Application"};
AlwaysOnTop(s);
//AlwaysOnTop(2307);
system("PAUSE");
return 0;
}
Probably the best you can do is to call WaitForInputIdle:
Waits until the specified process has finished processing its initial input and is waiting for user input with no input pending, or until the time-out interval has elapsed.
This is the closest you can get to a general way to wait until a process is showing its UI. It won't always do what you want, but it's the best there is.