Page 1 of 1

Win32 Image Editing Program Part 1. Rate Topic: -----

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 802
  • View blog
  • Posts: 2,362
  • Joined: 20-March 10

Posted 04 June 2012 - 05:54 AM

Win32 Image Editing Program Part 1.

Building upon the 'Printing a Bitmap to Screen and Printer' Tutorial.

I would like to discuss building a basic image or photo
manipulation program.

This program has been built on top of the previous Tutorial
at the end of that Tutorial I suggested that it could be used for the beginning of an Image manipulation Program.

The last program had however a lot of shortcomings

For instance we used StretchBlt to resize the picture instead of using expandable scrollbars.

There was no cut, copy and paste facilities.

In part one of this tutorial we will put right all these things.

However we need to slightly restructure our previous program
because in parts two and three it will grow to an unmanageable size without this restructuring.

The New Structure

main.cpp

Functions.h
WinProc.h
Resource.h

resource.rc


As with the previous tutorials I will post the code then
explain each section piece by piece.

First up is our resource.rc file

#include "resource.h"


ICO1 ICON DISCARDABLE "snoopy.ico"


//Menu creation
hMenu MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "Open Bitmap",  IDM_OPEN_BM
MENUITEM "Print Bitmap", IDM_PRINT_BM, GRAYED
MENUITEM "Save Bitmap",  IDM_SAVE_BM, GRAYED
MENUITEM SEPARATOR
MENUITEM "Exit Program", IDM_EXIT
END

POPUP "&Edit"
BEGIN
MENUITEM "Copy",  IDM_COPY,  GRAYED
MENUITEM "Cut",   IDM_CUT,   GRAYED
MENUITEM "Paste", IDM_PASTE, GRAYED
END

POPUP "&Zoom"
BEGIN
MENUITEM SEPARATOR
MENUITEM "Zoom In",  IDM_ZOOMIN, GRAYED
MENUITEM SEPARATOR
MENUITEM "Zoom Out",   IDM_ZOOMOUT, GRAYED
END

END



Code for this is pretty much the same as our previous
Bitmap Printing Demo.

The exceptions are an extra two menus called 'Edit'
with cut, copy and paste facilities and 'Zoom'
with Zoom In and Zoom Out.

These are all grayed out as initially there should be none
till we load something.

Next up is our resource header resource.h
This header contains up to date info on all resources.

#define _WIN32_WINNT 0x0500

#include <windows.h>

#define ICO1           100

#define hMenu          1000
#define IDM_OPEN_BM    1001
#define IDM_PRINT_BM   1002
#define IDM_SAVE_BM    1003
#define IDM_EXIT       1004
#define IDM_COPY       1005
#define IDM_CUT        1006
#define IDM_PASTE      1007
#define IDM_ZOOMIN     1008
#define IDM_ZOOMOUT    1009




Next is our main.cpp


#include "resource.h"
#include "WinProc.h"



/*   variables  */
char szClassName[ ] = "Snoopy's Image Editing Demo";



/*  Declare  procedures  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
HDC GetPrinterDC (HWND Hwnd);
BOOL OpenFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
BOOL SaveFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
void InitialiseDialog(HWND hwnd);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void SaveBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
bool BitmapToClipboard(HBITMAP hBM, HWND hWnd);
HBITMAP CopyScreenToBitmap(HWND Hwnd,int x1, int y1, int x2, int y2);
void PaintLoadBitmap(HWND hwnd,SCROLLINFO si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll);
void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos);
void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double oWidth, double oHeight, double StartxPos, double EndxPos, double StartyPos, double EndyPos, int xCurrentScroll, int yCurrentScroll);
void Paste(HWND hwnd, HBITMAP hBitmap, double Width, double Height , double oWidth, double oHeight ,HDC hdc, HDC hdcMem, HDC MemoryDC, double StartxPos, double EndxPos, double xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll );
void ZeroScrollbars(HWND hwnd, SCROLLINFO si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll);

/*Start of Program Entry point*/

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
    wincl.hIconSm = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = MAKEINTRESOURCE(hMenu);                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               szClassName,       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, SW_MAXIMIZE);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}



You will see this has changed dramatically as it now contains some function declarations and WinMain and thats about it.

Next WinProc.h

#ifndef WINPROC_H_INCLUDED
#define WINPROC_H_INCLUDED

#include "Functions.h"
#include "resource.h"
#include <Winspool.h>
#include <CommDlg.h>
#include <cmath>
#include <algorithm>


HPALETTE hpal;
HMENU menu;
HBITMAP hBitmap;
double bxWidth, bxHeight;
double bxWidth2, bxHeight2;
double zoom =0;
bool fZoom = false;
int cxsize = 0, cxpage = 0;
int cysize = 0, cypage = 0;
HDC hdc,hdcMem;
RECT rect,WinRect;
SCROLLINFO si;
BITMAP bitmap;
double StartxPos;
double StartyPos;
double EndxPos;
double EndyPos;

