Page 1 of 1

[win] Take a screenshot to clipboard

Posted: Sun Jul 31, 2011 9:16 pm
by stefbuet
With win7, using 'print screen' keyboard key to take a screenshot isn't working well with fullscreen applications. Most of the time only the first ever rendered frame is put into the clipboard. This function will basicly do the same work as print screen but it's working fine all the time:

Code: Select all

 
 
#include <windows.h>
#include <iostream> //for std::cout only
 
//! Create a screenshot of the scene and put it in the clipboard.
//!\param hwnd irrlicht window handle. Can be get thought IVideoDriver::getExposedVideoData.
//!\return true if sucess, false if an errror occured while processing.
bool createScreenShotToClipBoard(HWND hwnd) {
        
        //create the screenshot
        IImage *irrImg=driver->createScreenShot();
 
        HDC memHdc=CreateCompatibleDC(NULL);
 
       if(memHdc==NULL) {
                std::cout<<"Error : can't create HDC"<<std::endl;
                irrImg->drop();
                return false;
        }
 
        HDC H=GetDC(hwnd);
 
      if(H==NULL) {
                std::cout<<"Error : can't get DC"<<std::endl;
                DeleteDC(memHdc);
                irrImg->drop();
                return false;
        }
 
        //create the windows bitmap
        HBITMAP hBitmap=CreateCompatibleBitmap(H,WINDOW_WIDTH,WINDOW_HEIGHT);
        ReleaseDC(hwnd,H);
 
       if(hBitmap==NULL) {
                std::cout<<"Error : Can't create bitmap"<<std::endl;
                DeleteDC(memHdc);
                irrImg->drop();
                return false;
        }
 
        SelectObject(memHdc,hBitmap);
 
        LPBYTE bmpData=new BYTE[WINDOW_WIDTH*WINDOW_HEIGHT*3]; //1 BYTE per color channel, 3 BYTES per color
        
        //Store pixel data in the bytes array
        for(unsigned int j=0; j<WINDOW_HEIGHT; ++j) {
                for(unsigned int i=0; i<WINDOW_WIDTH; ++i) {
                        SColor irrPixelColor=irrImg->getPixel(i,WINDOW_HEIGHT-j);
                        bmpData[(j*WINDOW_WIDTH+i)*3]=irrPixelColor.getBlue();
                        bmpData[(j*WINDOW_WIDTH+i)*3+1]=irrPixelColor.getGreen();
                        bmpData[(j*WINDOW_WIDTH+i)*3+2]=irrPixelColor.getRed();
                }
        }
 
        //create the bitmapInfo object which hold bitmap information
        BITMAPINFO bi;
        bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
        bi.bmiHeader.biWidth = WINDOW_WIDTH;
        bi.bmiHeader.biHeight = WINDOW_HEIGHT;
        bi.bmiHeader.biBitCount = 24; //8 bit per channel, RGB
        bi.bmiHeader.biPlanes = 1;
        bi.bmiHeader.biCompression = BI_RGB;
        
        //put pixel bytes array directly into the bitmap
        if(!SetDIBits(memHdc,hBitmap,0,WINDOW_HEIGHT,bmpData,&bi,DIB_RGB_COLORS)) {
                std::cout<<"Error : can't set bitmap data"<<std::endl;
                return(false);
        }
 
        //free some memory
        DeleteDC(memHdc);
        irrImg->drop();
        delete[] bmpData;
 
        //Open the clipboard to put some data into it
        if(!OpenClipboard(hwnd)) {
                std::cout<<"Error : Can't open win clipboard"<<std::endl;
                DeleteObject(hBitmap);
                return(false);
        }
 
        //empty clipboard from other data which might be there
        if(!EmptyClipboard()) {
               std::cout<<"Error : Can't empty win clipboard"<<std::endl;
               DeleteObject(hBitmap);
                return(false);
        }
 
        //put bitmap data into clipboard
        if(SetClipboardData(CF_BITMAP,hBitmap)==NULL) {
                 std::cout<<"Error : Can't put the bitmap data into clipboard"<<std::endl;
                 DeleteObject(hBitmap);
                 return(false);
        }
 
        //delete the bitmap
        DeleteObject(hBitmap);
         
       //Close the clipboard so as to allow other apps to get back the screenshot
        if(!CloseClipboard())  {
            std::cout<<"Error : Can't close clipboard"<<std::endl; //other applications won't be able to use it
            return(false);
       }
 
       std::cout<<"A screenshot had been copyed to your clipboard."<<std::endl;
 
      return true;
}
 

Re: Take a screenshot to clipboard

Posted: Thu Aug 04, 2011 4:12 pm
by christianclavet
Hi,

Just by curiosity, theses function:

Code: Select all

//clip board part
        OpenClipboard(hwnd);
        EmptyClipboard();
        SetClipboardData(CF_BITMAP,hBitmap);
        CloseClipboard();


Do they need a specific include? (I assume there is, and that is only windows platform code)
For a quick googling around you should include "afxwin.h" to have the CWnd class (part of the windows MFC)

Can you give me more detail? Never used thoses before...

Re: Take a screenshot to clipboard

Posted: Thu Aug 04, 2011 4:16 pm
by stefbuet
Just windows.h, this is the basic win32 API, not MFC.
This snippet is only using windows API but that was to resolve a win7 problem initially. I added a tag on the OP title to specify that.
WINDOW_WIDTH and WINDOW_HEIGHT are the screen size, not necessary const.
I also changed the code:
-now every possible error is handled (with a bool return value)
-take the window handle as a parameter
-I added comments (documentation creation handled)
-headers

:wink: