Delphi - Capture a Window Image

I wanted to develop my own print screen function - but instead of just capturing the image to the clipboard, I wanted the option to also write the window image directly to a jpeg or png file.

Overview | Displaying the Target Window - SetForegroundWindow Hide and Show Capture the Desktop | Capture the Image | Comments


Overview

Since I want to copy a part of the screen image, the windows api call - BitBlt - was used. For that to work, the code needs Since BitBlt actually copies the pixels shown on the screen, the source window must be on top of all the other windows.


Displaying the Target Window

Once a handle is available, the window must be fully displayed on the screen to capture an image of it. You would think that providing the device context - GetWindowDC(hnd) - would be enough, but it is not! Apparently, BitBlt uses the context to get just the screen location and window size, but then gets the pixels directly from the screen.


SetForegroundWindow

One technique is to move the target window to the top of the z-order. Unfortunately, this takes a bit of time and there is no way to get a message indicating that the operation is complete. I "solved" this problem by setting a timer - 100 ms was enough for my test case, but no value is ever going to work all the time. To get the capture program back on top, I had to use windows again to change its z-order - I could not find a Delphi function to accomplish that.


Hide and Show

Another way to accomplish this is to hide and show the form capturing the image. Since this technique does not change the windows z-order, the selected form must already be on top of the other windows. In addition, the timer is still required to allow the target image enough time to be drawn before it is captured.

As a result, I use this technique when a sub-window is used to capture graphs from a parent form, but not when capturing a random window in another application.

By the way, when the code is encapsulated in a component, self will no longer represent the form. In that case, the following modification is necessary.


Capture the Desktop

When capturing the desktop, merely changing the z-order will not hide the application. To accomplish that, it is necessary to also hide the window. As a result, the "best" approach is to both Perhaps providing checkboxes so the user can control these is should be considered.


Capture the Image

The actual capture code uses BitBlt, a handle, and a bitmap.


Comments

The code I used actually does not capture a form window - it gets the window (control) that is under the mouse. As a result, it is able to capture a piece of a form. For some applications, that might be considered a bug. However, I like it because it makes it easier to document some of the controls I design. To get the whole form, release the mouse on a blank area .. or on the form window border.

Unfortunately, when a complete application window (form) is captured in Windows XP, whatever is behind the two upper corners is also captured. This is because those corners are rounded. (This is how I know that BitBlt is copying pixels from the screen and not from some internal context buffer.) Therefore, you need to place objects of the appropriate color behind the corners.

With transparent window borders (Vista and beyond), additional noise will be added to the image.

To provide a white background, you can open notepad and center that target window over that.


Author: Robert Clemenzi
URL: http:// mc-computing.com / Languages / Delphi / CaptureWindowImage.html