手把手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. 希望能簡化到一個對話框中。