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.
Related
I created a global mouse hook where I tried to change the x and y cursor position that the hooked application receives without actually moving the cursor. For some reason it did not work. So I tried to change the cursor position to see if it would change anything. But that didn't work either; the input reached the window before the cursor moved. Below is my code.
LRESULT CALLBACK procMouseMsg(int nCode, WPARAM wParam, LPARAM lParam){
//this is the hook procedure
if (wParam == WM_LBUTTONDOWN){
// Tactic #1 -problem: Nothing seems to happen...?
((PMSLLHOOKSTRUCT)lParam)->pt.x = 389; //
((PMSLLHOOKSTRUCT)lParam)->pt.y = 15;
// Tactic #2 -problem: cursor moves after input hits hooked application
SetPhysicalCursorPos(389, 15);
// Tactics were not used at the same time.
}
return CallNextHookEx(hkKey, nCode, wParam, lParam);
}
void __stdcall SetHook()
{
if (hkMouse == NULL){
hkMouse = SetWindowsHookEx(WH_MOUSE_LL, procMouseMsg, hInstHookDll, 0);
}
}
Am I missing something big here? Maybe I should just kill the input in CallNextHookEx and then move the cursor, manually send an input and then move the cursor back? I feel like this should be easier.
BTW I'm not writing a keylogger or anything sketchy. I'm trying to do an operating system overlay. It seems like people assume the worst.
I am working a program to simulate keyboard and mouse clicks programmatically. It need to send the clicks to a target window handle (ex: notepad edit control). I am getting the handle of notepad window and generating generating WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP messages for that window. The events are stored in queue, and later on played using a WH_JOURNALPLAYBACK hook.
For the code snippet below, the target hwnd in the playback proc though set correctly, messages never reach to the target handle. If I bring the notepad to foreground, it does receive the messages.
I am not sure why WH_JOURNALPLAYBACK ignores the handle parameter. I would have liked to generate a series of automation messages for various handles and played it back so that even without bringing the window into focus we can send keyboard and mouse events.
Please let me know
if messages to various target handles can be sent using a journal
playback hook
why in code below hwnd is ignored
..
#include <queue>
#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
using std::error;
struct Event
{
UINT msg;
UINT wparam;
UINT lparam;
HWND hwnd;
Event(UINT m, UINT wp, UINT lp, HWND h)
:msg(m),
wparam(wp),
lparam(lp),
hwnd(h)
{}
};
HHOOK jhook= NULL;
std::queue<Event> events;
bool gotoNextMsg = false;
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
switch( code )
{
case HC_SKIP:
cout<<"skip: "<<endl;
if(!events.empty())
{
events.pop();
}
break;
case HC_GETNEXT:
{
cout<<"next: "<<events.size()<<endl;
gotoNextMsg = true;
EVENTMSG * evm = (EVENTMSG*) lParam;
Event e = events.front();
switch(e.msg)
{
case WM_KEYDOWN:
cout<<"WM_KEYDOWN"<<endl;
break;
case WM_KEYUP:
cout<<"WM_KEYUP"<<endl;
break;
case WM_SYSKEYDOWN:
cout<<"WM_SYSKEYDOWN"<<endl;
break;
case WM_SYSKEYUP:
cout<<"WM_SYSKEYUP"<<endl;
break;
}
cout<<"handle: "<<e.hwnd<<endl;
cout<<"handle1:"<<evm->hwnd<<endl;
evm->message = e.msg;
evm->paramL = e.wparam;
evm->paramH = e.lparam;
evm->hwnd = e.hwnd;
evm->time = ::GetTickCount();
}
break;
default:
if( code < 0 )
::CallNextHookEx(jhook, code, wParam, lParam);
break;
}
if(events.empty())
{
cout<<"uinstalled"<<endl;
::UnhookWindowsHookEx(jhook);
::PostMessage(NULL, WM_USER+100, 0, 0);
}
return 0;
}
A journal hook injects events into the system message queue. For keyboard and mouse messages, the system dispatches them to the current focused window, same as if the user had input them manually. The HWND you specify in the event is not used, it gets replaced during dispatching.
And if you consider that a recorded journal can be played multiple times, and its data can persist across application instances and even reboots, and that HWNDs can be reused for different things over time, it should make sense why a journal playback cannot make use of an event's HWND even if the system message queue were not involved.
So, you cannot use WH_JOURNALPLAYBACK to target a specific window that is not in the foreground. You would have to send the recorded messages yourself. But be aware of some caveats that Raymond Chen has blogged about:
You can't simulate keyboard input with PostMessage
Simulating input via WM_CHAR messages may fake out the recipient but it won't fake out the input system
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.
I'm new to the WTL C++. I'm really confused about the parameters that go into the RedrawWindows function especially for the flags. I'm just trying to update a window everytime I draw a line, but I don't exactly understand how
LRESULT CDrawView::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
int xPos= GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
end.X = xPos;
end.Y = yPos;
Pen pen(Color(0, 0, 255));
m_GraphicsImage.DrawLine(&pen, start.X, start.Y, end.X, end.Y);
I try to call RedrawWindow here,
RedrawWIndow(NULL,NULL, NULL, RDW_INTERNALPAINT)
So everytime I release the left mouse button the window gets updated. I'm having a really hard time understanding the parameters that go into the Redraw Function. I tried putting them all null minus the last one but Visual studio says that the function doesn't take 4 parameters even though I read the msdn microsoft...
You are not calling the global RedrawWindow.
You're calling the member function CWindow::RedrawWindow, which takes 3 parameters.
BOOL RedrawWindow(
LPCRECT lpRectUpdate = NULL,
HRGN hRgnUpdate = NULL,
UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE
); throw()
Edit:
These three parameters all have default arguments, meaning they don't need to be supplied an RedrawWindow() alone should work.
This is not the way you should use and you are supposed to be using the API. Your mouse button handler should call Invalidate() or InvalidateRect with specific part of the window you are marking as needing an update. Your window will then receive WM_PAINT event at the first OS convenience and your paint handler would paint the line.
RedrawWindow might work out this time, however is likely to be a base of a next problem very soon because you are already on the wrong way.
I have a win 32 application written in c++ which sets the low level keyboard hook. now i want to sendInput to any app like word / notepad. how do i do this?
i have already done enough of using findwindow / sendmessage. for all these, i need to know edit controls. finding the edit control is very difficult.
since SendInput works for any windows application, i want to use it. the problem is i get a call to my callback function with the pressed key.
for e.g i pressed A and i want to send U+0BAF unicode character to the active applciation windows. in this case, assume it is notepad.
the problem is i get two characters U+0BAF and A in the notepad.
A is being sent because i am calling CallNextHookEx( NULL, nCode, wParam, lParam);
if i return 1 after sendInput, then nothing is sent to notepad.
any suggestion?
If I understood your problem correctly, you should ignore "injected" key events in your hook procedure, like this:
LRESULT CALLBACK
hook_proc( int code, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT* kbd = (KBDLLHOOKSTRUCT*)lParam;
// Ignore injected events
if (code < 0 || (kbd->flags & LLKHF_INJECTED)) {
return CallNextHookEx(kbdhook, code, wParam, lParam);
}
...
Update: additionally, you have to eat characters and notify some other routine for a character press through Windows messages.
Example:
...
// Pseudocode
if (kbd->vkCode is character) {
if (WM_KEYDOWN == wParam) {
PostMessage(mainwnd, WM_MY_KEYDOWN, kbd->vkCode, 0);
return 1; // eat the char, ie 'a'
}
}
return CallNextHookEx(kbdhook, code, wParam, lParam);
And, in some other module, you handle WM_MY_KEYDOWN:
ie, #define WM_MY_KEYDOWN (WM_USER + 1)
and call the appropriate routine that will generate new key events.