In questo nuovo articolo tratteremo sempre di programmazione Windows tramite il linguaggio C++ ( basta scaricare Visual C++ Express gratuitamente dal sito Microsoft ) ed in particolare vedremo come implementare un’applicazione molto semplice che consenta di catturare lo schermo e stamparlo a video all’interno del nostro programma, ovviamente con le dovute proporzioni. Un buon esercizio potrebbe essere quello di estendere le funzionalità dell’applicazione, ad esempio per gestire 24 bit di colore oppure salvare l’immagine catturata in un file.
// File di intestazione CorsoVC.h #include <windows.h> #define APP_NAME "Catturare lo schermo" #define IDM_EXIT 102 #define IDM_ABOUT 103 #define IDM_CAPTURE 104 LRESULT CALLBACK AppWndProc(HWND, UINT, WPARAM, LPARAM); // File sorgente CorsoVC.cpp #define WIN32_LEAN_AND_MEAN #include "CorsoVC.h" static HWND m_hWndMain = NULL; static HINSTANCE m_hInst = NULL; static HBITMAP m_hBit = NULL; static int InitApplication(HINSTANCE); static int InitInstance(HINSTANCE); static void ContextMenu(HWND); static HBITMAP GetWindowImage(HWND, LPRECT); int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPreInst, LPSTR lpszCmdLine, int iShowCmd) { MSG msg; if(!InitApplication(hInst)) return FALSE; if (!InitInstance(hInst)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return TRUE; } LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_EXIT: SendMessage(m_hWndMain, WM_CLOSE, 0, 0L); break; case IDM_ABOUT: MessageBox(m_hWndMain, "Lo screen capture da \ RGPSoft di Rossi Giampaolo", "Splash Window", MB_OK|MB_ICONINFORMATION); break; case IDM_CAPTURE: m_hBit = GetWindowImage(NULL, NULL); InvalidateRect(m_hWndMain, NULL, FALSE); break; } break; case WM_CONTEXTMENU: ContextMenu(m_hWndMain); break; case WM_SIZE: DefWindowProc(hWnd, uMsg, wParam, lParam); return 0; case WM_CLOSE: DestroyWindow(m_hWndMain); if (m_hBit) DeleteObject(m_hBit); break; case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(hWnd, &ps); if (m_hBit == NULL) { int iMode = SetBkMode(ps.hdc, TRANSPARENT); DrawText(ps.hdc, "Click destro per visualizzare il menu!", 38, &ps.rcPaint, DT_SINGLELINE|DT_CENTER|DT_VCENTER); SetBkMode(ps.hdc, iMode); } else { BITMAP bm; HDC hdc = CreateCompatibleDC(ps.hdc); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdc, m_hBit); GetObject((HBITMAP)m_hBit, sizeof(bm), &bm); StretchBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left, ps.rcPaint.bottom - ps.rcPaint.top, hdc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); SelectObject(hdc, hOldBitmap); DeleteDC(hdc); } EndPaint(hWnd, &ps); } break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); } int InitApplication(HINSTANCE hInst) { WNDCLASS wc; wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)AppWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wc.lpszClassName = "CAPTURE_CLASS"; wc.lpszMenuName = NULL; return RegisterClass(&wc); } int InitInstance(HINSTANCE hInst) { m_hInst = hInst; m_hWndMain = CreateWindowEx(0, "CAPTURE_CLASS", APP_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 500, 500, NULL, NULL, hInst, NULL); if (!m_hWndMain) return FALSE; ShowWindow(m_hWndMain, SW_SHOW); UpdateWindow(m_hWndMain); return TRUE; } void ContextMenu(HWND hWnd) { HMENU hMenu; POINT pt; GetCursorPos(&pt); hMenu = CreatePopupMenu(); AppendMenu(hMenu, MF_STRING, IDM_CAPTURE, "&Cattura schermo"); AppendMenu(hMenu, MF_SEPARATOR, 0, ""); AppendMenu(hMenu, MF_STRING, IDM_ABOUT, "&Info"); AppendMenu(hMenu, MF_STRING, IDM_EXIT, "&Esci"); TrackPopupMenu(hMenu, 0, pt.x, pt.y, 0, hWnd, NULL); DestroyMenu(hMenu); } HBITMAP GetWindowImage(HWND hWnd, LPRECT lpRect) { HDC hdc, hdcMem; HBITMAP hBit, hBitOld; RECT rc; POINT pt; if (hWnd == NULL) hdc = CreateDC("DISPLAY", NULL, NULL, NULL); else hdc = GetDC(hWnd); hdcMem = CreateCompatibleDC(hdc); if (lpRect == NULL) { if (hWnd == NULL) SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); else GetClientRect(hWnd, &rc); } else CopyRect(&rc, lpRect); hBit = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top); hBitOld = (HBITMAP)SelectObject(hdcMem, hBit); pt.x = rc.left; pt.y = rc.top; if (hWnd != NULL) { ClientToScreen(hWnd, &pt); ScreenToClient(hWnd, &pt); } BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, pt.x, pt.y, SRCCOPY); SelectObject(hdcMem, hBitOld); DeleteDC(hdcMem); if (hWnd == NULL) DeleteDC(hdc); else ReleaseDC(hWnd, hdc); return hBit; }
La funzione che consente di catturare lo schermo è GetWindowImage e come argomenti ha l’handle della finestra da catturare che se nullo prende tutto lo schermo ed il rettangolo da catturare che se nullo consente di acquisire l’intero schermo. Come potete notare si tratta di creare dei device context in memoria e poi selezionarci la bitmap. Se aveste delle domande da pormi vi posso rispondere sul nostro forum.