Vista/Win7 Ingame-Screens are black :( GETDC Problem?
Hey we are coding a tool which takes screens automatically ingame. The Problem is that on Viste/Win7 Systems the Screens are only black...I found some inof about getdc and bitblt...The problem seem to related to them. The Coder is very busy with his job atm and I try to get some help during the time. And not very known with C++...but our Coder gave me the code for the Screenshot part...Maybe someone can help.
Maybe this is a reason too...?
Desktop Window Manager
The desktop composition feature, introduced in Windows Vista, fundamentally changes the way applications display pixels on the screen. When desktop composition is enabled, individual windows no longer draw directly to the screen or primary display device as they did in previous versions of Microsoft Windows. Instead, their drawing is redirected to off-screen surfaces in video memory, which are then rendered into a desktop image and presented on the display.
Code:
QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
{
RECT r;
GetClientRect(winId, &r);
if (w < 0) w = r.right - r.left;
if (h < 0) h = r.bottom - r.top;
#ifdef Q_OS_WINCE_WM
if (qt_wince_is_pocket_pc()) {
QWidget *widget = QWidget::find(winId);
if (qobject_cast<QDesktopWidget *>(widget)) {
RECT rect = {0,0,0,0};
AdjustWindowRectEx(&rect, WS_BORDER | WS_CAPTION, FALSE, 0);
int magicNumber = qt_wince_is_high_dpi() ? 4 : 2;
y += rect.top - magicNumber;
}
}
#endif
// Create and setup bitmap
HDC display_dc = GetDC ;
HDC bitmap_dc = CreateCompatibleDC(display_dc);
HBITMAP bitmap = CreateCompatibleBitmap(display_dc, w, h);
HGDIOBJ null_bitmap = SelectObject(bitmap_dc, bitmap);
// copy data
HDC window_dc = GetDC(winId);
BitBlt(bitmap_dc, 0, 0, w, h, window_dc, x, y, SRCCOPY
#ifndef Q_OS_WINCE
| CAPTUREBLT
#endif
);
// clean up all but bitmap
ReleaseDC(winId, window_dc);
SelectObject(bitmap_dc, null_bitmap);
DeleteDC(bitmap_dc);
QPixmap
I found the following code but haven't tried it yet. Could this do the trick?
Code:
1.
#include<iostream>
2.
#include<windows.h>
3.
using namespace std;
4.
5.
inline int GetFilePointer(HANDLE FileHandle){
6.
return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
7.
}
8.
9.
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
10.
bool Success=0;
11.
HDC SurfDC=NULL;
12.
HBITMAP OffscrBmp=NULL;
13.
HDC OffscrDC=NULL;
14.
LPBITMAPINFO lpbi=NULL;
15.
LPVOID lpvBits=NULL;
16.
HANDLE BmpFile=INVALID_HANDLE_VALUE;
17.
BITMAPFILEHEADER bmfh;
18.
if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
19.
return 0;
20.
if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
21.
return 0;
22.
HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
23.
BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
24.
if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL)
25.
return 0;
26.
ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
27.
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
28.
SelectObject(OffscrDC, OldBmp);
29.
if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
30.
return 0;
31.
if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
32.
return 0;
33.
if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
34.
return 0;
35.
if ((BmpFile = CreateFile(filename,
36.
GENERIC_WRITE,
37.
0, NULL,
38.
CREATE_ALWAYS,
39.
FILE_ATTRIBUTE_NORMAL,
40.
NULL)) == INVALID_HANDLE_VALUE)
41.
return 0;
42.
DWORD Written;
43.
bmfh.bfType = 19778;
44.
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
45.
if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
46.
return 0;
47.
if (Written < sizeof(bmfh))
48.
return 0;
49.
if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL))
50.
return 0;
51.
if (Written < sizeof(BITMAPINFOHEADER))
52.
return 0;
53.
int PalEntries;
54.
if (lpbi->bmiHeader.biCompression == BI_BITFIELDS)
55.
PalEntries = 3;
56.
else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
57.
(int)(1 << lpbi->bmiHeader.biBitCount) : 0;
58.
if(lpbi->bmiHeader.biClrUsed)
59.
PalEntries = lpbi->bmiHeader.biClrUsed;
60.
if(PalEntries){
61.
if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL))
62.
return 0;
63.
if (Written < PalEntries * sizeof(RGBQUAD))
64.
return 0;
65.
}
66.
bmfh.bfOffBits = GetFilePointer(BmpFile);
67.
if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL))
68.
return 0;
69.
if (Written < lpbi->bmiHeader.biSizeImage)
70.
return 0;
71.
bmfh.bfSize = GetFilePointer(BmpFile);
72.
SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
73.
if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
74.
return 0;
75.
if (Written < sizeof(bmfh))
76.
return 0;
77.
return 1;
78.
}
79.
bool ScreenCapture(int x, int y, int width, int height, char *filename){
80.
HDC hDc = CreateCompatibleDC(0);
81.
HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);
82.
SelectObject(hDc, hBmp);
83.
BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);
84.
bool ret = SaveBMPFile(filename, hBmp, hDc, width, height);
85.
DeleteObject(hBmp);
86.
return ret;
87.
}
88.
89.
int main() {
90.
int x1 = 0;
91.
int y1 = 0;
92.
int x2 = GetSystemMetrics(SM_CXSCREEN);
93.
int y2 = GetSystemMetrics(SM_CYSCREEN);
94.
ScreenCapture(x1, y1, x2 - x1, y2 - y1, "rename_me_before_upload.bmp");
95.
cin.ignore();
96.
return 0;
97.
}
Re: Vista/Win7 Ingame-Screens are black :( GETDC Problem?
I think the problem comes from the lack of reservation of space for the bytes of the header of the bitmap and the bitmap itself.
In the example, you have these allocations at lines 24 and 31. They are missing in your code.
Re: Vista/Win7 Ingame-Screens are black :( GETDC Problem?
The code is fragmented and so it is hard to follow. It looks like you are getting a windowID for some window and trying to capture from its DC directly. I don't know about desktop composition, but that may be the problem. In some of the capture utilities I've seen, they capture individual windows in the same way they do an entire screen capture; however, they just limit the bitblt to the rectangle of the window being captured. This might work in your case.