/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     PAINTSTRUCT ps;


    // These variables are required by BitBlt.

    

    static BOOL fBlt;
    static BOOL fLoad;           // TRUE if BitBlt occurred
    static BOOL fScroll;         // TRUE if scrolling occurred
    static BOOL fSize;           // TRUE if fBlt & WM_SIZE

    static BOOL mmov;
    static BOOL cut;
    static BOOL paste;
    // 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
    static HWND hwndViewer;

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        InitialiseDialog(hwnd);
        hwndViewer = SetClipboardViewer(hwnd);

        menu = GetMenu(hwnd);


        // 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;
        return 0;

    case WM_LBUTTONDOWN:
    {
        StartxPos = LOWORD(lParam);
        StartyPos = HIWORD(lParam);



        return 0;
    }

    case WM_LBUTTONUP:
    {
        EndxPos = LOWORD(lParam);
        EndyPos = HIWORD(lParam);

        mmov = true;
        InvalidateRect(hwnd,&rect,true);
        return 0;
    }



    case WM_QUERYNEWPALETTE:
        if (!hpal)
            return FALSE;
        hdc = GetDC(hwnd);
        SelectPalette (hdc, hpal, FALSE);
        RealizePalette (hdc);
        InvalidateRect(hwnd,NULL,TRUE);
        ReleaseDC(hwnd,hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if (!hpal || (HWND)wParam == hwnd)
            break;
        hdc = GetDC(hwnd);
        SelectPalette (hdc, hpal, FALSE);
        RealizePalette (hdc);
        UpdateColors(hdc);
        ReleaseDC(hwnd,hdc);
        break;

    case WM_DRAWCLIPBOARD:
    {

        if (hwndViewer)
        {
            SendMessage(hwndViewer,message, wParam, lParam);
        }

        EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
        InvalidateRect(hwnd, NULL, true);
        return 0;
    }

    case WM_CHANGECBCHAIN:
    {
        if((HWND)wParam == hwndViewer)
        {
            hwndViewer = (HWND)lParam;
        }
        else if(hwndViewer)
        {
            SendMessage(hwndViewer,message,wParam, lParam);
        }

        return 0;
    }



    case WM_COMMAND:
        switch LOWORD(wParam)
        {

        case IDM_OPEN_BM:
        {

            hdc = NULL;
			
            OpenFileDialog(hwnd, szFileName, (TCHAR*)"Open a Bitmap File.");

            if(szFileName!= NULL)
            {
                ZeroMemory(&hBitmap, sizeof(HBITMAP));
                hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
                if(hBitmap)
                {
                    EnableMenuItem(menu, IDM_SAVE_BM, MF_ENABLED);
                    EnableMenuItem(menu, IDM_PRINT_BM, MF_ENABLED);
                    EnableMenuItem(menu, IDM_ZOOMIN, MF_ENABLED);
                    EnableMenuItem(menu, IDM_ZOOMOUT, MF_ENABLED);
                    cxpage = GetDeviceCaps (hdc, HORZRES);
                    cypage = GetDeviceCaps (hdc, VERTRES);
                    GetObject(hBitmap,sizeof(BITMAP),&bitmap);
                    bxWidth = bitmap.bmWidth;
                    bxHeight = bitmap.bmHeight;
                    bxWidth2 = bxWidth;
                    bxHeight2 = bxHeight;
                    rect.left = 0;
                    rect.top =0;
                    rect.right = (long)&cxpage;
                    rect.bottom = (long)&cypage;
					zoom =0;
			        fZoom =false;
                    fBlt = TRUE;
                    fLoad = TRUE;
                    hdc = CreateCompatibleDC(NULL);
                    if(IsClipboardFormatAvailable(CF_BITMAP))
                    {
                        EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
                    }
                    InvalidateRect(hwnd,&rect,true);


                }
            }
            return 0;
        }

        case IDM_PRINT_BM:
        {
            DOCINFO di= { sizeof (DOCINFO), TEXT ("Printing Picture...")};

            HDC prn;



            prn = GetPrinterDC(hwnd);
            cxpage = GetDeviceCaps (prn, HORZRES);
            cypage = GetDeviceCaps (prn, VERTRES);
            hdcMem = CreateCompatibleDC(prn);
            HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

            StartDoc (prn, &di);
            StartPage (prn) ;
            SetMapMode (prn, MM_ISOTROPIC);
            SetWindowExtEx(prn, cxpage,cypage, NULL);
            SetViewportExtEx(prn, cxpage, cypage,NULL);

            SetViewportOrgEx(prn, 0, 0, NULL);
			StretchBlt(prn, 0, 0, cxpage, cypage, hdcMem, 0, 0, (int)bxWidth, (int)bxHeight, SRCCOPY);
            EndPage (prn);
            EndDoc(prn);
            DeleteDC(prn);
            SelectObject(hdcMem, hbmOld);
            DeleteDC(hdcMem);

            return 0;
        }

        case IDM_SAVE_BM:
        {
            BOOL result = SaveFileDialog(hwnd,szFileName,(TCHAR*)"Save a Bitmap.");
            if(result != false)
            {
                PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hBitmap);
                hdc= GetDC(hwnd);
                SaveBMPFile(hwnd, szFileName, pbi, hBitmap, hdc);
            }
            return 0;
        }

        case IDM_EXIT:
        {
            PostQuitMessage(0);
            return 0;

        }

        case IDM_COPY:
        {
            int cutwidth = (int)abs(StartxPos - EndxPos);
            int cutheight = (int)abs(StartyPos - EndyPos);

            HBITMAP hbmp;

            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }

            ZeroMemory(&hbmp, sizeof(HBITMAP));


            hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);
            if(hbmp == NULL)
            {
                MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
            }


            BitmapToClipboard(hbmp, hwnd);
            DeleteBitmap(hbmp);


            return 0;
        }

        case IDM_CUT:
        {
            int cutwidth = (int)abs(StartxPos - EndxPos);

            int cutheight = (int)abs(StartyPos - EndyPos);
            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }

            HBITMAP hbmp;
            ZeroMemory(&hbmp, sizeof(HBITMAP));
            hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);


            if(hbmp == NULL)
            {
                MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
            }
            OpenClipboard(hwnd);
            EmptyClipboard();
            CloseClipboard();

            BitmapToClipboard(hbmp, hwnd);
            DeleteBitmap(hbmp);


            cut = true;
            InvalidateRect(hwnd,&rect,true);
            return 0;
        }
        case IDM_PASTE:
        {
            paste = true;

            InvalidateRect(hwnd,NULL,true);
            return 0;
        }

        case IDM_ZOOMOUT:
        {


            zoom = zoom - 25;
            if (zoom < -75)
            {
                zoom = -75;
            }
            bxWidth2 = bxWidth + (bxWidth*(zoom/100));
            bxHeight2 = bxHeight + (bxHeight*(zoom/100));

            fZoom = true;

            GetWindowRect(hwnd, &WinRect);
            cxsize = WinRect.right;
            cysize = WinRect.bottom;
            int t1 =(int)(bxWidth2-cxsize);
            if (t1 < 0)
            {
                ShowScrollBar(hwnd,SB_HORZ,false);

            }
            xMaxScroll = max(t1,0);
            xCurrentScroll = min(xCurrentScroll, xMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = xMinScroll;
            si.nMax   = (int)bxWidth2;
            si.nPage  = cxsize;
            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.
            int t2 = (int)bxHeight2 - cysize;
            yMaxScroll = max(t2, 0);
            yCurrentScroll = min(yCurrentScroll, yMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = yMinScroll;
            si.nMax   = (int)bxHeight2;
            si.nPage  = cysize;
            si.nPos   = yCurrentScroll;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

            InvalidateRect(hwnd,&WinRect,true);
            return 0;
        }

        case IDM_ZOOMIN:
        {


            zoom = zoom + 25;
            if (zoom >  75)
            {
                zoom = 75;
            }
            bxWidth2 = bxWidth + (bxWidth*(zoom/100));
            bxHeight2 = bxHeight + (bxHeight*(zoom/100));

            fZoom = true;

            GetWindowRect(hwnd, &WinRect);
            cxsize = WinRect.right;
            cysize = WinRect.bottom;
            int t1 = (int)(bxWidth2-cxsize);
            if (t1 > 0)
            {
                ShowScrollBar(hwnd,SB_HORZ,true);

            }
            xMaxScroll = max(t1,0);
            xCurrentScroll = min(xCurrentScroll, xMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = xMinScroll;
            si.nMax   = (int)bxWidth2;
            si.nPage  = cxsize;
            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.
            int t2 = (int)bxHeight2 - cysize;
            yMaxScroll = max(t2, 0);
            yCurrentScroll = min(yCurrentScroll, yMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = yMinScroll;
            si.nMax   = (int)bxHeight2;
            si.nPage  = cysize;
            si.nPos   = yCurrentScroll;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
            InvalidateRect(hwnd,&WinRect,true);

            return 0;
        }

        break;
        }

    case WM_PAINT:
    {


        hdc = BeginPaint(hwnd, &ps);


        hdcMem = CreateCompatibleDC(hdc);
        HDC MemoryDC= CreateCompatibleDC(hdc);
        if (fLoad)
        {
            PaintLoadBitmap(hwnd, si, bitmap, cxsize, cysize, xMaxScroll, xCurrentScroll, xMinScroll, yMaxScroll, yCurrentScroll, yMinScroll);

            fLoad= FALSE;

        }
        if (fBlt)
        {
            SelectObject(hdcMem, hBitmap);
            SetStretchBltMode(hdc,HALFTONE);

            StretchBlt(hdc, 0, 0,(int)bxWidth2,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, SRCCOPY);

        }

        // 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)
        {
            SelectObject(hdcMem, hBitmap);
            SetStretchBltMode(hdc,HALFTONE);

            StretchBlt(hdc, 0, 0, (int)bxWidth2 ,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, 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)
        {

            SetStretchBltMode(hdc,HALFTONE);
            StretchBlt(hdc,0,0,(int)bxWidth2,(int)bxHeight2,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);

            fScroll = false;

        }

        if(fZoom == true)
        {

            SelectObject(hdcMem,hBitmap);
            SetStretchBltMode(hdc,HALFTONE);
            StretchBlt(hdc,0,0,(int)bxWidth2,(int)bxHeight2,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);

            fZoom = false;

        }


        if(mmov)
        {
            DrawBoundingBox(hdc, (int)StartxPos, (int)EndxPos, (int)StartyPos, (int)EndyPos);
            mmov = false;
            EnableMenuItem(menu, IDM_COPY, MF_ENABLED);
            EnableMenuItem(menu, IDM_CUT, MF_ENABLED);

        }

        if(cut)
        {


            Cut(hdc, hdcMem, hBitmap, (int)bxWidth2, (int)bxHeight2, (int)bxWidth, (int)bxHeight, StartxPos, EndxPos, StartyPos, EndyPos, xCurrentScroll, yCurrentScroll);

            cut = false;


        }

        if(paste)
        {

            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }


            StartxPos = ((StartxPos)*(bxWidth/bxWidth2));
            StartyPos = ((StartyPos)*(bxHeight/bxHeight2));
            EndxPos = (EndxPos+xCurrentScroll);
            EndyPos = (EndyPos+yCurrentScroll);



            

            Paste(hwnd, hBitmap, bxWidth2, bxHeight2 ,bxWidth, bxHeight ,hdc, hdcMem, MemoryDC, StartxPos, EndxPos, xCurrentScroll, StartyPos, EndyPos, yCurrentScroll );


            //Reset Scrollbars to zero
            ZeroScrollbars(hwnd, si, bitmap, cxsize, cysize, xCurrentScroll, yCurrentScroll, xMaxScroll, yMaxScroll, xMinScroll, yMinScroll);


            paste = false;

        }


        EndPaint(hwnd, &ps);
        DeleteDC(hdcMem);
        DeleteDC(MemoryDC);
        return 0;
    }



    case  WM_SIZE:
    {


        cxsize = LOWORD(lParam);
        cysize = HIWORD(lParam);
        rect.right = cxsize;
        rect.bottom = cysize;




        fSize = TRUE;

        // The horizontal scrolling range is defined by
        // (bitmap_width) - (client_width). The current horizontal
        // scroll value remains within the horizontal scrolling range.
        int t1 = (int)(bxWidth2-cxsize);
        xMaxScroll = max(t1,0);
        xCurrentScroll = min(xCurrentScroll, xMaxScroll);
        si.cbSize = sizeof(si);
        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
        si.nMin   = xMinScroll;
        si.nMax   = (int)bxWidth2;
        si.nPage  = (int)cxsize;
        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.
        int t2 = (int)bxHeight2 - cysize;
        yMaxScroll = max(t2, 0);
        yCurrentScroll = min(yCurrentScroll, yMaxScroll);
        si.cbSize = sizeof(si);
        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
        si.nMin   = yMinScroll;
        si.nMax   = (int)bxHeight2;
        si.nPage  = cysize;
        si.nPos   = yCurrentScroll;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        InvalidateRect(hwnd, &WinRect, true);
        break;
    }
    case WM_HSCROLL:
    {
        int xDelta;     // xDelta = new_pos - current_pos
        int xNewPos;    // new position
        int yDelta = 0;

        switch (LOWORD(wParam))
        {
            // User clicked the scroll bar shaft left of the scroll box.
        case SB_PAGEUP:
            xNewPos = xCurrentScroll - 50;
            break;

            // User clicked the scroll bar 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.
        xMaxScroll = (int)bxWidth2;
        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 ;

        // 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, (PRECT) NULL,
                       SW_INVALIDATE);
        InvalidateRect(hwnd, &WinRect, true);

        // 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 scroll bar shaft above the scroll box.
        case SB_PAGEUP:
            yNewPos = yCurrentScroll - 50;
            break;

            // User clicked the scroll bar 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.
        yMaxScroll = (int)bxHeight2;
        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, (PRECT) NULL,
                       SW_INVALIDATE);
        InvalidateRect(hwnd,&WinRect, true);

        // Reset the scroll bar.
        si.cbSize = sizeof(si);
        si.fMask  = SIF_POS;
        si.nPos   = yCurrentScroll;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        break;
    }


    case WM_DESTROY:
        ChangeClipboardChain(hwnd, hwndViewer);
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);

    }
    return 0;

}


