Reputation: 41
I'm working on an application to detect a pop-up dialog and then automatically dismiss it. I'm writing this as a C++/Win32 app. The dialog box is generated by IE 7 and I can detect the window, but several methods to get the OK button to "click" have failed.
Doing searches for other people's solutions, sending these messages to the button handle seems to have worked in a lot of situations:
PostMessage( handle, WM_LBUTTONDOWN, 0, 0 );
PostMessage( handle, WM_LBUTTONUP, 0, 0 );
PostMessage( handle, BM_SETSTATE, 1, 0 );
It has no effect on the button state in my tests though.
I can send tab characters to the main window and see that the OK button gets focus, but then sending return characters does nothing.
To learn more about this I used Spy++ to get information about the window hierarchy and what messages are delievered when I manually click the OK button.
Looking at the message log and reading about WM_MOUSEACTIVATE seamed to offer a solution. The log info shows that 0002166C was the button window. So in my code I tried this:
GetClassNameA( handle, str, str_size );
if( strcmp( str, "Internet Explorer_Server" ) != 0 )
return TRUE; // Not the window we're interested in.
// Send a message to activate the button window and have it process a mouse click.
PostMessage( handle, WM_MOUSEACTIVATE, (WPARAM) dialog_handle, MAKELPARAM( HTCLIENT, WM_LBUTTONDOWN );
Based on the window hierarchy and message log, I think the window with the class name "Internet Explorer_Server" is the button. Maybe I'm wrong, because it does seem like an odd class name for a button...
Below is a link to the window hierarchy image, message log when I manually click the OK button. Last is the code that's executed on a 1 second timer ticket, looking for the window.
Any insight and help is appreciated!
Image of the window hierarchy, source, window messages, and test dialog source are available here:
https://sites.google.com/site/matthewmillersmiscellanea/Home/
Upvotes: 4
Views: 6932
Reputation: 301
To close continually a specific popup given that you know the window class name and window caption
#define UNICODE
#include <windows.h>
#pragma comment(lib, "user32")
int main (int nn, char ** aa)
{
while (true) {
HWND iHandle = FindWindow (L"theWindowClassName", L"theWindowCaption");
if (iHandle > 0) SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
Sleep (200); // check 5 times per second
}
return 0;
}
if one is not known or too generic (e.g. "Dialog") you can omit it by passing a null
HWND iHandle = FindWindow (L"theWindowClassName", 0);
or
HWND iHandle = FindWindow (0, L"theWindowCaption");
of course this will close all windows with the given names.
Upvotes: 2
Reputation: 4855
Ideally, you should create a DLL which exports a Global CBT Window Hook. This would allow you to get early notification when a dialog is going to be created. This would avoid the need to drain resources by constantly polling.
Once you've detected that a dialog is about to be created, you have two options:
1) Prevent the dialog creation.
I don't recommend this, it causes all sorts of problems with code that was fully expecting a valid HWND to be returned by CreateDialog();
2) Asynchronously control the dialog.
We achieved this by using PostMessage with a Registered user message and picking it up by hooking the WNDPROC. When you get this message, then you have to decide how to kill the dialog that you're in.
There are multiple ways to exit the dialog:
a) Simulate pressing OK, Cancel, Abort, No buttons using WM_COMMAND(BN_CLICKED) (as Chris comments). You can use GetDlgItem(), look for the WindowText and make your choice. However, this doesn't work for non-US-English. There may be some distance in leveraging the Accessibility API here though.
b) Simulate closing the dialog with PostMessage(WM_CLOSE, m_hWnd). This doesn't always work as expected - some dialogs have no [X] close button and their client code is expecting a specific button to be pressed instead.
c) Simulate user input using the SendInput() API. This worked around dialogs that had anti-popup-killer code in them :)
Our final solution was a rule+heuristic-based approach that had a configuration file which we could tweak when the app/IE dialogs changed their ID's, class names or parent class names.
Upvotes: 3