[WinAPI] DC and pixel data

BlitzMax Forums/BlitzMax Programming/[WinAPI] DC and pixel data

Good evening
I have a problem. I need my desktop in a pixmap and the GDI function "GetPixel" is too slow. After hours of search I have found this code.
<Click>
Sounds logical, i need a pointer to the pixel data, easy.
The Blitz Max version:

Strict 

Extern "Win32"
	Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
	Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
	Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
	Function SelectObject(hdc:Int, obj:Int)
	Function CreateCompatibleDC(hdc:Int)
	Function GetDesktopWindow()
	Function GetWindowDC(hwnd:Int)
	Function GetDeviceCaps(hdc:Int, index:Int)
	Function DeleteDC(hdc:Int)
	Function DeleteObject(obj:Int)
	Function ReleaseDC(hwdn:Int, hdc:Int)
End Extern 


Type RGBQuad
	Field R:Byte
	Field G:Byte
	Field B:Byte
	Field Res:Byte
End Type


Type BITMAPINFOHEADER
	Field biSize:Int
	Field biWidth:Long
	Field biHeight:Long
	Field biPlanes:Short
	Field biBitCount:Short
	Field biCompression:Int
	Field biSizeImage:Int
	Field biXPelsPerMeter:Long
	Field biYPelsPerMeter:Long
	Field biClrUsed:Int
	Field biClrImportant:Int
End Type


Type BITMAPINFO
	Field bmiHeader:Byte Ptr
	Field bmiColors:Byte Ptr
End Type


Const HORZRES:Int = 8
Const VERTRES:Int = 10


Local HwndDesktop:Int
Local hdcDesktop:Int
Local hdcMem:Int
Local DesktopWidth:Int
Local DesktopHeight:Int
Local bmpMem:Int
Local Header:BITMAPINFOHEADER
Local INFO:BITMAPINFO
Local Buf:Byte Ptr 

DebugLog ""

HwndDesktop = GetDesktopWindow()

If HwndDesktop
	DebugLog "Desktop Hwnd found"
EndIf



hdcDesktop = GetWindowDC(HwndDesktop)

If hdcDesktop
	DebugLog "Desktop DC found"
EndIf


hdcMem = CreateCompatibleDC(hdcDesktop)

If hdcMem
	DebugLog "Compatible dc created"
EndIf



DesktopWidth = GetDeviceCaps(hdcDesktop, HORZRES)
DebugLog "DesktopWidth: "+DesktopWidth


DesktopHeight = GetDeviceCaps(hdcDesktop, VERTRES)
DebugLog "DesktopHeight: "+DesktopHeight


bmpMem  = CreateCompatibleBitmap(hdcDesktop, DesktopWidth, DesktopHeight)

If bmpMem
	DebugLog "Compatible bitmap created"
EndIf

If SelectObject(HdcMem, bmpMem)
	DebugLog "bmpMem selected into the dcMem"
EndIf



Header = New BITMAPINFOHEADER
Header.biSize         = SizeOf(Header)
Header.biWidth        = DesktopWidth
Header.biheight       = DesktopHeight
Header.biPlanes       = 1
Header.biBitCount     = 24
Header.biCompression  = 0


INFO                  = New BITMAPINFO
Info.bmiHeader        = Header


If BitBlt(hdcMem,0,0,Header.biWidth,Header.biHeight, hdcDesktop,0,0,ROP_SRCCOPY)	
	DebugLog "BitBlt successful"
EndIf



If GetDIBits(hdcMem, bmpMem, 0, Header.biHeight, Buf, info, 0)
	DebugLog "GetDIBits successful"
Else
	DebugLog "WHY...WHYYYY?????"
EndIf


DebugLog ""

DeleteDC(HdcMem)
DeleteObject(bmpMem)
ReleaseDC(hwndDesktop, hdcDesktop)


I´m tired and disappointed.
The GetDIBits function returns 0 and I dont know where the problem is (Wrong Type structure, Wrong Ptr?)
Thx for help.
Mfg Suco

Ok, I have found the solution. The problem ist on the BITMAPINFO Type. If I copy the BITMAPINFOHEADER directly into the BITMAPINFO type, it runs fine.

My small GetDesktopPixmap function