#endif // WINPROC_H_INCLUDED





This contains our Windows Procedure and things like WM_COMMAND and WM_PAINT.

Finally Functions.h

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED

#include <fstream>
#include <windows.h>
#include <windowsx.h>

using namespace std;

static OPENFILENAME ofn;
char szFileName[500]= "\0";


HDC GetPrinterDC (HWND Hwnd)
{

// Initialize a PRINTDLG structure's size and set the PD_RETURNDC flag set the Owner flag to hwnd.
// The PD_RETURNDC flag tells the dialog to return a printer device context.
    HDC hdc;
    PRINTDLG pd = {0};
    pd.lStructSize = sizeof( pd );
    pd.hwndOwner = Hwnd;
    pd.Flags = PD_RETURNDC;

// Retrieves the printer DC
    PrintDlg(&pd);
    hdc =pd.hDC;
    return hdc ;


}

BOOL OpenFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName)

{
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hInstance = GetModuleHandle(NULL);
    ofn.lpstrCustomFilter = NULL;
    ofn.nMaxCustFilter = 0;
    ofn.nFilterIndex = 0;

    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = pFileName;
    ofn.lpstrFileTitle = NULL;
    ofn.lpstrTitle = pTitleName;
    ofn.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST;
    ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\0\0");



    return GetOpenFileName(&ofn);
}

BOOL SaveFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName)

{
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hInstance = GetModuleHandle(NULL);
    ofn.lpstrCustomFilter = NULL;
    ofn.nMaxCustFilter = 0;
    ofn.nFilterIndex = 0;

    ofn.hwndOwner = hwnd;
    ofn.lpstrFile = pFileName;
    ofn.lpstrFileTitle = NULL;
    ofn.lpstrTitle = pTitleName;
    ofn.Flags = OFN_EXPLORER|OFN_OVERWRITEPROMPT;
    ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\0\0");



    return GetSaveFileName(&ofn);
}

void InitialiseDialog(HWND hwnd)
{
    ZeroMemory(&ofn, sizeof(ofn));

    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.hInstance = NULL;
    ofn.lpstrCustomFilter = NULL;
    ofn.nMaxCustFilter = 0;
    ofn.nFilterIndex = 0;
    ofn.lpstrFile = szFileName;
    ofn.nMaxFile = 500;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = MAX_PATH;
    ofn.lpstrInitialDir = NULL;
    ofn.lpstrTitle = NULL;
    ofn.Flags = 0;
    ofn.nFileOffset = 0;
    ofn.nFileExtension = 0;
    ofn.lpstrDefExt = NULL;
    ofn.lCustData = 0L;
    ofn.lpfnHook = NULL;
    ofn.lpTemplateName = NULL;
}


void SaveBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC)
{
    std::ofstream hf;                  // file handle
    BITMAPFILEHEADER hdr;       // bitmap file-header
    PBITMAPINFOHEADER pbih;     // bitmap info-header
    LPBYTE lpBits;              // memory pointer
    DWORD cb;                   // incremental count of bytes
    BYTE *hp;                   // byte pointer


    pbih = (PBITMAPINFOHEADER) pbi;
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

    if (!lpBits)
    {
        MessageBox(hwnd,"GlobalAlloc","Error", MB_OK );
    }
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,DIB_RGB_COLORS))
    {
        MessageBox(hwnd,"GetDIBits","Error",MB_OK );
    }
// Create the .BMP file.
    hf.open(pszFile,std::ios::binary);
    if (hf.fail() == true)
    {
        MessageBox( hwnd,"CreateFile","Error", MB_OK);
    }

    hdr.bfType = 0x4d42;  // File type designator "BM" 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
    hdr.bfReserved1 = 0;
    hdr.bfReserved2 = 0;
// Compute the offset to the array of color indices.
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
    hf.write((char*) &hdr, sizeof(BITMAPFILEHEADER));
    if (hf.fail() == true )
    {
        MessageBox(hwnd,"WriteFileHeader","Error",MB_OK );
    }
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
    hf.write((char*) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD));
    if (hf.fail() == true )
    {
        MessageBox(hwnd,"WriteInfoHeader","Error",MB_OK );
    }
// Copy the array of color indices into the .BMP file.
    cb = pbih->biSizeImage;
    hp = lpBits;
    hf.write((char*) hp, (int) cb);
    if (hf.fail() == true )
    {
        MessageBox(hwnd,"WriteData","Error",MB_OK );
    }
// Close the .BMP file.
    hf.close();
    if (hf.fail() == true)
    {
        MessageBox(hwnd,"CloseHandle","Error",MB_OK );
    }

// Free memory.
    GlobalFree((HGLOBAL)lpBits);
}
//End of BMP Save


PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{
    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD cClrBits;
// Retrieve the bitmap color format, width, and height.
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))
    {
        MessageBox(hwnd,"GetObject","Error",MB_OK );
    }
// Convert the color format to a count of bits.
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
    if (cClrBits == 1)
        cClrBits = 1;
    else if (cClrBits <= 4)
        cClrBits = 4;
    else if (cClrBits <= 8)
        cClrBits = 8;
    else if (cClrBits <= 16)
        cClrBits = 16;
    else if (cClrBits <= 24)
        cClrBits = 24;
    else cClrBits = 32;

// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)

    if (cClrBits != 24)
    {
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR,sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
    }
// There is no RGBQUAD array for the 24-bit-per-pixel format.
    else
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));

// Initialize the fields in the BITMAPINFO structure.
    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = bmp.bmWidth;
    pbmi->bmiHeader.biHeight = bmp.bmHeight;
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
    if (cClrBits < 24)
    {
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
    }
// If the bitmap is not compressed, set the BI_RGB flag.
    pbmi->bmiHeader.biCompression = BI_RGB;

// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
    pbmi->bmiHeader.biClrImportant = 0;

    return pbmi; //return BITMAPINFO
}

