Why can’t I get the pixels of a window that isn’t visible on screen?


If the window isn't visible on the screen, then the pixels simply don't exist.

The Windows painting model follows the principle of "Don't save anything you can recalculate". Consider: You have a 640x480 display in 16-color mode. That's 150KB of video memory. Take four copies of Notepad and maximize each one. If each of those copies of Notepad required an offscreen cached bitmap, you would be using 450KB of memory just to retain those bits. If your computer has only 640KB, that doesn't leave much memory for anything else.

Think about what programs need to display. In the vast majority of cases, the programs already need to keep track of the information needed to generate the display anyway, and usually in a more compact form. Notepad, for example, has an edit control which in turn holds the text being edited. Displayed or not, the edit control needs to keep track of the text. (It's not like Notepad would use OCR to read the pixels from the screen and convert them back to text when it needs them!) Any program that has a scroll bar needs to manage information that is not visible on screen. It's hardly a stretch to make it manage information that is visible.

If you do want to get the pixels from a window that isn't visible on screen, you can try sending it the WM_PRINT message, though this requires that the window you're sending it to even bothers to support the WM_PRINT message. (Many don't.) If you are using Windows XP or later, you can use the PrintWindow function.

Comments (30)
  1. waleri says:

    Is it possible to use WM_PAINT instead, in order to "cheat" those apps that doesn’t support WM_PRINT? MSDN says WM_PAINT should not be send directly, but how would window proc knows whether it is sent directly or via UpdateWindow()?

  2. Carlos says:

    That’s why Windows has all those funky artifacts when moving windows around, and just goes to heck when a window hangs (ever see the hall of mirrors?) Makes sense for Win3.1 and maybe Win95 with limited memory machines of the time, but in the age of 2000 and XP, it’s pretty lame. Longhorn will finally fix that by keeping track of a full bitmap of each window in memory and compositing a final single window in the GPU’s memory.

  3. asdf says:

    Feng Yuan’s famous article about this: http://www.fengyuan.com/article/wmprint.html

  4. JT says:

    Ha! Does anybody else remember that the original PC BIOS had a function for scraping character codes (OCR’ing) from the pixel buffer memory? The PC BASIC’s screen text editor used this feature! You could

    1. Put the screen into graphics mode.

    2. LIST your program

    3. Move the cursor into the text

    4. Change something

    5. And finally press ENTER

    and BASIC would record the changed line in the program. (Of course, the line had to start with a line number (and there were rules about line continuation that I cannot recall).)

    BUT if between 2 and 3 you drew a line through the text, the edit would fail. The OCR required exact pixel-for-pixel matches to character bitmaps. I don’t remember how the FG/BG pixel coloring affected all this.

    I’m quite sure that the earlY MS Windows designers were aware of BASIC’s pixel scraping habits. I also bet that they never seriously considered doing anything like it.

  5. kalleboo says:

    It’s interesting to see that MacOS X has the opposite approach, but then again look at how much RAM it enjoys to use…

  6. BillG says:

    640KB should be enough for anybody.

  7. Ulric says:

    it possible to use WM_PAINT instead, in order to "cheat" those apps that doesn’t support WM_PRINT?

    No, applications use BeginPaint in WM_PAINT to obtain where to draw.

  8. foxyshadis says:

    "Longhorn will finally fix that by keeping track of a full bitmap of each window in memory and compositing a final single window in the GPU’s memory."

    Gee, just what I want, every maximized app using another 4 megs. (I run almost everything maximized, 32bit, 1280×800, often 6-7 apps at once, sometimes dozens.) And that’s if MDI apps are all one image. Yeah, great ‘fix’. Let’s rename it to OS L. =D

  9. Rosyna says:

    For the person that mentioned OS X, it uses compositing and if a window is fully obscured for a while, it’s data will be compressed. Then if it goes even longer without being unobscured, it’ll be swapped to disk, thereby taking up no RAM. If another app wants to access the contents of the window, it’ll be swapped back into main memory and decompressed.

  10. Mihai says:

    "If the window isn’t visible on the screen, then the pixels simply don’t exist."

    What if the window class has (the long forgoten) CS_SAVEBITS stlyle. Yes, I know this is probably never the case, but just curious.

  11. CS_SAVEBITS is a strange case because the bits it saves are thrown away at the slightest provocation. (And those bits aren’t saved with the window being covered; they’re saved with the >covering< window.)

  12. Mike says:

    To make things more complicated there are layered windows and the WS_EX_LAYERED style. Layered windows basically draw everything to a GDI-supplied backbuffer and then get composed to the screen. The bits are persistent in this case.

  13. Why does OS X go through the labor of compressing and swapping out a window’s contents when it could just have the window repaint itself when needed again?

    Otherwise, the increased memory usage of fully buffered windows can be discounted by the fact that video cards now come with more than enough of their own RAM to hold it all.

  14. MGrier says:

    Search the web for the debates about whether X11 should have provided guaranteed server side backing for windows. Lots of arguments for, lots of arguments against.

    What’s interesting is that almost all the arguments "for" were around making it easier for programs. The arguments "against" were about efficiency, scalability and the fact that programs could be authored to use a drawing library that maintained a client-side bitmap cache and easily respond to redraw messages.

    Sounds like a familliar debate.

  15. Joshua asks "why have backing store, why not just let app repaint?"

    Lots of reasons! Performance of the the composited graphics system is a big one – no time to wait for apps to redraw content when you’re trying to deal with windows that have shadows and non 1.0 alphas, etc.

    Functionality is another one. Since the OS always has access to a window’s backing store it makes things like Exposè really easy – likewise with animated minimizing. Apps just draw to their backing store and the OS takes care of the transformations on screen without the app having to know anything.

    Another is sexiness — OS X looks smoother simply because you NEVER get windows with big blank spaces or outlines because the content isn’t there (at all, or yet).

    Tearing, and flickering are evil. Many many apps already double buffer to avoid that, so with OS X rather than have every app do that themselves (at least the apps that care about their appearance) OS X does it for them automatically and offers a bunch of new features like compression and paging of "old" backing stores.

  16. Merle says:

    "Longhorn will finally fix that by keeping track of a full bitmap of each window in memory and compositing a final single window in the GPU’s memory."

    I agree with foxyshadis; that’s obscene.

    So when I’m coding at 1600x1200x24bits, that’s 5.7M per window. With a mere ten windows, 60M is eaten up.

    Talk about bloat. Just so a minimized window can know what it looks like?

  17. waleri says:

    Mike,

    WS_EX_LAYERED windows uses WM_PRINT in order to dump the content into a backbuffer. As far as I know, backbuffer isn’t keeped, so one still have no access to window’s bits. Beside, we’re talking about hidden/obscured windows, which aren’t displayed on screen at the moment, so WS_EX_LAYERD doesn’t matter

  18. R. Bemrose says:

    ""Longhorn will finally fix that by keeping track of a full bitmap of each window in memory and compositing a final single window in the GPU’s memory."

    I agree with foxyshadis; that’s obscene.

    So when I’m coding at 1600x1200x24bits, that’s 5.7M per window. With a mere ten windows, 60M is eaten up.

    Talk about bloat. Just so a minimized window can know what it looks like?"

    If this is in Longhorn, I’d think it more likely that they’d use LZ77 (used by DEFLATE, GZIP, PNG) or something similar to do lossless compression of the stored bitmap.

  19. Mike says:

    Layered windows do keep thier backbuffer until the window size is changed (including minimizing it) at which time it’s discarded. It’s easy enough to test – have your favorite GUI skeleton code use layered windows and you pretty much never see WM_PAINT unless you force it or resize the window.

    Although I just tried have one app try to read the client area of a different app that used layered windows but had it’s window covered by still a third app. It didn’t work – there was no output at all. GDI returned no errors.

  20. Chris says:

    Some of you are forgetting that the full-on Aero Glass mode of Longhorn recommends at least 128MB of video RAM. That’s where all this "bloat" is supposed to go.

    1600x1200x32 rounded up to the next MB for overhead is 16 full screen windows in 128MB. And the LH graphics subsystem can virtualize VRAM so if your card is low-speced the excess can spill over into system RAM if needed.

    And if you don’t like it you can turn it off.

  21. JamesW says:

    @buffer doubters

    Windows got it right when this system was designed – memory was precious and you certainly didn’t want to be using it storing invisible stuff. But in the brave new translucent twenty first century, where gobs of memory is cheap, the tables have turned: Mac OS X does it right and apparently Longhorn will too.

    It’s not just about cutesy GUIs either. Real world example: I have a list box whose data set updates frequently and I want it to display new data dynamically. On Windows it is flicker city – so I spend a day implementing my own double buffering and it more or less works. Problem is a colleague has already been hacking away at the list view header control and whatever he’s done thwarts my code… Meanwhile on OS X – IT JUST WORKED IN THE FIRST PLACE. This is important: I don’t need über skills to get flicker free GUI – the OS provides it.

    Doubters, the equation has shifted: burn some RAM for a better GUI; it’s worth it.

  22. Merle says:

    R. Bemrose: "If this is in Longhorn, I’d think it more likely that they’d use LZ77 (used by DEFLATE, GZIP, PNG) or something similar to do lossless compression of the stored bitmap."

    Maybe so — but then you’re losing some of the speed.

  23. asdf says:

    I also don’t the point in compressing the bitmap when you minimize or page out the memory after a certain amount of time. A window is expected to redraw reasonably fast when you’re resizing it so that that speed resizing it is about the same speed you get when needing to uncover it in those situations.

  24. waleri says:

    Perhaps Longhorn, *would* implement such behaviour for *certain* windows, not all. Sometimes this would make sense – for example if the window contains complex drawing or something. Some sort of WS_BACKBUFFER flag can do the trick. Currently, applications with complex drawings should either repaint themselves or implement such backbuffering – that isn’t very hard. Modern video adapters has hundreds of MB, and even on 32MB adapters couple 5MB can fit in video memory that is not currently in use.

    However, all of the above (in this post) is pure theory and speculation. We should simply wait for longhorn and see, and/or download a (beta) SDK (if any) and see what it says about that matter.

  25. zzz says:

    Instead of claiming Longhorn doing this or that, I’ll claim that by the time it ships, every shipping $1000+ laptop will have either 128 MB of suitably fast memory for the needs of LH.

    But it wouldn’t surprise me if LH worked just fine on a bit older laptops aswell. Like those of whose buyers were smart enough to look for PS2 support in their laptops display adapter.

    Mine runs Battlefield 2 – get that ;-)

  26. sierra says:

    I know I am writing at a wrong place. I am a new memeber and need to post a comment (actually a query) to ‘oldnewthing’ about spam emails. How do I do that?

    Again, very sorry for interrupting this.

  27. R. Bemrose says:

    Merle: You may be right. I’ve never tried balancing large amounts of data compression in real time.

    Then again, I also hadn’t considered that Windows might use the display adapters memory to store them until after I posted that, either.

  28. Ben Hutchings says:

    Backing store really isn’t that horribly expensive. It was used by default in AmigaOS, where the feature was called "smart refresh", and that was running on very small systems, though with comparatively generous amounts of video RAM (in fact in the smaller systems there was nothing but video RAM). It made for quite snappy windowing even on a 68000.

  29. On AmigaOS, smart refresh was optional by setting a suitable flag on the window creation call, but it was so useful that people soon patched the CreateWindow function to force it everywhere smart refresh.

  30. Allen Bauer says:

    Uh.. excuse me? I’ve recently tried using the PrintWindow API, and for me if I use it on a partially clipped child window, it doesn’t actually paint the clipped (by the parent window or other children) portions of the window on my DC. Is this a limitation I’ve encountered or is it actually intended to only be used for top-level windows only?

Comments are closed.