Rem 
DesktopPixmap function by Suco-X
End Rem 

Strict 


Function GetDesktopPixmap:TPixmap()
	
	Extern "Win32"
		Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
		Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
		Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
		Function SelectObject(hdc:Int, obj:Int)
		Function CreateCompatibleDC(hdc:Int)
		Function GetDesktopWindow()
		Function GetWindowDC(hwnd:Int)
		Function GetDeviceCaps(hdc:Int, index:Int)
		Function DeleteDC(hdc:Int)
		Function DeleteObject(obj:Int)
		Function ReleaseDC(hwdn:Int, hdc:Int)
		Function BitBlt(hdc,x,y,w,h,src_dc,src_x,src_y,dwrop)
	End Extern 


	?Win32
	
		Type BITMAPINFO
			Field biSize:Int
			Field biWidth:Int
			Field biHeight:Int
			Field biPlanes:Short
			Field biBitCount:Short
			Field biCompression:Int
			Field biSizeImage:Int
			Field biXPelsPerMeter:Int
			Field biYPelsPerMeter:Int
			Field biClrUsed:Int
			Field biClrImportant:Int
			
			Field R:Byte
			Field G:Byte
			Field B:Byte
			Field Res:Byte
		End Type
		
		
		Const HORZRES:Int = 8
		Const VERTRES:Int = 10
	
		Local HwndDesktop:Int
		Local hdcDesktop:Int
		Local hdcMem:Int
		Local DesktopWidth:Int
		Local DesktopHeight:Int
		Local bmpMem:Int
		Local INFO:BITMAPINFO
		Local FinalPixmap:TPixmap
	
		HwndDesktop = GetDesktopWindow()
	
		If Not HwndDesktop
			Return Null
		EndIf
		
		
		hdcDesktop = GetWindowDC(HwndDesktop)
		
		If Not HdcDesktop
			Return Null
		EndIf
		
		
		hdcMem = CreateCompatibleDC(hdcDesktop)
		
		If Not HdcMem
			Return Null
		EndIf
		
		
		DesktopWidth = GetDeviceCaps(hdcDesktop, HORZRES)
		DesktopHeight = GetDeviceCaps(hdcDesktop, VERTRES)
	
		If DesktopWidth = 0 Or DesktopHeight = 0
			Return Null
		EndIf
		
		
		bmpMem  = CreateCompatibleBitmap(hdcDesktop, DesktopWidth, DesktopHeight)
	
		If Not BmpMem
			Return Null
		EndIf
		
		
		If Not SelectObject(HdcMem, bmpMem)
			Return Null
		EndIf
		
		Info                = New BITMAPINFO
		Info.bisize         = SizeOf(INFO)
		info.BiWidth        = DesktopWidth
		Info.biHeight       = DesktopHeight
		Info.biPlanes       = 1
		info.biBitCount     = 32
		Info.biCompression  = 0
		
		
		If Not BitBlt(hdcMem,0,0,Info.biWidth,Info.biHeight, hdcDesktop,0,0,ROP_SRCCOPY)	
			Return Null
		EndIf
		
		FinalPixmap = CreatePixmap(info.biWidth, info.biHeight, PF_BGRA8888)
		
		If Not GetDIBits(hdcMem, bmpMem, 0, Info.biHeight, FinalPixmap.PixelPtr(0,0), info, 0)
			Return Null
		EndIf
		
		FinalPixmap = YFlipPixmap(FinalPixmap)
		
		DeleteDC(HdcMem)
		DeleteObject(bmpMem)
		ReleaseDC(hwndDesktop, hdcDesktop)
		
		Return FinalPixmap
		
	?
	
	?Linux
		Return Null
	?
	
	?MacOs
		Return Null
	?
End Function



Local Time:Int = MilliSecs()

Local DesktopScreen:TPixmap = GetDesktopPixmap()

Time = MilliSecs()-Time

Print ""
Print "PixmapsPerSecond: "+(1000/Time)
Print ""

If DesktopScreen = Null
	Print "TEST FEHLGESCHLAGEN"
EndIf



Graphics 1024, 768,0

DrawPixmap DesktopScreen,0,0
Flip
WaitKey()


Please test, Win32 only

Mfg Suco

