我想写个截图程序

来源:互联网 发布:linux的shell 编辑:程序博客网 时间:2024/05/03 17:13

手把手VC截图小工具,附源码

一直都想写个截图程序,觉得蛮有意思的。看到网上这位兄弟的思路蛮清晰的,就自己跟着做下,并记录了流程,做个备份。

1.首先是构建个基于对话框的程序。在OnInitDialog中

注册热键,并隐藏当前对话框。在资源里把对话框设为无边框。

BOOL CCutterDlg::OnInitDialog(){    RegisterHotKey(m_hWnd,1001,MOD_CONTROL|MOD_ALT,VK_F7);    RegisterHotKey(m_hWnd,1002,MOD_CONTROL|MOD_ALT,VK_F8);    ShowWindow(SW_HIDE);    CDialog::OnInitDialog();    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE}
在OnDestroy()对热键注销。

void CCutterDlg::OnDestroy(){CDialog::OnDestroy();// TODO: 在此处添加消息处理程序代码UnregisterHotKey(m_hWnd,1001); UnregisterHotKey(m_hWnd,1002); }

在OnPaint要对对话框再做一次隐藏。

ShowWindow(SW_HIDE);


2.对热键进行声明、关联及响应

afx_msg LRESULT OnHotKey(WPARAM wp,LPARAM lp);

BEGIN_MESSAGE_MAP(CCutterDlg, CDialog)...ON_MESSAGE(WM_HOTKEY,OnHotKey)END_MESSAGE_MAP()

LRESULT CCutterDlg::OnHotKey(WPARAM wp,LPARAM lp)//快捷键{if(wp==1001){int x=GetSystemMetrics(SM_CXSCREEN);   int y=GetSystemMetrics(SM_CYSCREEN);CRect cr(CPoint(0,0),CPoint(x,y));HBITMAP hb=myGetScreenBmp(cr);ShowDlgS shows(hb);shows.DoModal();}if (wp==1002){exit(1);}return 0;}

3.热键响应部分,用到了ShowDlgS ,这是一个无边框的对话框。

ShowDlgS.h

#pragma once// ShowDlgS 对话框class ShowDlgS : public CDialog{DECLARE_DYNAMIC(ShowDlgS)public:ShowDlgS(CWnd* pParent = NULL);   // 标准构造函数ShowDlgS(HBITMAP hb,CWnd* pParent=NULL);virtual ~ShowDlgS();// 对话框数据enum { IDD = IDD_DIALOG1 };protected:CBitmap m_bmp;HBITMAP m_hBmp;CPoint m_ptBegin;CPoint m_ptMid;CPoint m_ptEnd;bool m_bBegin;bool m_bEnd;virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持DECLARE_MESSAGE_MAP()public:afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnLButtonUp(UINT nFlags, CPoint point);afx_msg void OnPaint();virtual BOOL OnInitDialog();afx_msg void OnMouseMove(UINT nFlags, CPoint point);};

ShowDlgS.cpp
// ShowDlgS.cpp : 实现文件//#include "stdafx.h"#include "Cutter.h"#include "ShowDlgS.h"#include "screen.h"IMPLEMENT_DYNAMIC(ShowDlgS, CDialog)ShowDlgS::ShowDlgS(CWnd* pParent /*=NULL*/)    : CDialog(ShowDlgS::IDD, pParent){}ShowDlgS::ShowDlgS(HBITMAP hb,CWnd* pParent):CDialog(ShowDlgS::IDD, pParent){        m_hBmp=hb;    m_bBegin=false;    m_bEnd=false;}ShowDlgS::~ShowDlgS(){}void ShowDlgS::DoDataExchange(CDataExchange* pDX){    CDialog::DoDataExchange(pDX);}BEGIN_MESSAGE_MAP(ShowDlgS, CDialog)    ON_WM_LBUTTONDOWN()    ON_WM_LBUTTONUP()    ON_WM_PAINT()    ON_WM_MOUSEMOVE()END_MESSAGE_MAP()void ShowDlgS::OnLButtonDown(UINT nFlags, CPoint point){    // TODO: 在此添加消息处理程序代码和/或调用默认值    if (m_bEnd)    {        return;    }    m_ptBegin=point;    m_ptMid=point;    m_bBegin=true;    CDialog::OnLButtonDown(nFlags, point);}void ShowDlgS::OnLButtonUp(UINT nFlags, CPoint point){    // TODO: 在此添加消息处理程序代码和/或调用默认值    if (!m_bBegin||m_bEnd)    {        return;    }    m_bEnd=true;    m_ptEnd=point;    if (m_ptBegin==m_ptEnd)    {        return;    }    CBrush * pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//set touming    CClientDC dc(this);    CBrush *pOldBrush=dc.SelectObject(pBrush);//select brush    dc.Rectangle(CRect(m_ptBegin,m_ptEnd));    dc.SelectObject(pOldBrush);//save old brush    HBITMAP hbm=myGetScreenBmp(CRect(m_ptBegin,m_ptEnd));    CFileDialog   dlg(FALSE,NULL,_T("cut.bmp"),OFN_OVERWRITEPROMPT,_T("(*.bmp)"));    if ( dlg.DoModal()!=IDOK )         SendMessage(WM_CLOSE);    //get path    CString sFileName=dlg.GetPathName();    mySaveBitmapToFile(hbm,sFileName);    SendMessage(WM_CLOSE);    //CDialog::OnLButtonUp(nFlags, point);}void ShowDlgS::OnPaint(){    CPaintDC dc(this); // device context for painting    // TODO: 在此处添加消息处理程序代码    // 不为绘图消息调用 CDialog::OnPaint()    m_bmp.Attach(m_hBmp);    // TODO: Add your message handler code here        BITMAP bmInfo;    ::GetObject( m_bmp.m_hObject, sizeof(BITMAP), &bmInfo );    INT nWidth, nHeigh;    nWidth = bmInfo.bmWidth;    nHeigh = bmInfo.bmHeight;    CDC pDC;    pDC.CreateCompatibleDC(&dc);    pDC.SelectObject(&m_bmp);    dc.BitBlt(0, 0, nWidth, nHeigh, &pDC, 0, 0, SRCCOPY);    m_bmp.Detach();    CBrush * pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//set touming    CBrush *pOldBrush=dc.SelectObject(pBrush);//select brush    dc.Rectangle(CRect(m_ptBegin,m_ptEnd));    dc.SelectObject(pOldBrush);//save old brush}BOOL ShowDlgS::OnInitDialog(){    CDialog::OnInitDialog();    /*bo add begin*/    int x=GetSystemMetrics(SM_CXSCREEN);                    //获取屏幕分辨率的x    int y=GetSystemMetrics(SM_CYSCREEN);                    //获取屏幕的分辨率的y    CDialog::ModifyStyle(WS_BORDER,0,0);                            //清除VC的对话框    this->SetWindowPos(&wndTopMost,0,0,x,y, SWP_SHOWWINDOW);     /*bo add end*/    return TRUE;  // return TRUE unless you set the focus to a control}void ShowDlgS::OnMouseMove(UINT nFlags, CPoint point){    // TODO: 在此添加消息处理程序代码和/或调用默认值    if (!m_bBegin||m_bEnd)    {        return;    }    m_ptEnd=point;        //while move mouse clean reprint the window    Invalidate(true);    //darw rec    CDC   *pDC=GetDC();       BLENDFUNCTION   bf;       bf.BlendOp   =0;       bf.BlendFlags   =0;       bf.SourceConstantAlpha=50;       bf.AlphaFormat   =   0;       int   bmWidth;       int   bmHeight;       bmWidth=bmHeight=600;       CDC   MemDC;       MemDC.CreateCompatibleDC(pDC);                     CBitmap   bitmap;       bitmap.CreateCompatibleBitmap(pDC,bmWidth,bmHeight);         CBitmap   *pold=MemDC.SelectObject(&bitmap);       CBrush   brush(RGB(255,0,0));       CBrush   *pL=MemDC.SelectObject(&brush);       CRgn   rgn;       MemDC.Rectangle(m_ptBegin.x,m_ptMid.y,m_ptEnd.x,m_ptEnd.y);    rgn.CreateRectRgn(m_ptBegin.x,m_ptMid.y,m_ptEnd.x,m_ptEnd.y);    pDC->SelectClipRgn(&rgn);       AlphaBlend(pDC->m_hDC,           0,0,point.x+bmWidth,point.y+bmHeight,           MemDC.GetSafeHdc(),0,0,bmWidth,bmHeight,bf);       rgn.DeleteObject();       MemDC.Rectangle(m_ptMid.x,m_ptBegin.y,m_ptEnd.x,m_ptMid.y);    rgn.CreateRectRgn(m_ptMid.x,m_ptBegin.y,m_ptEnd.x,m_ptMid.y);    pDC->SelectClipRgn(&rgn);       AlphaBlend(pDC->m_hDC,           0,0,point.x+bmWidth,point.y+bmHeight,           MemDC.GetSafeHdc(),0,0,bmWidth,bmHeight,bf);       rgn.DeleteObject();       //last point    m_ptMid=point;}

4.用来保存位图的文件

screen.h

#pragma onceHBITMAP myGetScreenBmp(CRect &rc);//截屏函数,rc为截屏区域,用屏幕坐标bool mySaveBitmapToFile(HBITMAP hBitmap , CString lpFileName);//保存位图函数

screen.cpp
#include "stdafx.h"#include "screen.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endifbool mySaveBitmapToFile(HBITMAP hBitmap, CString lpFileName){//设备描述表  HDC hDC;//当前显示分辨率下每个像素所占字节数int iBits;//位图中每个像素所占字节数WORD wBitCount;//定义调色板大小   DWORD dwPaletteSize=0;// 位图中像素字节大小DWORDdwBmBitsSize = 0;// 位图文件大小DWORD dwDIBSize = 0;// 写入文件字节数DWORD dwWritten = 0;BITMAP Bitmap;   BITMAPFILEHEADER   bmfHdr;//位图文件头结构       BITMAPINFOHEADER   bi;//位图信息头结构     LPBITMAPINFOHEADER lpbi; //指向位图信息头结构,定义文件,分配内存句柄,调色板句柄//计算位图文件每个像素所占字节数HANDLE  fh, hDib, hPal,hOldPal=NULL; hDC = CreateDC(_T("DISPLAY"),NULL,NULL,NULL);iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);DeleteDC(hDC);if (iBits <= 1)wBitCount = 1;else if (iBits <= 4)wBitCount = 4;else if (iBits <= 8)wBitCount = 8;else {if (iBits <= 24)wBitCount = 24;elsewBitCount = 32;//原来没有,应有}//计算调色板大小if (wBitCount <= 8)dwPaletteSize = (1 << wBitCount) *sizeof(RGBQUAD);//设置位图信息头结构GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);bi.biSize            = sizeof(BITMAPINFOHEADER);bi.biWidth           = Bitmap.bmWidth;bi.biHeight          = Bitmap.bmHeight;bi.biPlanes          = 1;bi.biBitCount         = wBitCount;bi.biCompression      = BI_RGB;bi.biSizeImage        = 0;bi.biXPelsPerMeter     = 0;bi.biYPelsPerMeter     = 0;bi.biClrUsed         = 0;bi.biClrImportant      = 0;dwBmBitsSize = ((Bitmap.bmWidth*wBitCount+31)/32)*4*Bitmap.bmHeight;//为位图内容分配内存hDib  = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));if(hDib==NULL)AfxMessageBox(_T("null"));lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);*lpbi = bi;// 处理调色板   hPal = GetStockObject(DEFAULT_PALETTE);if (hPal){hDC  = ::GetDC(NULL);hOldPal = SelectPalette(hDC, (HPALETTE)hPal, FALSE);RealizePalette(hDC);}// 获取该调色板下新的像素值GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,(LPSTR)lpbi + sizeof(BITMAPINFOHEADER)+dwPaletteSize,(LPBITMAPINFO)lpbi, DIB_RGB_COLORS);//恢复调色板   if (hOldPal){SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);RealizePalette(hDC);::ReleaseDC(NULL, hDC);}//创建位图文件    fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);if (fh == INVALID_HANDLE_VALUE)return FALSE;// 设置位图文件头bmfHdr.bfType = 0x4D42;  // "BM"dwDIBSize    = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;  bmfHdr.bfSize = dwDIBSize;bmfHdr.bfReserved1 = 0;bmfHdr.bfReserved2 = 0;bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER)+ dwPaletteSize;// 写入位图文件头WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);// 写入位图文件其余内容WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);//消除内存分配  GlobalUnlock(hDib);GlobalFree(hDib);CloseHandle(fh);return TRUE;}HBITMAP myGetScreenBmp(CRect &rc)//rc为屏幕坐标,非客户区坐标{HWND hwnd = ::GetDesktopWindow();HDC hsrc = ::GetDC(hwnd);HDC hmemdc = ::CreateCompatibleDC(hsrc);rc.NormalizeRect();SIZE sz;sz.cx=rc.right-rc.left;sz.cy=rc.bottom-rc.top;HBITMAP hbmp = ::CreateCompatibleBitmap(hsrc,sz.cx,sz.cy);HGDIOBJ holdbmp = ::SelectObject(hmemdc,hbmp);::BitBlt(hmemdc,0,0,sz.cx,sz.cx,hsrc,rc.left,rc.top,SRCCOPY);::SelectObject(hmemdc,holdbmp);::DeleteObject(hmemdc);::ReleaseDC(hwnd,hsrc);return hbmp;}

5.还没结束。

a.对截图的过程中,还没充分理解。

b. 希望能简化到一个对话框中。