This question already has an answer here:
C++ Hotkey to run function
(1 answer)
Closed 5 years ago.
I'm trying to code a little "virus" (just a fun joke program which messes around with the cursor and makes some beep sounds). However, I want to close this process with my F9 key.
Here's what I have so far:
void executeApp()
{
while (true)
{
if (GetAsyncKeyState(VK_F9) & 0x8000)
{
exit(0);
}
Sleep(200);
}
}
I made a thread that runs this function. However, when I run my entire code and press F9, the process still runs. Only when I press it 2-3 times, it comes up with an Error: "Debug Error! abort() has been called."
It would be nice if someone knows how I can kill my process via a hotkey.
Here is the whole code of the program:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <ctime>
#include <thread>
#include <random>
using namespace std;
//random number gen for while loops in cursor/beep functions.
random_device rd;
mt19937 eng(rd());
uniform_int_distribution<> distr(1, 100);
//variables used for this program.
int random, Dur, X, Y, Freq;
HWND mywindow, Steam, CMD, TaskMngr;
char Notepad[MAX_PATH] = "notepad.exe";
char Website[MAX_PATH] = "http:\\www.google.de";
//functions
void RandomCursor(), Beeper(), OpenStuff(), executeApp();
//threads
thread cursor(RandomCursor);
thread beeps(Beeper);
thread openstuff(OpenStuff);
thread appexecute(executeApp);
int main()
{
srand(time(0));
random = rand() % 3;
system("title 1337app");
cursor.join();
beeps.join();
appexecute.join();
return 0;
}
//void SetUp()
//{
// mywindow = FindWindow(NULL, "1337app");
// cout << "oh whats that? let me see.\n";
// Sleep(1000);
// ShowWindow(mywindow, false);
//}
void Beeper()
{
while (true)
{
if (distr(eng) > 75)
{
Dur = rand() % 206;
Freq = rand() % 2124;
Beep(Dur, Freq);
}
Sleep(1500);
}
}
//void OpenStuff()
//{
// ShellExecute(NULL, "open", Notepad, NULL, NULL, SW_MAXIMIZE);
// ShellExecute(NULL, "open", Website, NULL, NULL, SW_MAXIMIZE);
//}
void RandomCursor()
{
while (true)
{
if (distr(eng) < 50)
{
X = rand() % 302;
Y = rand() % 202;
SetCursorPos(X, Y);
}
Sleep(500);
}
}
void executeApp()
{
while (true)
{
if (GetAsyncKeyState(VK_F9) & 0x8000)
{
exit(0);
}
Sleep(200);
}
}
GetAsyncKeyState() returns two pieces of information, but you are looking at only one of them and it is the one that is not very useful to your code.
Per the documentation:
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.
When you AND the return value with 0x8000, you are testing only the most significant bit, which means you are testing only if the key is currently down at the exact moment that GetAsyncKeyState() is called. Which is why it usually takes several presses, or holding down the key for awhile, for your code to detect the key press. You have a race condition in your code.
You should also AND the return value with 0x0001 to check if the key has been pressed and released in between the times that you call GetAsyncKeyState():
if (GetAsyncKeyState(VK_F9) & 0x8001)
Or simply:
if (GetAsyncKeyState(VK_F9) != 0)
That being said, what you really should do instead is actually monitor the keyboard and let it tell you when the key is pressed. Either:
use RegisterHotKey(), handling WM_HOTKEY window messages.
use RegisterRawInputDevices(), handling WM_INPUT window messages.
use SetWindowsHookEx() to monitor key presses using a callback function instead of a window (but you still need a message loop).
Update: Since your code does not have an HWND of its own, try SetWindowsHookEx(), eg:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <ctime>
#include <thread>
#include <random>
using namespace std;
//random number gen for while loops in cursor/beep functions.
random_device rd;
mt19937 eng(rd());
uniform_int_distribution<> distr(1, 100);
//variables used for this program.
int random, Dur, X, Y, Freq;
HWND mywindow, Steam, CMD, TaskMngr;
char Notepad[MAX_PATH] = "notepad.exe";
char Website[MAX_PATH] = "http://www.google.de";
HANDLE hExitApp = NULL;
//functions
//void SetUp()
//{
// mywindow = FindWindow(NULL, "1337app");
// cout << "oh whats that? let me see.\n";
// Sleep(1000);
// ShowWindow(mywindow, false);
//}
void Beeper()
{
if (WaitForSingleObject(hExitApp, 0) == WAIT_TIMEOUT)
{
do
{
if (distr(eng) > 75)
{
Dur = rand() % 206;
Freq = rand() % 2124;
Beep(Dur, Freq);
}
}
while (WaitForSingleObject(hExitApp, 1500) == WAIT_TIMEOUT);
}
}
//void OpenStuff()
//{
// ShellExecute(NULL, NULL, Notepad, NULL, NULL, SW_MAXIMIZE);
// ShellExecute(NULL, NULL, Website, NULL, NULL, SW_MAXIMIZE);
//}
void RandomCursor()
{
if (WaitForSingleObject(hExitApp, 0) == WAIT_TIMEOUT)
{
do
{
if (distr(eng) < 50)
{
X = rand() % 302;
Y = rand() % 202;
SetCursorPos(X, Y);
}
}
while (WaitForSingleObject(hExitApp, 500) == WAIT_TIMEOUT);
}
}
LRESULT CALLBACK MyLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_KEYUP:
if (reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam)->vkCode == VK_F9)
SetEvent(hExitApp);
break;
}
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
void executeApp()
{
PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, &MyLowLevelKeyboardProc, NULL, 0);
if (hook)
{
MSG msg;
do
{
if (MsgWaitForMultipleObjects(1, &hExitApp, FALSE, INFINITE, QS_ALLINPUT) != (WAIT_OBJECT_0+1))
break;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while (true);
UnhookWindowsHookEx(hook);
}
SetEvent(hExitApp);
}
int main()
{
hExitApp = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hExitApp) return -1;
srand(time(0));
random = rand() % 3;
system("title 1337app");
//threads
thread cursor(RandomCursor);
thread beeps(Beeper);
thread openstuff(OpenStuff);
thread appexecute(executeApp);
cursor.join();
beeps.join();
openstuff.join();
appexecute.join();
CloseHandle(hExitApp);
return 0;
}
Related
In Win32 C++, How to WaitForSingleObject and Detect Ctrl-C at the same time?
I tried the following console application by compiling it in the Code::Blocks C++ compiler for windows.
Then, I tried pressing Control-C many times while running... it basically doesn't call the control-c handler while the main thread is in "WaitForSingleObject".
Is there a way to fix this?
Eventually, I want my Control-C handler to kill the secondary thread using TerminateThread and return control to mainthread breaking WaitForSingleObject... But, because of the wait the second thread is written i can't change any of the code...
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD id);
DWORD WINAPI fun2(void*);
atomic<DWORD> threadid {0};
int main()
{
DWORD threadid1;
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, &threadid1);
threadid = threadid1;
WaitForSingleObject(H1, INFINITE);
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%ld)\n", id);
if (threadid != 0) {
HANDLE H2 = OpenThread(THREAD_TERMINATE, FALSE, threadid);
if (H2) {
//TerminateThread(H2, 0);
//threadid = 0;
CloseHandle(H2);
}
}
return TRUE;
}
DWORD WINAPI fun2(void*)
{
// This thread will eventually do some work...
// and I don't want to rewrite this code...
// to check for a flag from another thread...
int count = 0;
while(1) {
printf("count: %d\n", count);
Sleep(1000);
}
return 0;
}
A SetConsoleCtrlHandler() handler gets run by the OS in its own thread. This is stated as much in the documentation:
https://learn.microsoft.com/en-us/windows/console/handlerroutine
An application-defined function used with the SetConsoleCtrlHandler function. A console process uses this function to handle control signals received by the process. When the signal is received, the system creates a new thread in the process to execute the function.
You need to have that signal thread notify your worker thread to terminate itself, you can't (safely) just terminate the thread directly (ie, DO NOT use TerminateThread()).
Try this:
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD);
DWORD WINAPI fun2(void*);
atomic<bool> exitThread {false};
int main()
{
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, NULL);
if (H1)
{
WaitForSingleObject(H1, INFINITE);
CloseHandle(H1);
}
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%lu)\n", id);
exitThread = true;
return TRUE;
}
DWORD WINAPI fun2(void*)
{
// This thread will eventually do some work...
int count = 0;
while (!static_cast<bool>(exitThread)) {
printf("count: %d\n", count++);
Sleep(1000);
}
return 0;
}
However, do note that creating a thread just to wait on it is a waste of a thread. You may as well just do your work in main() directly instead, eg:
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <atomic>
using namespace std;
BOOL WINAPI fun1(DWORD);
atomic<bool> exitApp {false};
int main()
{
cout << "Hello world!" << endl;
SetConsoleCtrlHandler(fun1, TRUE);
// This will eventually do some work...
int count = 0;
while (!static_cast<bool>(exitApp)) {
printf("count: %d\n", count++);
Sleep(1000);
}
return 0;
}
BOOL WINAPI fun1(DWORD id)
{
Beep(750, 300);
printf("CtrlHandler:(%lu)\n", id);
exitApp = true;
return TRUE;
}
I cleaned up your code slightly and it seems like the Ctrl+C handler is running when expected (even though it doesn't do anything particularly useful). When I type Ctrl+C, I see that fun1 can run multiple times while the main thread is running WaitForSingleObject.
Your original code for fun1 was beeping before printing, and it wasn't flushing the stdout buffer, so maybe you thought the code wasn't actually running or that it was getting delayed.
Note that I am just answering questions you asked about detecting Ctrl+C while waiting for an object; I'm not attempting to help you do anything useful in your Ctrl+C handler.
Here is the cleaned-up version of your code that I used for testing:
#include <windows.h>
#include <stdio.h>
#include <atomic>
std::atomic<DWORD> threadid {0};
BOOL WINAPI fun1(DWORD id) {
printf("fun1: %ld\n", id);
fflush(stdout);
Beep(750, 100);
// This doesn't do anything useful; can be removed.
if (threadid != 0) {
HANDLE H2 = OpenThread(THREAD_TERMINATE, FALSE, threadid);
if (H2) { CloseHandle(H2); }
}
return 1;
}
DWORD WINAPI fun2(void *) {
unsigned int count = 0;
while(1) {
count++;
printf("count: %d\n", count);
fflush(stdout);
Sleep(4000);
}
return 0;
}
int main() {
printf("Hello world!\n");
fflush(stdout);
SetConsoleCtrlHandler(fun1, TRUE);
DWORD threadid1;
HANDLE H1 = CreateThread(NULL, 0, fun2, 0, 0, &threadid1);
threadid = threadid1;
printf("Waiting for single oblect.\n");
fflush(stdout);
WaitForSingleObject(H1, INFINITE);
printf("Done waiting for single oblect.\n");
fflush(stdout);
return 0;
}
Example output:
Hello world!
Waiting for single oblect.
count: 1
count: 2
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
fun1: 0
count: 3
count: 4
I compiled the code in MSYS2, targeting 64-bit Windows, with this command:
g++ -std=gnu++20 -Wall -Wextra test.cpp
I am trying to hide the caret in console, in C++ (or C as well, same thing), but when I maximize the window, the caret reappears. Is there any solution to this other than just hiding it every time the window size is changed, or doing it after every specific event?
The function I'm using:
void ShowConsoleCursor (const bool flag)
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = flag;
SetConsoleCursorInfo(out, &cursorInfo);
}
EDIT: I'm also thinking that I could create a separate thread that hides the caret every x milliseconds. Would that be a viable option? I'm doing this for a personal project by the way.
You could create a thread to handle the WINDOW_BUFFER_SIZE_EVENT like:
#include <windows.h>
#include <stdio.h>
HANDLE hStdin;
void ShowConsoleCursor(const bool flag)
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = false;
SetConsoleCursorInfo(out, &cursorInfo);
}
VOID ErrorExit(LPCSTR str)
{
printf("%s\n",str);
exit(0);
}
VOID ResizeEventProc(WINDOW_BUFFER_SIZE_RECORD wbsr)
{
printf("Resize event\n");
printf("Console screen buffer is %d columns by %d rows.\n", wbsr.dwSize.X, wbsr.dwSize.Y);
ShowConsoleCursor(false);
}
DWORD WINAPI Thread(LPVOID lpParameter)
{
DWORD cNumRead, i;
INPUT_RECORD irInBuf[128];
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
ErrorExit("GetStdHandle");
while (true)
{
// Wait for the events.
if (!ReadConsoleInput(
hStdin, // input buffer handle
irInBuf, // buffer to read into
128, // size of read buffer
&cNumRead)) // number of records read
ErrorExit("ReadConsoleInput");
for (i = 0; i < cNumRead; i++)
{
switch (irInBuf[i].EventType)
{
case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing
ResizeEventProc(irInBuf[i].Event.WindowBufferSizeEvent);
break;
}
}
}
return 0;
}
int main(VOID)
{
ShowConsoleCursor(false);
DWORD tid = 0;
HANDLE hThread = CreateThread(NULL, 0, Thread, 0, 0, &tid);
//To Do
WaitForSingleObject(hThread, INFINITE);
return 0;
}
i have an HID usb rfid reader that act like a keyboard,
i don't want to put a textbox on my form (WPF) to recieve the text from it because i have other requirements .
instead i am trying to capture the key pressed events and process them . for that i have tried three differents methods :
Windows Hook (c++)
this is the most simple testcase example that illustrate the issue
#include <iostream>
#include <fstream>
#include <Windows.h>
#pragma comment(lib, "user32.lib")
HHOOK keyboardHook{ NULL };
DWORD lastkey = 0;
LRESULT CALLBACK MyLowLevelKeyBoardProc(const int nCode, const WPARAM wParam, const LPARAM lParam)
{
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT *)lParam;
switch (wParam)
{
case WM_KEYUP:
if (lastkey == 13)
system("cls");
std::cout << "KeyUp event : " << kb->vkCode << std::endl;
lastkey = kb->vkCode;
break;
}
return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, MyLowLevelKeyBoardProc, NULL, 0);
if (keyboardHook == NULL) {
std::cout << "Keyboard hook failed!" << std::endl;
}
while (GetMessage(NULL, NULL, 0, 0));
return 0;
}
Raw input API
by handling the WM_INPUT message (too many code to show)
oblita interception library
the most interesting solution that i will use if i fix the problem
#include "stdafx.h"
#include "C:\Dev\WPF\Interception\library\interception.h"
#include "C:\Dev\WPF\Interception\Interception-1.0.0\samples\utils.h"
#include <string>
#include <iostream>
enum ScanCode
{
SCANCODE_X = 0x2D,
SCANCODE_Y = 0x15,
SCANCODE_ESC = 0x01
};
int main()
{
using namespace std;
InterceptionContext context;
InterceptionDevice device;
InterceptionStroke stroke;
wchar_t hardware_id[500];
string buffer = "";
//raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_UP | INTERCEPTION_FILTER_KEY_UP);
while (interception_receive(context, device = interception_wait(context), &stroke, 1) > 0)
{
if (interception_is_keyboard(device))
{
InterceptionKeyStroke &keystroke = *(InterceptionKeyStroke *)&stroke;
if (keystroke.code == SCANCODE_ESC) break;
size_t length = interception_get_hardware_id(context, device, hardware_id, sizeof(hardware_id));
if (wcsstr(hardware_id, L"04F3&PID_0009") == 0)
interception_send(context, device, &stroke, 1); // Real Keyboard
else
{
// RFID reader
if (keystroke.code == 28)
{
std::cout << buffer << endl;
buffer = "";
}
else
buffer = buffer + std::to_string(keystroke.code);
}
}
}
interception_destroy_context(context);
return 0;
}
all the three methods gave me the same problem :
some keys are randomly lost during the read, instead of having the 10 characters i my have 8/9 only .
if i use the rfid reader on blocnote no character is lost so there is no problem with the reader .
so my question is : how to ensure that no message/key is lost by windows on the hooks , even if the read operation may take 10 seconds .
thanks and good day .
I am using settimer to start the timer. I want to change the timer value everytime the timer lapses.
The code is as below:
#include<iostream>
#include <windows.h>
#include <stdio.h>
#include<WinUser.h>
#pragma comment( lib, "user32.lib" )
void main()
{
int id = 1;
static bool isStart = false;
static long l = 10000;
while(1)
{
int n;
MSG msg = {0};
{
SetTimer(NULL, id,l,NULL);
while(GetMessage(&msg,NULL, 0,0))
{
// Post WM_TIMER messages to the hwndTimer procedure.
if (msg.message == WM_TIMER)
{
std::cout << "Timer expired";
KillTimer(NULL, id);
msg.message = 0x0;
l = 20000;
break;
}
}
}
}
}
Even though I change the value to 20000 its not taking, the timer is set only once.
Need help on this.
Thanks
You need to use the return value of SetTimer to kill the timer
int main(int argc, char **argv)
{
static bool isStart = false;
static long l = 5000;
while(1)
{
int n;
MSG msg = {0};
UINT_PTR p = SetTimer(NULL, 0,l,NULL);
while(GetMessage(&msg,NULL, 0,0))
{
// Post WM_TIMER messages to the hwndTimer procedure.
if (msg.message == WM_TIMER)
{
std::cout << "Timer expired" << std::endl;
KillTimer(NULL, p);
msg.message = 0x0;
l = 20000;
break;
}
}
}
}
SetTimer From MSDN
Return value
Type: Type: UINT_PTR If the function succeeds and the hWnd parameter
is NULL, the return value is an integer identifying the new timer. An
application can pass this value to the KillTimer function to destroy
the timer.
I'm having a problem when trying to run the following code:
#include "header.h"
int main()
{
id = GetCurrentProcessId();
EnumWindows(hEnumWindows, NULL);
Sleep(5000);
//MoveWindow(hThis, 450, 450, 100, 100, TRUE);
system("pause");
return 0;
}
//header.h
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
using namespace std;
DWORD id = 0;
HWND hThis = NULL;
BOOL CALLBACK hEnumWindows(HWND hwnd, LPARAM lParam)
{
DWORD pid = 0;
pid = GetWindowThreadProcessId(hwnd, NULL);
if (pid == id)
{
hThis = GetWindow(hwnd, GW_OWNER);
if (!hThis)
{
cout << "Error getting window!" << endl;
}
else
{
char *buffer = nullptr;
int size = GetWindowTextLength(hThis);
buffer = (char*)malloc(size+1);
if (buffer != nullptr)
{
GetWindowText(hThis, buffer, size);
cout << pid << ":" << buffer << endl;
free(buffer);
}
}
}
return TRUE;
}
When I run this code nothing is output to the screen almost as if the program is not attached. I tried running it under a console and windows subsystem in VS2013.
According to the GetCurrentProcessId docs, the API
Retrieves the process identifier of the calling process.
GetWindowThreadProcessId, on the other hand,
Retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
The return value is the identifier of the thread that created the window.
So looking at your call:
pid = GetWindowThreadProcessId(hwnd, NULL);
You're actually getting back a thread ID, not a process ID. So when you compare pid to id, you're comparing a process ID and a thread ID, and that's just not going to work. Try this instead:
GetWindowThreadProcessId(hwnd, &pid);
(Note: I can't actually test whether this works, since EnumWindows requires a top-level window to enumerate and I ran this as a console app. Let me know if this answer doesn't work for you and I'll delete it.)
(As a second note, you don't need to use NULL anymore, even for WinAPI stuff like HWND. nullptr will work perfectly fine.)
I assume you're trying to find the "Main" window from the ProcessID.. In that case, this MAY help:
#include "stdafx.h"
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
struct WindowHandleStructure
{
unsigned long PID;
HWND WindowHandle;
};
BOOL CALLBACK EnumWindowsProc(HWND WindowHandle, LPARAM lParam)
{
unsigned long PID = 0;
WindowHandleStructure* data = reinterpret_cast<WindowHandleStructure*>(lParam);
GetWindowThreadProcessId(WindowHandle, &PID);
if (data->PID != PID || (GetWindow(WindowHandle, GW_OWNER) && !IsWindowVisible(WindowHandle)))
{
return TRUE;
}
data->WindowHandle = WindowHandle;
return FALSE;
}
HWND FindMainWindow(unsigned long PID)
{
WindowHandleStructure data = { PID, nullptr };
EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&data));
return data.WindowHandle;
}
int main()
{
HWND Window = FindMainWindow(GetCurrentProcessId());
std::wstring Buffer(GetWindowTextLength(Window) + 1, L'\0');
GetWindowText(Window, &Buffer[0], Buffer.size());
std::wcout << Buffer.c_str() << L"\n";
system("pause");
return 0;
}