WinApi capturing messages in default proc is not "definitive"? - winapi

I can disable window movement by doing this in the message loop:
case WM_MOVING:
GetWindowRect(hWnd, (RECT*)lParam);
break;
This, however does not work if you remove the call to GetWindowRect(). Why ?
This looks like the message loop is only modifying the message in passing (WM_MOVING.lParam points to the destination RECT of the movement). The message still gets processed (by the system ?). Just doing a break; does not throw away the message, the window is movable.
The message is processed no matter what (even if you don't call DefWindowProc() on it), you can just set its lParam so that the window goes back to its initial position. Is there no way to discard the message completely ? And who's doing the processing ? (obviously, the system is, is there a ubiquitous DefWindowProc() up there in the sky - that you cannot turn off- ?)
What is exactly going on ?

WM_MOVING is one of calbacks done inside callig SetWindowPos. Window is moved after returnig from callback, and after finally moving window next is send WM_MOVE. There are also WM_NCCALCSIZE, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGE, WM_GETMINMAXINFO, WM_SIZING, WM_SIZE.
Some messages when routed to DefWindowProc do real work (for example WM_NCPAINT, WM_ERASEBKGND), some are used for gathering information for further processing (WM_NCHITTEST, WM_GETMINMAXINFO), some are used for notifying you about changes (WM_MOVING, WM_MOVE, WM_SETTINGCHANGE) or actions (WM_COMMAND, WM_LBUTTONDOWN). It is recommended that when you don't process message, you should route it through DefWindowProc. If you fail to do this for some messages that wouldn't have any effect, but for others you will miss essential functionality.
For modifying interactive moving or sizing of a window, WM_NCHITTEST is a good choice. You can disable default action activated by part of window, or implement selected action on any part of the window.
case WM_NCHITTEST:
{
LRESULT r = DefWindowProc( hwnd, msg, wparam, lparam );
if ( r == HTCAPTION )
r = HTNOWHERE;
return r;
}
Or try bellow code and see what happens when left or top border is dragged.
case WM_NCHITTEST:
{
LRESULT r = DefWindowProc( hwnd, msg, wparam, lparam );
if ( r == HTLEFT )
r = HTTOP;
else if ( r == HTTOP )
r = HTLEFT;
return r;
}

The "Window Procedures" doc says:
For example, the system defines a window procedure for the combo box
class (COMBOBOX); all combo boxes then use that window procedure
I imagine that procedure belongs with the system (the appropriate system DLL, comctl32.dll I guess, unless you subclass it), but it executes in the app thread of course (after it loads that DLL). What that excerpt, and the apparent behavior suggest is the following:
If the style you select requires a title bar, a title bar window (a
system facility) is instantiated for your app, with its own
windowProc, let's say "sysTtlBarProc".
When you try to move this window,
messages (system-created, starting from the input driver) are sent to
both your app's windowProc() and to sysTtlBarProc()
sysTtlBarProc() waits on your windowProc() (which can call DefWindowProc() or not) to return before acting on the message
This would explain the behavior: this protocol gives your windowProc() a chance to act (on its own) and/or modify the message, thus potentially modifying sysTtlBarProc's behavior. This is just a general concept, some messages I guess are purely informative (you can't change sysTtlBarProc's behavior for these), you can only monitor what's happening, and do something of your own next to what sysTtlBarProc() does.
This can easily be demonstrated by doing this :
case WM_SIZING:
case WM_MOVING:
Sleep(1000);
break;
You can then try and move/resize the window and watch the new "sluggish" behavior. Whoever is processing those two WM_SIZING/MOVING messages (you're not calling DefWinProc(), and you're not doing anything with the messages) is definitely delaying his work by a second now.

Related

Child windows does not receive WM_DESTROY?

I packaged the winapi CreateWindowEx into a simple class. Since every window sharing a same wndProc(hwnd,msg,wparam,lparam), I put every window created by CreateWindowEx into a map to distribute msg, like this:
wndProc(hwnd, msg, wparam, lparam){
if(map[hwnd]!=nil){
switch(msg){
map[hwnd].wndProc(...)
}
}
}
And each time a window or its parent window being destroyed, remove it from the map:
case WM_DESTROY: delete(map, hwnd)
But things like buttons do not receive WM_DESTROY. I printed all msg in WM_NOTIFY and WM_COMMAND but i got noting.
So how can I remove those child windows form the map at the right time? Or a way distribute the msg without creating a hwnd map?
They certainly do get that message. But their window procedure is inside Windows, not inside your program. So you never see it. Something you can read in the MSDN documentation, note how WM_DESTROY doesn't get any special treatment. Nor generate a notification that your parent window can see.
Short from automatically removing all the child windows when you see the parent window destroyed, subclassing controls is a pretty standard requirement for C++ class library wrappers. Best to not invent your own btw, this has been done many times already.
So how can I remove those child windows form the map at the right time?
You have to subclass every window you create, either with SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubClass(), then you will receive all of the WM_DESTROY messages.
Or a way distribute the msg without creating a hwnd map?
Frameworks like ATL and VCL handle that by dynamically allocating a thunk for each window and putting the object pointer right in the thunk, then use the thunk as the window procedure. That way, whenever the thunk is called, it passes the message directly to its associated object.

Sending WM_HSCROLL to other program

Im trying to scroll other program (PowerPoint 2013) by sending WM_HSCROLL,
and it will work only if I offer the correct LPARAM (not NULL) to SendMessage.
The value of LPARAM is dynamic, it will change if you close and open a new program.
Now I can only get its value by hooking WM_HSCROLL and clicking scroll bar manually.
// This is my code:
LPARAM lParam = 0x0a616c38; // Found by hooking WM_HSCROLL
SendMessage(hTarget, WM_HSCROLL, SB_LINERIGHT, lParam);
So is it possible to get the correct LPARAM programatically?
Many thanks!
p.s. The scroll bar is not a real window in PowerPoint 2013.
p.s. It returns 1 if I use GetScrollInfo(hTarget, SB_CTL, &scrollinfo), but all values inside scrollinfo are zero.
p.s. Office Home and Student 2013 Official Site
Did you try to call GetLastError?
GetScrollInfo will probably not work across process boundaries, so I would say that's why you're not getting valid values back.
The lParam value of a WM_HSCROLL message is either NULL for the standard window scroll bar, or the handle of the scroll control. The handle of the scroll control will obviously change every time the program is run, so you need to find that out yourself before you can reliably simulate scroll input.
To do this, you can use the FindWindowEx function to search the parent window (hTarget in your example) for child windows of class "SCROLLBAR". As you will probably find more than one scrollbar child window you'll need some way to tell them apart - most probably, via the window's GWL_ID value as this will probably not change from run to run.

SendInput after EnableWindow in Windows 7

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);

