C++開發截屏小程序,Win32程序,可以顯示截屏區域並保存。
上次的流星雨屏幕程序就簡單涉及到GDI繪圖了,這次簡單介紹幾個API函數,涉及到GDI的。
GetDC,獲取當前創建的窗口的設備環境。
CreateDC,獲取當前屏幕的設備環境。
CreateCompatibleDC,創建一個兼容性的設備環境(相當於一個虛擬的設備環境)
BitBlt,這個函數,相當於拷貝,將一個環境的設備內容拷貝到另一個設備中。
CreateCompatibleBitmap,創建一塊畫布,將其放在兼容性的DC裏面,這樣就可以在裏面畫圖了,當然還要放入畫筆和畫刷這些。
介紹完這些函數之後,那麼設計思路就來了:
- 首先當然還是定義並創建窗口,還有消息循環。
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDC_CAPTURESCREEN));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 將實例句柄存儲在全局變量中
//創建自己的窗口
hWnd = CreateWindow(szWindowClass, szTitle, WS_POPUP,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
//顯示和更新窗口
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
return TRUE;
}
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
//playsound只能播放wav格式,而mcisendstring可以播放任意格式的。
//PlaySound("yixi.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
mciSendString("open ./abc.mp3 alias bk",
0, 0, 0);
mciSendString("play bk repeat", 0, 0, 0);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此放置代碼。
MSG msg;
HACCEL hAccelTable;
// 初始化全局字符串
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CAPTURESCREEN, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance); //註冊類
// 執行應用程序初始化:
if (!InitInstance(hInstance, nCmdShow)) //初始化窗口
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CAPTURESCREEN));
// 主消息循環:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
- 之後獲取當前屏幕的設備環境,
- 然後將它保存到兼容性的DC中,這就相當於將當前屏幕圖片放到一個緩衝區中。在WM_CREATE消息裏面做這個動作。
void ScreenDisplay()
{
HDC disDc = ::CreateDC("DISPLAY", NULL, NULL, NULL);
g_memDC = ::CreateCompatibleDC(disDc);
g_ScreenW = GetDeviceCaps(disDc, HORZRES);
g_ScreenH = GetDeviceCaps(disDc, VERTRES);
HBITMAP hbitmap = CreateCompatibleBitmap(disDc, g_ScreenW, g_ScreenH);
SelectObject(g_memDC, hbitmap);
BitBlt(g_memDC, 0, 0, g_ScreenW, g_ScreenH, disDc, 0, 0, SRCCOPY);
}
-
接着再將它放到我們創建的窗口中,這時就會看到整個桌面就不動了,就呈現的是一張圖片,
-
之後我們就可以在這張圖片上繪製我們想截取的區域。
-
呈現的是靜止的圖片,如果繪製之後,需要更新,這就用到一個函數InvalidateRgn,會無效選定的區域,這樣會觸發消息WM_PAINT,所以在這個消息裏面將重新繪製圖形,然後顯示即可。
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: 在此添加任意繪圖代碼...
SelectObject(hdc, hpen);
SelectObject(hdc, hBrush);
BitBlt(hdc, 0, 0, g_ScreenW, g_ScreenH, g_memDC, 0, 0, SRCCOPY);
Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
EndPaint(hWnd, &ps);
break;
- 接下來就是繪製想要區域的操作,需要用到的幾個鼠標的消息函數,鼠標按下,鼠標彈起,鼠標移動,鼠標雙擊。
那麼思路來了:
鼠標按下,確定左上角的點,然後鼠標移動繪製矩形區域,然後鼠標彈起,確定右下角的點,這樣矩形區域繪製完成。
case WM_LBUTTONDOWN:
{
if (!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.left = pt.x;
rect.top = pt.y;
rect.right = pt.x;
rect.bottom = pt.x;
InvalidateRgn(hWnd, 0, FALSE);
Isdowmn = TRUE;
}
}
break;
case WM_LBUTTONUP:
{
if (Isdowmn == TRUE&&!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, FALSE);
Isdowmn = FALSE;
Iselect = TRUE;
}
}
break;
case WM_MOUSEMOVE:
{
if (Isdowmn == TRUE&&!Iselect)
{
POINT pt;
GetCursorPos(&pt);
rect.right = pt.x;
rect.bottom = pt.y;
InvalidateRgn(hWnd, 0, FALSE);
}
}
break;
最後鼠標雙擊將截取到的圖片保存剪切板,這樣就完成了屏幕截取。
case WM_LBUTTONDBLCLK:
if (Iselect == TRUE)
{
int iNum = MessageBox(hWnd, "截圖成功!", "張一西", MB_OKCANCEL | MB_ICONINFORMATION);
if (iNum == 1)
{
CopyToCliboard();
Iselect = FALSE;
PostQuitMessage(0);
}
else
{
Iselect = FALSE;
}
}
break;
void CopyToCliboard()
{
HDC hScreenDC = ::CreateDC("DISPLAY", 0, 0, 0);
HDC memDC = ::CreateCompatibleDC(hScreenDC);
int Width = rect.right - rect.left-2;
int Height = rect.bottom - rect.top-2;
HBITMAP hBmap = CreateCompatibleBitmap(hScreenDC, Width, Height);
HBITMAP hOldBmap = (HBITMAP)SelectObject(memDC, hBmap);
BitBlt(memDC, 0, 0, Width, Height, hScreenDC, rect.left+1, rect.top+1, SRCCOPY);
HBITMAP hNewBmap = (HBITMAP)SelectObject(memDC, hOldBmap);
if (OpenClipboard(0)) //打開粘貼板
{
EmptyClipboard(); //清空粘貼板
SetClipboardData(CF_BITMAP, hNewBmap); //把圖片放入粘貼板
CloseClipboard(); //關閉粘貼板
}
}
代碼地址:https://download.csdn.net/download/qq_34430371/12316559