以前写的抓图程序。里面实现了系统热键及系统托盘的功能。最近想做个东西用到这个功能,所以翻出来看看。
// PrintScreenDlg.h : header file
//
#if !defined(AFX_PRINTSCREENDLG_H__9CB8322A_B3F5_4916_8051_B808B83AE4EB__INCLUDED_)
#define AFX_PRINTSCREENDLG_H__9CB8322A_B3F5_4916_8051_B808B83AE4EB__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/
// CPrintScreenDlg dialog
class CPrintScreenDlg : public CDialog
{
// Construction
public:
CPrintScreenDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CPrintScreenDlg)
enum { IDD = IDD_PRINTSCREEN_DIALOG };
CString m_HotKey;
BOOL m_bSaveToFile;
int m_FileType;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CPrintScreenDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CPrintScreenDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnPrtsrc();
afx_msg void OnExit();
afx_msg void OnDestroy();
afx_msg long OnHotKey(WPARAM wParam, LPARAM lParam);
afx_msg void OnHidden();
afx_msg void OnIconNotify(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
VOID MenuPopup_Notify(int nCmd);
enum { printscreen=1, };
NOTIFYICONDATA m_nid;
VOID PrintWholeScreen();
VOID SaveCapturedBitmap(HBITMAP hCaptureBitmap);
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_PRINTSCREENDLG_H__9CB8322A_B3F5_4916_8051_B808B83AE4EB__INCLUDED_)
// PrintScreenDlg.cpp : implementation file
//
#include "stdafx.h"
#include "PrintScreen.h"
#include "PrintScreenDlg.h"
#include <windows.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define WM_ICONNOTIFY (WM_USER + 909)
/
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CPrintScreenDlg dialog
CPrintScreenDlg::CPrintScreenDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPrintScreenDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CPrintScreenDlg)
m_HotKey = _T("Ctrl+D");
m_bSaveToFile = FALSE;
m_FileType = 0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CPrintScreenDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPrintScreenDlg)
DDX_Text(pDX, IDC_HOTKEY, m_HotKey);
DDX_Check(pDX, IDC_CHKSAVETOFILE, m_bSaveToFile);
DDX_CBIndex(pDX, IDC_CMBFILETYPE, m_FileType);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CPrintScreenDlg, CDialog)
//{{AFX_MSG_MAP(CPrintScreenDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(ID_PRTSRC, OnPrtsrc)
ON_BN_CLICKED(ID_EXIT, OnExit)
ON_WM_DESTROY()
ON_MESSAGE(WM_HOTKEY, OnHotKey)
ON_MESSAGE(WM_ICONNOTIFY, OnIconNotify)
ON_BN_CLICKED(ID_HIDDEN, OnHidden)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/
// CPrintScreenDlg message handlers
BOOL CPrintScreenDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//regester the hotkey
RegisterHotKey(this->GetSafeHwnd(),printscreen,MOD_CONTROL,'D');
return TRUE; // return TRUE unless you set the focus to a control
}
void CPrintScreenDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CPrintScreenDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CPrintScreenDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
VOID CPrintScreenDlg::PrintWholeScreen()
{
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = ::GetDesktopWindow();
HDC hDesktopDC = ::GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap =CreateCompatibleBitmap(hDesktopDC,
nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC,hCaptureBitmap);
BitBlt(hCaptureDC,0,0,nScreenWidth,nScreenHeight,hDesktopDC,0,0,SRCCOPY);
if (m_bSaveToFile)
{
SaveCapturedBitmap(hCaptureBitmap);
}
if(!OpenClipboard())
MessageBox("open clipboard failed!","Warning");
else
{
if(!EmptyClipboard())
MessageBox("clear clipboard failed!","Warning");
else
{
SetClipboardData(CF_BITMAP,hCaptureBitmap);
}
CloseClipboard();
}
::ReleaseDC(hDesktopWnd,hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}
VOID CPrintScreenDlg::SaveCapturedBitmap(HBITMAP hCaptureBitmap)
{
HDC hDC = NULL;
//当前分辨率下每象素所占字节数
int iBits = 0;
//位图中每象素所占字节数
WORD wBitCount = 0;
//定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
//位图属性结构
BITMAP Bitmap;
//位图文件头结构
BITMAPFILEHEADER bmfHdr;
//位图信息头结构
BITMAPINFOHEADER bi;
//指向位图信息头结构
LPBITMAPINFOHEADER lpbi;
//定义文件,分配内存句柄,调色板句柄
HANDLE fh, hDib, hPal,hOldPal=NULL;
//计算位图文件每个像素所占字节数
hDC = CreateDC("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;
GetObject(hCaptureBitmap, 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.biClrImportant = 0;
bi.biClrUsed = 0;
dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
//为位图内容分配内存
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
if (NULL == hDib)
{
CString errmsg ;
errmsg.Format("分配%u内存失败,GlobalAlloc()返回错误码:%u。\r\n%s(%u)",
dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER),
GetLastError(),
__FILE__,
__LINE__);
MessageBox(errmsg,_T("Error"));
return;
}
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, hCaptureBitmap, 0, (UINT)Bitmap.bmHeight,
(LPSTR)lpbi + sizeof(BITMAPINFOHEADER) + dwPaletteSize,
(BITMAPINFO*)lpbi, DIB_RGB_COLORS);
//恢复调色板
if(hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
::ReleaseDC(NULL, hDC);
}
//创建位图文件
CString szFileName;
SYSTEMTIME Systime;
GetLocalTime(&Systime);
szFileName.Format("%u-%u-%u-%02u%02u.bmp",
Systime.wYear, Systime.wMonth, Systime.wDay, Systime.wHour, Systime.wMinute);
fh = CreateFile(szFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL ,NULL);
if(fh == INVALID_HANDLE_VALUE) return ;
// 设置位图文件头
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;
}
void CPrintScreenDlg::OnPrtsrc()
{
// TODO: Add your control notification handler code here
ShowWindow(SW_HIDE);
UpdateData();
PrintWholeScreen();
ShowWindow(SW_NORMAL);
}
void CPrintScreenDlg::OnExit()
{
// TODO: Add your control notification handler code here
SendMessage(WM_CLOSE);
}
void CPrintScreenDlg::OnDestroy()
{
UnregisterHotKey(this->GetSafeHwnd(),1);
Shell_NotifyIcon(NIM_DELETE, &m_nid);
CDialog::OnDestroy();
// TODO: Add your message handler code here
}
long CPrintScreenDlg::OnHotKey(WPARAM wParam,LPARAM lParam)
{
switch(wParam) {
case printscreen:
{
OnPrtsrc();
}
break;
default:
return 1;
}
return 0;
}
void CPrintScreenDlg::OnHidden()
{
// TODO: Add your control notification handler code here
// 初始化系统托盘图标
m_nid.cbSize = sizeof(NOTIFYICONDATA);
m_nid.hWnd = GetSafeHwnd();
m_nid.uID = 128;
m_nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
m_nid.uCallbackMessage = WM_ICONNOTIFY;
m_nid.hIcon = m_hIcon;
strcpy(m_nid.szTip, "I am here! :)");
Shell_NotifyIcon(NIM_ADD, &m_nid);
ShowWindow(SW_HIDE);
}
void CPrintScreenDlg::OnIconNotify(WPARAM wParam, LPARAM lParam)
{
switch(lParam) {
case WM_LBUTTONDBLCLK:
// Load main window here
{
Shell_NotifyIcon(NIM_DELETE, &m_nid);
ShowWindow(SW_NORMAL);
SetForegroundWindow();
}
break;
case WM_RBUTTONUP:
{
TRACE("case WM_RBUTTONUP");
POINT point;
CMenu menuPopup;
// Get mouse position
GetCursorPos(&point);
// Popup context menu
BOOL bSuc = menuPopup.LoadMenu(IDR_MENURIGHT);
if (!bSuc)
{
MessageBox("LoadMenu failed !");
return;
}
int nCmd = menuPopup.TrackPopupMenu(TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_BOTTOMALIGN|TPM_RETURNCMD,
point.x, point.y, this, NULL);
MenuPopup_Notify(nCmd);
}
break;
default:
break;
}
return;
}
VOID CPrintScreenDlg::MenuPopup_Notify(int nCmd)
{
switch( nCmd )
{
case ID_MENUITEM_SHOW:
{
Shell_NotifyIcon(NIM_DELETE, &m_nid);
ShowWindow(SW_NORMAL);
SetForegroundWindow();
}
break;
case ID_MENUITEM_EXIT:
{
Shell_NotifyIcon(NIM_DELETE, &m_nid);
SendMessage(WM_CLOSE);
}
break;
default:
break;
}
return;
}