News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

CS_OWNDC

Started by jj2007, November 22, 2013, 08:19:57 PM

Previous topic - Next topic

jj2007

Occasionally we argue about what the GetDC & BeginPaint family really does, and we complain about lousy documentation. Now I found a top-notch reference to this problem (scroll down to comment of 5 Jun 2006 3:25 AM):

Quote[Well, some experimentation tells me that DCs are not cross-process after all (they were in Windows 3.1), so I apologize for the misinformation. I am not a substitute for formal documentation.

By "cross-process" I meant that a DC handle, once created, is valid in any process. (This was true in Windows 3.1 though apparently not any more.) The handle doesn't "become" cross-process any more than a window handle "becomes" cross-process. The DC cache is per-thread (or at least was in Windows 3.1; things may be different nowadays). If a thread calls "GetDC", it looks in the cache of DCs recently released by that thread. The two concepts (visibility and cache affinity) are unrelated. Passports are per-country but are globally valid - nobody seems confused by that. -Raymond]

My highlighting. If Raymond Chen isn't so sure, how can ordinary coders know what Windows does under the hood?

There are some interesting points in the blog, though:
- CS_OWNDC can be faster because GetDC & BeginPaint always return the same DC, so you can keep your bitmaps & pens & brushes selected
- some people use more than one DC to paint e.g. with different fonts; this fails miserably with CS_OWNDC because, well, the system doesn't give you two different DCs...
- painting with two different DCs can be significantly (30%) faster, depending on your setup.

TWell

OpenGL info says:
QuoteWhat should I do before the window is created?
Be sure to use the CS_OWNDC flag.
If you are doing plain old WinMain coding, RegisterClassEx() takes the WNDCLASSEX structure.
WNDCLASSEX.style should have the CS_OWNDC
If you are using MFC (SDI or MDI project), override PreCreateWindow and add the CS_OWNDC to cs.
For CDialog based project, PreCreateWindow doesn't get called.
This flag is really needed for Win9x systems.
Since DCs (device contexts) consume resources, the OS does not assign a DC but might share it between multiple windows and GUI elements.
On WinNT and its derivatives, it is said that resources are not a problem and it assigns a unique DC per window.
For good practice, I recommend using CS_OWNDC.

jj2007

Thanks, TWell. I found another answer, 15 years old (MSJ 2/1998, Paul DiLascia):
Quote
In the normal case (a common DC), Windows must grab the DC from its cache and initialize it with drawing objects and attributes every time your app requests the DC by calling GetDC or BeginPaint. This takes CPU cycles. On top of that, your app may then call a gajillion functions to create and select the pens, brushes, and fonts, select them into the DC, set up the mapping mode, and so on—all of which takes even more CPU cycles on every paint message.
As an alternative, you can tell Windows to use a private DC, which you do by specifying the CS_OWNDC class style. With a private DC, Windows doesn't initialize the DC every time you call GetDC or BeginPaint (though you must still call these functions, as well as ReleaseDC or EndPaint). Instead, Windows allocates a private DC for every instance of your window class and keeps it around for the lifetime of the window. Since the DC remembers its state, you don't have to set it up from scratch every time you get a paint message. If you select a red brush, it will remain selected until you either select a different brush or destroy the window. The performance benefits are obvious. A private DC can boost speed considerably for graphics-intensive apps like CAD and desktop publishing. Such apps typically have a current pen, brush, font, mapping mode, foreground/background color, and so on. If you use a common DC, you have to select these objects with every paint message; with a private DC, you need to select them only once to start, and then again whenever the user chooses a new pen or color.
If private DCs are so good, why not use them all the time? In the old 16-bit days, DCs were a scarce resource. You had to be careful about using a private DC because if too many apps did, Windows could run out of DCs. That's because in Windows 3.1, all USER and GDI objects come from 64KB LocalAlloc-style heaps with 16-bit offsets into the heap. But Windows 3.1 is a thing of the past. What about Win32?
The answer depends on what Win32 platform you're talking about—Windows 95 or Windows NT®. Here's what the official Platform SDK documentation says about private DCs in Windows NT:
"If you were programming for 16-bit Windows, you were told to avoid the use of your own DCs because the system could only support a few. This is not true on Windows NT. Use the creation style CS_OWNDC as much as you can when you call the RegisterClass function. This avoids repeated calling of the relatively expensive GetDC and ReleaseDC functions every time you have to draw. It also preserves the selected objects in your own DC in between calls, eliminating the need to select them again after each call to GetDC."
Since Windows NT is a true 32-bit operating system with a flat memory model and gobs of memory, you can use CS_OWNDC to your heart's content.

Finally, MSDN (my highlighting):
Quote
Private device contexts are display DCs that, unlike common device contexts, retain any changes to the default data even after an application releases them. Private device contexts are used in applications that perform numerous drawing operations such as computer-aided design (CAD) applications, desktop-publishing applications, drawing and painting applications, and so on. Private device contexts are not part of the system cache and therefore need not be released after use. The system automatically removes a private device context after the last window of that class has been destroyed.

dedndave

it may take some getting used to
i am accustomed to selecting and re-selecting in each pass of WM_PAINT