Screen Capturing for Windows 3.0

This utility helps you get your foot in the Window 3.0 programming door


February 01, 1991
URL:http://www.drdobbs.com/windows/screen-capturing-for-windows-30/184408495

Figure 1


Copyright © 1991, Dr. Dobb's Journal

FEB91: SCREEN CAPTURING FOR WINDOWS 3.0

SCREEN CAPTURING FOR WINDOWS 3.0

A useful utility for grabbing screen images

Jim Conger

Jim is the author of C Programming For MIDI, MIDI Sequencing In C (M&T Books), and articles for Electronic Musician magazine. He can be reached via CompuServe (73220,324).


Snap3 is a program that allows you to grab any part of a Windows 3.0 application screen and paste it to the clipboard. Once in the clipboard, you can use the Write or Word for Windows Paste command to paste the image directly into your documents. Not only is the program a handy tool, but understanding how it works is a good introduction into the sometimes mysterious world of Windows 3 programming.

I use Snap3 to grab representative images from the running program I'm documenting, adding the image to the manual as I write. The utility can also be used to create help screens by letting you cut and paste images from the program into your help source file, created with Windows. (For more information on the Microsoft Help compiler, refer to "Building an Efficient Help System" by Leo Notenboom and Michael Vose [DDJ, June 1990]).

Snap3

The idea for Snap3 came from a similar public domain program called "Snap" available on the CompuServe MSWIN forum. Because Snap is a Windows 2.x program, it generates those nasty warning messages every time you run it in Windows 3.0 Standard or 386 Enhanced Mode. I decided to write a 3.0 version, and cut the program down to the bare essentials.

When you run the program, a window (see Figure 1) with two menu items will appear, the first item being "Start Capture." When this item is clicked, the mouse cursor turns to a crosshair which you can move to the upper left of the screen area you want to capture. By pressing the left mouse button and dragging the mouse down, you will "draw" a rectangle on the screen. You stretch the rectangle to encompass the area you want to capture and then release the button. The graphics image captured shows up in Snap3's window. The other key function is "Clear Buffer," which clears the Snap3 window and empties the clipboard. Snap3 also has an About function and a simple Help screen.

Snap3 Source Code

From a programmer's point of view, all Snap3 is doing is grabbing a bitmap off of the screen and pasting it to the Windows clipboard that is common to all Windows applications. The captured bitmap is then available for a Paste operation from Word For Windows, Paintbrush, or other similar applications. You can also see the image by clicking open Windows' clipboard viewer.

The Snap3 program is broken up into four files. The NMAKE file (Listing One) calls the C compiler (cl), the resource compiler (rc), and the linker (link) to build the finished program. All Windows programs have a definition file that provides basic information as to the program's name and organization. SNAP3.DEF (Listing Two) is an example of the simplest possible DEF file. The resource file SNAP3.RC (Listing Three) gives the name of the program's icon and defines the program menu. Following normal Windows programming practice, the menu items are numbered based on #define statements in the header file SNAP3.H (Listing Four ). The header file also includes the function prototypes. The actual program code is in SNAP3.C (Listing Five). There are only three functions. The WinMain( ) function loads the program icon that was created using the SDK Paint application that comes with the Windows 3.0 SDK.

The SNAP3.C WndProc( ) function contains all of the program logic. Capturing starts when you select the Start Capture menu item, generating a IDM_START message, changing the cursor to IDC_CROSS. Once capturing starts, WM_MOUSEMOVE messages cause the rectangular region captured by the mouse to be outlined. The function OutlineBlock( ) at the end of the listing does the drawing. One sneaky thing here is that the outline rectangle's lines are drawn with the logical R2_NOT operator (function SetROP2( )). This causes drawing the lines in the same place twice to erase the lines. Windows includes a number of built-in functions for dealing with bitmap images. These work at a fairly high level, freeing you from having to worry about how the pixel data is stored or manipulated. SNAP3 uses several of these functions to do the capture of the screen image.

The transfer of the image to the clipboard happens when you release the mouse button, generating a WM_LBUTTONUP message. A memory area for the bitmap is created using CreateCompatibleBitmap( ). StretchBlt( ) copies from the screen device to the memory device. Then SetClipboardData( ) alerts Windows that the clipboard should now look to the bitmap memory area for its data.

If Snap3 is not minimized down to an icon, it will display the captured image in its window. Any time a WM_PAINT message is received, it copies the clipboard bitmap (if any) to the Snap3 window area. The Windows function StretchBlt( ) does the copying of the bitmap to the screen image.


_SCREEN CAPTURING FOR WINDOWS 3.0_
by Jim Conger


[LISTING ONE]



ALL: snap3.exe