bool BitmapToClipboard(HBITMAP hBM, HWND hWnd)
{
    if (!OpenClipboard(hWnd))
        return false;
    EmptyClipboard();

    BITMAP bm;
    GetObject(hBM, sizeof(bm), &bm);

    BITMAPINFOHEADER bi;
    ZeroMemory(&bi, sizeof(BITMAPINFOHEADER));
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = bm.bmBitsPixel;
    bi.biCompression = BI_RGB;
    if (bi.biBitCount <= 1)	// make sure bits per pixel is valid
        bi.biBitCount = 1;
    else if (bi.biBitCount <= 4)
        bi.biBitCount = 4;
    else if (bi.biBitCount <= 8)
        bi.biBitCount = 8;
    else // if greater than 8-bit, force to 24-bit
        bi.biBitCount = 24;

    // Get size of color table.
    SIZE_T dwColTable = (bi.biBitCount <= 8) ? (1 << bi.biBitCount) * sizeof(RGBQUAD) : 0;

    // Create a device context with palette
    HDC hDC = GetDC(NULL);
    HPALETTE hPal = static_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
    HPALETTE hOldPal = SelectPalette(hDC, hPal, FALSE);
    RealizePalette(hDC);

    // Use GetDIBits to calculate the image size.
    GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight), NULL,
              reinterpret_cast<LPBITMAPINFO>(&bi), DIB_RGB_COLORS);
    // If the driver did not fill in the biSizeImage field, then compute it.
    // Each scan line of the image is aligned on a DWORD (32bit) boundary.
    if (0 == bi.biSizeImage)
        bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

    // Allocate memory
    HGLOBAL hDIB = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPINFOHEADER) + dwColTable + bi.biSizeImage);
    if (hDIB)
    {
        union tagHdr_u
        {
            LPVOID             p;
            LPBYTE             pByte;
            LPBITMAPINFOHEADER pHdr;
            LPBITMAPINFO       pInfo;
        } Hdr;

        Hdr.p = GlobalLock(hDIB);
        // Copy the header
        CopyMemory(Hdr.p, &bi, sizeof(BITMAPINFOHEADER));
        // Convert/copy the image bits and create the color table
        int nConv = GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight),
                              Hdr.pByte + sizeof(BITMAPINFOHEADER) + dwColTable,
                              Hdr.pInfo, DIB_RGB_COLORS);
        GlobalUnlock(hDIB);
        if (!nConv)
        {
            GlobalFree(hDIB);
            hDIB = NULL;
        }
    }
    if (hDIB)
        SetClipboardData(CF_DIB, hDIB);
    CloseClipboard();
    SelectPalette(hDC, hOldPal, FALSE);
    ReleaseDC(NULL, hDC);
    return NULL != hDIB;
}



HBITMAP CopyScreenToBitmap(HWND Hwnd,int x1, int y1, int nWidth, int nHeight)
{
    HDC hScrDC,hMemDC; // screen DC and memory DC
    HBITMAP hxBitmap, hOldBitmap; // handles to deice-dependent bitmaps





// create a DC for the screen and create
// a memory DC compatible to screen DC

     hScrDC = GetDC(Hwnd);



    if((hMemDC = CreateCompatibleDC(hScrDC))==NULL)
    {

        MessageBox(Hwnd,"Can not create compatible DC","Error",MB_OK);
        return NULL;
    }


// create a bitmap compatible with the screen DC
    if((hxBitmap = CreateCompatibleBitmap(hScrDC, nWidth-1, nHeight-1))==NULL)
    {
        MessageBox(Hwnd,"Can not create compatible Bitmap","Error",MB_OK);

        return NULL;
    }

// select new bitmap into memory DC
    hOldBitmap = (HBITMAP)SelectObject(hMemDC, hxBitmap);

    if(hOldBitmap == NULL)
    {
        MessageBox(Hwnd,"Can not select old Bitmap","Error",MB_OK);
        return NULL;
    }

// bitblt screen DC to memory DC
    if(!BitBlt(hMemDC, 0, 0, nWidth-2, nHeight-2, hScrDC, x1+1, y1+1, SRCCOPY))
    {
        MessageBox(Hwnd,"Can not read screen memory","Error",MB_OK);
        return NULL;
    }

// select old bitmap back into memory DC and get handle to bitmap of the screen

    hxBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
    if(hxBitmap == NULL)
    {
        MessageBox(Hwnd,"Can not select object","Error",MB_OK);
        return NULL;
    }
// clean up
    DeleteDC(hScrDC);
    DeleteDC(hMemDC);

// return handle to the bitmap

    return hxBitmap;
}


void PaintLoadBitmap(HWND hwnd,SCROLLINFO si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll)
{


    // The horizontal scrolling range is defined by
    // (bitmap_width) - (client_width). The current horizontal
    // scroll value remains within the horizontal scrolling range.
    int t1 =(bitmap.bmWidth-pcxsize);
    xMaxScroll = max(t1,0);
    xCurrentScroll = min(xCurrentScroll, xMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = xMinScroll;
    si.nMax   = bitmap.bmWidth;
    si.nPage  = pcxsize;
    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.
    int t2 = bitmap.bmHeight - pcysize;
    yMaxScroll = max(t2, 0);
    yCurrentScroll = min(yCurrentScroll, yMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = yMinScroll;
    si.nMax   = bitmap.bmHeight;
    si.nPage  = pcysize;
    si.nPos   = yCurrentScroll;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}

void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos)
{
    HPEN greenPen=CreatePen(PS_SOLID, 1, RGB(0,255,0));
    SelectObject(hdc, greenPen);

    SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));


    MoveToEx(hdc, StartxPos, StartyPos, NULL);
    Rectangle(hdc, StartxPos, StartyPos , EndxPos, EndyPos);


}

void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double oWidth, double oHeight, double StartxPos, double EndxPos, double StartyPos, double EndyPos, int xCurrentScroll, int yCurrentScroll)
{
    RECT crect;
    StartxPos = StartxPos*(oWidth/Width);
    StartyPos = StartyPos*(oHeight/Height);
    EndxPos = EndxPos*(oWidth/Width);
    EndyPos = EndyPos*(oHeight/Height);

    crect.left = (long)StartxPos+xCurrentScroll;
    crect.top =  (long)StartyPos+yCurrentScroll;
    crect.right = (long)EndxPos+xCurrentScroll;
    crect.bottom = (long)EndyPos+yCurrentScroll;

    SelectObject(hdcMem, hBitmap);

    FillRect(hdcMem, &crect, GetStockBrush(LTGRAY_BRUSH));
    SetStretchBltMode(hdc,HALFTONE);
    StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll,(int)oWidth,(int)oHeight, SRCCOPY);

}

void Paste(HWND hwnd, HBITMAP hBitmap,double Width,double Height ,double oWidth, double oHeight ,HDC hdc, HDC hdcMem, HDC MemoryDC, double StartxPos, double EndxPos, int xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll )
{
    HBITMAP clip;
    BITMAP clipmap;



    ZeroMemory(&clip, sizeof(HBITMAP));
    ZeroMemory(&clipmap, sizeof(BITMAP));
    OpenClipboard(hwnd);

    clip = (HBITMAP)GetClipboardData(CF_BITMAP);
    GetObject(clip,sizeof(BITMAP),&clipmap);
    SelectObject(MemoryDC, clip);

    SelectObject(hdcMem,hBitmap);

    BitBlt(hdcMem, (int)StartxPos+xCurrentScroll, (int)StartyPos+yCurrentScroll ,(int)oWidth,
              (int)oHeight, MemoryDC ,0,0,SRCCOPY);
    SetStretchBltMode(hdc,HALFTONE);
    StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll, (int)oWidth, (int)oHeight, SRCCOPY);


    CloseClipboard();
    DeleteBitmap(clip);
}

void ZeroScrollbars(HWND hwnd, SCROLLINFO si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll)
{
    int t1 =(bitmap.bmWidth-cxsize);
    xMaxScroll = max(t1,0);
    xCurrentScroll = min(xCurrentScroll, xMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = xMinScroll;
    si.nMax   = bitmap.bmWidth;
    si.nPage  = cxsize;
    si.nPos   = 0;
    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

    // The scrolling range is defined by
    // (bitmap_height) - (client_height). The current
    // scroll value remains within the scrolling range.
    int t2 = bitmap.bmHeight - cysize;
    yMaxScroll = max(t2, 0);
    yCurrentScroll = min(yCurrentScroll, yMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = yMinScroll;
    si.nMax   = bitmap.bmHeight;
    si.nPage  = cysize;
    si.nPos   = 0;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
    xCurrentScroll = 0;
    yCurrentScroll =0;
}

#endif // FUNCTIONS_H_INCLUDED



This contains all of our Functions,a lot of which shall be new but a few old familiar ones will also be present.

link to

gdi32
user32
kernel32
winspool
comdlg32
opengl32


This is not a Unicode build so please
if you are using Visual Studio change the character set to
Multi-Byte.

Its been tested under Code::Blocks and Visual Studio.
It compiles fine with no errors or warnings under both.

For those who are impatient you can now hit build & compile.

For the rest of you, it's the explanation part.


The Explanation Part.

First of all I wont be going over old ground that I already covered in

Bitmap Printing Tutorial In C++ Win32

there would be little point to that I will however refer you back to the Tutorial and I will simply hereafter refer to it as BPT for short.

Part 1.

main.cpp

#include "resource.h"
#include "WinProc.h"



/*   variables  */
char szClassName[ ] = "Snoopy's Image Editing Demo";



/*  Declare  procedures  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
HDC GetPrinterDC (HWND Hwnd);
BOOL OpenFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
BOOL SaveFileDialog(HWND hwnd, LPTSTR pFileName ,LPTSTR pTitleName);
void InitialiseDialog(HWND hwnd);
PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp);
void SaveBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC);
bool BitmapToClipboard(HBITMAP hBM, HWND hWnd);
HBITMAP CopyScreenToBitmap(HWND Hwnd,int x1, int y1, int x2, int y2);
void PaintLoadBitmap(HWND hwnd,SCROLLINFO si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll);
void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos);
void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, int bxWidth, int bxHeight, int StartxPos, int EndxPos, int StartyPos, int EndyPos, int xCurrentScroll, int yCurrentScroll);
void Paste(HWND hwnd, HBITMAP hBitmap, int bxWidth, int bxHeight ,HDC hdc, HDC hdcMem, HDC MemoryDC, int StartxPos, int EndxPos, int xCurrentScroll, int StartyPos, int EndyPos, int yCurrentScroll );
void ZeroScrollbars(HWND hwnd, SCROLLINFO si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll);



Most of this code will be familiar to you from BPT but there are some new additions in
the procedures.

CopyScreenToBitmap copies an area of the screen to a bitmap and is used in copy and cut functions.

DrawBoundingBox this deals with drawing
a green box around an area you have selected by left clicking and dragging.
It is used in cut, copy and paste functions.

Part 2.

WinMain

/*Start of Program Entry point*/

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
    wincl.hIconSm = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE(ICO1));
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = MAKEINTRESOURCE(hMenu);                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               szClassName,       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, SW_MAXIMIZE);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


