2016-11-01 124 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。我應該使用什麼?非常感謝! –