Related
I loaded "html.html" file in Firefox browser and used the following code to refresh it which works fine.
int main()
{
HWND v;
v = FindWindow(NULL, "Mozilla Firefox");
if (v == NULL)
print("not found");
else
{
print("found");
PostMessage(v, WM_KEYDOWN, VK_F5, 0);
PostMessage(v, WM_KEYUP, VK_F5, 0);
}
}
I loaded the same file in Google Chrome browser and modified the window title in the previous code to "html.html - Google Chrome". The code finds the window but the browser is not refreshed. The same (no refresh) happens with Opera and Microsoft Edge.
What am I missing here?
EDIT 1:
I used the following to send Ctrl+F5, but I still cannot refresh Chrome.
PostMessage(v, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(v, WM_KEYDOWN, VK_F5, 0);
PostMessage(v, WM_KEYUP, VK_F5, 0);
PostMessage(v, WM_KEYUP, VK_CONTROL, 0);
EDIT 2:
(After being asked about tests with other automation software.)
I prefer to use pure WinAPI. Also, I already have the right key because F5 is used to refresh those browsers. To prove that, I called SetForegroundWindow() before sending the key and it will refresh all browsers.
But I cannot use SetForegroundWindow() because I need to keep the browser in the background, also calling this function is just overhead since without it, the code works fine for Firefox.
So what is the difference between Firefox and the others in this specific matter?
I have been learning C# and use Microsoft Visual Studio which makes it very easy and enjoyable to create windows forms with various controls like progress bars, drop down menus, file-system browsers etc..
Can the same thing be done with C, and are there any recommended programs?
(I have learned some C and would like to make graphical interfaces a step further than just in the console, I guess this is quite hard?).
The windows API was (and still is) a C API. Documented on msdn.microsoft.com.
The simplest way to create a Windows application with a simple form, in C, without using any external frameworks is this program:
#include <Windows.h>
#include "Resource.h"
BOOL CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return TRUE;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hNull, LPTSTR cmdLine, int cmdShow)
{
return DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_MAINDIALOG),NULL,DialogProc,0L);
}
The assumption is that, in addition to this main.c file, you use the Visual Studio resource editor to create a resource script file (.rc) with a dialog resource that you lay out your controls on.
If you are using Visual Studio Express a resource editor is not included and you will need a 3rd party editor (they are available) to lay out the dialog.
GTK+ at http://www.gtk.org/documentation.php
I've read a lot about how to add an icon to an application built with Visual Studio, but I have no idea how to do this with Eclipse Galileo / C / MinGW.
Can anyone write a description, or give me a link ta a description ?
In Windows, the icons as well as some other elements (cursors, bitmaps, ...) have to be specified in a resource file, which once compiled will be linked to the program.
First an example on how to add an icon to a Windows program which will illustrate it's use within Eclipse. Here is a simple program that just creates a window, look at the time we fill the WNDCLASSEX, the icon of the application is referenced there:
resources.h - this file may be used to assign a value to a resource identifier, and so use the value instead:
#define AppIcon 101
The next file is the resources file, you may create it manually or from within Eclipse as well, to create it in Eclipse, right click the directory you want it to be (in this case is src) and select New -> File. There write the name you want and click Finish. To edit it from within Eclipse right click it and select Open with -> Text Editor.
resources.rc - the icon will be specified here:
#include "resources.h"
// The icon path I used will be needed by Eclipse.
// If you want to use back-slashes you have to scape them (\\ instead of \):
AppIcon ICON "../src/icon.ico"
demoicon.c - the file containing the code of the program:
#include <windows.h>
#include "resources.h"
const char *ClassName = "DemoIcon";
// Declaration of the window procedure, to be used in the WNDCLASSEX struct:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd) {
WNDCLASSEX wc;
HWND hWnd;
MSG msg;
// Filling the structure:
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
// Remember this just loads 32x32, use LoadImage() instead for other dimensions (16x16, 48x48, ...):
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(AppIcon));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = ClassName;
// Here we'll use LoadImage, as we need a 16x16 mini icon:
wc.hIconSm = LoadImage(hInstance,MAKEINTRESOURCE(AppIcon),IMAGE_ICON,16,16, LR_DEFAULTCOLOR);
// Registering the class:
if(!RegisterClassEx(&wc)) {
MessageBox(NULL,
"Could not register window.",
"Error",
MB_ICONEXCLAMATION | MB_OK);
return -1;
}
// Create the window using the "MainWindow" class:
hWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
ClassName,
"Demo Icon",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
200,
150,
NULL,
NULL,
hInstance,
NULL);
// If the window was not created show error and exit:
if(hWnd == NULL) {
MessageBox(NULL,
"Could not create window.",
"Error",
MB_ICONEXCLAMATION | MB_OK);
return -1;
}
// Set the windows show state, to show it:
ShowWindow(hWnd, nShowCmd);
// Draw the window:
UpdateWindow(hWnd);
// Retrieve messages from the message queue:
while(GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Implementation of the window procedure, will handle the messages:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch(uMsg) {
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
Now, in your Eclipse project source directory make sure you have all the files (in the example the 3 files mentioned before and the icon file).
After that go to Project -> Properties.
There, go to C/C++ Build -> Settings -> Build Steps tab.
There you'll see Pre-build steps -> Command. The command you fill in there will be executed before the compilation starts, so you'll tell it to compile the resource file. As you are using MinGW the resource compiler is windres:
windres ../src/resources.rc -o ../Resources/resources.o
As you can see I'll be placing the compiled resource file in a directory called Resources, you may leave it where you want (and so the name of the file, it doesn't have to be named resources.rc).
Now go to the Tool Settings tab.
There, go to MinGW C Linker -> Miscellaneous, and in other objects add the object file created before, in this case you should add:
Resources/resources.o
As this is a Windows app, add the option -mwindows to the linker flags at the top of the same tab.
Done, when building your project Eclipse will compile the resource file first and then link the generated object as any other object file of your project.
I hope it's clear enough to read through this.
Eclipse isn't set to look at resource files. BUG. So they also have steps to add it to processing. Here are the steps for June. [http://wiki.eclipse.org/CDT/User/FAQ#How_to_handle_Resource-Script-Files_.27.2A.rc.27_with_CDT.3F][1]
How to handle Resource-Script-Files '*.rc' with CDT?
Currently handling of windres.exe with CDT is not possible. You can not add the .rc file to the project to be compiled and linked with automatically. This is already raised as a bug in bugzilla.
One way is to create a Pre-Build Step. Under menue
Project | Properties | C/C++-Build | Settings | Build Steps | Pre-Build Steps
fill in the command-line:
windres --use-temp-file -i..\MyProject.rc -o..\MyProject_rc\MyProject_rc.o
Make the object known to the linker. Under menue
Project | Properties | C/C++-Build | Settings
Tool Settings | MinGW C++ Linker | Miscellaneous | Other Objects
click the icon 'Add', fill in the line:
"C:\MyWorkspace\MyProject\MyProject_rc\MyProject_rc.o"
'MyWorkspace' and 'MyProject' replace with whatever is fitting for your purpose.
You have to add the folder .\MyProject_rc before you build.
The path to windres.exe must be known to eclipse.
The way I did it was by creating a file
icon.rc
#define AppIcon 101
AppIcon ICON "../icon.ico"
Then invoke windres via command prompt with
windres my.rc -O coff -o my.res
It'll compile several files for you -- keep the one called icon.res and rename it as libicon.a. Finally include it in your program by adding it as a library under
Project -> Properties -> Build -> Settings -> C++ Linker -> Libraries
(make sure you tell Eclipse where to find the file using the library paths section underneath).
Hope this helps!
I zip up all of the icons I want to use within the project first. Then
Rename the .zip to a .jar
Create a resource folder if you havent got one already (I use "lib")
Then place the jar file inside the resource folder.
Then one simple addition to the project properties:
by right clicking and Configure "Java Build Path" - select the Libraries tab. Click on the Add JARs button and add the icons.jar to the libraries - then save.
Now its easy to allocate the desired image icon inside the Window Builder editor for example as the jar containing your icons appears within the Image Selection mode chooser within the Classpath resource list. Everything works as it should and compiles fine.
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
I'm currently trying to integrate some animation drawing code of mine into a third party application, under the form of an external plugin.
This animation code in realtime 3d, based on OpenGL, and is supposed to render as fast as it can, usually at 60 frames per second.
In my base application, where I'm the king of the world, I control the application message pump, so that drawing occurs whenever possible. Like that :
for (;;)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
do
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
}
draw();
}
Now that I'm no more king in the world, I have to play nice with the application messages, so that it keeps being responsive. To my knowledge, as I'm a plugin, I can't hijack the whole application message pump ; so I tried various things, doing my drawing in WM_PAINT message handler :
Use WM_TIMER, which doesn't work :I don't know in advance which time step I need (often not fixed) and the timing in not accurate.
Call InvalidateRect as soon as I'm done drawing, doesn't work : completely prevents the rest of the application of being responsive and doing its own refreshing.
Create a 'worker' thread, whose only job is to post a user message to the plugin window. This message is posted as soon as the drawing is finished (signaled by an event). The user message handler, in turn, calls InvalidateRect (see there).
So far, my last attempt is the better, and sometimes work fine.
DWORD WINAPI PaintCommandThreadProc(LPVOID lpParameter)
{
Plugin* plugin = static_cast<Plugin*>(lpParameter);
HANDLE updateEvent = plugin->updateEvent();
while (updateEvent == plugin->updateEvent())
{
::WaitForSingleObject(updateEvent, 100);
::Sleep(0);
if (updateEvent == plugin->updateEvent())
{
::PostMessage(plugin->hwnd(), WM_USER+0x10, 0, 0);
}
}
return 0;
}
...
LRESULT CALLBACK PluginWinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
bool processDefault = true;
LRESULT result = 0;
Plugin* plugin = reinterpret_cast<Plugin*>( GetWindowLong(hWnd, GWL_USERDATA) );
switch (msg) {
...
case WM_GL_MESSAGE:
{
::InvalidateRect( hWnd, NULL, FALSE );
processDefault = false;
result = TRUE;
}
break;
case WM_PAINT:
{
draw(hWnd);
::SetEvent( plugin->updateEvent() );
processDefault = false;
result = TRUE;
}
break;
...
}
if (processDefault && plugin && plugin->m_wndOldProc)
result = ::CallWindowProc(plugin->m_wndOldProc, hWnd, msg, wParam, lParam);
return result;
}
On some occasions, the host application still seems to miss messages. The main characteristics of the problem are that I have to press the 'Alt' key for modal dialogs to show up ; and I have to move the mouse to give some processing time to the host application !...
Is there any 'industry standard' solution for this kind of as-often-as-you-can animation repaint problem ?
Each thread has its own message queue, and messages sent to a window arrive in the queue of the thread that created the window. If you create your plugin window yourself, you can create it in a separate thread, and that way you will have complete control over its message pump.
An alternative solution (which imho is better), is to only have OpenGL rendering in a separate thread. All OpenGL calls must occur in the thread that created the OpenGL context. However, you can create a window in one thread (your application main thread), but create the OpenGL context in another thread. That way the original application message pumps stays intact, and in your rendering thread you can loop forever doing rendering (with calls to SwapBuffers to vsync).
The main problem with that second solution is that communication between the plugin WindowProc and the rendering loop must take into account threading (ie. use locks when accessing shared memory). However since the message pump is separate from rendering, it can be simultaneous, and your message handling is as responsive as it can get.