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.
Related
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
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.
It might be a simple question, but I don't know where to start the search for the answer. How do I create two individual windows interface in one application using native winapi? Do I put two CreateWindow() functions using same HINSTANCE? What if I want a login screen windows and the content page such that login screen comes first, and after I press the button, the login screen is destroyed, and the content page appears. How do I do such trick?
I was thinking of using DestroyWindow and then CreateWindow inside the button click message. However, this would mean the main while loop (for translate/dispatch msg) in WinMain will exit its loop and cause the whole program to exit. Another way is to pre-create it in WinMain, but how would I notify the WinMain if the button was clicked and enter the second loop instead of exiting the program?
You're over-thinking it. To create two windows, call CreateWindow twice. It's just that simple.
Calling DestroyWindow does not cause your program to exit its message pump. Calling PostQuitMessage is what does that. So don't do that.
When the button is clicked, destroy the one window and create the other. There are no tricks. The message pump delivers messages to all windows (unless you're doing it wrong by explicitly requesting messages for one window, but you shouldn't do that).
If my application crashes, I use an ExceptionFilter to catch the crash, perform some final actions, then show a message box to the user that the application has crashed.
Because the application already crashed, there's not much I can (or I dare) to do, because if I do too much, the executed code might access corrupted memory and crash again.
Some of the things I currently can't do (or I don't dare to do) is to close network connections, Oracle database sessions, ...
Problem is that if an application crashes, and the user is out to lunch while the MessageBox is open, other users might be blocked, because of the open database session. Therefore I want:
Either a MessageBox with a time-out. Problem is that you can't do this with the standard MessageBox Win32 API function, and I don't want to make a specific dialog for it (because I want to minimize the executed logic after the crash)
Or the possibility to close the MessageBox from another thread (the other thread can provide the time-out logic).
Did I overlook something in the Win32 API and is there a possibility to have a MessageBox with a time-out?
Or what is the correct way to close an open MessageBox from another thread (how to get the MessageBox handle, how to close it, ...)?
While I agree that spawning a new process to display a fire-and-forget dialog is probably best, FWIW there is actually a timeoutable messagebox function exported from user32 on XP & above; MessageBoxTimeout (as used by things like WShell.Popup())
Quick copy/paste solution:
int DU_MessageBoxTimeout(HWND hWnd, const WCHAR* sText, const WCHAR* sCaption, UINT uType, DWORD dwMilliseconds)
{
// Displays a message box, and dismisses it after the specified timeout.
typedef int(__stdcall *MSGBOXWAPI)(IN HWND hWnd, IN LPCWSTR lpText, IN LPCWSTR lpCaption, IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);
int iResult;
HMODULE hUser32 = LoadLibraryA("user32.dll");
if (hUser32)
{
auto MessageBoxTimeoutW = (MSGBOXWAPI)GetProcAddress(hUser32, "MessageBoxTimeoutW");
iResult = MessageBoxTimeoutW(hWnd, sText, sCaption, uType, 0, dwMilliseconds);
FreeLibrary(hUser32);
}
else
iResult = MessageBox(hWnd, sText, sCaption, uType); // oups, fallback to the standard function!
return iResult;
}
You should ask yourself, why you want a messagebox in the first place. When it is OK that the message box is not seen when noone is sitting in front of the computer, why isn't it OK that the user doesn't see a message when his program disappears?
If you really want it, I think the simplest solution is to spawn a new process displaying the message. It can run as long as it wants and does not interfer with your crashing program.
I noticed that if the main thread simply exits the application while the other thread still has the ::MessageBox open, that the MessageBox is being adopted by a process called CSRSS. This solves my problem, since this only requires a time-out on the Event in the main thread (WaitForSingleObject with timeout).
However, this raised another question: https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv.
This does not justify a thread.
The best solution would be to use a modal dialog box that registers a timer for auto-close.
What about just logging the event to a local file (and record memory dumps or whatever information you might need for later debugging)?
You could close your application, close network connections and do your housekeeping stuff.
As soon as the application is started again, you can inform your user (based on local file information) that the application has crashed during last execution.
A Win32 MessageBox really is a dialog, with a dialog message pump. You can therefore rely on standard Win32 timer messages (WM_TIMER). Send one to your own window, and when you do get it, dismiss the MessageBox by sending a WM_COMMAND/BN_CLICKED message to the ID_OK button.
The messagebox, since it's a dialog, will be class "#32770". Since it's the only dialog box you will have open, it's easy to find amongst your child windows.
I would run your original code from inside a wrapper application that does a CreateProcess and then a MsgWaitForMultipleObjects on the process handle (most process launching code samples use WaitForSingleObject, but you need to guard against messaging deadlock scenarios). Your watching process can then detect the failure of the spawned process, pop up its own timed-out dialog, and exit on user response or timeout.
I think that's the cleanest solution which prevents your unstable program having to execute any code.
I'm working on a win32 DialogBox based app. This uses DialogBox() to create the dialog box, and has a dialog box procedure which does all the usual things.
The dialog box has some static text controls on it, and generally I'm showing text in these via SendDlgItemMessage() from within the dialog box procedure.
However at one point the DialogBox initiates a lengthy operation. This operation has a callback with a series of status messages. I'm having some trouble showing these messages on the dialog box, for two reasons:
The callback function doesn't know what the dialog box HWND is, because it gets called from the code which carries out the lengthy operation. I suppose I can define a file scope HWND variable and copy the dialog box HWND into it from the dialog box procedure just before the lengthy operation is started. That way, the callback function could have access to the dialog box HWND. But that seems awfully kludgy: is there a more elegant way?
The dialog box procedure is blocked while the lengthy operation happens. This doesn't matter because it's an embedded system. But will Windows even show the text in the dialog box if I issue a SendDlgItemMessage() while the dialog box procedure is blocked?
edit I've done some investigations using SendDlgItemMessage() to send a WM_SETTEXT to a static text control on a dialog. The text is displayed immediately even if the dialog box procedure is blocked.
Well, your dialog HWND is a singleton so it isn't the end of the world. But yes, the standard way this is done is by passing an opaque pointer to the code that gets the job done. Compare with the lParam argument of EnumWindows() for example, the callback gets that pointer back.
Whether a control repaints itself immediately is an implementation detail. I only know of progress bar doing this. You could call UpdateWindow on the dialog window handle to get any pending paint updates flushed to the screen.
The all-around better mouse trap is to perform long running tasks on a worker thread. Avoids Windows displaying the "Not Responding" ghost window, avoids timeouts on broadcast messages and numerous potential deadlock problems. But tends to be tricky to get right, you cannot update the window directly from the worker thread.