I'm new to WinAPI and I already created an empty window. Now I want to make a little hack for the tutorial program of Cheat Engine. I already know, how to change values in the memory of other processes. But as soon as I changed a value in the tutorial program, I'm forced to click a "next" button. So my question is: Is it possible to send a click command to a window of another process? I have a handle of the window, a handle of the process and the process id (if it is not the same).
The only thing I know about the buttons is, that their text is always "next".
Here is a shortened version of my code:
HWND hWnd = FindWindow (NULL, L"Window's title"); // Search startup window
DWORD pid; // Get process id
GetWindowThreadProcessId (hWnd, &pid);
HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid); // Get access to process
DWORD base = 0x789ABCDE; // Get value of static pointer
ReadProcessMemory (hProc, &base, &base, 4, NULL);
WORD offset = 0xBCDE; // Write to memory
WriteProcessMemory (hProc, (void *)(base + offset), (void *)5000, 4, NULL);
// Send click command (???)
Sorry, if my english and/or some technical terms aren't correct, but I'm new to Win32.
EDIT:
I discovered, that the tutorial forbits every memory access, so my project will never work. In addition, GetLastError(); always returns ERROR_INVALID_PARAMETER when I try to install a second windows procedure for the tutorial program. Do I have to use hProc instead of pid in SetWindowsHookEx (WH_CALLWNDPROC, &fnHook, NULL, pid);?
The simplest way to do this is to use SendMessage() to send an WM_LBUTTONDOWN and then a WM_LBUTTONUP message to the given window, something like
// x, y are the coords
SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
SendMessage(hWnd, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(x, y));
This may or may not work in your particular case; if the spot that you're trying to click is actually in a child window or a popup you've just "clicked" the wrong window, and a lot of apps rely on other messages.
The more reliable way to do it is to call SetWindowsHookEx(WH_MOUSE, ...), and "play" the mouse messages through the given hook procedure. I haven't done that in a couple of decades so can't really talk about it in detail.
Normally, if a program selects an object into a device context, or changes its properties, it should change them back before releasing the device context. What happens if it doesn't?
Let's say I do this:
HDC hdc = GetDC(some_window);
SelectObject(hdc, some_font);
SetTextColor(hdc, 0x123456);
SetBkColor(hdc, 0xFEDCBA);
SetROP2(hdc, R2_XORPEN);
ReleaseDC(some_window, hdc);
and some_window's window class does not have the CS_OWNDC or CS_CLASSDC flag. What happens?
Of the functions you listed, SelectObject is the only one that would cause a problem if the object is not de-selected (by selecting the original object). This would cause the some_font resource to be leaked because the DC would have been holding an open handle on it at the time it was released.
You should be doing this:
HDC hdc = GetDC(some_window);
HGDIOBJ hOldObj = SelectObject(hdc, some_font);
// ...
SelectObject(hdc, hOldObj);
ReleaseDC(some_window, hdc);
Or perhaps this:
HDC hdc = GetDC(some_window);
int nSaved = SaveDC(hdc);
SelectObject(hdc, some_font);
// ...
RestoreDC(nSaved);
ReleaseDC(some_window, hdc);
As MSDN notes :
Each of these functions returns a handle identifying a new object.
After an application retrieves a handle, it must call the
SelectObject function to replace the default object. However, the application should save the handle identifying the default object and
use this handle to replace the new object when it is no longer needed.
When the application finishes drawing with the new object, it must
restore the default object by calling the SelectObject function
and then delete the new object by calling the DeleteObject
function. Failing to delete objects causes serious performance
problems.
The failure to restore the original font object causes a handle leak. The OS will retain the handle to some_font. If this code is executed repeatedly then another handle is leaked every time. You will see the Handles count in Task Manager building up. If this goes on for a long time there will eventually be painting failures that appear as junk.
I'm pretty new to OpenCV and I'm trying to get my bearings by looking at, and running, sample code.
One of the sample programs that I was looking at is a program for displaying webcam video. Here are the important lines (the program doesn't execute farther than this):
// Make frame.
CvCapture* capture = cvCaptureFromCAM(0);
if(!capture) {
printf("Webcam not initialized....");
}
// Display video in frame.
Unfortunately, the if statement always executes. For some reason, capture is not initialized.
Even stranger, when I run the program, it even gives me a GUI to select the webcam that I want to use:
However, even after I select the webcam, capture is not initialized!
What does this mean? How do I fix this?
Thanks for any suggestions.
It is possible that OpenCV cannot access the webcam until after you select it. In that case, try looping until the webcam is available:
CvCapture *capture = NULL;
do {
// you could also try passing in CV_CAP_ANY or -1 instead of 0
capture = cvCaptureFromCAM(0);
} while (!capture);
If this still doesn't work, call cvErrorStr(cvGetErrStatus()) to get a string explaining the error.
I'm trying to use the following code to press a button on my other application:
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
ButtonHandle = FindWindowEx(wnd, 0, "SaveButton", "&Save");
SendMessage(wnd, WM_COMMAND, MAKEWORD(GetDlgCtrlID(ButtonHandle), BN_CLICKED ), (LPARAM)ButtonHandle);
}
It doesn't work. I tried passing different handles to MAKEWORD and to change the WPARM and LPARAM but nothing.
Any ideas on how to click a button on another application's window?
Code is appreciated.
Thanks.
EDIT:
The reason it doesn't seem to work permissions. I sent a PostMessage() and the result was an error with GetLastError() = 5 (or Access Denied).
Any ideas?
EDIT2 I don't mean to be rude but please please please, I already searched all the API's including getting and setting the regions for the button and then sending a button down and button up, getting the control ID, getting the class ID and a zillion more.
The reason I asked the question here in the first place is because I already exhausted my search on the internet.
If you know the answer PLEASE POST CODE, do not suggest an API and that's it, show me how does that API solves the problem. It's not hard.
thank you.
EDIT 3: The question's answer was selected automatically when the bounty finished. The question still remains without an answer.
Are you sure that "SaveButton" class name is valid? Do you get the button
handle?
Try to send messages to ButtonHandle window (directly to the button).
Update: I believe this should work,
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
See the following solution, also you can use
SendMessage(ButtonHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, 0, 0);
Or
SendMessage(ButtonHandle, BM_CLICK, 0, 0);
HWND buttonHandle = 0;
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"&Save") == 0)
{
buttonHandle = handle;
return false;
}
return true;
}
void main()
{
HWND windowHandle = FindWindowA(NULL,"Do you want to Save?");
if(windowHandle != 0)
{
BOOL ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
if(buttonHandle != 0)
{
LRESULT res = SendMessage(buttonHandle,BM_CLICK,0,0);
//SendMessage(buttonHandle,WM_LBUTTONDOWN,0,0);
//SendMessage(buttonHandle,WM_LBUTTONUP,0,0);
}
}
}
Note:
Getting sure from the window text,button text (check if there is space at the end of the window title)
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
SendMessage(btnHandle, WM_LBUTTONDOWN, 0, 0);
SendMessage(btnHandle, WM_LBUTTONUP, 0, 0);
You have to send a button click twice. Not sure why (maybe the first click only activates the window of the button), but I'm using this code for a long time and it always worked for me.
maybe this can help:
http://www.cplusplus.com/forum/beginner/8806/
Access Denied errors on SendMessage or PostMessage make no sense unless the process sending the message is running at a lower integrity level than the target process.
This should not be happening unless the process that owns the target window is being run "asAdministrator" or is a service. And its damn hard for services to create windows on the interactive desktop with Windows 6 and up.
You can do some reading about Integrity Levels Here if they apply even remotely to this situation. Internet Explorer is about the only other application that 'opts in' to the integrity security model by purposely lowering the integrity level of itself in order to sandbox itself more effectively.
If you can raise the window containing the button you can send raw mouse event to a position within the boundaries of button.
There are two function to simulate mouse event SendInput and mouse_event. I recommend using mouse_event function. To raise a window you can use ShowWindow. I don't know how to get the handle of a button, but if you have its hWnd its easy to find its absolute position using GetWindowRect function. Try using these, if you run into any problems I will be glad to help.
Or define a custom WM within your application window to handle save request. WM_CUSTOM or WM_USER (cant remember which) marks the start of user defined window messages.
When I have to do these kind of things I use SendKeys. It is VB-ish and C# provides a nice interface to use but for C/C++ you'll have to do it <this way>. What is nice with it is that you could write scripts and run them instead of hard coding it in your code.
Microsoft is now pushing Active Accessibility (MSAA) for UI Automation,
(It has been renamed a number of times over the years)
see
UI Automation and Microsoft Active Accessibility
Using UI Automation for Automated Testing
UI Automation Clients for Managed Code
Sorry I don’t have any simple code to get you started. As “SendMessage()” does not seem to be working for you, I don’t know of another option apart from “UI Automation”
I am assuming you have check with Spy++ (installed with MsDev) that you message are being send to the correct button etc – and that the button is a standard windows buttons. My first instant would say use “SendMessage()" or "PostMessage()” but given the numbers of answers about “SendMessage()” and the fact it is not working for you. I expect someone is going on…
//Send digit 4 to the already opened calc.exe
HWND windowHandle;
windowHandle = FindWindowA(NULL,"Calculator");
if(windowHandle != 0)
ret = EnumChildWindows(windowHandle,GetButtonHandle,0);
BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
char label[100];
int size = GetWindowTextA(handle,label,sizeof(label));
if(strcmp(label,"4") == 0)
{
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONDOWN,(WPARAM)0x0001,0);
PostMessage(handle ,WM_LBUTTONUP,(WPARAM)0x0001,0);
return false;
}
return true;
}
You can use sendkeys (as tr3 said) to send mouse clicks, which is different than using SendMessage. It is also less direct and more hack-ish, but is useful for automation (in VBS).
Also, just a guess but the problem could be that your message handling is broken somewhere by not calling the base class member. Example:
void CMyClass::OnMessageY(CWnd *cwnd)
{
CBaseClass::OnMessageY(cwnd);
//... my code
}
if you sure ButtonHandle are valid handle you can use pair WM_LBUTTONDOWN and WM_LBUTTONUP message instead of BN_CLICKED
HWND ButtonHandle;
if( (wnd = FindWindow(0, "Do you want to save?")) )
{
SendMessage(ButtonHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
SendMessage(ButtonHandle, WM_LBUTTONUP, MK_LBUTTON, 0);
}
A non-C approach: Use Java and the java.awt.Robot class to move the mouse around perform real clicks (I guess there is something in the Windows World for this, too).
Problem: You have to know where your button is :D
My app. will be running on the system try monitoring for a hotkey; when the user selects some text in any window and presses a hotkey, how do I obtain the selected text, when I get the WM_HOTKEY message?
To capture the text on to the clipboard, I tried sending Ctrl + C using keybd_event() and SendInput() to the active window (GetActiveWindow()) and forground window (GetForegroundWindow()); tried combinations amongst these; all in vain. Can I get the selected text of the focused window in Windows with plain Win32 system APIs?
TL;DR: Yes, there is a way to do this using plain win32 system APIs, but it's difficult to implement correctly.
WM_COPY and WM_GETTEXT may work, but not in all cases. They depend on the receiving window handling the request correctly - and in many cases it will not. Let me run through one possible way of doing this. It may not be as simple as you were hoping, but what is in the adventure filled world of win32 programming? Ready? Ok. Let's go.
First we need to get the HWND id of the target window. There are many ways of doing this. One such approach is the one you mentioned above: get the foreground window and then the window with focus, etc. However, there is one huge gotcha that many people forget. After you get the foreground window you must AttachThreadInput to get the window with focus. Otherwise GetFocus() will simply return NULL.
There is a much easier way. Simply (miss)use the GUITREADINFO functions. It's much safer, as it avoids all the hidden dangers associated with attaching your input thread with another program.
LPGUITHREADINFO lpgui = NULL;
HWND target_window = NULL;
if( GetGUIThreadInfo( NULL, lpgui ) )
target_window = lpgui->hwndFocus;
else
{
// You can get more information on why the function failed by calling
// the win32 function, GetLastError().
}
Sending the keystrokes to copy the text is a bit more involved...
We're going to use SendInput instead of keybd_event because it's faster, and, most importantly, cannot be messed up by concurrent user input, or other programs simulating keystrokes.
This does mean that the program will be required to run on Windows XP or later, though, so, sorry if your running 98!
// We're sending two keys CONTROL and 'V'. Since keydown and keyup are two
// seperate messages, we multiply that number by two.
int key_count = 4;
INPUT* input = new INPUT[key_count];
for( int i = 0; i < key_count; i++ )
{
input[i].dwFlags = 0;
input[i].type = INPUT_KEYBOARD;
}
input[0].wVK = VK_CONTROL;
input[0].wScan = MapVirtualKey( VK_CONTROL, MAPVK_VK_TO_VSC );
input[1].wVK = 0x56 // Virtual key code for 'v'
input[1].wScan = MapVirtualKey( 0x56, MAPVK_VK_TO_VSC );
input[2].dwFlags = KEYEVENTF_KEYUP;
input[2].wVK = input[0].wVK;
input[2].wScan = input[0].wScan;
input[3].dwFlags = KEYEVENTF_KEYUP;
input[3].wVK = input[1].wVK;
input[3].wScan = input[1].wScan;
if( !SendInput( key_count, (LPINPUT)input, sizeof(INPUT) ) )
{
// You can get more information on why this function failed by calling
// the win32 function, GetLastError().
}
There. That wasn't so bad, was it?
Now we just have to take a peek at what's in the clipboard. This isn't as simple as you would first think. The "clipboard" can actually hold multiple representations of the same thing. The application that is active when you copy to the clipboard has control over what exactly to place in the clipboard.
When you copy text from Microsoft Office, for example, it places RTF data into the clipboard, alongside a plain-text representation of the same text. That way you can paste it into wordpad and notepad. Wordpad would use the rich-text format, while notepad would use the plain-text format.
For this simple example, though, let's assume we're only interested in plaintext.
if( OpenClipboard(NULL) )
{
// Optionally you may want to change CF_TEXT below to CF_UNICODE.
// Play around with it, and check out all the standard formats at:
// http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx
HGLOBAL hglb = GetClipboardData( CF_TEXT );
LPSTR lpstr = GlobalLock(hglb);
// Copy lpstr, then do whatever you want with the copy.
GlobalUnlock(hglb);
CloseClipboard();
}
else
{
// You know the drill by now. Check GetLastError() to find out what
// went wrong. :)
}
And there you have it! Just make sure you copy lpstr to some variable you want to use, don't use lpstr directly, since we have to cede control of the contents of the clipboard before we close it.
Win32 programming can be quite daunting at first, but after a while... it's still daunting.
Cheers!
Try adding a Sleep() after each SendInput(). Some apps just aren't that fast in catching keyboard input.
Try SendMessage(WM_COPY, etc. ).