How to check if a window button is pressed C++ - c++

How can I test if a button is being pressed ?
I am using EnumChildWindows() to enumerate the child windows of a given window, and one of the child window is a button, I want to test if that specific button is being pressed.
My code until know is:
BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lParam)
{
char buffer[256];
GetWindowText(hwnd, buffer, sizeof(buffer));
cout << buffer << endl;
return true;
}
int main()
{
HWND hwnd = FindWindow(0, "Window to find");
EnumChildWindows(hwnd, MyEnumProc, 0);
return 0;
}

You can send the BM_GETSTATE message to the button control, if it is pressed the result will be
BST_PUSHED.

You need to inject a DLL into the process space, hook the window message loop (like you used to hand code a subclassed window in native Win32 API C code, Window Proc) (google-able) and listen to the actual messages.
All of this is ancient stuff for me, and I'm afraid that recent Windows versions (hopefully) made this a little bit more difficult to do.
That said, if you can get the application trusted with the right level of permissions, you should still be able to do this

Related

How to use run-time dll injecting to write into a Running and Temp notepad/txt file

Basically I created a simple Dll injection code with a basic Dll that shows a message box and my question is how can I now use the Dll file to make it write text into the Notepad while its running and it hasn't been saved/is temporary?
Is there a way to find a path to the file?
(i don't think so because its still writing into the ram and is untitled so doesn't have a save on any drives)
Or is there a stream i can write into?
Like Timo said in the comment, you can get the handle to the Notepad's Window, and then use it to write text into it, and it even wouldn't require from you to inject your DLL into the Notepad Process.
In Windows, every window is receiving messages from the Operating System (or from other programs, like what you're going to try out), those messages tell the window what action was made, for instance - Pressing down a key, or pressing a mouse button. That way, the program controlling the Window will know what kind of action it's supposed to do.
You can use the Spy++ Tool (spyxx.exe, comes builtin in every Visual Studio) to track what Windows does when you press a key down the keyboard into the Notepad's Window.
You can read further about the topic of window messages here:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/window-messages
And working with Spy++ here:
https://learn.microsoft.com/en-us/visualstudio/debugger/introducing-spy-increment?view=vs-2019
Opening Spy++, we can see all the Windows in the our session, and we look for the Notepad's:
how it looks
Small POC I made for searching the appropriate Window, according to what found by Spy++ (forgive me for the globals, and make sure you are aware of what I did here):
HWND notepad_window;
HWND notepad_edit;
BOOL CALLBACK GetEditWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
if (0 != GetClassNameW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Edit"))
{
std::wcout << "Found it" << text << std::endl;
notepad_edit = hWnd;
return false;
}
}
return true;
}
BOOL CALLBACK GetNotepadWindow(HWND hWnd, LPARAM lParam)
{
wchar_t window_text[MAX_PATH] = { 0 };
// Fun fact - The GetWindowTextW also posts a window message to the window, the WM_GETTEXT message
if (0 != GetWindowTextW(hWnd, window_text, MAX_PATH))
{
std::wstring text(window_text);
if (std::wstring::npos != text.find(L"Notepad"))
{
std::wcout << "Found it" << text << std::endl;
notepad_window = hWnd;
return false;
}
}
return true;
}
int wmain()
{
EnumWindows(GetNotepadWindow, 0);
EnumChildWindows(notepad_window, GetEditWindow, 0);
}
After you have the HWND, you can start dealing with the message posting. You can use Spy++ again to 'tap' on the Notepad's Edit Window, and see every Window Message sent when pressing down a key, you will see the WM_KEYDOWN, followed by a WM_KEYUP most likely.
Then, you can use the PostMessage WinAPI function to post your own WM_KEYDOWN/KEYUP messages to the Notepad Window, hence controlling the input it gets.

does not go inside the Windows GetMessage loop on console application

I want to detect keypress in C++ and i need to use Windows System Call. So, i did some research and this is what i got using Hooks and Message:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
using namespace std;
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION) {
switch (wParam) {
case WM_KEYDOWN:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
char c = char(MapVirtualKey(p->vkCode, MAPVK_VK_TO_CHAR));
cout << c << endl;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
int main() {
HHOOK HKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) > 0) {
cout << "bRet = " << bRet << endl; // I want to do something here, but the program doesn't seem to go in here
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(HKeyboard);
return 0;
}
My question is why my program doesn't go inside the loop(and instead stuck on GetMessage function)? I need it to set conditions to terminate after some seconds, so where should i put the conditions? I know the GetMessage function reads Message, but when i press keys on my keyboard it still not going in and the callback function works just fine.
The events are posted to the active window. Console windows are owned by the console subsystem, csrss.exe, and it receives the events, then translates them to characters and puts them in the console object which is your application's stdin.
If you want to process events the Win32 GUI way, you should use a Win32 window (e.g. RegisterClass and CreateWindow), not a console window.
If you just want the callbacks to work for a certain period of time, you can use an alertable wait such as SleepEx or MsgWaitForMultipleObjects, which accept a timeout.
That's not surprising, there aren't really any messages on your thread queue and you have no window so there's no window queue either.
If you want to play with values returned from your hook, put the code in the hook callback function.
I should warn you that hooks like these won't work in console applications since the console window resides in another process. Also, if you look at the MSDN page for SetWindowsHookEx, you'll see that WH_KEYBOARD_LL is a global hook only, ie you have to put your hook handler in a DLL library and inject the hook in the other applications. Then you have to handle the 32/64 bit issue yourself.
And as a last note, when you say cout << c; in your handler, that would be printing in the process's output file handle, not your own.

C++: Trying to hook a message box and change its position

I recently started coding in C++ and I am very new to it. (I code in Javascript, PHP, Java and Obj-C more often)
I'm practicing how to hook a message box and change its position. This is what I have in my .cpp file (after reading this SO post).
#include <iostream>
#pragma comment(lib,"User32.lib")
#include <windows.h>
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if ((pcs->style & WS_DLGFRAME) || (pcs->style & WS_POPUP))
{
HWND hwnd = (HWND)wParam;
SetWindowPos(hwnd, HWND_TOP,130,122, 0, 0,SWP_NOSIZE);
}
}
return (CallNextHookEx(hhookCBTProc, nCode, wParam, lParam));
}
int main(void)
{
hhookCBTProc = SetWindowsHookEx(WH_CBT,pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox ( NULL, "Hooked!", "oh my", MB_OK );
UnhookWindowsHookEx(hhookCBTProc);
return 0;
}
For some reason the position of the message box isn't changing. Where did it go wrong?
(I know I can create a customized window or dialog. But I am doing it this way because I want to learn how to hook a message box and where I did wrong.)
Firstly you should check in the debugger that your hook is actually being called, if you haven't already.
Secondly, at the time the HCBT_CREATEWND hook event is triggered, the window has only just been created - the system has yet to size and position it. It will do this with the values in the CREATESTRUCT after the hook returns - overriding your SetWindowPos call.
See the docs from MSDN on the lParam value for this particular hook event:
Specifies a long pointer to a CBT_CREATEWND structure containing
initialization parameters for the window. The parameters include the
coordinates and dimensions of the window. By changing these
parameters, a CBTProc hook procedure can set the initial size and
position of the window.
Therefore, the correct way to use this hook to change a window's position is to modify the values in the CREATESTRUCT directly.
Also note that it's quite possible that the dialog manager sizes and positions the window after creation, so if you find that this still isn't working for you, you may need to try watching for the HCBT_MOVESIZE event instead.
From the docs
At the time of the HCBT_CREATEWND notification, the window has been
created, but its final size and position may not have been determined
and its parent window may not have been established.
Maybe try hooking into CBT_ACTIVATE instead.

Creating Responsive Windows winapi c++

I am just learning to create a gui using the winapi, but i have run into an issue. I can create a window like this
#include "stdafx.h"
#include <windows.h>
int main()
{
HWND hwnd = CreateWindow(L"STATIC",NULL,WS_VISIBLE|WS_SYSMENU|WS_CAPTION,0,0,600,600,NULL,NULL,NULL,NULL);
UpdateWindow(hwnd);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_gettch();
}
But the windows will not close when the close button is clicked, and the window can not be dragged around or moved. I was wondering how i would enable these features of the window.
Static windows are not there for normal windows, you should try and look up how to register and handle your own class with RegisterWindowEx then use the same class name to create a window. You have to have your own window procedure in order to handle messages.
All window classes registered by the system run their own default window procudure and as far as I know none of them handle WM_CLOSE ( that is the close button ) this is why you can't close it.
For you main windows always use something like WS_OVERLAPPEDWINDOW so it'll be clear if it's okay or not and from that eliminate the flags you don't need.
How you set it up :
WNDCLASSEX wndcls;
HWND hMainWnd;
// Register your own window class
ZeroMemory(&wndcls,sizeof(WNDCLASSEX));
wndcls.cbSize=sizeof(WNDCLASSEX);
wndcls.style=CS_VREDRAW+CS_HREDRAW;
wndcls.lpfnWndProc=&appWndFunc;
wndcls.hInstance=hInstance;
wndcls.hIcon=hMainIcon; // or just LoadIcon(hInstance,MAKEINTRESOURCE(IDI_MAIN_ICON))
wndcls.hIconSm=hMainIcon;
wndcls.hCursor=LoadCursor((HINSTANCE)NULL,IDC_ARROW);
wndcls.hbrBackground=(HBRUSH)COLOR_APPWORKSPACE;
wndcls.lpszClassName="myWndClass";
if (RegisterClassEx(&wndcls)==0)
{
// failed to register class name
return false;
}
// Create window with your own class
hMainWnd=CreateWindowEx(0,\
"myWndClass","widnow title",\
WS_OVERLAPPEDWINDOW|WS_VISIBLE,\
0,\
0,\
250,\
250,\
hMainWnd,NULL,hInstance,NULL);
if (hMainWnd==(HWND)NULL)
{
// failed to create main window
return false;
}
Then your main loop :
bool bAppMainLoop=false
while(!bAppMainLoop)
{
WaitMessage();
while(PeekMessage(&emsg,NULL,0,0,PM_NOREMOVE))
{
if(GetMessage(&emsg,NULL,0,0)==0)
{
bAppMainLoop=true;
break;
}
TranslateMessage(&emsg);
DispatchMessage(&emsg);
}
}
This is a bit more than usual setup, so let me explain , in order to not burn CPU, you wait for a message with WaitMessage, it'll block until something happens, like move window, click, paint etc. PeekMessage will return true if there is a message so calling it in a while loop will make sure it drains the message quene, GetMessage will obtain the message if it returns 0 it means that your app called the PostQuitMessage(0) so a WM_QUIT arrived was found in the message loop that means it's time to break out from the message loop. The rest Translate and Dispatch does what it name says.
Finally you need your own window procedure :
LRESULT CALLBACK appWndFunc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
if (uMsg==WM_CLOSE)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
DefWindowProc is essential that handles all commonly occurring messages from the system, thus you don't need to handle those here. You simply respond to the WM_CLOSE message which is sent when you want to close the window and post a quit message into the message loop that you will catch and exit.
Additional info :
It's not required to release your stuff since windows does that for you so it wont be locked the next time you start your program , but it's a good practice to at least Unregister your window class after your main loop.
Btw that is the wrong main function : WinMain that is the correct one. Plus to avoid even more bugs make sure you compile a windows GUI application.

SendMessage does not work with Word app

I am making a little aplication and I need to make a click over a position in a word document.
I am using "sendMessage, although I also was using "postMessage" getting the same result.
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
HWND win_handle = FindWindow(L"OpusApp", NULL);
if (win_handle != NULL)
{
POINT win_coords = {1310, 360};
POINT ctrl_coords = win_coords;
ScreenToClient(win_handle, &win_coords);
WCHAR windowsText1[200];
GetWindowText(win_handle, windowsText1, 200);
//SetCapture(win_handle);
LPARAM lParam = MAKELPARAM(win_coords.x, win_coords.y);
LRESULT hr_d = SendMessage(win_handle, WM_LBUTTONDOWN, 0, lParam);
LRESULT hr_u = SendMessage(win_handle, WM_LBUTTONUP, 0, lParam);
}
return 0;
}
Any suggestion?
Regards.
First, you shouldn't use SendMessage or PostMessage to send input. It may work for some programs, but directly sending or posting the message doesn't update the internal state that's associated with input, which can make odd things happen, such as not detecting the input.
That's why the function SendInput exists. This injects input on the same level that the mouse driver uses, so Windows will correctly maintain its state. Of course, this is for global input. If there's no way to ensure that the window will be in the foreground, you may want to look into UI Automation.