views:

239

answers:

1

I want to make a screen shot and display it in the window of my program, but so far I have only been able to make the screen white.

What am I doing wrong?

Code:

#include <windows.h>


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

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("screen") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("Digital Clock"),
                          WS_POPUP|WS_DLGFRAME|WS_VISIBLE, //WS_OVERLAPPEDWINDOW| WS_MAXIMIZE,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, SW_MAXIMIZE);// iCmdShow) ;
     UpdateWindow (hwnd) ;

     while (GetMessage (&msg, NULL, 0, 0))
          {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
          }
     return msg.wParam ;
     }



LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL   f24Hour, fSuppress ;
     static HBRUSH hBrushRed ;
     static int    cxClient, cyClient ;
     HDC           hdc ;
     PAINTSTRUCT   ps ;
     TCHAR         szBuffer [2] ;
   HGDIOBJ hMem;  // HBITMAP hMem;  
  HDC compdc;

     switch (message)
     {
     case WM_CREATE:
          hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
    keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_EXTENDEDKEY, 0); //get screen snapshot into clipboard
    OpenClipboard(NULL); 
    hMem = GetClipboardData(CF_BITMAP);   

   case WM_SETTINGCHANGE:

          return 0 ;

     case WM_SIZE:
          cxClient = LOWORD (lParam) ;
          cyClient = HIWORD (lParam) ;
          return 0 ;

     case WM_TIMER:
          InvalidateRect (hwnd, NULL, TRUE) ;
          return 0 ;

     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
   compdc = CreateCompatibleDC(hdc);
          SelectObject(compdc,hMem);
    BitBlt(hdc,0,0,cxClient,cyClient,compdc,20,20,SRCCOPY);

          EndPaint (hwnd, &ps) ;
          return 0 ;
     case WM_KEYDOWN:
     switch(wParam)
     {
     case VK_ESCAPE:
                  DeleteObject (hBrushRed);
                 PostQuitMessage (0) ;
     }

     case WM_DESTROY:

          DeleteObject (hBrushRed) ;
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}
+1  A: 

First of all, I'd avoid using the clipboard like this does -- the user should see changes in the clipboard only after an explicit cut or copy.

Instead, you should capture the contents of the screen directly. Given that you're doing this with raw Win32 calls, you'd start by defining a couple of extra variables in your WndProc:

static HBITMAP bmp;
static RECT r;

Then in your WM_CREATE handler, you'd have code something like this to actually capture the screen:

{
// First get a DC to the entire screen.
 HDC s = GetDC(NULL);

// Then get the size of the screen:
 r.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
 r.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 r.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
 r.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);

// Then create a bitmap to hold the picture of the screen:
 bmp = CreateCompatibleBitmap(s, r.right, r.bottom);

// Create a memory DC and select that BMP into it:
 HDC mem=CreateCompatibleDC(s);
 HBITMAP old = (HBITMAP)SelectObject(mem, bmp);

// Copy the bits from the screen to our DC (and our BMP that's selected into it.
 BitBlt(mem, 0, 0, r.right, r.bottom, s, 0, 0, SRCCOPY);

// Clean up:
 SelectObject(mem, old);
 DeleteDC(mem);
 ReleaseDC(NULL, s);
}
break;

Then in your WM_PAINT handler, you'd have code like this to draw that to your window:

{
 hdc = BeginPaint(hWnd, &ps);

// Create a compatible DC and select our BMP into it:
  HDC mem=CreateCompatibleDC(hdc);
  HBITMAP old = (HBITMAP)SelectObject(mem, bmp);

// Copy bits from our BMP to our window:
  BitBlt(hdc, 0, 0, r.right, r.bottom, mem, 0, 0, SRCCOPY);

// Clean up:
  SelectObject(hdc, old);
  DeleteDC(mem);
 EndPaint(hWnd, &ps);
 break;
}
Jerry Coffin