/********************************************************************/
//                                                                   / 
//   File:          WinGrab.c                                        /
//   Function:      Whole Screen Grabber for Window 3.0              /
//   Description:   Grab whole picture from screen into clipboard.   /
//                  The data formats are BITMAP and COLOR PALETTES.  /
//   Programmer:    Achen ( EE Graduate Student of UF )              /
//   Date:          Jan 14, 1991                                     /
//   Note:          All rights are free.                             /
//                                                                   /
/********************************************************************/

#define  NOCOMM                                 // disable some definitions
#define  DEFAULT_PALETTE_SIZE 20                // default value.

#include <windows.h>

/****************************************/
//                                       /
//   Functions defined in this file      /
//                                       /
/****************************************/
DWORD FAR PASCAL CheckGrabHotKey(WORD nCode, WORD wParam , LONG lParam);
BOOL  FAR PASCAL LibMain();
VOID      PASCAL GrabToClipBoardByBitmap();
VOID      PASCAL BitmapToDIB();

FARPROC lpfnOldKbdHook;                         // old Keyboard function hook

/***************************************************************************/
//  LibMain()                                                               /
//                                                                          /
//  Function: Initialize the keyboard hook.                                 /
//                                                                          /
/***************************************************************************/
BOOL FAR PASCAL LibMain()
{
    if( (lpfnOldKbdHook = SetWindowsHook(WH_KEYBOARD, (FARPROC)CheckGrabHotKey) ) )
        MessageBox( NULL,"Window Screen Grabber installed O.K.\n\n"
           " Copy whole screen to clipboard by pressing : \n\n"
           " F8 = using BITMAP and PALETTE formats.\n"
           " F9 = using DIB (Device Indenpent Bitmap) format.",
           "WinGrab Ver. 1.0 by Achen", MB_OK );
    else
        MessageBox( NULL,"Screen Grabber failed to install.", "WinGrab", MB_OK );

    return (int)lpfnOldKbdHook ;
}


/***************************************************************************/
//  CheckGrabHotKey                                                         /
//                                                                          /
//  Function:  Keyboard hook routine to check Hot Keys                      /
//                                                                          /
/***************************************************************************/
DWORD FAR PASCAL CheckGrabHotKey(WORD nCode, WORD wParam , LONG lParam)
{
    switch( nCode ) {
        case HC_ACTION:
            if( lParam & 0x80000000L )          // if key is being released ?
                switch (wParam) {
                    case VK_F8:
                    case VK_F9:                 // Grab the Whole Screen. 
                        if( OpenClipboard( NULL ) ) {
                            EmptyClipboard();
                            CloseClipboard();
                            GrabToClipBoardByBitmap();
                            if( wParam == VK_F9 )
                                BitmapToDIB();
                        }
                        break;
                }
        default:
        return DefHookProc( nCode, wParam, lParam, &lpfnOldKbdHook );
    }
}


/****************************************************************************/
//  GrabToClipBoardByBitmap                                                  /
//                                                                           /
//  Function: Grabs the screen picture into a bitmap and                     /
//            a palette ( if supported ), then puts them into the clipboard  /
//                                                                           /
/****************************************************************************/
VOID PASCAL GrabToClipBoardByBitmap()
{
HDC     hDC, hMemoryDC, hPalette, hOldBitmap, hBitmap;
WORD    ScreenXlen, ScreenYlen, PaletteSize;
LPLOGPALETTE lpPalette;

    // get the Device Content of whole screen.
    if( !( hDC = CreateDC( "DISPLAY", NULL, NULL, NULL ) ) ) return;

    // get screen Width and Height.
    ScreenXlen = GetDeviceCaps( hDC, HORZRES );
    ScreenYlen = GetDeviceCaps( hDC, VERTRES );

    // Create a memory DC compatible with the current video device. 
    if( !( hMemoryDC = CreateCompatibleDC( hDC ) ) ){
        DeleteDC( hDC );
        return;
    }

    // Add color palettes to clipboard.
    if( !(PaletteSize = GetDeviceCaps( hDC, SIZEPALETTE ) ) )
         PaletteSize = DEFAULT_PALETTE_SIZE;
    hPalette    = GlobalAlloc( GPTR, (LONG)PaletteSize * sizeof(PALETTEENTRY)+sizeof(LOGPALETTE));
    lpPalette   = (LPLOGPALETTE) GlobalLock( hPalette );
    lpPalette->palVersion    = 0x300;
    lpPalette->palNumEntries = PaletteSize;
    if( GetDeviceCaps( hDC, SIZEPALETTE ) )     // if system palette exists ?
        GetSystemPaletteEntries( hDC, 0, PaletteSize,(LPPALETTEENTRY)lpPalette->palPalEntry );
    else
        GetPaletteEntries( GetStockObject(DEFAULT_PALETTE), 0, PaletteSize,(LPPALETTEENTRY)lpPalette->palPalEntry );

    // create a bitmap for the whole screen. 
    if( (hBitmap = CreateCompatibleBitmap( hDC, ScreenXlen, ScreenYlen ) ) ){

        // Select the bitmap into memory DC. 
        hOldBitmap = SelectObject( hMemoryDC, hBitmap );

        // copy the whole screen picture into this bitmap.
        BitBlt( hMemoryDC, 0, 0, ScreenXlen, ScreenYlen, hDC, 0, 0, SRCCOPY);
        hBitmap = SelectObject( hMemoryDC, hOldBitmap );

        if( OpenClipboard( NULL ) ){
            EmptyClipboard();            // let Clipboard handles this Bitmap.
            if( !SetClipboardData( CF_BITMAP, hBitmap ) ) 
                DeleteObject( hBitmap );
                                         // let Clipboard handle this Palette.
            SetClipboardData( CF_PALETTE, CreatePalette(lpPalette) );
            CloseClipboard();
        }else{
            DeleteObject( hBitmap );     // open clipboard failed.
            MessageBox( NULL,"Can't Open Clipboard !!!", "WinGrab", MB_OK);
        }
    }else{ 
        MessageBox( NULL,
           "Screen Grabber failed, Need more memory ?", "WinGrab", MB_OK );
    }

    GlobalUnlock( hPalette  );
    GlobalFree  ( hPalette  );
    DeleteDC    ( hMemoryDC );
    DeleteDC    ( hDC       );
}


