Programmatically closing a dialog box - win32 - c++

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/

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.

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.

Related

Close OleCreatePropertyFrame externally

I am using OleCreatePropertyFrame to display property pages of the webcam. But, I wasn't able to make the dialog modal or close the frame externally when closing the camera.
OleCreatePropertyFrame(
NULL, // Parent window
0, 0, // Reserved
lpcostr, // Caption for the dialog box
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
Any help is appreciated.
OleCreatePropertyFrame is standard API for modal dialog box meaning that it is supposed that the mesasge box is displayed until closed interactively. That is, you are not supposed to be able to close it from code.
This function always creates a modal dialog box and does not return until the dialog box is closed.
One of the ways to make the dialog modal is to re-implement property page host (IPropertyPage and friends) and put it into your customized UI as a modeless window or otherwise. It is quite doable overall, and mostly expects basic knowledge of COM.
Another [traditional?] trick to close standard modal UI externally is to PostQuitMessage into the inner message loop of OleCreatePropertyFrame API so that it closes the dialog box in response to non-interactive signal, and then remove pending WM_QUIT message from the outer message loop, added by the API after closing the dialog in attempt to forward quit command further.

Win32 API: App Freezes after opening dialog window

I am trying to open "Open File Dialog" of an already opened notepad app on a button click event with win32 API. Here is the code:
void onButonClicked()
{
HWND hWnd = ::FindWindow(NULL, L"Untitled - Notepad");
HMENU hWndMenu = ::GetMenu(hWnd);
HMENU hWndSubMenu = ::GetSubMenu(hWndMenu, 0);
SendMessage(hWnd, WM_COMMAND, GetMenuItemID(hWndSubMenu, 1), 0);
}
This works fine and opens the "Open Dialog". But it freezes my app. If I try to move my app window with mouse, it hangs and shows "Not Responding" on title bar. I have also tried opening this dialog window in a separate thread, but no luck. How to solve this issue?
The code you show us looks like you want to control NOTEPAD:
The reason why it blocks is simple. SendMessage send the WM_COMMAND message to NOTEPAD and waits until it is processed. Notpad itself receives the WM_COMMAND message and shows it file open dialog and waits for the user input.
This is all done inside the handling of the WM_COMMAND message and SendMessage will only return when this handling is done. So either the user aborts the dialog, or he selects a file and the file gets opened.
PS: Your question is not detailed enough what yo really want to do.
In the comments you state:
I want to open a file with win32 code without user intervention.
In that case your entire approach is wrong. Pass the name of the file to ShellExecuteEx, and let the system open the file.
As for why your current code blocks, that's simple enough. SendMessage is synchronous and only returns once the message has been processed. And the message processing completes when the modal file dialog is closed. But hacking away at Notepad in this manner is never the correct solution to a problem. Please refrain.
To prevent your program from hanging, you can use PostMessage instead of SendMessage:
PostMessage(hWnd, WM_COMMAND, GetMenuItemID(hWndSubMenu, 1), 0);
You may want to further study the difference: What is the difference between Send Message and Post Message and how these relate to C# ,WPF and Pure windows programming?
In general there is a very big difference between SendMessage and PostMessage in the windows API.
SendMessage will run the associated callback (i.e. the thing supposed to receive the message) directly and return after the message has been completely processed. This is 'blocking' your app because notepad only returns from this call after the (modal) file dialog has returned.
PostMessage will add a message to the applications message queue and return immediately; at some later point the application (notepad) will process this message.
All of this said what you are doing is probably not a good idea - this kind of remote control of other applications raises some serious security concerns.

Prevent window movement

I currently have a small game which runs in a win32 window. I just noticed that when I hold the top of the window (the bar which has the closing button) it freezes my application. I would like to disable this as it manages to completely destroy my application (timers continue to count).
It seems that with even the most minimalistic settings for creation of the window it still has this feature. How can I disable this? I currently have:
HWND hWnd = CreateWindowW( L"Game",L"Game",
0x00000000L | 0x00080000L,
wr.left,
wr.top,
wr.right-wr.left,
wr.bottom-wr.top,
NULL,
NULL,
wc.hInstance,
NULL );
I read that my thread is ignored while dragging, if I am forced into using 2 threads could someone please provide a small example of usage?
Or should I stop the timers? (what message should I catch, and would it even be catched?)
Update
I am using instances of my time class to handle timings which looks something like:
Timer::Timer() {
__int64 frequency;
QueryPerformanceFrequency( (LARGE_INTEGER*)&frequency );
invFreqMilli = 1.0f / (float)((double)frequency / 1000.0);
StartWatch();
}
void Timer::StartWatch() {
startCount = 0;
currentCount = 0;
watchStopped = false;
QueryPerformanceCounter( (LARGE_INTEGER*)&startCount );
}
My Win32 message loop contains: mousemove, keyup and keydown.
When DefWindowProc handles WM_SYSCOMMAND with either SC_MOVE or SC_SIZE in the wParam, it enters a loop until the user stops it by releasing the mouse button, or pressing either enter or escape. It does this because it allows the program to render both the client area (where your widgets or game or whatever is drawn) and the borders and caption area by handling WM_PAINT and WM_NCPAINT messages (you should still receive these events in your Window Procedure).
It works fine for normal Windows apps, which do most of their processing inside of their Window Procedure as a result of receiving messages. It only effects programs which do processing outside of the Window Procedure, such as games (which are usually fullscreen and not affected anyway).
However, there is a way around it: handle WM_SYSCOMMAND yourself, resize or move yourself. This requires a good deal of effort, but may prove to be worth it. Alternatively, you could use setjmp/longjmp to escape from the Window Procedure when WM_SIZING is sent, or Windows Fibers along the same lines; these are hackish solutions though.
I solved it (using the first method) this past weekend, if you're interested I have released the code to the public domain on sourceforge. Just make sure to read the README, especially the caveat section. Here it is: https://sourceforge.net/projects/win32loopl/
Since the title bar to the user that he/she can move the window, you could remove that title bar and borders altogether. See "opening a window that has no title bar with win32" for an example.
When the game launches or is paused, you could show your own UI elements to allow the user to move the game window in these specific situations but only then.
You can check for the size/move loop using the WM_ENTERSIZEMOVE and WM_EXITSIZEMOVE messages.

How to close a MessageBox window by its handle with C++

I have a multi-threaded application that may display a MessageBox for a user's interaction. The message box itself is displayed from a worker thread, after a user picks a context menu command from the app's system tray icon, so the user can technically continue using the app while the message box is displayed. This works great until a user issues "Exit" command, at which point I need to find a way to close any open message boxes.
I did my homework and I was able to obtain HWND handle for the main (dialog) window of the message box (using this method.) I checked the HWND to be correct using Spy++, so HWND itself is not the issue. What happens is that when I do PostMessage(hMsgBoxWnd, WM_CLOSE, 0, 0); from another thread to the message box, it simply ignores this message and doesn't close.
Any idea how to close the message-box by its window handle?
MessageBox() simply does not process WM_CLOSE in all sitations:
SendMessage/PostMessage WM_CLOSE to MessageBox window does not always work
You should use PostThreadMessage to post to the threads specific message queue

C++/Win32 API - SetFocus to button does not work

HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.