I am working on Win32 UI. I want to know the difference Between GetDC and BeginPaint. When to Use which API and when not to use which API.
GetDC simply returns the handle to the device context, which can be used any time anywhere to do your own drawing. BeginPaint on the other hand prepares the window for painting, and also provides information on what should be painted (such as whether the background needs repainting and the rect that needs to be painted).
Examples of when to use each? BeginPaint is most commonly seen inside WM_PAINT handlers (MSDN: An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.). GetDC can be used anywhere, so if you want to draw on an external window. Basically anytime thats not in a WM_PAINT handler. BeginPaint and EndPaint also have some affect on the caret. Read msdn for more details.
GetDC() is not a substitute for Begin+EndPaint(). If you try, you'll find that your UI thread starts to burn 100% cpu core and your WM_PAINT handler getting called over and over again.
The big one is BeginPaint(), it clears the update region of the window. The value of PAINTSTRUCT.rcPaint. WM_PAINT is generated as long as the window has a dirty rectangle, created by an InvalidateRect() call by either the window manager or your program explicitly calling it. BeginPaint() clears it.
BeginPaint is intended to be called only in response to WM_PAINT message. The device context obtained by it points to the invalidated (to-be-redrawn) area of the window. It should be then released using EndPaint.
GetDC can be called at any time. The device context obtained by it points to the whole client area of the window. To release it, you should call ReleaseDC.
Related
I need to know if it is safe to store some calculated non-client area RECT (not the window rect neither the client one, it is a based on some calculation) from the WM_NCCALCSIZE message and use it later in the WM_NCPAINT without the need to do the whole recalculation process again in WM_NCPAINT!?
i.e. is WM_NCPAINT always called immediately after WM_NCCALCSIZE?
I need to save the hassle of doing the recalculation process in WM_NCPAINT message, because DefWindowProc from WM_NCCALCSIZE already does all what I need to start my calculations based on what it does.
TIA.
i.e. is WM_NCPAINT always called immediately after WM_NCCALCSIZE?
I test this sample which provided by krsi, we can find that WM_NCCALCSIZE is always called before WM_NCPAINT, but this does not mean that no other messages were called in the middle. For example, when testing, after receiving WM_NCCALCSIZE, WM_PAINT will be called first, and then WM_NCPAINT will be called.
You seem to be customizing the non-client area, I think you can first read Nonclient Area.
In general, processing these messages for standard windows is not
recommended, because the application must be able to draw all the
required parts of the nonclient area for the window. For this reason,
most applications pass these messages to DefWindowProc for default
processing.
An application that creates custom nonclient areas for its windows
must process these messages. When doing so, the application must use a
window device context to carry out drawing in the window. The window
device context enables the application to draw in all portions of the
window, including the nonclient area. An application retrieves a
window device context by using the GetWindowDC or GetDCEx function
and, when drawing is complete, must release the window device context
by using the ReleaseDC function.
If you just consider whether the size of the custom client area will change when WM_NCPAINT is called, I can't give a suitable answer because I haven't seen your code and I don't know what kind of project you need to complete.
I just tested the sample in another link, the non-client area will always maintain the border size of 4pixel, and the calculation is also performed in WM_NCCALCSIZE.
I am trying to capture screenshot of inactive window with PrintWindow. It works correctly for calculator and for capturing Google Chrome, but for some other applications, like games, it saves white area.
What could be the reasons for PrintWindow to fail and how to validate them?
EDIT: I want tool to report why window can not be captured
Every window has a default implementation for WM_PRINT, you will use it if you call PrintWindow() and don't use the PW_CLIENTONLY flag. Provided by the default window procedure, DefWindowProc(). It is pretty straight-forward, it creates a memory DC and sends WM_PAINT. So what you get in the bitmap is the same you get on the screen. Everybody happy.
But that only works for windows that actually use WM_PAINT to render their content. The chips are down when it doesn't, most any game actually renders with DirectX and does so at a high rate, not relying on WM_PAINT messages. A program that uses a layered window with alpha transparency doesn't either, you can typically recognize them from a fancy blended border.
What such a program should do is write their own message handler for WM_PRINT/CLIENT and render their surface into the device context. Necessary because the default implementation doesn't know beans about DirectX surfaces.
Games just don't do this, that's extra code they have to write that just about nobody ever actually uses. You'll inevitably end up with an empty bitmap. Nothing you can do about it of course.
The documentation for PrintWindow provides information on its implementation:
The application that owns the window referenced by hWnd processes the PrintWindow call and renders the image in the device context that is referenced by hdcBlt. The application receives a WM_PRINT message or, if the PW_PRINTCLIENT flag is specified, a WM_PRINTCLIENT message. For more information, see WM_PRINT and WM_PRINTCLIENT.
Whether or not PrintWindow returns a window's content is subject to the window procedure handling the WM_PRINT or WM_PRINTCLIENT message[1] appropriately. If a window doesn't handle either of those messages, it will not render anything into the provided device context.
[1]Standard window implementations provide a message handler for WM_PRINT/WM_PRINTCLIENT through DefWindowProc. Custom window class implementations need to provide their own.
when the program is doing calculations in c++,c#,vb.net you can use the application::doevents() to refresh the screen so the screen do not freeze. how can you do this in assembly particular masm
I tried putting
invoke SendMessage, hWin, WM_SETREDRAW, 0, 0
invoke SendMessage, hWin, WM_SETREDRAW, 1, 0
in the loop part of my program but it does not work.
I also tried
invoke SendMessage, hWin, WM_SETREDRAW, 1, 0
but that does not work either
Application::DoEvents does a lot more than just refresh the screen. It actually pumps the message queue for the application's UI thread. If you wanted to do this in assembler, you would need to pump the message queue yourself. However, I don't recommend this. Using DoEvents in any UI framework is a definite anti-pattern, whether it provides such a function or not. More information is here and here.
If all you want to do is ensure that your listbox control gets repainted, then you need to invalidate it and force a redraw. In WinForms, that would be:
myListBox.Invalidate();
myListBox.Update();
In assembler, you will need to invoke the appropriate Win32 API functions yourself. In particular, you can use InvalidateRect to invalidate the client area of your listbox control and then UpdateWindow to ensure that it gets repainted immediately.
I don't know the syntax for MASM, but in unmanaged C++, it would look like this:
InvalidateRect(hListBox, /* handle to your listbox control */
NULL, /* invalidate the entire client area */
TRUE); /* erase the background */
UpdateWindow(hListBox);
In most cases, invalidating the window is enough. You don't need to force an immediate repaint, because the next time that your application processes messages (in its regular message loop), it will process a WM_PAINT message and redraw the control. The only reason this wouldn't work is if you were blocking the UI thread by performing some type of long-running operation, which you should not be doing in the first place—spin off a background thread to perform calculations.
The reason sending a WM_SETREDRAW message doesn't work here is because that basically sets a flag indicating whether the control is allowed to redraw itself. As the linked documentation explains, the window still needs to be redrawn in order to see the changes. It says you can force this by calling, e.g., RedrawWindow or doing the same thing we did above.
ShowWindow(g_hWnd, 1);
UpdateWindow(g_hWnd);
I am wondering why we need to call UpdateWindow following the ShowWindow?
It is entirely unnecessary, your window will paint just fine without it.
You'll see a minor benefit from it if your program goes off doing lots of stuff after creating the window but before entering the message loop. The user has something to look at. A splash screen is the more typical approach.
ShowWindow does not repaint the window. The call to UpdateWindow sends WM_PAINT message to the window and thus repainting it.
Normally, the system sends WM_PAINT only if the message queue is empty. Under normal circumstances this is good enough and it actually optimizes out a lot of unnecessary repaint. The messages in the queue often will change application state which can often result in invalidating part of the window, and hence result in yet another painting (so the user sees the new application state). So the repaint just happens after all such messages are handled and the system thinks the new window content will be valid for some time (until yet another message(s) come into the queue).
However if you need to force the WM_PAINT immediately and bypass the logic above, you may force sending WM_PAINT (if there is an invalid region) by calling UpdateWindow().
ShowWindow causes a WM_PAINT message, whereas anything which makes a previously hidden part of a window visible. UpdateWindow does any outstanding paint message(s) to be delivered immediately, waiting until the paint processing is complete until returning. Without the call to UpdateWindow the message isn't received until your program goes into the message loop. This avoids any possible delay in response to the user.
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.)