I'm trying to send BM_CLICK to a window in another process.
When the target button get clicked, the target window pops up a modal dialog, then my calling thread never return even I send the timeout to 1 second.
SendMessageTimeout(handle, BM_CLICK, 0, 0, SMTO_ABORTIFHUNG | SMTO_NORMAL, 1000, NULL);
What's the reason of this? Is there any idea I can prevent this?
There are some potential solutions:
Use PostMessage with WM_LBUTTONDOWN and WM_LBUTTONUP to simulate the click
If I remember correctly, PostMessage doesn't support BM_CLICK, isn't it?
Related
I know this sounds evil but my intention is not this at all.
A user has clicked "delay shot" and a countdown starts, during that time they go focus another application, then after countdown user expects my app to take back focus.
SetForegroundWindow fails when it runs from appliction with PID X while application with PID Y is focused.
This worked to bring my window forward, but it doesn't get focus:
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
It sets the window to be always on top. However focus is not put into my window. And then setting it back to HWND_NOTOPMOST leaves it there, even though its not top most, but it still doesnt have focus. Running SetForegroundWindow won't do the trick after these calls to SetWindowPos Is there anyway to steal focus?
I have tried a combination of:
SwitchToThisWindow
SetWindowPos
ShowWindow
SetForegroundWindow
But can't seem to figure it out.
Another reason I think this has to be possible is because Mac OSX allows it with NSApplication activateIgnoringOtherApps: and Linux's allow it too. I'd like to get this cross platform.
As a last resort I was going to use the HWND_TOPMOST method, then GetWindowRect then SetCursorPos and send single click to my window at pos 0,0, I really don't want to though as there might be something at 0,0 and it shouldn't be auto clicked on.
This always works, no matter what app is in foreground (like Task Manager, etc.):
AllocConsole();
auto hWndConsole = GetConsoleWindow();
SetWindowPos(hWndConsole, 0, 0, 0, 0, 0, SWP_NOZORDER);
FreeConsole();
SetForegroundWindow(hWnd);
As the comment says, SetForegroundWindow is sometimes useless intentionally. Basically, two ways are used to bypass restrictions:
Simulate keyboards / mouses
Get privileges
There is some smarter magic to achieve the goal without directly clicking the window you are going to activate. Since I'm not familiar with GUI, I would suggest inject code directly into current foreground window and hand over the foreground right.
Besides there're some examples on simulating.
http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo.aspx
I'm using the win32sdk, but some messages would never work as expected while mouse was captured by calling SetCapture(), such as:
case WM_LBUTTONDOWN:
SetCapture(hWnd);
SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
ReleaseCapture();
return 0;
The Window won't be maximized. but why?
Additional,
1. if I use PostMessage() instead, it works.
2. if I use PostMessage() instead and remove the ReleaseCapture(); statement, it doesn't work again.
In general:
PostMessage is asynchronous and you call ReleaseCapture() before WM_SYSCOMMAND is processed. So you have only one question: Why you can't maximize if mouse is captured?
I haven't found any info on this but read here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646262(v=vs.85).aspx
"When the mouse is captured, menu hotkeys and other keyboard accelerators do not work." I suppose WM_SYSCOMMAND is not processed also because of this restriction. May be it was done like this to keep coords consistent.
As norekhov said menu hotkeys don't work when the mouse is captured. When the mouse is captured the the only action a user can take that will result in the WM_SYSCOMMAND message being sent is to use a system menu hotkey.
Note that the WM_SYSCOMMAND message is only meant to be used to notify a window of a user initiated action. When you send it to a window, you're in essence trying to mimic a user's action. In this case you don't need to do this. You can tell the window to maximize itself directly:
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
In this case it won't appear to be a user command, so it won't be ignored because the mouse has been captured.
I'm handling ESC key in my application and when this key is received I wish to close the current window.
Should I simply call DestroyWindow(hWnd) or should I SendMessage(WM_CLOSE, hWnd, 0, 0), or should I be closing the current window in some different way?
You should PostMessage(hWnd, WM_CLOSE, 0, 0). It puts the WM_CLOSE message into the window's message queue for processing, and the window can close properly as the message queue is cleared.
You should use PostMessage instead of SendMessage. The difference is that PostMessage simply puts the message into the message queue and returns; SendMessage waits for a response from the window, and you don't need to do that in the case of WM_CLOSE.
It is up to you which you use. Should the Esc key act just like clicking the close button, or should it definitely destroy the window?
The default implementation of WM_CLOSE (as found in DefWindowProc) calls DestroyWindow, so if you're not handling WM_CLOSE specifically then one is as good as another. But WM_CLOSE doesn't necessarily have to call DestroyWindow, though, so if the window in question handles it then it could do something else. For example, it could pop up a "Are you sure?"-type message box, or simply do nothing. DestroyWindow will bypass all of that.
Either PostMessage or SendMessage WM_CLOSE
I'm writing a small Windows application in Visual C++ without MVC. Its really small, it just contains one textfield, an OK-Button and an Cancel-Button.
The application is started by a background-process when user starts printing. When opening the application doesn't get focus, isn't even visible.
For the user it's importend that the application is directly in focus, so they have as lease clicks as possible to use it.
I tried many many things to get the application in focus:
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hWnd);
ShowWindow(hWnd, SW_RESTORE);
SetFocus(hWnd);
I even repeated this calls in a timer. All of this doesn't work. Now I found some remarks on MSDN:
The system restricts which processes can set the foreground window. A
process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
Anybody knows a workaround for this?
There is no workaround for this. The whole point of this new Windows behavior is to prevent applications from bringing themselves to the foreground on their own and being a nuisance. In your case, I would suggest using a notification icon and showing a balloon message when necessary instead of a window. However, even in this case your notification icon can be hidden by the user and there is no workaround, for the same reason as above.
Now, this is coming from a Java developer and not a Visual C++ developer, but can you maybe set the frame/window/whatever-its-called-in-visual-c to be always on top? In Java, if you have a JFrame, say myJFrame, you can call myJFrame.setAlwaysOnTop(true) and it stays on top of all other windows. This seems to be a simple workaround to your problem, however it may not be desirable for the user if it's blocking something of theirs on screen.
http://www.thescarms.com/vbasic/alttab.aspx seems to do the job
void forceToFront(HWND hWnd) {
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow == hWnd) {
// Window is already Foreground-window
return;
}
if (SetForegroundWindow(hWnd)) {
// could set window to foreground without any tricks
return;
}
// attach thread of foreground-window to this window
DWORD foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL);
DWORD myThread = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(foregroundThread, myThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, myThread, false);
}
I have a child window that is maximized within a parent.
It needs to be disabled so that it doesn't receive inputs until I press a key.
When I press key 'A' for instance, I want the child window to be enabled, receive inputs sent with SendInput() and disable again.
So I do this:
EnableWindow( hwnd, TRUE );
SetForegroundWindow( hwnd);
SetFocus( hwnd);
Sleep(50);
SendInput()...x7-8 times
EnableWindow( hwnd, FALSE );
Now, EnableWindow functions work fine, except window misses some of the inputs. I tried to put some delay after EnableWindow (like 6-7 seconds!!) and still it doesn't work right.
I tried SetWindowPos() to have it update its frame, I tried setting the WS_DISABLE bit manually but still no luck. Inputs work fine if the child window is enabled all the time.
Any help is appreciated.
A Child window is serviced by the same thread as it's parent window. So the send SendInput doesn't do any good unless you go back to the pump and handle the events before you disable the window again.
If you explain what you are trying to accomplish, we could probably give you a better way to do it. But in any case, at the very least you need to run a message pump after SendEvents until you run out of events.
Be aware the a pump will also pump other messages, so it may make your whole design fall over. But, here it is.
// process messages until the queue is empty.
//
MSG msg;
while (PeekMessage(&msg, NULL, 0, PM_REMOVE))
{
// make sure we don't eat the quit message.
if (WM_QUIT == msg.message)
{
PostQuitMessage();
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Oh, and the Sleep() isn't doing anything useful, you can take it out.
Edit: this code goes after the SendInput call and before the window is disabled.
You may also want to use it instead of Sleep() to get the window to settle down before
you SendInput.
Instead of SendInput, I would try sending keyboard or mouse messages directly to the child window. For example:
EnableWindow(hwnd, TRUE);
SendMessage(hwnd, WM_KEYDOWN, ..., ...);
SendMessage(hwnd, WM_KEYUP, ..., ...);
// etc...
EnableWindow(hwnd, FALSE);