Just by processing the WM_SIZE message, is it possible to know if the window was restored from a minimized state ?
No it is not -
wParam will be SIZE_RESTORED (0)
and lParam will have the new size of the window.
Unless you stored in the window when it was minimized, you will not be able to know when it is restored from this message alone.
Not directly from the current parameters.
But if you store the parameters passed to WM_SIZE every time you receive the message, then you just check whether the last parameter passed was a SIZE_MINIMIZED.
Will the GetWindowPlacement Function work?
Retrieves the show state and the restored, minimized, and maximized positions of the specified window.
Related
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.
I'm a bit confused currently: Are WM_CLOSE and ::CloseWindow in any way "related" or are for completely different things?
The docs for Closing Windows don't mention the API function CloseWindow at all. Should CloseWindow be really called "MinimizeWindow" or what am I missing?
CloseWindow and WM_CLOSE are completely unrelated. The CloseWindow function is badly named. Its inverse function, OpenWindow is similarly badly named given that it restores windows.
I suspect these names dates back a very long way indeed, probably to Windows version 1 or 2. I'm speculating that what we now call minimize and restore were, back then, called close and open.
The usual way to minimize or restore a window is to call ShowWindow passing SW_MINIMIZE or SW_RESTORE.
I suggest that you forget all about CloseWindow and OpenWindow.
CloseWindow is an unusually poorly named winapi function. It doesn't actually close a window, it just minimizes it. What you possibly meant was DestroyWindow().
WM_CLOSE is normally a message that's generated by default window procedure, in response to the user pressing Alt+F4 or clicking the window's close button. The underlying message is WM_SYSCOMMAND, SC_CLOSE. It can be generated in code as well, like a Window + Close menu item.
You can listen for WM_CLOSE in your window procedure or the MFC message map. The user will expect the window to be closed. So you normally call DestroyWindow(). You don't have to, you might display a message box for example and ask the user if data should be saved. And if he clicks No then you don't call DestroyWindow().
I would say ignore CloseWindow and OpenWindow() for the reasons the previous poster suggested. However, while technically doable, it is considered bad form to handle whether to save or actually destroy a window (ie prompting the user) during WM_DESTROY. Once DestroyWindow is called and the OS sends a WM_DESTROY message, the expectation is to prepare for the destruction of the window. So the workflow should have be like this:
Send a WM_CLOSE to the window handle in question. CloseWindow SHOULD do this, like DestroyWindow sends a WM_DESTROY message or ShowWindow sends a WM_SHOWWINDOW message. But again, since it doesn't, send the WM_CLOSE to the window.
Next, during the processing of the WM_CLOSE message, you can ask the user if they wish to save anything, or if they intend to actually close the window. If they cancel closing the window, simply return ZERO to tell the OS you processed the message. If the user indicates they wish to proceed, THEN you can call DestroyWindow OR simply pass the message to DefWindowProc, which the promptly do the same. Any saving of files should happen during the processing of WM_CLOSE. During the processing of WM_DESTROY, you should delete any dynamically allocated memory associated with the window and free resources. And finally FYI, WM_NCDESTROY is the last message a window receives.
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.
I know that WM_PAINT tells a window that it needs to repaint itself entirely, but apparently that's not the message that gets sent when it's been covered partially and then the window that was in front of it is no longer in the way and it needs to repaint the dirty portion. Does anyone know what message is sent in this case?
EDIT: Found the problem:
The issue involved a Delphi control I wrote to embed a SDL rendering surface on a Delphi form. SDL has an API to build its renderer on another window's HWND, and it marks it as a "foreign window".
SDL usually handles WM_PAINT internally, so I ended up having to add some code to SDL's WindowProc to forward the message on to the external WindowProc if it's a foreign window. That was working sometimes, but it turns out there was a glitch that was stripping the foreign window flag from the window's data structure, so it was swallowing the message instead of passing it on to my app. Once I fixed that, I started getting the WM_PAINT messages all the time.
Why do you say it's apparently not? WM_PAINT should be called for partial redraws (the updated rect is returned by BeginPaint or GetUpdateRect). If it doesn't appear to be getting called, there may be a bug elsewhere in your app that's preventing it. What are you seeing that leads you to believe that it's not working?
WM_PAINT is sent to indicate that some portion (including the entirity) of the window needs to be repainted.
Call GetUpdateRect() to get a rectangle that bounds the region to be updated. This information is also included in the PAINTSTRUCT (as the rcPaint field) passed to BeginPaint().
The BeginPaint() function returns the rect that requires validation in its 2nd parameter: http://msdn.microsoft.com/en-us/library/dd183362(VS.85).aspx
case WM_PAINT:
{
PAINTSTRUCT psPaint;
HDC hdc = BeginPaint( hwnd, &psPaint );
// psPaint.rcPaint contains invalidated area
EndPaint (hwnd, &psPaint);
}
return 0;
Look at psPaint.rcPaint : http://msdn.microsoft.com/en-us/library/dd162768(VS.85).aspx
I'm pretty certain the Win32 API uses WM_PAINT even for partial repaints. From MSDN:
The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window. [My italics].
That link has the full detail on WM_PAINT but if, as you say, the WM_PAINT message is not being sent for partial redraws, the Spy++ is the tool you need to find out for sure.
Take a look at WM_PRINTCLIENT. There are some circumstances when WM_PAINT is not sent and a WM_PRINTCLIENT message is sent instead. (AnimateWindow for example.)
In handling a WM_GETMINMAXINFO message, I attempt to alter the parameter MINMAXINFO structure by changing the ptMaxSize. It doesn't seem to have any effect. When I receive the WM_SIZE message, I always get the same value, no matter whether I increase or decrease the ptMaxSize in the WM_GETMINMAXINFO.
Are you sure your window is maximized? As per http://msdn.microsoft.com/en-us/library/ms632605(VS.85).aspx, MINMAXINFO::ptMaxSize controls the maximum size of the window wen maximized.
If you want to control the maximum tracking size of your window (the maximum size when the window is normal), you need to modify MINMAXINFO::ptMaxTrackSize.
Make sure you are handling the WM_GETMINMAXINFO message in the window procedure of the main application.
The message only makes sense when handled by the main frame window and will have no effect if the message is handled by one of the child window procedures.
A window must have the WS_THICKFRAME or WS_CAPTION style to receive WM_GETMINMAXINFO.
This is basically all you need to know.