2016-11-01 7 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, перейдите в Project Properties -> Manifest инструментов, набор DPI осведомленности в "Per Monitor High DPI Aware" или "High DPI Aware"

Если вы используют некоторые старый компилятор ...

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 файл в свой проект с Тхи Содержание 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. Что мне тогда использовать? И огромное спасибо! –