How can I stop window rendering and later resume?

I'd like to prevent my window from being updated until I finish receiving data from the server and render it. Can I hook on the WM_PAINT event, or better still call some Win32API method to prevent the window from being updated and unfreeze it later?
More info:
In the context of an MMC snapin written in C#, our application suffers from annoying flickering and double sorting behaviour:
We use MMC's listViews, but since we subscribe to the sort event.
MMC does it's own magic and sorts the page being displayed (and we can't override that), and when we receive a reply from our server we change the listView again.
each row change is done sequentially, there's no beginUpdate etc. (AFAIK).
Normally hooking into WM_PAINT is the way to go, but make sure you also ignore all WM_ERASEBKGND notifcations, otherwise you'll still get flicker, because Windows erases the Windows area for you. (Return non-zero to prevent Windows from doing that)
One other possibility is to use the LockWindowUpdate function, but it has some drawbacks:
Only one window can be locked
Upon unlock the whole desktop and all sub-windows (i.e. everything) is repainted, resulting in short flash of the whole desktop. (It's worse on XP than on Vista)
Some controls have BeginUpdate and EndUpdate APIs for this purpose.
If you do something (e.g. hook and ignore paint events) do disable painting, then a way to force a repaint later is to call the Invalidate method.
OK, after all searching and checking I've found that LockUpdateWindow is bad idea - see for example articles of Raimond Chen OldNewThing. But even to implement the idea of SetRedrawWindow wasn't so simple - because what I had was only received from IConsole2* pConsole->GetMainWindow() HWND handler of main window. By setting it to SetRedraw = FALSE it was disappeared in very strange manner. Though to make the procedure run only for the TreeView and not for the whole application (ours left panel) I ran
EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw
where SetChildRedraw callback was defined in next way:
#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam)
{
RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
DECLARE_STRING(sText)
GetClassName(hwndChild, sText, MAX_PATH);
if (wcsstr(sText, L"SysTreeView32") != NULL)
{
SetWindowRedraw(hwndChild, lParam);
if (lParam == TRUE)
{
GetWindowRect(hwndChild, &rcChildRect);
InvalidateRect(hwndChild, &rcChildRect, TRUE);
}
}
return TRUE;
}

How can I tell if a window has focus? (Win32 API)

Using the Win32 API (in C, but that's inconsequential), how can I tell if a given window (identified by HWND) has focus?
I'm hooking an application watching for an event, and when that event occurs I want to check if the application already has focus. If it doesn't, I want to flash the window until they give focus to it.
Alternately, does the FlashWindowEx struct flag FLASHW_TIMERNOFG that flashes until the window has focus just not flash if the window already has focus?
I cannot test this now since I am not in my development environment, but I was under the impression that it would flash anyways, which is what I'm trying to avoid.
Also, if it matters, the application uses DirectX in this window.
GetActiveWindow will return the top-level window that is associated with the input focus. GetFocus will return the handle of the window that has the input focus.
This article might help:
http://www.microsoft.com/msj/0397/Win32/Win320397.aspx
Besides gkrogers answer using GetActiveWindow, you can also maintain a boolean variable for the window you want to know if it has focus or not by trapping the WM_SETFOCUS and WM_KILLFOCUS events, or WM_ACTIVATE:
WndProc() ..
case WM_SETFOCUS:
puts( "Got the focus" ) ;
break ;
case WM_KILLFOCUS:
puts( "Lost the focus" ) ;
break;
case WM_ACTIVATE:
if( LOWORD(wparam) == WA_INACTIVE )
puts( "I AM NOW INACTIVE." ) ;
else // WA_ACTIVE or WA_CLICKACTIVE
puts( "MEGAZORD ACTIVATED kew kew kew (flashy-eyes)" ) ;
break ;
Do you really mean "focus" or do you mean "active?"
One window has the focus -- the one that's first in line to get keyboard events. The outer window (that the user can drag around the screen) is "active" if one of its subwindows has the focus, but it might or might not have focus itself.
Use GetForegroundWindow function to get the Hwnd that you are focusing right now. Then you just need to compare it to the window of your application to check whether it contains focus or not.
For multiple modeless children:
Within the child you could save the focus, 13/08/2019 Visual Studio 2017.
You can save the focus so the parent knows which modeless child was clicked on.
In the child's callback handler:
case WM_CHILDACTIVATE: // Only gets called when the child border is click on.
//CurrentFocus = hDlg; // Example: can save the focus globally for parent usage.
//Beep(2000, 250); // So you can test
break;
case WM_GETMINMAXINFO: // Gets called when child window is being moved or sized.
//Beep(2000, 250);
break;
case WM_LBUTTONDOWN: // Only called when cursor is inside the child client area
//CurrentFocus = hDlg; // Following the focus.
//Beep(2000, 250);
break;

Resources