Saturday, 31 August 2013

GetDIBits failing when trying to save screenshot with ctypes?

GetDIBits failing when trying to save screenshot with ctypes?

I'm attempting to take and save a screenshot using just ctypes. I'm not
terrifically familiar with the Windows API, so I've been leaning pretty
heavily on the various example in the Microsoft Developer Network.
I've been using the following code from the MSDN as a template to try to
recreate with ctypes.
void SaveBitmap(char *szFilename,HBITMAP hBitmap)
{
HDC hdc=NULL;
FILE* fp=NULL;
LPVOID pBuf=NULL;
BITMAPINFO bmpInfo;
BITMAPFILEHEADER bmpFileHeader;
do{
hdc=GetDC(NULL);
ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS);
if(bmpInfo.bmiHeader.biSizeImage<=0)
bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL)
{
//MessageBox( NULL, "Unable to Allocate Bitmap Memory",
break;
}
bmpInfo.bmiHeader.biCompression=BI_RGB;
GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo,
DIB_RGB_COLORS);
if((fp = fopen(szFilename,"wb"))==NULL)
{
//MessageBox( NULL, "Unable to Create Bitmap File", "Error",
MB_OK|MB_ICONERROR);
break;
}
bmpFileHeader.bfReserved1=0;
bmpFileHeader.bfReserved2=0;
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
bmpFileHeader.bfType='MB';
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
}while(false);
if(hdc) ReleaseDC(NULL,hdc);
if(pBuf) free(pBuf);
if(fp) fclose(fp);
However, I'm having terrible luck getting the GetDIBits function to
succeed. I'm moderately confident that I've got the actual screengrab code
correct, but the save code is giving me a lot of trouble. And
frustratingly, I'm not sure why these functions are failing.
My Python code:
libc = ctypes.cdll.msvcrt
# handle to the entire desktop Window
hdc = windll.user32.GetDC(None)
# DC for the entire window
h_dest = windll.gdi32.CreateCompatibleDC(hdc)
width = windll.user32.GetSystemMetrics(SM_CXSCREEN)
height = windll.user32.GetSystemMetrics(SM_CYSCREEN)
hb_desktop = windll.gdi32.CreateCompatibleBitmap(hdc, width, height)
windll.gdi32.SelectObject(h_dest, hb_desktop)
print windll.gdi32.BitBlt(h_dest, 0,0, width, height, hdc, 0, 0, 'SRCCOPY')
# Save Section
# ==============
bmp_info = BITMAPINFO()
# hdc = windll.user32.GetDC(None)
bmp_info.bmiHeader.biSize = len(bytes(BITMAPINFOHEADER))
print windll.gdi32.GetDIBits(hdc, hb_desktop, 0,0, None, byref(bmp_info),
0x00)
bmp_info.bmiHeader.biSizeImage = bmp_info.bmiHeader.biWidth
*abs(bmp_info.bmiHeader.biHeight) * (bmp_info.bmiHeader.biBitCount+7)/8;
pBuf = libc.malloc(bmp_info.bmiHeader.biSizeImage)
bmp_info.bmiHeader.biCompression = 0x00000000
print windll.gdi32.GetDIBits(hdc, hb_desktop, 0,
bmp_info.bmiHeader.biHeight, pBuf, byref(bmp_info), 0x00)
bmp_header = BITMAPFILEHEADER()
bmp_header.bfReserved1 = 0
bmp_header.bfReserved2 = 0
bmp_header.bfSize = len(bytes(BITMAPFILEHEADER) + bytes(BITMAPINFOHEADER)
+ bytes(bmp_info.bmiHeader.biSizeImage))
bmp_header.bfType = 0x4D42
bmp_header.bfOffBits = len(bytes(BITMAPFILEHEADER) + bytes(BITMAPINFOHEADER))
fp = libc.fopen('asdfasd.bmp',"wb")
libc.fwrite(byref(bmp_header),
len(bytes(BITMAPFILEHEADER)), 1, fp)
libc.fwrite(byref(bmp_info.bmiHeader),
len(bytes(BITMAPFILEHEADER)), 1, fp)
libc.fwrite(pBuf, bmp_info.bmiHeader.biSizeImage, 1, fp)
I've added print statements to each GetDIBits call, and sure enough,
they're all returning a failed code. I'm completely stumped here.

No comments:

Post a Comment