This is absolutely perfect for my form-editor project, and if you don't mind I would appreciate it if I could use a modifed version of it (with credits) :-)

With this one you pass in *any* gadget, and it makes a pixmap copy of whatever it is displaying.
?win32
Rem
bbdoc: Modified from an original example by Suco-X
End Rem
Function GetGadgetPixmap:TPixmap(gad:TGadget)
	
	Extern "Win32"
		Function GetDIBits(hdc:Int, bitmap:Int, Start:Int, Num:Int, bits:Byte Ptr, lpbi:Byte Ptr, usage:Int)
		Function CreateCompatibleBitmap(hdc:Int, Width:Int, Height:Int)
		Function CreateDIBSection(hdc:Int, pbmi:Byte Ptr, usage:Int, Bits:Byte Ptr, hSection:Int, Offset:Int)
		Function SelectObject(hdc:Int, obj:Int)
		Function CreateCompatibleDC(hdc:Int)
		Function GetGadgetWindow()
		Function GetWindowDC(hwnd:Int)
		Function GetDeviceCaps(hdc:Int, index:Int)
		Function DeleteDC(hdc:Int)
		Function DeleteObject(obj:Int)
		Function ReleaseDC(hwdn:Int, hdc:Int)
		Function BitBlt(hdc:Int,x:Int,y:Int,w:Int,h:Int,src_dc:Int,src_x:Int,src_y:Int,dwrop:Int)
		Function GetDC(hwnd:Int)
	End Extern 


	Type BITMAPINFO
		Field biSize:Int
		Field biWidth:Int
		Field biHeight:Int
		Field biPlanes:Short
		Field biBitCount:Short
		Field biCompression:Int
		Field biSizeImage:Int
		Field biXPelsPerMeter:Int
		Field biYPelsPerMeter:Int
		Field biClrUsed:Int
		Field biClrImportant:Int
		
		Field R:Byte
		Field G:Byte
		Field B:Byte
		Field Res:Byte
	End Type
	
	
	Const HORZRES:Int = 8
	Const VERTRES:Int = 10

	Local HwndGadget:Int
	Local hdcGadget:Int
	Local hdcMem:Int
	Local width:Int
	Local height:Int
	Local bmpMem:Int
	Local INFO:BITMAPINFO
	Local FinalPixmap:TPixmap

	HwndGadget = QueryGadget(gad, QUERY_HWND)

	If Not HwndGadget
		Return Null
	EndIf
	
	
	hdcGadget = GetDC(HwndGadget)
	
	If Not HdcGadget
		Return Null
	EndIf
	
	
	hdcMem = CreateCompatibleDC(hdcGadget)
	
	If Not HdcMem
		Return Null
	EndIf
	
	
	width = GadgetWidth(gad)
	height = GadgetHeight(gad)

	If width = 0 Or height = 0
		Return Null
	EndIf
	
	
	bmpMem  = CreateCompatibleBitmap(hdcGadget, width, height)

	If Not BmpMem
		Return Null
	EndIf
	
	
	If Not SelectObject(HdcMem, bmpMem)
		Return Null
	EndIf
	
	Info                = New BITMAPINFO
	Info.bisize         = SizeOf(INFO)
	info.BiWidth        = width
	Info.biHeight       = height
	Info.biPlanes       = 1
	info.biBitCount     = 32
	Info.biCompression  = 0
	
	
	If Not BitBlt(hdcMem,0,0,Info.biWidth,Info.biHeight, hdcGadget,0,0,ROP_SRCCOPY)	
		Return Null
	EndIf
	
	FinalPixmap = CreatePixmap(info.biWidth, info.biHeight, PF_BGRA8888)
	
	If Not GetDIBits(hdcMem, bmpMem, 0, Info.biHeight, FinalPixmap.PixelPtr(0,0), info, 0)
		Return Null
	EndIf
	
	FinalPixmap = YFlipPixmap(FinalPixmap)
	
	DeleteDC(HdcMem)
	DeleteObject(bmpMem)
	ReleaseDC(hwndGadget, hdcGadget)
	
	Return FinalPixmap
End Function
?

It allows me to get around the win32 problem of not being able to have a button on the window that I don't want to click on.

Excellent :-D