我想寫個截圖程序

手把手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 once

HBITMAP myGetScreenBmp(CRect &rc);//截屏函數,rc爲截屏區域,用屏幕座標
bool mySaveBitmapToFile(HBITMAP hBitmap , CString lpFileName);//保存位圖函數


screen.cpp
#include "stdafx.h"
#include "screen.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

bool mySaveBitmapToFile(HBITMAP hBitmap, CString lpFileName)
{
	//設備描述表  
	HDC hDC;

	//當前顯示分辨率下每個像素所佔字節數
	int iBits;

	//位圖中每個像素所佔字節數
	WORD wBitCount;

	//定義調色板大小   
	DWORD dwPaletteSize=0;
	// 位圖中像素字節大小
	DWORD	dwBmBitsSize = 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;
		else
			wBitCount = 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. 希望能簡化到一個對話框中。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章