The following example enables the user to capture the screen content into a bitmap and scroll the bitmap in the client area.
HDC hdc;
PAINTSTRUCT ps;
SCROLLINFO si;
/* These variables are required by BitBlt. */
static HDC hdcWin; /* window DC */
static HDC hdcScreen; /* DC for entire screen */
static HDC hdcScreenCompat; /* memory DC for screen */
static HBITMAP hbmpCompat; /* bitmap handle for old DC */
static BITMAP bmp; /* bitmap data structure */
static BOOL fBlt; /* TRUE if BitBlt occurred */
static BOOL fScroll; /* TRUE if scrolling occurred */
static BOOL fSize; /* TRUE if fBlt & WM_SIZE */
/* These variables are required for horizontal scrolling. */
static int xMinScroll; /* minimum horizontal scroll value */
static int xCurrentScroll; /* current horizontal scroll value */
static int xMaxScroll; /* maximum horizontal scroll value */
/* These variables are required for vertical scrolling. */
static int yMinScroll; /* minimum vertical scroll value */
static int yCurrentScroll; /* current vertical scroll value */
static int yMaxScroll; /* maximum vertical scroll value */
switch (uMsg) {
case WM_CREATE:
/*
* Create a normal DC and a memory DC for the entire
* screen. The normal DC provides a snapshot of the
* screen contents. The memory DC keeps a copy of this
* snapshot in the associated bitmap.
*/
hdcScreen = CreateDC("DISPLAY", (LPCSTR) NULL,
(LPCSTR) NULL, (CONST DEVMODE *) NULL);
hdcScreenCompat = CreateCompatibleDC(hdcScreen);
/*
* Retrieve the metrics for the bitmap associated with the
* regular device context.
*/
bmp.bmBitsPixel =
(BYTE) GetDeviceCaps(hdcScreen, BITSPIXEL);
bmp.bmPlanes = (BYTE) GetDeviceCaps(hdcScreen, PLANES);
bmp.bmWidth = GetDeviceCaps(hdcScreen, HORZRES);
bmp.bmHeight = GetDeviceCaps(hdcScreen, VERTRES);
/* The width must be byte-aligned. */
bmp.bmWidthBytes = ((bmp.bmWidth + 15) &~15)/8;
/* Create a bitmap for the compatible DC. */
hbmpCompat = CreateBitmap(bmp.bmWidth, bmp.bmHeight,
bmp.bmPlanes, bmp.bmBitsPixel, (CONST VOID *) NULL);
/* Select the bitmap for the compatible DC. */
SelectObject(hdcScreenCompat, hbmpCompat);
/* Initialize the flags. */
fBlt = FALSE;
fScroll = FALSE;
fSize = FALSE;
/* Initialize the horizontal scrolling variables. */
xMinScroll = 0;
xCurrentScroll = 0;
xMaxScroll = 0;
/* Initialize the vertical scrolling variables. */
yMinScroll = 0;
yCurrentScroll = 0;
yMaxScroll = 0;
break;
case WM_SIZE: {
int xNewSize;
int yNewSize;
xNewSize = LOWORD(lParam);
yNewSize = HIWORD(lParam);
if (fBlt)
fSize = TRUE;
/*
* The horizontal scrolling range is defined by
* (bitmap_width) - (client_width). The current horizontal
* scroll value remains within the horizontal scrolling range.
*/
xMaxScroll = max(bmp.bmWidth-xNewSize, 0);
xCurrentScroll = min(xCurrentScroll, xMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = xMinScroll;
si.nMax = xMaxScroll;
si.nPage = xNewSize;
si.nPos = xCurrentScroll;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
/*
* The vertical scrolling range is defined by
* (bitmap_height) - (client_height). The current vertical
* scroll value remains within the vertical scrolling range.
*/
yMaxScroll = max(bmp.bmHeight - yNewSize, 0);
yCurrentScroll = min(yCurrentScroll, yMaxScroll);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = yMinScroll;
si.nMax = yMaxScroll;
si.nPage = yNewSize;
si.nPos = yCurrentScroll;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
break;
case WM_PAINT: {
PRECT prect;
hdc = BeginPaint(hwnd, &ps);
/*
* If the window has been resized and the user has
* captured the screen, use the following call to
* BitBlt to paint the window's client area.
*/
if (fSize) {
BitBlt(ps.hdc,
0, 0,
bmp.bmWidth, bmp.bmHeight,
hdcScreenCompat,
xCurrentScroll, yCurrentScroll,
SRCCOPY);
fSize = FALSE;
}
/*
* If scrolling has occurred, use the following call to
* BitBlt to paint the invalid rectangle.
*
* The coordinates of this rectangle are specified in the
* RECT structure to which prect points.
*
* Note that it is necessary to increment the seventh
* argument (prect->left) by xCurrentScroll and the
* eighth argument (prect->top) by yCurrentScroll in
* order to map the correct pixels from the source bitmap.
*/
if (fScroll) {
prect = &ps.rcPaint;
BitBlt(ps.hdc,
prect->left, prect->top,
(prect->right - prect->left),
(prect->bottom - prect->top),
hdcScreenCompat,
prect->left + xCurrentScroll,
prect->top + yCurrentScroll,
SRCCOPY);
fScroll = FALSE;
}
EndPaint(hwnd, &ps);
}
break;
case WM_HSCROLL: {
int xDelta; /* xDelta = new_pos - current_pos */
int xNewPos; /* new position */
int yDelta = 0;
switch (LOWORD(wParam)) {
/* User clicked the shaft left of the scroll box. */
case SB_PAGEUP:
xNewPos = xCurrentScroll - 50;
break;
/* User clicked the shaft right of the scroll box. */
case SB_PAGEDOWN:
xNewPos = xCurrentScroll + 50;
break;
/* User clicked the left arrow. */
case SB_LINEUP:
xNewPos = xCurrentScroll - 5;
break;
/* User clicked the right arrow. */
case SB_LINEDOWN:
xNewPos = xCurrentScroll + 5;
break;
/* User dragged the scroll box. */
case SB_THUMBPOSITION:
xNewPos = HIWORD(wParam);
break;
default:
xNewPos = xCurrentScroll;
}
/* New position must be between 0 and the screen width. */
xNewPos = max(0, xNewPos);
xNewPos = min(xMaxScroll, xNewPos);
/* If the current position does not change, do not scroll.*/
if (xNewPos == xCurrentScroll)
break;
/* Set the scroll flag to TRUE. */
fScroll = TRUE;
/* Determine the amount scrolled (in pixels). */
xDelta = xNewPos - xCurrentScroll;
/* Reset the current scroll position. */
xCurrentScroll = xNewPos;
/*
* Scroll the window. (The system repaints most of the
* client area when ScrollWindowEx is called; however, it is
* necessary to call UpdateWindow in order to repaint the
* rectangle of pixels that were invalidated.)
*/
ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
SW_INVALIDATE);
UpdateWindow(hwnd);
/* Reset the scroll bar. */
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = xCurrentScroll;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
}
break;
case WM_VSCROLL: {
int xDelta = 0;
int yDelta; /* yDelta = new_pos - current_pos */
int yNewPos; /* new position */
switch (LOWORD(wParam)) {
/* User clicked the shaft above the scroll box. */
case SB_PAGEUP:
yNewPos = yCurrentScroll - 50;
break;
/* User clicked the shaft below the scroll box. */
case SB_PAGEDOWN:
yNewPos = yCurrentScroll + 50;
break;
/* User clicked the top arrow. */
case SB_LINEUP:
yNewPos = yCurrentScroll - 5;
break;
/* User clicked the bottom arrow. */
case SB_LINEDOWN:
yNewPos = yCurrentScroll + 5;
break;
/* User dragged the scroll box. */
case SB_THUMBPOSITION:
yNewPos = HIWORD(wParam);
break;
default:
yNewPos = yCurrentScroll;
}
/* New position must be between 0 and the screen height. */
yNewPos = max(0, yNewPos);
yNewPos = min(yMaxScroll, yNewPos);
/* If the current position does not change, do not scroll.*/
if (yNewPos == yCurrentScroll)
break;
/* Set the scroll flag to TRUE. */
fScroll = TRUE;
/* Determine the amount scrolled (in pixels). */
yDelta = yNewPos - yCurrentScroll;
/* Reset the current scroll position. */
yCurrentScroll = yNewPos;
/*
* Scroll the window. (The system repaints most of the
* client area when ScrollWindowEx is called; however, it is
* necessary to call UpdateWindow in order to repaint the
* rectangle of pixels that were invalidated.)
*/
ScrollWindowEx(hwnd, -xDelta, -yDelta, (CONST RECT *) NULL,
(CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL,
SW_INVALIDATE);
UpdateWindow(hwnd);
/* Reset the scroll bar. */
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = yCurrentScroll;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}
break;
case WM_COMMAND: /* uMsg: command from app. menu */
switch(wParam) {
case IDM_STC:
/*
* Copy the contents of the current screen
* into the compatible DC.
*/
BitBlt(hdcScreenCompat, 0, 0, bmp.bmWidth,
bmp.bmHeight, hdcScreen, 0, 0, SRCCOPY);
/*
* Copy the compatible DC to the client area.
*/
hdcWin = GetDC(hwnd);
BitBlt(hdcWin, 0, 0, bmp.bmWidth, bmp.bmHeight,
hdcScreenCompat, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hdcWin);
fBlt = TRUE;
break;
default:
return (DefWindowProc(hwnd, uMsg,
wParam, lParam));
}
break;