This is the entry point of our program it registers a new class and sets up a new window hwnd.

It shows the window maximised as this makes more sense for loading picture files.

It sets up a message loop which it intercepts
dialog messages for our program the ones not
acted on are passed back to the OS.

It names WindowProcedure as the callback procedure where some of these messages will be acted on.


Part 3.

WM_CREATE

switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        InitialiseDialog(hwnd);
        hwndViewer = SetClipboardViewer(hwnd);

        menu = GetMenu(hwnd);
        

        // 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;
        return 0;


We first set up our window as a Clipboard Viewer.

Set the menu.

We set all our flags to false.

fBlt deals with 'has the screen been blitted ?'
fScroll deals with 'has the screen been scrolled ?'
fSize deals with 'has the screen been resized ?'

Finally we set the horizontal and vertical scrollbars to zero.


case WM_LBUTTONDOWN:
    {
        StartxPos = LOWORD(lParam);
        StartyPos = HIWORD(lParam);



        return 0;
    }

    case WM_LBUTTONUP:
    {
        EndxPos = LOWORD(lParam);
        EndyPos = HIWORD(lParam);

        mmov = true;
        InvalidateRect(hwnd,&rect,true);
        return 0;
    }




WM_LBUTTONDOWN if a left mouse button is pressed store the position on screen where that
occurred in the variables StartxPos and StartyPos.
WM_LBUTTONUP if a left mouse button is released store the position on screen where that occurred in the variables EndxPos and EndyPos, the flag mmov is set to true and the
screen is redrawn.

case WM_QUERYNEWPALETTE:
        if (!hpal)
            return FALSE;
        hdc = GetDC(hwnd);
        SelectPalette (hdc, hpal, FALSE);
        RealizePalette (hdc);
        InvalidateRect(hwnd,NULL,TRUE);
        ReleaseDC(hwnd,hdc);
        return TRUE;

    case WM_PALETTECHANGED:
        if (!hpal || (HWND)wParam == hwnd)
            break;
        hdc = GetDC(hwnd);
        SelectPalette (hdc, hpal, FALSE);
        RealizePalette (hdc);
        UpdateColors(hdc);
        ReleaseDC(hwnd,hdc);
        break;



Deals with getting the proper color palette for the screen no matter which bitmap we load.

 case WM_DRAWCLIPBOARD:
    {

        if (hwndViewer)
        {
            SendMessage(hwndViewer,message, wParam, lParam);
        }

        EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
        InvalidateRect(hwnd, NULL, true);
        return 0;
    }

    case WM_CHANGECBCHAIN:
    {
        if((HWND)wParam == hwndViewer)
        {
            hwndViewer = (HWND)lParam;
        }
        else if(hwndViewer)
        {
            SendMessage(hwndViewer,message,wParam, lParam);
        }

        return 0;
    }




We need to set up our program as a clipboard viewer in a possible chain of clipboard viewers
other programs that are also clipboard viewers need access to the clipboard as well.

