Categories: VC/C++Windows

Finestre con il Buco in Windows

Questo esercizio è stato il primo che ho fatto dopo aver imparato a creare le finestre con l’SDK di Windows e mi è sembrato incredibile poter sviluppare delle finestre con dei buchi, si avete capito bene, dei buchi dai quali poter vedere sotto. Tutto questo è possibile grazie ad una semplice funzione

int SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw);

che permette di associare ad una finestra, e non ad un DC, un’area di clipping, questo significa che è possibile definire un’area di qualsiasi forma contenuta in un HRGN, assegnarla alla finestra e vedere tutto l’output della finestra stessa tagliato entro i limiti della regione. Prendiamo allora il codice di una semplice finestra ed inseriamogli le modifiche per bucarla, in particolare inseriremo un buco che assomiglia a quello delle chiavi, così possiamo sbirciare tutto quello che sta sotto di essa.

// File di intestazione CorsoVC.h

#include <windows.h>

#define APP_NAME "Finestra con il buco"

#define IDM_EXIT  102
#define IDM_ABOUT 103

LRESULT CALLBACK AppWndProc(HWND, UINT, WPARAM, LPARAM);

// File sorgente CorsoVC.cpp

#define WIN32_LEAN_AND_MEAN

#include "CorsoVC.h"

static HWND m_hWndMain;
static HINSTANCE m_hInst;
static HRGN m_hRgnView;
static RECT m_rcHole;
static int InitApplication(HINSTANCE);
static int InitInstance(HINSTANCE);
static int SetClipArea(HWND);

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);
   }
   if (m_hRgnView)
      DeleteObject(m_hRgnView);
   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;
      }
      break;
   case WM_SIZE:
   case WM_MOVE:
      DefWindowProc(hWnd, uMsg, wParam, lParam);
      SetClipArea(hWnd);
      return 0;
   case WM_CLOSE:
      DestroyWindow(m_hWndMain);
      break;
   case WM_PAINT:
   {
      PAINTSTRUCT ps;
      BeginPaint(hWnd, &ps);
      DrawEdge(ps.hdc, &m_rcHole, EDGE_SUNKEN, BF_RECT);
      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 = "HOLE_CLASS";
   wc.lpszMenuName = NULL;
   return RegisterClass(&wc);
}

int InitInstance(HINSTANCE hInst)
{
   m_hInst = hInst;
  m_hWndMain = CreateWindowEx(0, "HOLE_CLASS", APP_NAME,
      WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME,
      CW_USEDEFAULT, CW_USEDEFAULT, 500, 500,
      NULL, NULL, hInst, NULL);
   if (!m_hWndMain)
      return FALSE;
   SetClipArea(m_hWndMain);
   ShowWindow(m_hWndMain, SW_SHOW);
   UpdateWindow(m_hWndMain);
   return TRUE;
}

int SetClipArea(HWND hWnd)
{
   RECT rcHole, rcArea, rcCirc;
   POINT pt[3];
   HRGN hRgnHole, hRgnWnd, hRgnCirc, hRgnTriangle;
   POINT ptOffset;
   GetWindowRect(hWnd, &rcArea);
   rcArea.right -= rcArea.left;
   rcArea.bottom -= rcArea.top;
   rcArea.left = 0;
   rcArea.top = 0;
   CopyRect(&rcHole, &rcArea);
   rcHole.top += GetSystemMetrics(SM_CYCAPTION);
   ptOffset.x = GetSystemMetrics(SM_CXSIZEFRAME) +
      GetSystemMetrics(SM_CXEDGE);
   ptOffset.y = GetSystemMetrics(SM_CYSIZEFRAME) +
      GetSystemMetrics(SM_CYEDGE);
   InflateRect(&rcHole, ptOffset.x, ptOffset.y);
   InflateRect(&rcHole, -rcArea.right / 6, -rcArea.bottom / 8);
   m_hRgnView = CreateRectRgn(0, 0, 10, 10);
   hRgnWnd = CreateRectRgnIndirect(&rcArea);
   hRgnHole = CreateRectRgnIndirect(&rcHole);
   CopyRect(&rcCirc, &rcHole);
   InflateRect(&rcCirc, -
      (rcHole.right - rcHole.left) / 4, 0);
   rcCirc.bottom = rcHole.top +
      (rcHole.bottom - rcHole.top) / 3;
   hRgnCirc = CreateEllipticRgnIndirect(&rcCirc);
   pt[0].x = rcCirc.left +
         (rcHole.right - rcHole.left) / 4;
   pt[0].y = rcCirc.top +
         (rcCirc.bottom - rcCirc.top) / 2;
   pt[1].x = rcHole.right;
   pt[1].y = rcHole.bottom;
   pt[2].x = rcHole.left;
   pt[2].y = rcHole.bottom;
   hRgnTriangle = CreatePolygonRgn((LPPOINT)&pt,
      3, ALTERNATE);
   CombineRgn(hRgnHole, hRgnCirc, hRgnTriangle, RGN_OR);
   CombineRgn(m_hRgnView, hRgnWnd, hRgnHole, RGN_DIFF);
   DeleteObject(hRgnHole);
   DeleteObject(hRgnCirc);
   DeleteObject(hRgnTriangle);
   DeleteObject(hRgnWnd);
   SetWindowRgn(hWnd, m_hRgnView, TRUE);
   return TRUE;
}

Occorre creare una regione di forma ellittica, un’altra triangolare e sommarle, quindi sottrarre la regione della chiave e richiamare la funzione SetWindowRgn per fare in modo che la parte interna non ci sia nell’area di clipping della finestra, il risultato è una finestra con un buco al centro a forma di chiave.

Una finestra con un buco a forma di chiave

In questi esempi che vi propongo cerco di semplificare la programmazione di applicazioni anche complicate, ma l’SDK  di Windows è talmente vasto che non bastano 10 anni per conoscerlo tutto, occorre sapere a grandi linee il compito delle funzioni e poi andarsele a cercare nella guida in linea del compilatore. Se comunque avete bisogno di chiarimenti o fare delle semplici domande potete iscrivervi al forum, nella sezione dedicata alla programmazione.

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