/****************************************************************************/
//  BitmapToDIB                                                              /
//                                                                           /
//  Function: Transform the Bitmap and Palette in ClipBoard to DIB format.   /
//            and destroy Bitmap and Palette.                                /
//                                                                           /
/****************************************************************************/
VOID PASCAL BitmapToDIB()
{
HDC     hDC, hDIB, hPalette, hBitmap, hOldPalette;
WORD    ScreenXlen, ScreenYlen, DIBits, PaletteSize, InfoLen;
LPBITMAPINFO lpDIB;

    // open ClipBoard and read BITMAP and PALETTE.
    if( !OpenClipboard( NULL ) ) return; 
    hBitmap = GetClipboardData( CF_BITMAP  );
    hPalette= GetClipboardData( CF_PALETTE );
    if( !hBitmap || !hPalette ){
        CloseClipboard();
        return;
    }
    
    // Get DC and some attributes of the Vedio Device.
    hDC         = GetDC( NULL );
    ScreenXlen  = GetDeviceCaps( hDC, HORZRES );
    ScreenYlen  = GetDeviceCaps( hDC, VERTRES );
    DIBits      = GetDeviceCaps( hDC, PLANES) * GetDeviceCaps(hDC, BITSPIXEL);
    PaletteSize = 1 << DIBits;
    InfoLen     = sizeof(BITMAPINFOHEADER) + PaletteSize * sizeof( RGBQUAD );

    // allocate enough memory for DIB.
    if( (hDIB = GlobalAlloc( GPTR, (long)ScreenXlen*ScreenYlen*DIBits/8+InfoLen ))){
        lpDIB = (LPBITMAPINFO)GlobalLock( hDIB );

        // fill up DIB information structure. 
        lpDIB->bmiHeader.biSize          =  (long) sizeof(BITMAPINFOHEADER);
        lpDIB->bmiHeader.biWidth         =  (long) ScreenXlen;
        lpDIB->bmiHeader.biHeight        =  (long) ScreenYlen;
        lpDIB->bmiHeader.biPlanes        =  1;
        lpDIB->bmiHeader.biBitCount      =  DIBits;
        lpDIB->bmiHeader.biCompression   =  BI_RGB;

        // select and realize PALETTE.
        hOldPalette = SelectPalette( hDC, hPalette, 0 );
        RealizePalette( hDC );

        // Get DIB data from BITMAP.
        GetDIBits( hDC, hBitmap, 0, ScreenYlen, (LPSTR)lpDIB+InfoLen, lpDIB, DIB_RGB_COLORS);
        SelectPalette( hDC, hOldPalette, 0);

        // set DIB to ClipBoard.
        EmptyClipboard();
        GlobalUnlock( hDIB );               // let ClipBoard handle DIB.
        if( !SetClipboardData( CF_DIB, hDIB ) )
            GlobalFree( hDIB );
    }

    CloseClipboard();
    ReleaseDC( NULL, hDC );
}