We need to only process messages that are meant for us and pass on those messages that aren't.

    case WM_COMMAND:
        switch LOWORD(wParam)
        {

        case IDM_OPEN_BM:
        {

            hdc = NULL;
			
            OpenFileDialog(hwnd, szFileName, (TCHAR*)"Open a Bitmap File.");

            if(szFileName!= NULL)
            {
                ZeroMemory(&hBitmap, sizeof(HBITMAP));
                hBitmap = (HBITMAP)LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE|LR_VGACOLOR);
                if(hBitmap)
                {
                    EnableMenuItem(menu, IDM_SAVE_BM, MF_ENABLED);
                    EnableMenuItem(menu, IDM_PRINT_BM, MF_ENABLED);
                    EnableMenuItem(menu, IDM_ZOOMIN, MF_ENABLED);
                    EnableMenuItem(menu, IDM_ZOOMOUT, MF_ENABLED);
                    cxpage = GetDeviceCaps (hdc, HORZRES);
                    cypage = GetDeviceCaps (hdc, VERTRES);
                    GetObject(hBitmap,sizeof(BITMAP),&bitmap);
                    bxWidth = bitmap.bmWidth;
                    bxHeight = bitmap.bmHeight;
                    bxWidth2 = bxWidth;
                    bxHeight2 = bxHeight;
                    rect.left = 0;
                    rect.top =0;
                    rect.right = (long)&cxpage;
                    rect.bottom = (long)&cypage;
					zoom =0;
			        fZoom =false;
                    fBlt = TRUE;
                    fLoad = TRUE;
                    hdc = CreateCompatibleDC(NULL);
                    if(IsClipboardFormatAvailable(CF_BITMAP))
                    {
                        EnableMenuItem(menu, IDM_PASTE, MF_ENABLED);
                    }
                    InvalidateRect(hwnd,&rect,true);


                }
            }
            return 0;
        }

        case IDM_PRINT_BM:
        {
            DOCINFO di= { sizeof (DOCINFO), TEXT ("Printing Picture...")};

            HDC prn;



            prn = GetPrinterDC(hwnd);
            cxpage = GetDeviceCaps (prn, HORZRES);
            cypage = GetDeviceCaps (prn, VERTRES);
            hdcMem = CreateCompatibleDC(prn);
            HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);

            StartDoc (prn, &di);
            StartPage (prn) ;
            SetMapMode (prn, MM_ISOTROPIC);
            SetWindowExtEx(prn, cxpage,cypage, NULL);
            SetViewportExtEx(prn, cxpage, cypage,NULL);

            SetViewportOrgEx(prn, 0, 0, NULL);
			StretchBlt(prn, 0, 0, cxpage, cypage, hdcMem, 0, 0, (int)bxWidth, (int)bxHeight, SRCCOPY);
            EndPage (prn);
            EndDoc(prn);
            DeleteDC(prn);
            SelectObject(hdcMem, hbmOld);
            DeleteDC(hdcMem);

            return 0;
        }

        case IDM_SAVE_BM:
        {
            BOOL result = SaveFileDialog(hwnd,szFileName,(TCHAR*)"Save a Bitmap.");
            if(result != false)
            {
                PBITMAPINFO pbi = CreateBitmapInfoStruct(hwnd, hBitmap);
                hdc= GetDC(hwnd);
                SaveBMPFile(hwnd, szFileName, pbi, hBitmap, hdc);
            }
            return 0;
        }

        case IDM_EXIT:
        {
            PostQuitMessage(0);
            return 0;

        }

        case IDM_COPY:
        {
            int cutwidth = (int)abs(StartxPos - EndxPos);
            int cutheight = (int)abs(StartyPos - EndyPos);

            HBITMAP hbmp;

            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }

            ZeroMemory(&hbmp, sizeof(HBITMAP));


            hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);
            if(hbmp == NULL)
            {
                MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
            }


            BitmapToClipboard(hbmp, hwnd);
            DeleteBitmap(hbmp);


            return 0;
        }

        case IDM_CUT:
        {
            int cutwidth = (int)abs(StartxPos - EndxPos);

            int cutheight = (int)abs(StartyPos - EndyPos);
            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }

            HBITMAP hbmp;
            ZeroMemory(&hbmp, sizeof(HBITMAP));
            hbmp = CopyScreenToBitmap(hwnd,(int)StartxPos,(int)StartyPos,cutwidth,cutheight);


            if(hbmp == NULL)
            {
                MessageBox(hwnd,"Copy not created properly","Error",MB_OK);
            }
            OpenClipboard(hwnd);
            EmptyClipboard();
            CloseClipboard();

            BitmapToClipboard(hbmp, hwnd);
            DeleteBitmap(hbmp);


            cut = true;
            InvalidateRect(hwnd,&rect,true);
            return 0;
        }
        case IDM_PASTE:
        {
            paste = true;

            InvalidateRect(hwnd,NULL,true);
            return 0;
        }

        case IDM_ZOOMOUT:
        {


            zoom = zoom - 25;
            if (zoom < -75)
            {
                zoom = -75;
            }
            bxWidth2 = bxWidth + (bxWidth*(zoom/100));
            bxHeight2 = bxHeight + (bxHeight*(zoom/100));

            fZoom = true;

            GetWindowRect(hwnd, &WinRect);
            cxsize = WinRect.right;
            cysize = WinRect.bottom;
            int t1 =(int)(bxWidth2-cxsize);
            if (t1 < 0)
            {
                ShowScrollBar(hwnd,SB_HORZ,false);

            }
            xMaxScroll = max(t1,0);
            xCurrentScroll = min(xCurrentScroll, xMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = xMinScroll;
            si.nMax   = (int)bxWidth2;
            si.nPage  = cxsize;
            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.
            int t2 = (int)bxHeight2 - cysize;
            yMaxScroll = max(t2, 0);
            yCurrentScroll = min(yCurrentScroll, yMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = yMinScroll;
            si.nMax   = (int)bxHeight2;
            si.nPage  = cysize;
            si.nPos   = yCurrentScroll;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

            InvalidateRect(hwnd,&WinRect,true);
            return 0;
        }

        case IDM_ZOOMIN:
        {


            zoom = zoom + 25;
            if (zoom >  75)
            {
                zoom = 75;
            }
            bxWidth2 = bxWidth + (bxWidth*(zoom/100));
            bxHeight2 = bxHeight + (bxHeight*(zoom/100));

            fZoom = true;

            GetWindowRect(hwnd, &WinRect);
            cxsize = WinRect.right;
            cysize = WinRect.bottom;
            int t1 = (int)(bxWidth2-cxsize);
            if (t1 > 0)
            {
                ShowScrollBar(hwnd,SB_HORZ,true);

            }
            xMaxScroll = max(t1,0);
            xCurrentScroll = min(xCurrentScroll, xMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = xMinScroll;
            si.nMax   = (int)bxWidth2;
            si.nPage  = cxsize;
            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.
            int t2 = (int)bxHeight2 - cysize;
            yMaxScroll = max(t2, 0);
            yCurrentScroll = min(yCurrentScroll, yMaxScroll);
            si.cbSize = sizeof(si);
            si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
            si.nMin   = yMinScroll;
            si.nMax   = (int)bxHeight2;
            si.nPage  = cysize;
            si.nPos   = yCurrentScroll;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
            InvalidateRect(hwnd,&WinRect,true);

            return 0;
        }

        break;
        }



The WM_COMMAND deals with our Menu commands
Open Bitmap
Save Bitmap
Print Bitmap
Copy
Cut
Paste
Zoom In
Zoom Out
and Exiting the program

The first three we have already covered in the BPT so refer back to that for more information.


Copy

We get the width and height of our selection stored in local variables
cutwidth and cutheight and we use abs() here to get the absolute value.

We don't want any negative numbers caused by dragging from right to left.

We declare a local bitmap to store our selection in.

We go through a routine that checks even if we have dragged from right to left
we still end up with a correct selection which is inside the bounding box.

We initialize our local bitmap by filling it with a block of zeroes.

We use our CopyScreenToBitmap function it does what it says on the tin.

We copy our bitmap to the clipboard with our BitmapToClipboard function.

We release our temporary local bitmap as we dont want to hog resources and run out
of memory and crashing our program...yes that would be bad.

Cut

Basically the same thing as copy but you have to cut out parts of the picture as well.

Paste

Pasting is quite complicated you have to manage the dc in a certain way, taking into account
zooming, resizing and scrolling.... I know.

We set our paste flag to true and repaint the screen and hope it all works out on the flip side.

Zoom Out

I zoom out in 25% intervals you can change this to 10% if you wish to get finer control.

I stop at 75% zoomed out as I have to stop somewhere and this is what I chose.

I set the Zoom flag to true.

I resize the screen area into a new bitmap width and height.. I still want the original values untouched.

I have to resize the scrollbars as everything has changed by minus 25% so the scrollbars need to shrink by 25% too ... aghh where's my calculator...!!

I repaint the screen ..phew...

Zoom In

Basically the same thing instead we are going 25% bigger not smaller.

I make it sound so easy don't I ? :)

case WM_PAINT:
    {


        hdc = BeginPaint(hwnd, &ps);


        hdcMem = CreateCompatibleDC(hdc);
        HDC MemoryDC= CreateCompatibleDC(hdc);
        if (fLoad)
        {
            PaintLoadBitmap(hwnd, si, bitmap, cxsize, cysize, xMaxScroll, xCurrentScroll, xMinScroll, yMaxScroll, yCurrentScroll, yMinScroll);

            fLoad= FALSE;

        }
        if (fBlt)
        {
            SelectObject(hdcMem, hBitmap);
            SetStretchBltMode(hdc,HALFTONE);

            StretchBlt(hdc, 0, 0,(int)bxWidth2,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, SRCCOPY);

        }

        // 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)
        {
            SelectObject(hdcMem, hBitmap);
            SetStretchBltMode(hdc,HALFTONE);

            StretchBlt(hdc, 0, 0, (int)bxWidth2 ,(int)bxHeight2, hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight, 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)
        {

            SetStretchBltMode(hdc,HALFTONE);
            StretchBlt(hdc,0,0,(int)bxWidth2,(int)bxHeight2,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);

            fScroll = false;

        }

        if(fZoom == true)
        {

            SelectObject(hdcMem,hBitmap);
            SetStretchBltMode(hdc,HALFTONE);
            StretchBlt(hdc,0,0,(int)bxWidth2,(int)bxHeight2,hdcMem,xCurrentScroll,yCurrentScroll,(int)bxWidth,(int)bxHeight,SRCCOPY);

            fZoom = false;

        }


        if(mmov)
        {
            DrawBoundingBox(hdc, (int)StartxPos, (int)EndxPos, (int)StartyPos, (int)EndyPos);
            mmov = false;
            EnableMenuItem(menu, IDM_COPY, MF_ENABLED);
            EnableMenuItem(menu, IDM_CUT, MF_ENABLED);

        }

        if(cut)
        {


            Cut(hdc, hdcMem, hBitmap, (int)bxWidth2, (int)bxHeight2, (int)bxWidth, (int)bxHeight, StartxPos, EndxPos, StartyPos, EndyPos, xCurrentScroll, yCurrentScroll);

            cut = false;


        }

        if(paste)
        {

            int oldxpos = (int)StartxPos;
            int oldendpos = (int)EndxPos;
            int oldypos = (int)StartyPos;
            int oldendypos = (int)EndyPos;

            if (StartxPos > EndxPos)
            {
                StartxPos = oldendpos;
                EndxPos = oldxpos;
                StartyPos = oldendypos;
                EndyPos = oldypos;
            }


            StartxPos = ((StartxPos)*(bxWidth/bxWidth2));
            StartyPos = ((StartyPos)*(bxHeight/bxHeight2));
            EndxPos = (EndxPos+xCurrentScroll);
            EndyPos = (EndyPos+yCurrentScroll);



            

            Paste(hwnd, hBitmap, bxWidth2, bxHeight2 ,bxWidth, bxHeight ,hdc, hdcMem, MemoryDC, StartxPos, EndxPos, xCurrentScroll, StartyPos, EndyPos, yCurrentScroll );


            //Reset Scrollbars to zero
            ZeroScrollbars(hwnd, si, bitmap, cxsize, cysize, xCurrentScroll, yCurrentScroll, xMaxScroll, yMaxScroll, xMinScroll, yMinScroll);


            paste = false;

        }


        EndPaint(hwnd, &ps);
        DeleteDC(hdcMem);
        DeleteDC(MemoryDC);
        return 0;
    }



WM_PAINT it deals with painting the window under certain actions and conditions.

What ?

You want a better explanation than that ?

Oh alright then..

We set up a dc to the screen and two memory dc's that are compatible with the screen dc.

We use flags to determine what we should draw.

fLoad something has just been loaded , we should draw it and set the flag to false.

fBlt we need to Blit something this tends to remain true.

fSize someone has resized the window we need to re blit the entire screen.

fScroll someone has scrolled along the window we need to blit everything again.

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.

We do that in the scroll procedure ... yes I know I'm making your brain hurt.

fZoom someone has zoomed in or out, we need to re blit everything and we set the flag to false.

mmov deals with drawing a bounding box and we enable cut and copy facilities.

cut deals with cutting out bits from our picture .. there is no Undo yet so watch what your
doing with those scissors.

paste we see if someone has dragged right to left and make our corrections if they have.

we make some calclations on our startx and starty positions taking into consideration the change in aspect ratio if indeed there is any.

We call a function which does the pasting and zero the scrollbars after that.

We set the paste flag to false.

We end the painting and delete our temporary memory dc's.

 case  WM_SIZE:
    {


        cxsize = LOWORD(lParam);
        cysize = HIWORD(lParam);
        rect.right = cxsize;
        rect.bottom = cysize;




        fSize = TRUE;

        // The horizontal scrolling range is defined by
        // (bitmap_width) - (client_width). The current horizontal
        // scroll value remains within the horizontal scrolling range.
        int t1 = (int)(bxWidth2-cxsize);
        xMaxScroll = max(t1,0);
        xCurrentScroll = min(xCurrentScroll, xMaxScroll);
        si.cbSize = sizeof(si);
        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
        si.nMin   = xMinScroll;
        si.nMax   = (int)bxWidth2;
        si.nPage  = (int)cxsize;
        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.
        int t2 = (int)bxHeight2 - cysize;
        yMaxScroll = max(t2, 0);
        yCurrentScroll = min(yCurrentScroll, yMaxScroll);
        si.cbSize = sizeof(si);
        si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
        si.nMin   = yMinScroll;
        si.nMax   = (int)bxHeight2;
        si.nPage  = cysize;
        si.nPos   = yCurrentScroll;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        InvalidateRect(hwnd, &WinRect, true);
        break;
    }



We get the new size that everything has been resized to in cx and cy size.

We adjust the scrollbars and repaint the window.


case WM_HSCROLL:
    {
        int xDelta;     // xDelta = new_pos - current_pos
        int xNewPos;    // new position
        int yDelta = 0;

        switch (LOWORD(wParam))
        {
            // User clicked the scroll bar shaft left of the scroll box.
        case SB_PAGEUP:
            xNewPos = xCurrentScroll - 50;
            break;

            // User clicked the scroll bar 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.
        xMaxScroll = (int)bxWidth2;
        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 ;

        // 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, (PRECT) NULL,
                       SW_INVALIDATE);
        InvalidateRect(hwnd, &WinRect, true);

        // 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 scroll bar shaft above the scroll box.
        case SB_PAGEUP:
            yNewPos = yCurrentScroll - 50;
            break;

            // User clicked the scroll bar 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.
        yMaxScroll = (int)bxHeight2;
        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, (PRECT) NULL,
                       SW_INVALIDATE);
        InvalidateRect(hwnd,&WinRect, true);

        // Reset the scroll bar.
        si.cbSize = sizeof(si);
        si.fMask  = SIF_POS;
        si.nPos   = yCurrentScroll;
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE);

        break;
    }



WM_HSCROLL and WM_VSCROLL

are very basic scrollbar routines there is nothing out of the ordinary with them and
information can be found on msdn and in Petzold.

 case WM_DESTROY:
        ChangeClipboardChain(hwnd, hwndViewer);
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;
    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);

    }
    return 0;

}


#endif // WINPROC_H_INCLUDED



This is important when we exit we have to unregister our program as a clipboard viewer from the
chain of clipboard viewers. Its important for good OS performance badly written software can really slow it down... don't be that guy or gal...

Functions.

bool BitmapToClipboard(HBITMAP hBM, HWND hWnd)
{
    if (!OpenClipboard(hWnd))
        return false;
    EmptyClipboard();

    BITMAP bm;
    GetObject(hBM, sizeof(bm), &bm);

    BITMAPINFOHEADER bi;
    ZeroMemory(&bi, sizeof(BITMAPINFOHEADER));
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = bm.bmBitsPixel;
    bi.biCompression = BI_RGB;
    if (bi.biBitCount <= 1)	// make sure bits per pixel is valid
        bi.biBitCount = 1;
    else if (bi.biBitCount <= 4)
        bi.biBitCount = 4;
    else if (bi.biBitCount <= 8)
        bi.biBitCount = 8;
    else // if greater than 8-bit, force to 24-bit
        bi.biBitCount = 24;

    // Get size of color table.
    SIZE_T dwColTable = (bi.biBitCount <= 8) ? (1 << bi.biBitCount) * sizeof(RGBQUAD) : 0;

    // Create a device context with palette
    HDC hDC = GetDC(NULL);
    HPALETTE hPal = static_cast<HPALETTE>(GetStockObject(DEFAULT_PALETTE));
    HPALETTE hOldPal = SelectPalette(hDC, hPal, FALSE);
    RealizePalette(hDC);

    // Use GetDIBits to calculate the image size.
    GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight), NULL,
              reinterpret_cast<LPBITMAPINFO>(&bi), DIB_RGB_COLORS);
    // If the driver did not fill in the biSizeImage field, then compute it.
    // Each scan line of the image is aligned on a DWORD (32bit) boundary.
    if (0 == bi.biSizeImage)
        bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

    // Allocate memory
    HGLOBAL hDIB = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPINFOHEADER) + dwColTable + bi.biSizeImage);
    if (hDIB)
    {
        union tagHdr_u
        {
            LPVOID             p;
            LPBYTE             pByte;
            LPBITMAPINFOHEADER pHdr;
            LPBITMAPINFO       pInfo;
        } Hdr;

        Hdr.p = GlobalLock(hDIB);
        // Copy the header
        CopyMemory(Hdr.p, &bi, sizeof(BITMAPINFOHEADER));
        // Convert/copy the image bits and create the color table
        int nConv = GetDIBits(hDC, hBM, 0, static_cast<UINT>(bi.biHeight),
                              Hdr.pByte + sizeof(BITMAPINFOHEADER) + dwColTable,
                              Hdr.pInfo, DIB_RGB_COLORS);
        GlobalUnlock(hDIB);
        if (!nConv)
        {
            GlobalFree(hDIB);
            hDIB = NULL;
        }
    }
    if (hDIB)
        SetClipboardData(CF_DIB, hDIB);
    CloseClipboard();
    SelectPalette(hDC, hOldPal, FALSE);
    ReleaseDC(NULL, hDC);
    return NULL != hDIB;
}



HBITMAP CopyScreenToBitmap(HWND Hwnd,int x1, int y1, int nWidth, int nHeight)
{
    HDC hScrDC,hMemDC; // screen DC and memory DC
    HBITMAP hxBitmap, hOldBitmap; // handles to deice-dependent bitmaps





// create a DC for the screen and create
// a memory DC compatible to screen DC

     hScrDC = GetDC(Hwnd);



    if((hMemDC = CreateCompatibleDC(hScrDC))==NULL)
    {

        MessageBox(Hwnd,"Can not create compatible DC","Error",MB_OK);
        return NULL;
    }


// create a bitmap compatible with the screen DC
    if((hxBitmap = CreateCompatibleBitmap(hScrDC, nWidth-1, nHeight-1))==NULL)
    {
        MessageBox(Hwnd,"Can not create compatible Bitmap","Error",MB_OK);

        return NULL;
    }

// select new bitmap into memory DC
    hOldBitmap = (HBITMAP)SelectObject(hMemDC, hxBitmap);

    if(hOldBitmap == NULL)
    {
        MessageBox(Hwnd,"Can not select old Bitmap","Error",MB_OK);
        return NULL;
    }

// bitblt screen DC to memory DC
    if(!BitBlt(hMemDC, 0, 0, nWidth-2, nHeight-2, hScrDC, x1+1, y1+1, SRCCOPY))
    {
        MessageBox(Hwnd,"Can not read screen memory","Error",MB_OK);
        return NULL;
    }

// select old bitmap back into memory DC and get handle to bitmap of the screen

    hxBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
    if(hxBitmap == NULL)
    {
        MessageBox(Hwnd,"Can not select object","Error",MB_OK);
        return NULL;
    }
// clean up
    DeleteDC(hScrDC);
    DeleteDC(hMemDC);

// return handle to the bitmap

    return hxBitmap;
}


