Gdi+Take屏幕截图多个显示器

Gdi+ Take Screenshot multiple monitors

本文关键字:显示器 屏幕截图 Gdi+Take      更新时间:2023-10-16

我有一个在带有gdi plus和c++的windows平台上截屏的例程,它只适用于一个监视器,但当我在带有两个监视器的机器上运行它时,它只会拍摄一张照片。

这就是我正在做的:

#include <stdlib.h>
#include <windows.h>
#include <iostream>
#include <GdiPlus.h>
#include <wingdi.h>
#include <fstream>
#include <unistd.h>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "ws2_32.lib")
using namespace std;
// Se encarga de configurar, por asi decirlo, el formato
// de la imagen, este metodo es llamado en gdiscreen al
// momento de guardar la imagen.
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
  using namespace Gdiplus;
  UINT  num = 0;          // number of image encoders
  UINT  size = 0;         // size of the image encoder array in bytes
  ImageCodecInfo* pImageCodecInfo = NULL;
  GetImageEncodersSize(&num, &size);
  if(size == 0)
    return -1;  // Failure
  pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  if(pImageCodecInfo == NULL)
    return -1;  // Failure
  GetImageEncoders(num, size, pImageCodecInfo);
  for(UINT j = 0; j < num; ++j)
  {
    if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
    {
      *pClsid = pImageCodecInfo[j].Clsid;
      free(pImageCodecInfo);
      return j;  // Success
    }
  }
  free(pImageCodecInfo);
  return 0;
}
// Este es el metodo que tomo la captura.
// c es solo una variable que utilice para probar el
// metodo en un loop, la puede quitar y remplazar c
// por el log_sec_num.
inline void take_screenshot(const std::string & filename)
{
    using namespace Gdiplus;
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    {
        HDC scrdc, memdc;
        HBITMAP membit;
        scrdc = ::GetDC(0);
        int Height = GetSystemMetrics(SM_CYSCREEN);
        int Width = GetSystemMetrics(SM_CXSCREEN);
        memdc = CreateCompatibleDC(scrdc);
        membit = CreateCompatibleBitmap(scrdc, Width, Height);
        HBITMAP hOldBitmap =(HBITMAP) SelectObject(memdc, membit);
        BitBlt(memdc, 0, 0, Width, Height, scrdc, 0, 0, SRCCOPY);
        Gdiplus::Bitmap bitmap(membit, NULL);
        CLSID clsid;
        const char* name = filename.c_str();
        const size_t cSize = strlen(name)+1;
        wchar_t* wc = new wchar_t[cSize];
        mbstowcs (wc, name, cSize);
        GetEncoderClsid(L"image/png", &clsid);
        bitmap.Save(wc, &clsid,NULL);
        SelectObject(memdc, hOldBitmap);
        DeleteObject(memdc);
        DeleteObject(membit);
        ::ReleaseDC(0,scrdc);
    }
    GdiplusShutdown(gdiplusToken);
}
int main ()
{
    const std::string & filename = "C:\Screenshot.png";
    take_screenshot(filename);
}

如果试图获得整个屏幕,但我最终只得到了图片。有人能看到我的错误在哪里吗??

    int Height = GetSystemMetrics(SM_CYSCREEN);

引用MSDN文档中的一句话:"主显示器屏幕的高度"。您得到了您所要求的,主显示器是您的一台显示器。第一个。

请改用SM_CYVIRTUALSCREEN。与X.相同

可能的解决方案1

使用GetDC(0),您将只获得主监视器的HDC。来自CreateDC MSDN

如果系统上有多个监视器,则调用CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL)将创建一个涵盖所有监视器。

它可能会起作用,但它还没有经过测试。

可能的解决方案2

分别捕获每个桌面,然后合并它们。要获取所有显示器,请使用EnumDisplayMonitors。一些代码项目的文章中有一些工作示例。