Heya.
I have just tried implementing a screengrabber based on code found over at MSDN ... what's wrong with GetDIBits ? Is it wrong to grab the desktop this way?



;The following code was translated from cpp source located at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_87eb.asp

;-----------------------------------------------------------------------------------------------------------------------------------------------
;This procedure creates a named BMP file given pbi, bmphandle and dchandle of source image.
;-----------------------------------------------------------------------------------------------------------------------------------------------
CreateBMPFile PROC pszFile:DWORD, pbi:PTR BITMAPINFO, hBMP:HBITMAP , hDC:HDC
LOCAL hf:HANDLE ; // file handle
LOCAL hdr:BITMAPFILEHEADER ; // bitmap file-header
LOCAL pbih:PTR BITMAPINFOHEADER ; // bitmap info-header
LOCAL hdc:HANDLE
LOCAL hBMp:HANDLE
LOCAL lpBits:PTR BYTE ; // memory pointer
LOCAL dwTotal:DWORD ; // total count of bytes
LOCAL cb:DWORD ; // incremental count of bytes
LOCAL hp:PTR BYTE ; // byte pointer
LOCAL dwTmp:DWORD
;-----------------------------------------------------------------------------------------------------------------------------------------------
mov eax, pbi
mov pbih,eax
mov eax,hDC
mov hdc,eax
mov eax,hBMP
mov hBMp,eax
mov esi,pbih
push esi
mov lpBits ,$invoke (GlobalAlloc,GMEM_FIXED, .BITMAPINFOHEADER .biSizeImage)
pop esi
.if !eax
invoke MessageBox,0,CTXT("Failed GlobalAlloc"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp Byee
.endif
; // Retrieve the color table (RGBQUAD array) and the bits (array of palette indices) from the DIB.
push esi
invoke GetDIBits,hdc, hBMp, 0, .BITMAPINFOHEADER.biHeight, lpBits, esi, DIB_RGB_COLORS
pop esi
.if !eax
invoke MessageBox,0,CTXT("Failed GetDIBits"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif

; // Create the .BMP file.
push esi
mov hf , $invoke (CreateFile,pszFile,GENERIC_READ or GENERIC_WRITE, 0,0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)
pop esi
.if eax == INVALID_HANDLE_VALUE
invoke MessageBox,0,CTXT("Failed CreateFile"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif
mov hdr.bfType , 4d42h ; // 0x42 = "B" 0x4d = "M"

; // Compute the size of the entire file.
mov eax,.BITMAPINFOHEADER.biClrUsed
mov ebx,sizeof(RGBQUAD)
mul ebx
add eax,sizeof (BITMAPFILEHEADER)
add eax,.BITMAPINFOHEADER.biSize
add eax,.BITMAPINFOHEADER.biSizeImage
mov hdr.bfSize , eax

mov hdr.bfReserved1 , 0
mov hdr.bfReserved2 , 0

; // Compute the offset to the array of color indices.
mov eax,.BITMAPINFOHEADER.biClrUsed
mov ebx,sizeof (RGBQUAD)
mul ebx
add eax,sizeof(BITMAPFILEHEADER)
add eax,.BITMAPINFOHEADER.biSize
mov hdr.bfOffBits ,eax

; // Copy the BITMAPFILEHEADER into the .BMP file.
push esi
invoke WriteFile,hf, addr hdr, sizeof(BITMAPFILEHEADER), addr dwTmp, 0
pop esi
.if !eax
invoke MessageBox,0,CTXT("Failed WriteFile (FileHeader)"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif

; // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
mov eax,.BITMAPINFOHEADER.biClrUsed
mov ebx,sizeof (RGBQUAD)
mul ebx
add eax,sizeof(BITMAPINFOHEADER)
mov ebx,eax
push esi
invoke WriteFile,hf, esi, ebx, addr dwTmp, 0
pop esi
.if !eax
invoke MessageBox,0,CTXT("Failed WriteFile (InfoHeader)"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif

; // Copy the array of color indices into the .BMP file.
mov eax,.BITMAPINFOHEADER.biSizeImage
mov cb,eax
mov dwTotal ,eax
m2m hp , lpBits
push esi
invoke WriteFile,hf, hp, cb, addr dwTmp,0
pop esi
.if !eax
invoke MessageBox,0,CTXT("Failed WriteFile (ColorData)"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif
invoke CloseHandle,hf ; Close the .BMP file.
@@:
invoke GlobalFree,lpBits ; Free memory.
Byee:
ret
CreateBMPFile ENDP
;-----------------------------------------------------------------------------------------------------------------------------------------------

;-----------------------------------------------------------------------------------------------------------------------------------------------
;This procedure creates a BitMapInfo struct and returns a handle to it
;-----------------------------------------------------------------------------------------------------------------------------------------------
CreateBitmapInfoStruct PROC hBmp:HBITMAP
LOCAL bmp:BITMAP
LOCAL pbmi:PTR BITMAPINFO
LOCAL cClrBits:WORD
;-----------------------------------------------------------------------------------------------------------------------------------------------
push esi
; /* Retrieve the bitmap's color format, width, and height. */
invoke GetObject,hBmp, sizeof bmp, addr bmp
.if !eax
invoke MessageBox,0,CTXT("Failed GetObject"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif

; /* Convert the color format to a count of bits. */
xor eax,eax
xor ebx,ebx
mov ax,bmp.bmPlanes
mul bmp.bmBitsPixel
mov cClrBits ,ax

.if cClrBits == 1
nop
.elseif cClrBits <= 4
mov cClrBits , 4
.elseif cClrBits <= 8
mov cClrBits , 8;
.elseif cClrBits <= 16
mov cClrBits , 16;
.elseif cClrBits <= 24
mov cClrBits , 24;
.else
mov cClrBits , 32;
.endif

; Allocate memory for the BITMAPINFO structure. (This structure contains
; a BITMAPINFOHEADER structure and an array of RGBQUAD data structures.)
;pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) +
; sizeof(RGBQUAD) * (1<< cClrBits));

push esi
.if cClrBits != 24
xor ecx,ecx
mov eax,sizeof(RGBQUAD)
mov cx,cClrBits
shl ecx,1
mul ecx
add eax,sizeof(BITMAPINFOHEADER)
mov pbmi ,$invoke (LocalAlloc,LPTR, eax)
.else ; * There is no RGBQUAD array for the 24-bit-per-pixel format.
mov pbmi , $invoke (LocalAlloc,LPTR,sizeof(BITMAPINFOHEADER))
.endif
pop esi

; /* Initialize the fields in the BITMAPINFO structure. */

mov .BITMAPINFOHEADER.biSize , sizeof(BITMAPINFOHEADER);
m2m .BITMAPINFOHEADER.biWidth , bmp.bmWidth;
m2m .BITMAPINFOHEADER.biHeight , bmp.bmHeight;
m2m .BITMAPINFOHEADER.biPlanes , bmp.bmPlanes;
m2m .BITMAPINFOHEADER.biBitCount , bmp.bmBitsPixel

.if cClrBits < 24 ; pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
xor eax,eax
mov ax,cClrBits
shl eax,1
mov .BITMAPINFOHEADER.biClrUsed ,eax
.endif

; /* If the bitmap is not compressed, set the BI_RGB flag. */
mov .BITMAPINFOHEADER.biCompression , BI_RGB

; * Compute the number of bytes in the array of color
; * indices and store the result in biSizeImage.
; pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight;
mov eax,.BITMAPINFOHEADER.biWidth
xor ebx,ebx
mov bx,cClrBits
mul ebx
mov ebx,31
add eax,ebx ;+31
not ebx
and eax,ebx ;&~31
shr eax,3 ;/8
mov ebx,.BITMAPINFOHEADER.biHeight
mul ebx
mov .BITMAPINFOHEADER.biSizeImage ,eax

; * Set biClrImportant to 0, indicating that all of the device colors are important.
mov .BITMAPINFOHEADER.biClrImportant , 0

@@:
pop esi
mov eax, pbmi
ret
CreateBitmapInfoStruct ENDP
;-----------------------------------------------------------------------------------------------------------------------------------------------

;-----------------------------------------------------------------------------------------------------------------------------------------------
;This code takes a screenshot of the desktop window, saving it to a named bmpfile
;-----------------------------------------------------------------------------------------------------------------------------------------------
ScreenShot PROC pFile:DWORD, XX:DWORD,YY:DWORD
LOCAL hBmp:HANDLE
LOCAL hDC:HANDLE
LOCAL hMyDC:HANDLE
LOCAL pbmi:PTR BITMAPINFOHEADER

mov hDC, $invoke (GetDC,HWND_DESKTOP)
invoke CreateCompatibleDC,eax
mov hMyDC,eax
mov hBmp, $invoke (CreateCompatibleBitmap,eax,XX,YY)
.if eax==0
invoke MessageBox,0,CTXT("Failed CreateCompatibleBitmap"),CTXT("ERROR"),MB_OK+MB_ICONERROR
jmp @F
.endif
mov pbmi, $invoke (CreateBitmapInfoStruct,hBmp) ;returns pbmi
invoke CreateBMPFile,pFile, pbmi, hBmp , hMyDC
invoke LocalFree,pbmi
invoke DeleteObject,hBmp
invoke DeleteDC,hMyDC
invoke DeleteDC,hDC
@@: ret
ScreenShot ENDP
;-----------------------------------------------------------------------------------------------------------------------------------------------
Posted on 2003-04-16 23:33:39 by Homer