Cannot create a window - c++
I am trying to create a simple window but it does not work for some reason. I have actually tried this for the past few months. Even used some old code and it does not run at all for whatever reason.
Actually, the registerclass function does not return anything ever but this happened in the past too but I was still able to create a window. Nothing works this time
I tried:
Providing a valid value for all of the members of WNDCLASS
Running Debug/Release
Running as administrator
Using GetLastError (always returns 0)
Providing different class names, because I know some don't work for some reason, and also window names
This is my code:
WNDCLASSEXW lpClass = WNDCLASSEXW{ 0x00 };
lpClass.cbSize = sizeof(decltype(lpClass));
lpClass.style = (CS_HREDRAW | CS_VREDRAW);
lpClass.lpfnWndProc = ScreenProcess;
lpClass.hInstance = GetModuleHandleW(nullptr);
lpClass.lpszClassName = L"__TEST__";
lpClass.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
RegisterClassExW(&lpClass);
if (HWND hwnd = CreateWindowExW(WS_EX_APPWINDOW, lpClass.lpszClassName, L"abc", WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, nullptr, nullptr, lpClass.hInstance, nullptr))
{
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
}
printf("%d", GetLastError());
for (;;) {};
Did you define your window procedure as something like this?
LRESULT CALLBACK ScreenProcess(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
And instead of the infinite loop, place this:
MSG msg{0};
while(GetMessage(&msg, nullptr, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Also, the cbSize of the WNDCLASSEXW should be sizeof(WNDCLASSEXW). Also change the CreateSolidBrush(RGB(0, 0, 0)); to GetStockObject(BLACK_BRUSH);
Hope this helps!
Here's a version of your code that's working in VS2017 (using C++17). I've added debug prints so that you can see ScreenProcess() receiving mouse movements etc. I've also added a class (WindowsClassRegistrator) for handling one of the resources you allocate to show how you can extend the existing C structs to handle releasing of resources automatically.
I added a mapping between common Windows messages and their macro names to make it easier to follow what you actually get into your WndProc. Unknown Windows messages are collected and displayed when you click close on the app (on the task bar) so you can extend the messages you'd like to handle/display as you go.
I also added assertion function templates for throwing exceptions with proper errors messages that you can use around all WinAPI functions that have an easy way of checking if they've succeeded or not.
#include "pch.h" // if you use precompiled headers
#include <Windows.h>
#include <Windowsx.h> // GET_X_LPARAM, GET_Y_LPARAM
#include <Olectl.h> // OCM_BASE
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <stdexcept>
#include <map>
#include <unordered_set>
// --- bug hunting support functions start ---
std::string GetLastErrorString() {
DWORD le = GetLastError();
LPSTR lpBuffer = nullptr;
if (FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
0, le, 0,
reinterpret_cast<LPSTR>(&lpBuffer),
0, NULL
))
{
std::string rv(lpBuffer);
LocalFree(lpBuffer);
return rv;
}
else return std::to_string(le);
}
struct win_error : public std::runtime_error {
win_error(const std::string& prefix) :
std::runtime_error(prefix + ": " + GetLastErrorString())
{}
};
// assert that a function does NOT return a specific value
template<typename T>
inline T AssertNEQ(T value, const char* funcname, T got_value) {
if (value == got_value) throw win_error(funcname);
return got_value;
}
// assert that a function DOES return a specific value
template<typename T>
inline T AssertEQ(T value, const char* funcname, T got_value) {
if (value != got_value) throw win_error(funcname);
return got_value;
}
// --- bug hunting support functions end ---
class WindowsClassRegistrator : public WNDCLASSEXW {
ATOM wca;
public:
WindowsClassRegistrator(WNDPROC lpfnWndProc) :
WNDCLASSEXW{ 0 }, wca{}
{
this->cbSize = sizeof(WNDCLASSEXW);
this->style = CS_SAVEBITS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
this->lpfnWndProc = lpfnWndProc;
this->hInstance =
AssertNEQ<HMODULE>(NULL, "GetModuleHandleW", GetModuleHandleW(nullptr));
this->lpszClassName = L"__TEST__";
this->hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
this->wca =
AssertNEQ<ATOM>(NULL, "RegisterClassExW", RegisterClassExW(this));
}
WindowsClassRegistrator(const WindowsClassRegistrator&) = delete;
WindowsClassRegistrator(WindowsClassRegistrator&&) = delete;
WindowsClassRegistrator& operator=(const WindowsClassRegistrator&) = delete;
WindowsClassRegistrator& operator=(WindowsClassRegistrator&&) = delete;
~WindowsClassRegistrator() {
AssertNEQ<BOOL>(FALSE,
"UnregisterClassW", UnregisterClassW(GetAtomAsStr(), this->hInstance));
}
inline LPCWSTR GetAtomAsStr() const noexcept {
return reinterpret_cast<LPCWSTR>(this->wca);
}
inline HINSTANCE GetInstance() const noexcept {
return this->hInstance;
}
inline LPCWSTR GetClassName() const noexcept {
return this->lpszClassName;
}
};
std::multimap<UINT, std::string> messages = {
{WM_NULL, "WM_NULL"},
{WM_CREATE, "WM_CREATE"},
{WM_DESTROY, "WM_DESTROY"},
{WM_MOVE, "WM_MOVE"},
{WM_SIZE, "WM_SIZE"},
{WM_ACTIVATE, "WM_ACTIVATE"},
{WM_SETFOCUS, "WM_SETFOCUS"},
{WM_KILLFOCUS, "WM_KILLFOCUS"},
{WM_PAINT, "WM_PAINT"},
{WM_CLOSE, "WM_CLOSE"},
{WM_QUIT, "WM_QUIT"},
{WM_ERASEBKGND, "WM_ERASEBKGND"},
{WM_SHOWWINDOW, "WM_SHOWWINDOW"},
{WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
{WM_CANCELMODE, "WM_CANCELMODE"},
{WM_SETCURSOR, "WM_SETCURSOR"},
{WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE"},
{WM_VKEYTOITEM, "WM_VKEYTOITEM"},
{WM_CHARTOITEM, "WM_CHARTOITEM"},
{WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
{WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
{SPI_SETDRAGHEIGHT, "SPI_SETDRAGHEIGHT"},
{WM_HELP, "WM_HELP"},
{WM_CONTEXTMENU, "WM_CONTEXTMENU"},
{WM_GETICON, "WM_GETICON"},
{WM_NCCREATE, "WM_NCCREATE"},
{WM_NCDESTROY, "WM_NCDESTROY"},
{WM_NCCALCSIZE, "WM_NCCALCSIZE"},
{WM_NCHITTEST, "WM_NCHITTEST"},
{WM_NCPAINT, "WM_NCPAINT"},
{WM_NCACTIVATE, "WM_NCACTIVATE"},
{SPI_GETDOCKMOVING, "SPI_GETDOCKMOVING"},
{WM_KEYDOWN, "WM_KEYDOWN"},
{WM_KEYUP, "WM_KEYUP"},
{WM_CHAR, "WM_CHAR"},
{WM_SYSKEYDOWN, "WM_SYSKEYDOWN"},
{WM_SYSKEYUP, "WM_SYSKEYUP"},
{WM_SYSCHAR, "WM_SYSCHAR"},
{WM_SYSCOMMAND, "WM_SYSCOMMAND"},
{WM_MOUSEMOVE, "WM_MOUSEMOVE"},
{WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
{WM_LBUTTONUP, "WM_LBUTTONUP"},
{WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK"},
{WM_RBUTTONDOWN, "WM_RBUTTONDOWN"},
{WM_RBUTTONUP, "WM_RBUTTONUP"},
{WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK"},
{WM_MBUTTONDOWN, "WM_MBUTTONDOWN"},
{WM_MBUTTONUP, "WM_MBUTTONUP"},
{WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK"},
{WM_MOUSEWHEEL, "WM_MOUSEWHEEL"},
{WM_XBUTTONDOWN, "WM_XBUTTONDOWN"},
{WM_XBUTTONUP, "WM_XBUTTONUP"},
{WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT"},
{WM_IME_NOTIFY, "WM_IME_NOTIFY"},
{WM_HOTKEY, "WM_HOTKEY"},
{0x0313, ": https://stackoverflow.com/questions/10430377/winapi-undocumented-windows-message-0x0313-stable"},
{WM_PRINT, "WM_PRINT"},
{WM_APPCOMMAND, "WM_APPCOMMAND"},
};
std::unordered_set<UINT> unmapped_messages;
std::map<WPARAM, std::string> mk_down = {
{MK_CONTROL, "MK_CONTROL"},
{MK_LBUTTON,"MK_LBUTTON"},
{MK_MBUTTON,"MK_MBUTTON"},
{MK_RBUTTON,"MK_RBUTTON"},
{MK_SHIFT,"MK_SHIFT"},
{MK_XBUTTON1,"MK_XBUTTON1"},
{MK_XBUTTON2,"MK_XBUTTON2"}
};
constexpr int colw = 40;
std::string message_maker(const char* macro, UINT uMsg, UINT offset) {
std::stringstream ss;
ss << macro << " + " << std::hex << (uMsg - offset) << " (" << uMsg << ")";
return ss.str();
}
inline void DisplayMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) {
std::string message;
if (uMsg < WM_USER) {
// there may be duplicate macros for some messages, so show all of them
auto[rangefirst, rangelast] = messages.equal_range(uMsg);
if (rangefirst == rangelast) {
// unmapped message found, store it
unmapped_messages.emplace(uMsg);
rangefirst = messages.emplace(uMsg, ": " + std::to_string(uMsg) + " -- UNMAPPED MESSAGE");
rangelast = rangefirst;
++rangelast;
}
message = rangefirst->second;
while (++rangefirst != rangelast) message += " " + rangefirst->second;
}
else {
// https://learn.microsoft.com/en-us/windows/desktop/winmsg/ocm--base
#define REGISTERED_WINDOWS_MESSAGE_BASE (0xC000)
#define SYSRESERVED_BASE (0x10000)
if (uMsg < OCM__BASE)
message = message_maker("WM_USER", uMsg, WM_USER);
else if (uMsg < WM_APP)
message = message_maker("(WM_USER) OCM__BASE", uMsg, OCM__BASE);
else if (uMsg < REGISTERED_WINDOWS_MESSAGE_BASE)
message = message_maker("WM_APP", uMsg, WM_APP);
else if (uMsg < SYSRESERVED_BASE)
message = message_maker("Registered Window Message", uMsg, REGISTERED_WINDOWS_MESSAGE_BASE);
else
message = message_maker("Reserved by the system", uMsg, SYSRESERVED_BASE);
}
std::cout << std::setw(colw) << std::hex << message << std::setw(18) << wParam
<< std::setw(12) << lParam << "\n";
}
LRESULT CALLBACK ScreenProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
static std::string old_mouse_message;
switch (uMsg) {
case WM_MOUSEMOVE:
{
std::stringstream ss;
std::string new_mouse_message;
int xPos, yPos;
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
ss << std::setw(colw) << "WM_MOUSEMOVE" << std::dec
<< " x=" << std::setw(6) << xPos << " y=" << std::setw(6) << yPos;
for (auto&[wp, key] : mk_down)
if (wp&wParam) ss << " " << key;
new_mouse_message = ss.str();
if (new_mouse_message != old_mouse_message) {
std::cout << new_mouse_message << "\n";
old_mouse_message = std::move(new_mouse_message);
}
}
return 0;
case WM_NCHITTEST:
return HTCLIENT;
case WM_SETCURSOR:
return TRUE;
case WM_DESTROY:
std::cout << std::setw(colw) << "WM_DESTROY" << " ";
PostQuitMessage(0);
std::cout << "PostQuitMessage() done\n";
return 0;
default:
DisplayMsg(uMsg, wParam, lParam);
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
int main() {
try {
WindowsClassRegistrator wcr(ScreenProcess);
// use WS_VISIBLE so that you don't have to call ShowWindow()
HWND hWnd =
AssertNEQ<HWND>(NULL, "CreateWindowExW",
CreateWindowExW(
WS_EX_APPWINDOW,
wcr.GetAtomAsStr(),
L"Title string",
WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, // x
CW_USEDEFAULT, // y
0, // width
0, // height
nullptr,
nullptr,
wcr.GetInstance(),
nullptr
)
);
MONITORINFO mi = { sizeof(mi) }; // mi.cbSize = sizeof(mi);
AssertNEQ<BOOL>(FALSE, "GetMonitorInfo",
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), &mi)
);
AssertNEQ<BOOL>(FALSE, "SetWindowPos",
SetWindowPos(hWnd, HWND_TOP,
mi.rcMonitor.left, mi.rcMonitor.top,
(mi.rcMonitor.right - mi.rcMonitor.left) / 4, // 1/4 of the screen width
(mi.rcMonitor.bottom - mi.rcMonitor.top), // height
SWP_NOOWNERZORDER | SWP_FRAMECHANGED)
);
// paint a rectangle in the window
AssertNEQ<BOOL>(FALSE, "Rectangle", Rectangle(
AssertNEQ<HDC>(NULL, "GetDC", GetDC(hWnd)),
10, 10, 100, 100)
);
MSG uMsg;
while (AssertNEQ<BOOL>(-1, "GetMessage", GetMessage(&uMsg, nullptr, 0, 0))) {
TranslateMessage(&uMsg); // assertion would depend on message type
DispatchMessage(&uMsg); // assertion would depend on message type
}
DisplayMsg(uMsg.message, uMsg.wParam, uMsg.lParam); // WM_QUIT
if (unmapped_messages.size()) {
std::cout << "\nYou have collected unmapped messages: \n";
for (const auto&[msg, text] : messages) {
std::cout << "/* 0x" << std::setw(4) << std::setfill('0') << msg << " */ ";
if (unmapped_messages.count(msg) || text[0] == ':') {
std::cout << "{0x" << std::setw(4) << std::setfill('0') << msg;
}
else {
std::cout << "{" << text;
}
std::cout << ", \"" << text << "\"},\n";
}
}
return static_cast<int>(uMsg.wParam);
}
catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << "\n";
}
return 1;
} // the registered windows class will be unregistered here, when wcr goes out of
// scope
Here's a modified, single source file version of the default Win32 project template that Visual Studio generates for you. I've just stripped out the stuff related to resources, accelerators, menus, and the About box thing.
#include <windows.h>
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[] = L"Test App"; // The title bar text
WCHAR szWindowClass[] = L"__TestAppWindowClass__"; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = szWindowClass;
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Related
C++ Win API - FindWindow() or EnumWindows() to retrieve specific windows
I have the following problem with retrieving the window handle from a specific window (title and class name are known): There are two identical windows with different handles under two different processes, but FindWindow() can find the handle only from the newest window spawned, never from the first one. What can be used instead? Can EnumWindows() be used to retrieve a list of windows with the same characteristics?
Use the Win32 API EnumWindows , and then check which process each window belongs to by using the Win32 API GetWindowThreadProcessId. Here is a sample: #include <iostream> #include <Windows.h> using namespace std; BOOL CALLBACK enumProc(HWND hwnd, LPARAM) { TCHAR buf[1024]{}; GetClassName(hwnd, buf, 100); if (!lstrcmp(buf, L"Notepad")) { GetWindowText(hwnd, buf, 100); DWORD pid = 0; GetWindowThreadProcessId(hwnd, &pid); wcout << buf << " " << pid << endl; } return TRUE; } int main() { EnumWindows(&enumProc, 0); } If you need to check the window of each process, you can refer to this answer.
typedef struct { const char *name; const char *class; HWND handles[10]; int handlesFound; } SearchWindowInfo; SearchWindowInfo wi; wi.handlesFound = 0; wi.title = "WindowName"; wi.class = "ClassName"; BOOL CALLBACK searchWindowCallback(HWND hwnd, LPARAM lParam) { SearchWindoInfo *wi = (SearchWindoInfo *)lParam; char buffer[256]; if (wi->handlesFound == 10) return FALSE; buffer[255] = 0; if (wi->name) { int rc = GetWindowText(hwnd, buffer, sizeof(buffer)-1); if(rc) { if (strcmp(wi->name, buffer) == 0) { wi->handles[wi->handlesFound++] = hwnd; return TRUE; } } } if (wi->class) { int rc = GetClassName (hwnd, buffer, sizeof(buffer)-1); if(rc) { if (strcmp(wi->class, buffer) == 0) { wi->handles[wi->handlesFound++] = hwnd; return TRUE; } } } return TRUE; } EnumWindows(searchWindowCallback, (LPARAM)&wi); for(int i = 0; i < wi.handlesFound; i++) { // yeah... }
Keylogger and mousetracker: should I use non-blocking I/O?
I'm writing a simple keylogger/mouselogger in C/C++ for Windows. To do that, I use the Win32 functions LowLevelMouseProc and LowLevelKeyboardProc. If relevant, here is a GitHub gist with my code, which is ultra-elementary: define the event callback and register it along with a callback for SIGINT. I'll add a summarized version at the end of the question. My question is the following: in order to minimize overhead, how should I save these events to disk? Answers in both C or C++ are welcome. Is it a good practice to simply write to a buffered file each time I get a new event and let the file handle flushing when the buffer is full? I heard about non-blocking I/O but microsoft's doc says that there is an additional overhead. And finally, I'm not sure wether I should create a second thread for this. I'd like to use some sort of buffering to avoid many little disk I/O. Ideally I would write to disk once before my process is killed. But I have no idea how to achieve this. CODE: #include "pch.h" #include <stdio.h> #include <Windows.h> HHOOK handle; LRESULT CALLBACK lowLevelMouseProc( _In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam ) { MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam; if (wParam == WM_MOUSEMOVE) { // Best way to save pt.x and pt.y to disk? printf("%d %d \n", lp->pt.x, lp->pt.y); } return CallNextHookEx(0, nCode, wParam, lParam); } int main() { handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0); MSG msg; while (GetMessage(&msg, NULL, 0, 0)); UnhookWindowsHookEx(handle) return 0; }
Use 2 buffers. One for writing, one for reading (flushing to disk). Once some condition is met (buffer full, program shutdown, ...), swap the buffers and start flushing to disk in a seperate thread. This might look something like: #include <Windows.h> #include <vector> #include <thread> #include <fstream> #include <atomic> struct Point { long x, y; }; class Buffer { public: Buffer(std::string _file = "log.txt", const size_t _buffer_size = 100000) : buffer_size(_buffer_size), file(_file) { points1.reserve(_buffer_size); points2.reserve(_buffer_size); } void write(Point p) { buf->push_back(p); if (buf->size() >= buffer_size && !thread_running.load()) to_disk(); } private: const size_t buffer_size; const std::string file; std::atomic<bool> thread_running{ false }; std::vector<Point> points1, points2; std::vector<Point> *buf = &points1, *other = &points2; void swap_buffer() { std::swap(buf, other); } void to_disk() { swap_buffer(); auto tmp_buf = other; auto tmp_file = file; auto tmp_flag = &thread_running; auto fn = [tmp_buf, tmp_file, tmp_flag]() { tmp_flag->store(true); std::fstream f(tmp_file, std::ios::app); for (auto &v : *tmp_buf) f << v.x << ' ' << v.y << '\n'; tmp_buf->clear(); tmp_flag->store(false); }; std::thread t(fn); t.detach(); } }; Buffer buffer("log.txt"); HHOOK handle; LRESULT CALLBACK lowLevelMouseProc( _In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam ) { MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam; if (wParam == WM_MOUSEMOVE) { buffer.write({ lp->pt.x, lp->pt.y }); } return CallNextHookEx(0, nCode, wParam, lParam); } int main() { handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0); MSG msg; while (GetMessage(&msg, NULL, 0, 0)); UnhookWindowsHookEx(handle); return 0; } In this case, the buffer gets written to disk when a certain size limit is reached. This could be further optimized, by not checking the size on every write for example. Note: In this example, error handling is omitted and the lifetime of the internal buffers should be managed accordingly.
SetwindowsHookEX not working when application is not run in elevated mode on Windows 10
I have native dll for setting the windows hook and I am calling it in one of my windows application to set it to a target application. It works perfectly fine when the target application is run in admin(elevated) mode with CallWndProcHook call back triggered. But when I run my target application in non admin(not elevated) mode then the SetWindowsHookEx is successful but the CallWndProcHook call back does not get triggered. static LRESULT WINAPI CallWndProcHook(int nHookCode, WPARAM wParam, LPARAM lParam) { std::ofstream DEBUG_STRM; DEBUG_STRM.open (FILE, std::fstream::app); DEBUG_STRM << "\n CallWndProcHook entered"; return CallNextHookEx(g_hHook, nHookCode, wParam, lParam); } extern "C" __declspec( dllexport ) int _stdcall Start(long handle) { HWND objectHWND = (HWND)handle; DWORD processId; DWORD threadId; std::ofstream DEBUG_STRM; DEBUG_STRM.open (FILE, std::fstream::app); DEBUG_STRM << "\n Start hooking"; threadId = GetWindowThreadProcessId(objectHWND, &processId); HINSTANCE hInst = GetModuleHandle("textlocator.dll"); g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProcHook, hInst, threadId); if(g_hHook == NULL){ DEBUG_STRM << "\n Hook unsuccessful"; }else{ DEBUG_STRM << "\n Hook successful"; } if (g_hHook == 0) { return 0; } else { return 1; } DEBUG_STRM.close(); } Any help on it ?
C++ - How can I exit a program that has no window?
I'm new to C++, and I made myself a little program that can launch program through typing a command on the keyboard. In order to be able to launch a program whenever I want, I decided to set up a Low Level Keyboard Hook, which keep tracking key strokes and launch the specific program when the specific command was detected. The simple windows program was used to install the hook, the windows is not showed because all I need is the hook to listen in the background. So far it works fine, however, the minor but annoying problem is I have to terminate the program through Windows Task Manager, and it's quite inconvenient. I have managed to uninstall the hook by pressing F7 key, but it seems that the windows program which is not showed is the Parent of the hook, so the hook cannot exit the windows program. While I want them both terminated through pressing a key. Hopefully I have made myself clear. Is there any way that I could send a message from the hook to the windows program to ask it to exit? Or somehow I can terminate both of them in the hook program? Thanks in advance. Here is the code of the window program: #include <windows.h> #include "shortcut.h" #pragma comment( lib, "libhook.dll.a") // Link Hook.lib to the project long WINAPI WndProc(HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam) { switch(wMessage) { case WM_DESTROY: InstallHook(FALSE); // Unhook PostQuitMessage(0); break; default: return DefWindowProc(hWnd, wMessage, wParam, lParam); } return 0; } BOOL FileExists(LPCTSTR szPath) { DWORD dwAttrib = GetFileAttributes(szPath); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; WNDCLASS wndclass; HANDLE hMutex = NULL; char szAppName[20] = "shortcut"; hMutex = CreateMutex(NULL,TRUE,szAppName); //启动多线程 int dwRet = GetLastError(); if (hMutex) { if (dwRet == ERROR_ALREADY_EXISTS) { MessageBox(NULL, "Program is already runing.", "Oops!", MB_OK | MB_ICONINFORMATION); CloseHandle(hMutex); return FALSE; } } wndclass.style=0; wndclass.lpfnWndProc=(WNDPROC)WndProc; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hInstance=hInstance; wndclass.hIcon=NULL; wndclass.hCursor=LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); wndclass.lpszMenuName=NULL; wndclass.lpszClassName=(LPSTR)szAppName; if(!RegisterClass(&wndclass)) return FALSE; if (!FileExists("\\ShortCuts.txt")) { MessageBox(NULL, "Missing file: cannot load shortcut settings file.(Shortcuts.txt)", "ERROR",MB_OK|MB_ICONINFORMATION); exit(1); } if (!InstallHook(TRUE)) exit(1); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } Here is the code of the hook program: // Hook- a project to create the DLL and LIB files. // Microsoft Visual C++ 6.0 and above steps: // 1. Create a new Win32 Dynamic Link - Library project. // 2. Add hook.cpp and hook.h to the project. // 3. There is no step 3 :-). Just build your project and you will find // a Hook.dll and Hook.lib file in your map. #include <windows.h> #include <iostream> #include <fstream> #include <sstream> #include <string> #include <ctime> #include <map> #include <process.h> using namespace std; HHOOK hHook; HINSTANCE ghDLLInst=0; const char startChar = ';'; bool bChecking = false; string cmd; typedef map<string,string> COMMANDMAP; COMMANDMAP mShortcut; string logfilename="log.txt"; ofstream LOG; __declspec(dllexport)int InstallHook(BOOL bCode); BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwFunction, LPVOID lpNot) { ghDLLInst=(HINSTANCE)hModule; return TRUE; } DWORD WINAPI Runsystem(LPVOID lpParam) { WinExec((LPCSTR)lpParam, SW_SHOW); } string gettime() { time_t curTime; struct tm *locTime; char buf[80]; time(&curTime); locTime=localtime(&curTime); strftime(buf,80,"%Y-%m-%d %H:%M:%S",locTime); string s=buf; return s; } ostream& tout() { return LOG<< gettime()<< ": "; } void StartCheck() { bChecking=true; cmd.clear(); } void EndCheck() { bChecking=false; cmd.clear(); } LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if ((wParam == WM_KEYDOWN) && (nCode >= HC_ACTION)) // Only record when key pressed { KBDLLHOOKSTRUCT *pStruct = (KBDLLHOOKSTRUCT*)lParam; switch (pStruct->vkCode) { case VK_RETURN: { if (bChecking) { COMMANDMAP::iterator it; it=mShortcut.find(cmd); if (it!=mShortcut.end()) { tout()<<"received command \'"<<cmd<<"\', executing \'"<<it->second.c_str()<<endl; CreateThread(NULL, 0, Runsystem, (void*)it->second.c_str(),0,NULL); } else { tout()<<"received command \'" <<cmd<<"\', no matching."<<endl; } } EndCheck(); break; } case VK_F7: { InstallHook(false); break; } default: // Normal keys, convert them { BYTE KeyboardState[256]; GetKeyboardState(KeyboardState); WORD CharValue; if(ToAscii(pStruct->vkCode, pStruct->scanCode,KeyboardState,&CharValue,0) > 0) // Convert to char. { char character=char(CharValue); // tout()<<"received keyCode: "<<pStruct->vkCode<< " char: "<< character<<endl; if (bChecking) { cmd+=character; } if (!bChecking && (character == startChar)) { // tout()<<"Start checking..."<<endl; StartCheck(); } } break; } } } return (int)CallNextHookEx(hHook, nCode, wParam, lParam); } bool readline(ifstream &fin,string &sline) { do { getline(fin,sline); } while (!fin.eof() && ((sline[0]=='/' && sline[1]=='/') || sline.empty())); return fin.eof()?false:true; } // __declspec(dllexport) means that this function must be exported to a dll file. __declspec(dllexport)int InstallHook(BOOL bCode) { if(bCode) { // initialize shortcuts ifstream fin; LOG.open(logfilename.c_str(),ios_base::app); tout()<<"Reading config file."<<endl; fin.open("ShortCuts.txt"); if (fin) { string scmd,spath; char oneline[256]; while(readline(fin,scmd)&&readline(fin,spath)) { mShortcut[scmd]=spath; // LOG<<scmd<<','<<spath<<endl; } fin.close(); tout()<<"OK, "<<mShortcut.size()<<" shortcuts loaded."<<endl; } else { tout()<<"ERROR"<<endl; LOG.close(); exit(0); } hHook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, // Start the keyboard hook. (HINSTANCE)GetModuleHandle(NULL), NULL); if(!hHook) { tout()<<"Install hook failed."<<endl; return 0; } else { tout()<<"Install hook successful."<<endl; return 1; } } else { if (MessageBox(NULL,"Are you sure to exit KeyShortcut?","Exit",MB_YESNO|MB_ICONWARNING)==IDYES) { tout()<<"Uninstall hook successful."<<endl; LOG.close(); return UnhookWindowsHookEx(hHook); // Unhook the keyboardhook. } } }
For instance, you can use RegisterHotKey API function to set your own hotkey to a system and then handle this hotkey's message in your program(windowless) Added: If you want to send quit message from one process to another then your friend is PostThreadMessage(dwThreadId, WM_DESTROY, 0, 0);
C++: EnumDisplayMonitors callback inside a class
I have a problem with EnumDisplayMonitors callbacks. I want to get the number of screens and the screen resolutions of each one. It seems that it's working using this code. #include <windows.h> #include <iostream> #include <vector> #pragma comment(lib, "user32.lib") std::vector< std::vector<int> > screenVector; int screenCounter = 0; BOOL CALLBACK MonitorEnumProcCallback( _In_ HMONITOR hMonitor, _In_ HDC hdcMonitor, _In_ LPRECT lprcMonitor, _In_ LPARAM dwData ) { screenCounter++; MONITORINFO info; info.cbSize = sizeof(MONITORINFO); BOOL monitorInfo = GetMonitorInfo(hMonitor,&info); if( monitorInfo ) { std::vector<int> currentScreenVector; currentScreenVector.push_back( screenCounter ); currentScreenVector.push_back( abs(info.rcMonitor.left - info.rcMonitor.right) ); currentScreenVector.push_back( abs(info.rcMonitor.top - info.rcMonitor.bottom) ); std::cout << "Monitor " << currentScreenVector.at(0) << " -> x: " << currentScreenVector.at(1) << " y: " << currentScreenVector.at(2) << "\n"; } return TRUE; } int main() { BOOL b = EnumDisplayMonitors(NULL,NULL,MonitorEnumProcCallback,0); system("PAUSE"); return 0; } But when I transferred everything to my actual codebase and contained inside a class, it's returning an error. I don't know if I'm doing this right. -> Here's the snippet: ScreenManager::ScreenManager() { BOOL monitorInitialized = EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(this) ); } BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData ) { reinterpret_cast<ScreenManager*>(dwData)->callback(hMonitor,hdcMonitor,lprcMonitor); return true; } bool ScreenManager::callback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor){ screenCounter++; MONITORINFO info; info.cbSize = sizeof(MONITORINFO); BOOL monitorInfo = GetMonitorInfo(hMonitor,&info); if( monitorInfo ) { std::vector<int> currentScreenVector; currentScreenVector.push_back( screenCounter ); currentScreenVector.push_back( abs(info.rcMonitor.left - info.rcMonitor.right) ); currentScreenVector.push_back( abs(info.rcMonitor.top - info.rcMonitor.bottom) ); } return true; }
I just solved my problem by changing the callback function to public.