2016-11-01 90 views
3

我通过网络进行了一些研究,并找到了一些有用的代码。我改了一点,在试图捕捉整个屏幕,并产生我可以通过UDP数据包发送缓冲区:屏幕捕获无法使用C++和GDI捕获整个屏幕

#include <iostream> 
#include <Windows.h> 
#include <fstream> 

void CapruteScreenAndSaveToFile() 
{ 
    uint16_t BitsPerPixel = 24; 
    uint32_t Width = GetSystemMetrics(SM_CXSCREEN); 
    uint32_t Height = GetSystemMetrics(SM_CYSCREEN); 

    // Create Header 
    BITMAPFILEHEADER Header; 
    memset(&Header, 0, sizeof(Header)); 
    Header.bfType = 0x4D42; 
    Header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 

    // Create Info 
    BITMAPINFO Info; 
    memset(&Info, 0, sizeof(Info)); 
    Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    Info.bmiHeader.biWidth = Width; 
    Info.bmiHeader.biHeight = Height; 
    Info.bmiHeader.biPlanes = 1; 
    Info.bmiHeader.biBitCount = BitsPerPixel; 
    Info.bmiHeader.biCompression = BI_RGB; 
    Info.bmiHeader.biSizeImage = Width * Height * (BitsPerPixel > 24 ? 4 : 3); 

    // Capture screen and save to Pixels 
    char* Pixels = NULL; 
    HDC MemDC = CreateCompatibleDC(0);//Context); 
    HBITMAP Section = CreateDIBSection(MemDC, &Info, DIB_RGB_COLORS, (void**)&Pixels, 0, 0); 
    DeleteObject(SelectObject(MemDC, Section)); 
    BitBlt(MemDC, 0, 0, Width, Height, GetDC(0), 0, 0, SRCCOPY); 
    DeleteDC(MemDC); 

    // Concatenate everything 
    char * buffer = (char*)malloc(sizeof(Header) + sizeof(Info.bmiHeader) + (((BitsPerPixel * Width + 31) & ~31)/8) * Height); 

    memcpy(buffer, (char*)&Header, sizeof(Header)); 
    memcpy(buffer + sizeof(Header), (char*)&Info.bmiHeader, sizeof(Info.bmiHeader)); 
    memcpy(buffer + sizeof(Header) + sizeof(Info.bmiHeader), Pixels, (((BitsPerPixel * Width + 31) & ~31)/8) * Height); 

    // Save to file 
    std::fstream hFile("Foo.bmp", std::ios::out | std::ios::binary); 

    hFile.write(buffer, sizeof(Header) + sizeof(Info.bmiHeader) + (((BitsPerPixel * Width + 31) & ~31)/8) * Height); 

    // Clean up 
    hFile.close(); 
    DeleteObject(Section); 
    free(buffer); 
} 


int main() 
{ 
    CapruteScreenAndSaveToFile(); 

    return 0; 
} 

但似乎只捕捉到我的桌面,这部分:

enter image description here

即使我使用CreateCompatibleDC(0)。

+0

我测试你的代码在我的电脑上。它工作正常。生成的“bmp”具有全屏捕获功能。 – Naidu

+0

不要忘记有[SetWindowDisplayAffinity](https://msdn.microsoft.com/en-us/library/windows/desktop/dd375340.aspx)以及OpenGL。两者都可能成为您的代码的障碍,并使其失败。不是你想要解决的问题,而是你不可避免会遇到的问题。 – IInspectable

回答

4

如果计算机处于高DPI设置,并且应用程序不支持DPI,那么系统会对应用程序进行操作并给出错误的屏幕大小。

你会发现下面的代码显示的宽度和高度比实际屏幕尺寸:

uint32_t Width = GetSystemMetrics(SM_CXSCREEN); 
uint32_t Height = GetSystemMetrics(SM_CYSCREEN); 
std::cout << Width << " x " << Height << "\n"; 

的解决方案是增加DPI awareness应用。

要添加DPI兼容性:

在Visual Studio 2015年,转到项目属性 - >清单工具,设置DPI意识,以 “每监视器高DPI感知” 或 “高DPI感知”

如果您使用一些旧的编译器...

1)创建一个文件 “myapp.manifest” 与此内容:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <application xmlns="urn:schemas-microsoft-com:asm.v3"> 
    <windowsSettings> 
     <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware> 
    </windowsSettings> 
    </application> 
</assembly> 

2)添加* rc文件与THI项目S含量:

1 24 "myapp.manifest" 

3)重建项目

+0

这可能是正确的答案,但它在Windows 8.1中并不适用于我,这显然比Vista更新。因此,我仍然需要进一步的帮助。它说SetProcessDPIAware没有在这个范围内声明,即使我包含了Windows.h和链接的User32.lib。 –

+0

'SetProcessDPIAware'不起作用,因为您没有定义'_WIN32_WINNT'或者您正在使用不兼容的MinGW-32。无论如何,添加DPI认知的正确方法是通过清单文件。不要让这个问题变成一个难题,我必须猜测所有事情,提供一些最低限度的信息,以便获得可重现的错误。 –

+0

是的,我正在使用MinGW-32。我应该使用什么?非常感谢! –