My approach to this problem turned out to be correct only in several programs. Why it isn't universal?
Works fine on:
Firefox
Visual Studio Text Editor
Unfortunately, in some cases nothing happens(even if I click into a textbox area before execution of my program):
Google Chrome
Notepad
GetLastError returns always 0, even using SendMessage instead of PostMessage.Could you point out my mistake?
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++) //simulate 500 keystrokes of 'E'.
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,NULL);
PostMessage(hCurrentWindow,WM_KEYUP,0x45,NULL);
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
UPDATE after Maximus sugestion
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get set the window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45,0x45);
PostMessage(hCurrentWindow,WM_KEYUP,0x45,0x45);
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
There is no difference in effect.
UPDATE after Rob Kennedy's comment and Hans Passant's answer
#include <Windows.h>
#include <iostream>
int main()
{
HWND hCurrentWindow;
DWORD procID;
GUITHREADINFO currentWindowGuiThreadInfo;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get main the window handle\n";
GetWindowThreadProcessId(hCurrentWindow,&procID);
GetGUIThreadInfo(procID,¤tWindowGuiThreadInfo);
hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
if(!hCurrentWindow)
std::cout<<"Failed get the child window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
Now, "transparent" messages are sent every time. GetLastError() says:
ERROR_INVALID_WINDOW_HANDLE
1400 (0x578)
Invalid window handle.
GetLastError() "fixed"
int main()
{
HWND hCurrentWindow;
DWORD procID;
GUITHREADINFO currentWindowGuiThreadInfo;
Sleep(5000);
hCurrentWindow = GetForegroundWindow();
if(!hCurrentWindow)
std::cout<<"Failed get main the window handle\n";
GetWindowThreadProcessId(hCurrentWindow,&procID);
GetGUIThreadInfo(procID,¤tWindowGuiThreadInfo);
hCurrentWindow = currentWindowGuiThreadInfo.hwndFocus;
if(!hCurrentWindow)
std::cout<<"Failed get the child window handle\n";
std::cout<<"GO!!!\n";
for(int i=0; i<500; i++)
{
if(!PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC))) std::cout<<GetLastError()<<std::endl;
if(!PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC))) std::cout<<GetLastError()<<std::endl;
}
system("Pause");
return 0;
}
...outputs 1400 thousand times. Except this, nothing has changed.
This will of course happen when you post the message to the wrong window. Which is certainly the case for Notepad. It doesn't have just one window, something you can see with Spy++. GetForegroundWindow() returns you a top-level window, the frame window for Notepad. Inside of that frame window it has a child window, an EDIT control. That window needs to get the messages.
You'll need to jump through a few hoops to get that window, the GetFocus() function returns the window with the focus but that only works if you call it from the process that owns the window. When you do this out-of-process then you must first call GetWindowThreadProcessId() to get the ID of the thread that owns the foreground window. Then you must call GetGUIThreadInfo(), the GUITHREADINFO.hwndFocus it returns is the window handle you need.
This is still not without trouble, you cannot control the keyboard state of the process. In other words, the state of the Shift, Ctrl and Alt keys as well as any dead keys (like Alt+Gr on certain keyboard layouts). Favor sending WM_CHAR for typing keys.
Something else to bear in mind is that you can't always assume that the target application is handling user input in the same way. For example they could be using something GetAsyncKeyState() instead, causing your posted messages to have no effect at all.
You send lParam==NULL. It contains the scan code of the key which may be needed by the applications which aren't working currently.
Also, your code does not check the return value of GetForegroundWindow(). It may be NULL.
Lastly, you omit WM_CHAR, which is an important part of keyboard cycle.
Between sending the KeyDown and KeyUp you need any delay in some cases. I solved my similar situation by adding a pause of 100ms after KeyDown
{
PostMessage(hCurrentWindow,WM_KEYDOWN,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
Sleep(100);
PostMessage(hCurrentWindow,WM_KEYUP,0x45, MapVirtualKey(0x45,MAPVK_VK_TO_VSC));
}
Related
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.
I have the following code to demonstrate the problem.
A handler treating ctrl-C (CTRL_C_EVENT) and window-close (CTRL_CLOSE_EVENT) is installed.
After outputting something about the possible actions, an infinite loop is started, waiting for a user to either control-C or close the console window.
In both cases a message box with a yes/no choice is given.
For the ctrl-C this works fine, but clicking no when closing has no effect. Worse, after 5 seconds the whole thing is shut down anyway. This is quite according to docs, so my question is:
Is there an alternative that will allow me to return to the application, rather than having 5 seconds to say my prayers and getting shot anyway?
The code:
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib, "user32.lib")
BOOL myCtrlHandler(DWORD fdwCtrlType)
{
auto userwantstoquit = [](HWND wnd = nullptr)
{
return MessageBox(
wnd,
"Do you really want to stop?",
"CTRL tester",
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2 | MB_APPLMODAL
) == IDYES;
};
switch (fdwCtrlType)
{
case CTRL_C_EVENT:
// Console window handle is passed to prevent window interaction
// return TRUE will stop the signal, allow app to go on
// return FALSE will allow the other handlers to be called.
return !userwantstoquit(GetConsoleWindow());
case CTRL_CLOSE_EVENT:
// passing console window handle will not display the box
return !userwantstoquit();
default:
// use default handlers for everything else
return FALSE;
}
}
int main()
{
SetConsoleCtrlHandler(myCtrlHandler, TRUE);
puts("Press ctrl-C or close the console window using x");
while (true);
return 0;
}
MS docs say that in case of a CTRL-CLOSE signal any number of (console) cleanup routines already may have executed, so at this stage there is no way back.
Possibly, then, trying to add a windows message pump is the only potential solution, but that obviously smacks of overkill for a console app. But it may be the only way to go, also, since by using MessageBox (user32.dll), there will not be CTRL_LOGOFF or CTRL_SHUTDOWN events through the CtrlHandler function.
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.
#include <iostream>
#include <fstream>
#define _WIN32_WINNT 0x501
#include <windows.h>
using namespace std;
HHOOK hKeyboardHook = 0;
LRESULT CALLBACK KeyboardCallback(int code,WPARAM wParam,LPARAM lParam) {
cout << "a key was pressed" << endl;
ofstream myfile;
myfile.open ("hookcheck.txt", ios::ate | ios::app);
myfile << "a key was pressed\n";
myfile.close();
return CallNextHookEx(hKeyboardHook,code,wParam,lParam);
}
int main() {
HWND consoleWindow = GetConsoleWindow();
HINSTANCE hInstCons = (HINSTANCE)GetWindowLong( consoleWindow, GWL_HINSTANCE );
hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD, (HOOKPROC)KeyboardCallback, (HINSTANCE)consoleWindow, GetCurrentThreadId());
MessageBox(NULL, "It is keyboard time!", "Let's Go", MB_OK);
}
This code on every key press while the loop is going should print message on console and create a file, but nothing is happening. What do I wrong ?
I will quote from another topic:
Console windows are handled entirely by CSRSS, which is a system
process. Installing a hook into a process means injecting your DLL
into it. Since CSRSS is so important (it's vital for running of the
system, and code within runs as LocalSystem, which is the local
super-admin user), you're not allowed to inject code into it. So you
can't hook any of its windows.
There are no real window messages taking place in your simple console application, so your hook does not have to be called, and in your case you are not even injecting your hook but using thread mode hook only. Per MSDN documentation it is called when messages are about to be processed:
An application-defined or library-defined callback function used with
the SetWindowsHookEx function. The system calls this function whenever
an application calls the GetMessage or PeekMessage function and there
is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.
Now let me show you what you can do to start receiving calls on your hook:
MessageBox(NULL, _T("It is keyboard time!"), _T("Let's Go"), MB_OK);
//for(int i=0; i<=10; i++) {
// cout << i << endl;
// Sleep(1000);
//}
Do MessageBox and before closing it start typing - you will start getting hook calls.
Read the documentation for SetWindowsHookEx. Is it working, it will return NULL if it fails and GetLastError() can be called to get an error code to help diagnose what is wrong.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
Sleep(1000) suspends the execution of the current thread until the time-out interval elapses. It means that your program is not actually running (ie. processing messages) during this sleep.
You need to use a different kind of command, that will keep the message loop running. The simplest thing would be to wait for user input
while(true)
std::cin.get();
I have created a dll that hooked the keyboard and in there I used the DllMainfunction to retrieve a HINSTANCE that can be used in SetWindowsHookEx.
Next to that I also used 0 as the threadid so all threads get hooked.
Perhaps you could try a similar tactic as well.
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