win32-screenshot.cpp (4223B)
1 /* 2 * Copyright (c) 2009, The Mozilla Foundation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Mozilla Foundation nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY The Mozilla Foundation ''AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL The Mozilla Foundation BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Contributors: 28 * Ted Mielczarek <ted.mielczarek@gmail.com> 29 */ 30 /* 31 * win32-screenshot.cpp: Save a screenshot of the Windows desktop in .png 32 * format. If a filename is specified as the first argument on the commandline, 33 * then the image will be saved to that filename. Otherwise, the image will 34 * be saved as "screenshot.png" in the current working directory. 35 */ 36 37 // VS2015: Platform SDK 8.1's GdiplusTypes.h uses the min macro 38 #undef NOMINMAX 39 #undef WIN32_LEAN_AND_MEAN 40 #include <windows.h> 41 #include <gdiplus.h> 42 43 // Link w/ subsystem windows so we don't get a console when executing 44 // this binary. 45 #ifndef __MINGW32__ 46 # pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:wmainCRTStartup") 47 #endif 48 49 using namespace Gdiplus; 50 51 // From http://msdn.microsoft.com/en-us/library/ms533843%28VS.85%29.aspx 52 static int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) { 53 UINT num = 0; // number of image encoders 54 UINT size = 0; // size of the image encoder array in bytes 55 56 ImageCodecInfo* pImageCodecInfo = nullptr; 57 58 GetImageEncodersSize(&num, &size); 59 if (size == 0) return -1; // Failure 60 61 pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); 62 if (pImageCodecInfo == nullptr) return -1; // Failure 63 64 GetImageEncoders(num, size, pImageCodecInfo); 65 66 for (UINT j = 0; j < num; ++j) { 67 if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) { 68 *pClsid = pImageCodecInfo[j].Clsid; 69 free(pImageCodecInfo); 70 return j; // Success 71 } 72 } 73 74 free(pImageCodecInfo); 75 return -1; // Failure 76 } 77 78 #ifdef __MINGW32__ 79 extern "C" 80 #endif 81 int 82 wmain(int argc, wchar_t** argv) { 83 GdiplusStartupInput gdiplusStartupInput; 84 ULONG_PTR gdiplusToken; 85 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); 86 87 HWND desktop = GetDesktopWindow(); 88 HDC desktopdc = GetDC(desktop); 89 HDC mydc = CreateCompatibleDC(desktopdc); 90 int width = GetSystemMetrics(SM_CXSCREEN); 91 int height = GetSystemMetrics(SM_CYSCREEN); 92 HBITMAP mybmp = CreateCompatibleBitmap(desktopdc, width, height); 93 HBITMAP oldbmp = (HBITMAP)SelectObject(mydc, mybmp); 94 BitBlt(mydc, 0, 0, width, height, desktopdc, 0, 0, SRCCOPY | CAPTUREBLT); 95 SelectObject(mydc, oldbmp); 96 97 const wchar_t* filename = (argc > 1) ? argv[1] : L"screenshot.png"; 98 Bitmap* b = Bitmap::FromHBITMAP(mybmp, nullptr); 99 CLSID encoderClsid; 100 Status stat = GenericError; 101 if (b && GetEncoderClsid(L"image/png", &encoderClsid) != -1) { 102 stat = b->Save(filename, &encoderClsid, nullptr); 103 } 104 if (b) delete b; 105 106 // cleanup 107 GdiplusShutdown(gdiplusToken); 108 ReleaseDC(desktop, desktopdc); 109 DeleteObject(mybmp); 110 DeleteDC(mydc); 111 return stat == Ok ? 0 : 1; 112 }