snap3.obj : snap3.c
     cl -AS -c -DLINT_ARGS -Gsw -Oat -W2 -Zped snap3.c

snap3.res:  snap3.rc snap3.ico
     rc -r snap3.rc

snap3.exe : snap3.obj snap3.def snap3.res
     link /NOD snap3, , ,libw slibcew, snap3.def
     rc snap3.res






[LISTING TWO]


NAME           SNAP3
DESCRIPTION    'snap3 program for windows bitmap capture to clipboard'
EXETYPE      WINDOWS
STUB           'WINSTUB.EXE'
CODE           PRELOAD MOVEABLE
DATA           PRELOAD MOVEABLE MULTIPLE
HEAPSIZE       1024
STACKSIZE      4096
EXPORTS        WndProc






[LISTING THREE]


/* snap3.rc */
#include "snap3.h"

snap3   ICON   snap3.ico
snap3 MENU
BEGIN
   MENUITEM "&Start Capture"   IDM_START
   MENUITEM "&Clear Buffer",   IDM_CLEAR
   MENUITEM "&About",         IDM_ABOUT
   MENUITEM "\a&Help",         IDM_HELP
END






[LISTING FOUR]


/* snap3.h */

#define IDM_START   1   /* menu item id values */
#define IDM_CLEAR   2
#define IDM_ABOUT   3
#define IDM_HELP    4

/* function prototypes */
long  FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
void  OutlineBlock (HWND hWnd, POINT beg, POINT end) ;






[LISTING FIVE]


/* snap3.C -- Screen Capture to clipboard -- jim conger  */

#include <windows.h>
#include <stdlib.h>
#include "snap3.h"

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine,
    int nCmdShow)
{
     static char szAppName [] = "snap3" ;
     HWND        hWnd ;
     MSG         msg ;
     WNDCLASS    wndclass ;

     if (!hPrevInstance)
     {
          wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
          wndclass.lpfnWndProc   = WndProc ;
          wndclass.cbClsExtra    = 0 ;
          wndclass.cbWndExtra    = 0 ;
          wndclass.hInstance     = hInstance ;
          wndclass.hIcon         = LoadIcon (NULL, szAppName) ;
          wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
          wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
          wndclass.lpszMenuName  = szAppName ;
          wndclass.lpszClassName = szAppName ;

          if (!RegisterClass (&wndclass))
              return FALSE ;
    }
    hWnd = CreateWindow (szAppName, "Snap3",
         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
         GetSystemMetrics (SM_CXSCREEN) / 2,
         8 * GetSystemMetrics (SM_CYMENU),
         NULL, NULL, hInstance, NULL) ;
    ShowWindow (hWnd, nCmdShow) ;
    UpdateWindow (hWnd) ;

    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
    }
    return msg.wParam ;
}

long FAR PASCAL WndProc (HWND hWnd, unsigned iMessage, WORD wParam,
    LONG lParam)
{
     static BOOL    bCapturing = FALSE, bBlocking = FALSE, bStarted = FALSE ;
     static POINT   beg, end, oldend ;
     static short   xSize, ySize ;
     static HANDLE  hInstance ;
     HDC            hDC, hMemDC ;
     BITMAP         bm ;
     HBITMAP        hBitmap ;
     HICON          hIcon ;
     PAINTSTRUCT    ps ;
     switch (iMessage)
     {
         case WM_CREATE:    /* get program instance when window is created */
             hInstance = GetWindowWord (hWnd, GWW_HINSTANCE) ;
             break ;
         case WM_COMMAND:   /* one of the menu items has been clicked */
            switch (wParam)
            {
            case IDM_START:             /* the start capture item */
                bCapturing = TRUE ;
                bBlocking = bStarted = FALSE ;
                SetCapture (hWnd) ;                     /* grab mouse */
                SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
                CloseWindow (hWnd) ;                    /* minimize window */
                break ;
            case IDM_CLEAR:     /* clears screen and clipboard */
                OpenClipboard (hWnd) ;
                EmptyClipboard () ;
                CloseClipboard () ;
                InvalidateRect (hWnd, NULL, TRUE) ;     /* forces paint */
                break ;
            case IDM_ABOUT:     /* show about box */
               MessageBox (hWnd, "Snap3 - Windows screen capture to clipboard.
                                                          \nJim Conger 1990.",
                    "Snap3 About", MB_OK) ;
                break ;
            case IDM_HELP:
                MessageBox (hWnd, "After you click the Start Capture menu
                                      item, move the mouse to the upper left
                                      of the area you want to copy to the
                                      clipboard. Hold down the left mouse
                                      button while you drag the mouse to the
                                      lower right of the area. Once you release
                                      the mouse button, the area is sent to the
                                      clipboard and shown in Snap3's window.",
                    "Snap3 Help", MB_OK) ;
                break ;
            }
        case WM_LBUTTONDOWN:    /* starting capturing screen */
            if (bCapturing)
            {
                if (bStarted)
                {
                    bBlocking = TRUE ;
                    oldend = beg = MAKEPOINT (lParam) ;
                    OutlineBlock (hWnd, beg, oldend) ;
                    SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
                }
                else
                    bStarted = TRUE ;
            }
            break ;
        case WM_MOUSEMOVE:      /* show area as rectangle on screen */
            if (bBlocking)
            {
                end = MAKEPOINT (lParam) ;
                OutlineBlock (hWnd, beg, oldend) ;  /* erase old outline */
                OutlineBlock (hWnd, beg, end) ;     /* draw new one */
                oldend = end ;
            }
            break ;
        case WM_LBUTTONUP:      /* capture and send to clipboard */
            if (bBlocking)
            {
                bBlocking = bCapturing = FALSE ;
                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
                ReleaseCapture () ;                 /* free mouse */

                end = MAKEPOINT (lParam) ;
                OutlineBlock (hWnd, beg, oldend) ;  /* erase area outline */
                xSize = abs (beg.x - end.x) ;
                ySize = abs (beg.y - end.y) ;
                hDC = GetDC (hWnd) ;
                hMemDC = CreateCompatibleDC (hDC) ;
                hBitmap = CreateCompatibleBitmap (hDC, xSize, ySize) ;

                if (hBitmap)
                {
                    SelectObject (hMemDC, hBitmap) ;
                    StretchBlt (hMemDC, 0, 0, xSize, ySize,
                        hDC, beg.x, beg.y, end.x - beg.x,
                        end.y - beg.y, SRCCOPY) ;
                    OpenClipboard (hWnd) ;
                    EmptyClipboard () ;
                    SetClipboardData (CF_BITMAP, hBitmap) ; /* copy to */
                    CloseClipboard () ;                     /* clipboard */
                    InvalidateRect (hWnd, NULL, TRUE) ;     /* request paint*/
                }
                else
                    MessageBeep (0) ;
                DeleteDC (hMemDC) ;
                ReleaseDC (hWnd, hDC) ;
            }
            ShowWindow (hWnd, SW_RESTORE) ;     /* un-minimize window */
            break ;
        case WM_PAINT:      /* display contents of clipboard if bitmap */
            hDC = BeginPaint (hWnd, &ps) ;
            if (IsIconic (hWnd))    /* if window is iconic, show icon */
            {
                hIcon = LoadIcon (hInstance, "snap3") ;
                if (hIcon != NULL)
                    DrawIcon (hDC, 1, 1, hIcon) ;
            }
            else                    /* if not, show clipboard contents */
            {
                OpenClipboard (hWnd) ;
                if (hBitmap = GetClipboardData (CF_BITMAP)) /* if bitmap */
                {
                    hMemDC = CreateCompatibleDC (hDC) ;
                    SelectObject (hMemDC, hBitmap) ;
                    GetObject (hBitmap, sizeof (BITMAP), (LPSTR) &bm) ;
                    SetStretchBltMode (hDC, COLORONCOLOR) ;
                    StretchBlt (hDC, 0, 0, xSize, ySize, hMemDC, 0, 0,
                        bm.bmWidth, bm.bmHeight, SRCCOPY) ;
                    DeleteDC (hMemDC) ;
                }
                CloseClipboard () ;
            }

            EndPaint (hWnd, &ps) ;
            break ;
        case WM_DESTROY:
            PostQuitMessage (0) ;
            break ;
        default:
            return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
        }
   return 0L ;
}

/* OutlineBlock() writes a rectangle on screen given two corner points. R2_NOT
   style is used, so drawing twice on the same location erases outline. */
void OutlineBlock (HWND hWnd, POINT beg, POINT end)
{
     HDC   hDC ;

     hDC = CreateDC ("DISPLAY", NULL, NULL, NULL) ;
     ClientToScreen (hWnd, &beg) ;      /* convert to screen units */
     ClientToScreen (hWnd, &end) ;
     SetROP2 (hDC, R2_NOT) ;            /* use logical NOT brush */
     MoveTo (hDC, beg.x, beg.y) ;       /* draw rectangle */
     LineTo (hDC, end.x, beg.y) ;
     LineTo (hDC, end.x, end.y) ;
     LineTo (hDC, beg.x, end.y) ;
     LineTo (hDC, beg.x, beg.y) ;
     DeleteDC (hDC) ;
}


Copyright © 1991, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.