Categories: VC/C++Windows

Catturare lo Schermo in una Immagine Bitmap

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.

Share
Giampaolo Rossi

Sviluppatore di software gestionale da oltre 28 anni.

Published by
Giampaolo Rossi

Recent Posts

Un Abbonamento per Tutti i Software

Sono arrivato alla convinzione che un abbonamento per tutti i miei software gestionali sia il…

1 anno ago

Software di Magazzino Gratuito

MerciGest è un software per la gestione del magazzino completamente gratuito. Continua a leggere→

1 anno ago

Mettere il PC in Lock Screen

In ufficio può capitare di doversi allontanare dal proprio posto di lavoro, ecco che allora…

3 anni ago

Fare il reset togliendo la corrente

In questo articolo vedremo quando è più o meno utile togliere la corrente ad un…

3 anni ago

Prossimi Aggiornamenti Software

Dopo la pausa invernale dovuta al lavoro che devo fare per sostentarmi, eccomi di nuovo…

3 anni ago

Come Eliminare i Files in Windows

Vediamo come eliminare i files direttamente da Windows senza utilizzare il cestino. Continua a leggere→

4 anni ago