I'm a bit confused by the MSDN page for WM_PRINTCLIENT and related functionality in a few ways:
What value should I return from my window procedure? The documentation is missing a "Return value" section entirely. (It is also missing in the Visual Studio 2012 offline documentation disc's version of the page.) Raymond Chen's original scratch program returns zero; is this the preferred option?
The summary and Remarks section for WM_PRINTCLIENT indicates that I should only draw the client area, but the LPARAM lists all the possible WM_PRINT flags — so what should I do, ignore it and unconditionally draw just the client area or draw everything requested? (My intention with this question is not to second-guess the documentation; I'm just looking to implement this message correctly.)
I want to, as a convenience/kindness, provide the WM_PAINT with DC in wParam functionality mentioned in the WM_PAINT documentation as an option as well. How should I interpret LPARAM in this case? Or is there a reason I shouldn't provide this alternative route? (Corollary: if LPARAM is to be ignored, should I draw the entire client area unconditionally?)
Thanks.
Update Rephrasing the third part:
The documentation for WM_PAINT includes the paragraph
For some common controls, the default WM_PAINT message processing checks the wParam parameter. If wParam is non-NULL, the control assumes that the value is an HDC and paints using that device context.
I would like to provide this behavior in my control in addition to WM_PRINTCLIENT for completeness's sake. Is there a reason I should NOT do so? And if doing so wouldn't hurt, how should I interpret the lParam, and should I draw the entire client rect?
What value should I return from my window procedure?
You return 0 to indicate that the message was handled. Do not call DefWindowProc().
but the LPARAM lists all the possible WM_PRINT flags
That was a bit sloppy, a copy/paste fumble from the WM_PRINT article. The only flags you should test are PRF_ERASEBKGND, but only if you draw method requires having the background painted, and PRF_CLIENT, which will always be set in common usage of the message.
How should I interpret LPARAM in this case?
Hard to decode that question, WM_PAINT doesn't use the lparam argument. But yes, you want a common function that implements the painting so you can call it both from your WM_PAINT and your WM_PRINTCLIENT message handlers. Boilerplate code in your window procedure ought to look like:
case WM_PAINT: {
HDC hdc = BeginPaint(hWnd, &ps);
Draw(hdc);
EndPaint(hWnd, &ps);
break;
}
case WM_PRINTCLIENT: {
HDC hdc = (HDC)wParam;
DWORD flags = (DWORD)lParam;
if (flags & PRF_ERASEBKGND) SendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hdc, NULL);
if (flags & PRF_CLIENT) Draw(hdc);
break;
}
Where void Draw(HDC hdc) is your common paint function.
Related
I have a window which serves as an overlay, and only has some part of it non-transparent. The window has extended styles
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED
And the transparency is set with:
SetLayeredWindowAttributes(hwnd, RGB(255, 255, 255), 0, LWA_COLORKEY);
I do want to read the mouse events to implement the interactive part of the overlay.
So far i tried catching messages like
WM_MOUSEMOVE,
WM_KEYDOWN,
WM_NCLBUTTONDOWN,
in my WNDPROC and there they didn't fire. I assumed that was due to some of the window extended styles, and by removing one at a time i found out that it was layered window attribute which caused it. Sadly my app does depend on this attribute for its transparency.
Then i tried registering a windows hook for that very process and thread to intercept the mouse events. I don't know the internals of hooks at all - but i thought they get access to the messages before they enter the application's queue hence i hoped i could read them before whatever interferes passes them on. That didn't work sadly.
I registered the hook like so:
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetCurrentThreadId();
And the actual HOOKPROC was defined like this:
pub unsafe extern "system" fn HOOKPROC(ncode: c_int, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
println!("fired!");
CallNextHookEx(null_mut(), ncode, wparam, lparam)
}
Sadly this didn't output anything to STDOUT, but I do think that hook was registered as unhook function didn't return 0.
My next idea was to put the hook in the process which manages the previous window. However the below doesn't work.
app_state.hhook = SetWindowsHookExW(WH_MOUSE,
Some(Self::HOOKPROC),
GetModuleHandleW(null_mut()),
GetWindowThreadProcessId(
GetWindow(hwnd, GW_HWNDPREV), null_mut())
);
I think that it's due to the fact that i need to place the hook in a separate dll but event if it does work - this solution seem to be very dirty and will probably work in very few cases without requiring elevated privileges. What can i do to achieve the desired via accepted and cohesive code?
Just get rid of the WS_EX_TRANSPARENT style and use WS_EX_LAYERED by itself, and let the OS handle mouse input normally (no hook needed). Fully transparent pixels will fall-through as expected, and the window will receive input messages on non-transparent pixels.
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 am creating an application that can get text from the selected rectangle on any window. So I am doing this by hooking the ExtTextOut(A/W), TextOut(A/W), DrawText(A/W) apis.
I am able to retrieve the text from windows but in some special cases I am not able to get the text properly.
When I tried to debug it I saw that the HDC parameter of ExtTextOutW can not been used to get the HWND, because when I try to call WindowFromDC(hdc), it returns NULL HWND.
I tried to find out the reason then I found that this HDC is memoryDC so is there any way to get the HWND from that memory DC.
So Please somebody help me to get the actual HWND from the HDC.
I think you will have to follow that HDC as it is likely that it will be BitBlt(), or similar, to a HDC that is associated with an actual HWND:
cache the text written to memory HDCs
hook BitBlt(), and others, and check if the the source HDC of the BitBlt() is one of the memory HDCs that has had text written to it. If it is, check if the destination HDC has a HWND and if not then it is a memory HDC which must again be followed
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.)
CoInitialize(NULL) creates an STA by creating a hidden window. How to get an HWND handle for this window?
Function EnumThreadWindows does not work, in an example I tried:
...
CoInitialize(NULL);
EnumThreadWindows(GetCurrentThreadId(), EnumThreadWndProc, 0);
...
BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
m_hwnd = hwnd;
return FALSE;
}
Nothing ever enters the EnumThreadWndProc.
Any ideas?
This hidden window is Message-Only Window, It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
To find message-only windows, specify HWND_MESSAGE in the hwndParent parameter of the FindWindowEx function. In addition, FindWindowEx searches message-only windows as well as top-level windows if both the hwndParent and hwndChildAfter parameters are NULL.
Source:
MSDN
Btw, I would be VERY careful here - you really shouldn't be sending window messages to windows you don't own. Your code is highly likely to break in a future version of Windows.