void PaintLoadBitmap(HWND hwnd,SCROLLINFO si, BITMAP bitmap, int pcxsize, int pcysize, int xMaxScroll,int xCurrentScroll, int xMinScroll,int yMaxScroll, int yCurrentScroll ,int yMinScroll)
{


    // The horizontal scrolling range is defined by
    // (bitmap_width) - (client_width). The current horizontal
    // scroll value remains within the horizontal scrolling range.
    int t1 =(bitmap.bmWidth-pcxsize);
    xMaxScroll = max(t1,0);
    xCurrentScroll = min(xCurrentScroll, xMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = xMinScroll;
    si.nMax   = bitmap.bmWidth;
    si.nPage  = pcxsize;
    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.
    int t2 = bitmap.bmHeight - pcysize;
    yMaxScroll = max(t2, 0);
    yCurrentScroll = min(yCurrentScroll, yMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = yMinScroll;
    si.nMax   = bitmap.bmHeight;
    si.nPage  = pcysize;
    si.nPos   = yCurrentScroll;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
}

void DrawBoundingBox(HDC hdc, int StartxPos, int EndxPos, int StartyPos, int EndyPos)
{
    HPEN greenPen=CreatePen(PS_SOLID, 1, RGB(0,255,0));
    SelectObject(hdc, greenPen);

    SelectObject(hdc, GetStockObject(HOLLOW_BRUSH));


    MoveToEx(hdc, StartxPos, StartyPos, NULL);
    Rectangle(hdc, StartxPos, StartyPos , EndxPos, EndyPos);


}

void Cut(HDC hdc, HDC hdcMem, HBITMAP hBitmap, double Width, double Height, double oWidth, double oHeight, double StartxPos, double EndxPos, double StartyPos, double EndyPos, int xCurrentScroll, int yCurrentScroll)
{
    RECT crect;
    StartxPos = StartxPos*(oWidth/Width);
    StartyPos = StartyPos*(oHeight/Height);
    EndxPos = EndxPos*(oWidth/Width);
    EndyPos = EndyPos*(oHeight/Height);

    crect.left = (long)StartxPos+xCurrentScroll;
    crect.top =  (long)StartyPos+yCurrentScroll;
    crect.right = (long)EndxPos+xCurrentScroll;
    crect.bottom = (long)EndyPos+yCurrentScroll;

    SelectObject(hdcMem, hBitmap);

    FillRect(hdcMem, &crect, GetStockBrush(LTGRAY_BRUSH));
    SetStretchBltMode(hdc,HALFTONE);
    StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll,(int)oWidth,(int)oHeight, SRCCOPY);

}

void Paste(HWND hwnd, HBITMAP hBitmap,double Width,double Height ,double oWidth, double oHeight ,HDC hdc, HDC hdcMem, HDC MemoryDC, double StartxPos, double EndxPos, int xCurrentScroll, double StartyPos, double EndyPos, int yCurrentScroll )
{
    HBITMAP clip;
    BITMAP clipmap;



    ZeroMemory(&clip, sizeof(HBITMAP));
    ZeroMemory(&clipmap, sizeof(BITMAP));
    OpenClipboard(hwnd);

    clip = (HBITMAP)GetClipboardData(CF_BITMAP);
    GetObject(clip,sizeof(BITMAP),&clipmap);
    SelectObject(MemoryDC, clip);

    SelectObject(hdcMem,hBitmap);

    BitBlt(hdcMem, (int)StartxPos+xCurrentScroll, (int)StartyPos+yCurrentScroll ,(int)oWidth,
              (int)oHeight, MemoryDC ,0,0,SRCCOPY);
    SetStretchBltMode(hdc,HALFTONE);
    StretchBlt(hdc, 0, 0, (int)Width,(int)Height, hdcMem,xCurrentScroll,yCurrentScroll, (int)oWidth, (int)oHeight, SRCCOPY);


    CloseClipboard();
    DeleteBitmap(clip);
}

void ZeroScrollbars(HWND hwnd, SCROLLINFO si, BITMAP bitmap, int cxsize, int cysize,int xCurrentScroll, int yCurrentScroll, int xMaxScroll, int yMaxScroll, int xMinScroll, int yMinScroll)
{
    int t1 =(bitmap.bmWidth-cxsize);
    xMaxScroll = max(t1,0);
    xCurrentScroll = min(xCurrentScroll, xMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = xMinScroll;
    si.nMax   = bitmap.bmWidth;
    si.nPage  = cxsize;
    si.nPos   = 0;
    SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);

    // The scrolling range is defined by
    // (bitmap_height) - (client_height). The current
    // scroll value remains within the scrolling range.
    int t2 = bitmap.bmHeight - cysize;
    yMaxScroll = max(t2, 0);
    yCurrentScroll = min(yCurrentScroll, yMaxScroll);
    si.cbSize = sizeof(si);
    si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
    si.nMin   = yMinScroll;
    si.nMax   = bitmap.bmHeight;
    si.nPage  = cysize;
    si.nPos   = 0;
    SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
    xCurrentScroll = 0;
    yCurrentScroll =0;
}

#endif // FUNCTIONS_H_INCLUDED



Part 4.

Firstly I am not going over the Print Dialog or the Open and Save Dialogs or the routines dealing with loading and saving a bitmap I do all that in the BPT refer back to that if you need reminded.

I am going to start with the BitmapToClipboard function.

We try to open the clipboard if we cant we return false.

If we can we empty the clipboard and set up a new bitmap with a new bitmapinfoheader for it.

We create a device context that is compatible with the screen and load into it a palette which is the default palette now this palette changes its colors everytime we load a new image.

Now, Microsoft Windows uses 20 system colours (also referred to as "static colours"). These colours occupy the first 10 and the last 10 slots in the palette (so, in a palette with 256 colours the system colours are 0-9 and 246-255). If you include those system colours in your palette (at the same position as Windows puts them), the application can create a so-called "logical palette". Windows draws bitmaps much faster if an logical palette is used. This is
a best fit to the 'default' palette.

Logical palette: An application cannot access the system palette directly. Instead, it creates a logical palette object that is a best fit for the image that it wishes to display. The Palette Manager will then map this logical palette to the system palette.

Realization: The process of mapping a logical palette to the system palette. Since the Palette Manager has to contend with multiple applications, the realization process is involved

We lastly call RealizePalette and now you know why.

We use GetDIBits to get the image size if that fails we compute it.

We allocate memory for the DIB if all is well we put it on the ClipBoard.

We close the ClipBoard and restore the old palette.

We get rid of our temporary DC and bitmap.

Part 5.

CopyScreenToBitmap we set up some DC'S and HBitmaps
we get a DC for the window. We create a DC in memory which is compatible with the window DC,
we then create a bitmap which is compatible with the window DC.

We load this new bitmap into memory and blit the screen selection to this memory DC.

We do some housekeeping and return the newly created bitmap.

Part 6.

PaintLoadBitmap is a bit misleading as it just deals with scrollbar resizing after an initial image has been loaded and painted to screen.

Part 7.

DrawBoundingBox draws a nice green temporary bounding box on screen which does not affect the original image in any way. How do I do that ?

Im not telling you...

Well ok then, I never draw it to Memory if you don't understand how that works well too bad
as I have told you before.. yes I did, I did honestly.. :)

Part 8.

The Cut Function.

We again check if someone has dragged it right to left if they have reverse everything so we only cut what is inside the bounding box.. do I have to think of everything..?

Well yes I do and so should you.

We use FillRect with the light gray brush matching the window background color to give the illusion of cutting something.

We do this in Memory then blit the whole thing to the screen DC.

Part 9.

Pasting.

Pasting is quite tricky, we create a new bitmap and hbitmap.

We fill a block of memory with zeroes for them.

We open the clipboard.

We load whatever is in the clipboard into the hbitmap.

We get a bitmap image from the hbitmap.

We select the hbitmap into memory.

We select the original picture into memory.

We blit the clipboard dc hbitmap in memory to the original picture in memory.

We then blit the newly joined images to the screen DC.

Thus giving the illusion of pasting.

We close the clipboard and tidy up.

Part 10.

Finally...

We reset our scrollbars using the ZeroScrollBars function...

pretty straight forward....

resets scrollbar positions to zero.

References.

Petzold - Programming Windows.
MSDN



Well there you go Part 1 of our three part series on how to make a basic image editor
in the next part we will discuss image effects. Things like adding text and red eye reduction.

I am incredibly busy with work however so don't know when exactly I will have time to do all this.
But it will happen.

I am going to include the snoopy.ico ico and the Snoopettes.bmp as resources for you to play about with for this.

Bye for now.

Snoopy.

snoopy.ico

Snoopettes.bmp

Is This A Good Question/Topic? 0
  • +

Page 1 of 1