• Welcome to Dark Bit Factory & Gravity.
 

How to grab the desktop as a texture

Started by Jim, October 29, 2007

Previous topic - Next topic

0 Members and 0 Guests are viewing this topic.

Jim

Tested under Vista and XP.


#include <windows.h>

#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600

unsigned int texture[1024*1024];
GLuint hand;

HDC hdc = GetDC(NULL);
HDC mydc = CreateCompatibleDC(hdc);
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
HBITMAP mybmp = CreateCompatibleBitmap(hdc,w,h);

SelectObject(mydc, mybmp);

StretchBlt(mydc, 0,0,1024,1024, hdc,0,0,w,h, SRCCOPY);

ReleaseDC(NULL, hdc);

static struct
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColours[3];
} screen_bmi=
{
{
sizeof(BITMAPINFOHEADER),
1024,
1024,
1,
32,
BI_RGB,
0,
75,
75,
0,
0,
},
0x00,0x00,0xff,0x00,
0x00,0xff,0x00,0x00,
0xff,0x00,0x00,0x00,
};

int err = GetDIBits(mydc, mybmp, 0, 1024, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

glGenTextures(1, &hand);
glBindTexture(GL_TEXTURE_2D, hand);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

//might want to do this as Windows doesn't set the alpha channel
for (int z= 0; z < 1024*1024;z++) texture[z] |= 0xff000000;
glTexImage2D(GL_TEXTURE_2D, 0, 4, 1024,1024, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, texture);

//try it out
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, hand);

glColor4f(1,1,1,1);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,1.0f);
glVertex2i(0,0);
glTexCoord2f(0.0f,0.0f);
glVertex2i(0,SCREEN_HEIGHT);
glTexCoord2f(1.0f,0.0f);
glVertex2i(SCREEN_WIDTH,SCREEN_HEIGHT);
glTexCoord2f(1.0f,1.0f);
glVertex2i(SCREEN_WIDTH,0);
glEnd();


Jim
Challenge Trophies Won:

taj

karma++ Jim. I'll add this to my halloween entry once the voting is done so everyone can run it.
Chris
Challenge Trophies Won:

benny!

Yeah. Nice piece of code! K++, Jim !!!
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

Paul

Tried to make a blitzbasic version, but ended up with this...
only works in non debugmode
as you see in the screenshot, it doesn't work too well :(

Global width =api_GetSystemMetrics(0)
Global height=api_GetSystemMetrics(1)

Graphics width,height,32,1


Local hdc=api_getdc(0)
Local blitzhdc=api_getdc(SystemProperty("apphwnd"))

Local mydc = api_CreateCompatibleDC(hdc)


hidewindow
api_BitBlt(blitzhdc, 0, 0, width,height, hdc, 0,0, $CC0020)
showwindow


Local image=CreateImage(width,height)
CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image))


SetBuffer BackBuffer()
While Not KeyHit(1)
DrawImage(image,0,0)

Text 0,0,"Done"
Flip
Cls
Wend

Function showwindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,5)
End Function
Function hidewindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,0)
End Function


I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Rbz

@Paul: try to initialize your graphics screen "Graphics width,height,32,1" after "CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image))" command.
Challenge Trophies Won:

Paul

It seems as if the code hasto be run in fullscreen for it to work at all, so thats not an option :(
any other ideas?
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Jim

I'm not much of a bb programmer, but it looks like you missed out a bit - where do you create and copy to the compatible bitmap?

Jim
Challenge Trophies Won:

Paul

sry, here somes the code again but with coments:


Global width =api_GetSystemMetrics(0)
Global height=api_GetSystemMetrics(1)

Graphics width,height,32,1


Local blitzhdc=api_GetDC(SystemProperty("apphwnd")) ;get the blitzwindows device context

Local deskhdc=api_GetDC(api_GetDesktopWindow()) ;same for desktop

hidewindow
api_BitBlt(blitzhdc, 0, 0, width,height, deskhdc, 0,0, $CC0020);copy the desktop device context to the blitz frontbuffer(i think and it seems to work)
showwindow


Local image=CreateImage(width,height) ;create an empty iamge

CopyRect(0,0,width,height,0,0,FrontBuffer(),ImageBuffer(image)) ;copy the frontbuffer to our image. only problem is that it far too often doesn't get the whole screen


SetBuffer BackBuffer()
While Not KeyHit(1)
DrawImage(image,0,0)

Text 0,0,"Done"
Flip
Cls
Wend

Function showwindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,5)
End Function
Function hidewindow(hwnd=0)
If hwnd=0 Then hwnd=SystemProperty("apphwnd")
api_ShowWindow(hwnd,0)
End Function


I don't realy understand the compatible bitmap but i think that's the way to go.
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

zawran

Not really wanting to go off topic, since the topic is in the C/C++ section, but I did a search on the blitzresearch forum, and found this one in the code archieves. It should work for both images and textures. But I have not tested it though since I only have blitzmax installed at the moment.

Example usage:

tex = GetDesktop() ; creates a texture
image = GetDesktop(1) ; creates an image
GetDesktop(0,tex) ; updates a texture
GetDesktop(1,image) ; updates an image


Const SRCCOPY = $CC0020
Const CF_BITMAP = 2
Const SW_HIDE = 0
Const SW_SHOW = 5

Function GetDesktop(flag=0,update=0)

; ADAmor ZILTCH 2003
;
; This command must come after your GRAPHICS(3D) x,y command.
;
;  flag 0 = create texture
;       1 = create image
;
; if update is not 0 then it is the tex/image to update.

   DeskHwnd = GetDesktopWindow()

   ; Get screen coordinates
   fwidth  = GetSystemMetrics%(0)  ;RectWin\rightR  - RectWin\leftR
   fheight = GetSystemMetrics%(1)  ;RectWin\bottomR - RectWin\topR

   BlitzHwnd = GetActiveWindow()
   ShowWindow(BlitzHwnd,SW_HIDE)

   ; Get the device context of Desktop and allocate memory
   hdc = GetDC(DeskHwnd)
   Blitzhdc = GetDC(BlitzHwnd)

   ; Copy data
   BitBlt(Blitzhdc, 0, 0, fwidth, fheight, hdc, 0,0, SRCCOPY)

   ; Clean up handles
   ReleaseDC(DeskHwnd, hdc)
   ReleaseDC(BlitzHwnd, Blitzhdc)
   ShowWindow(BlitzHwnd,SW_SHOW)

   ; Create/update texture or image
   Select flag
     Case 0
       If update = 0 Then
         tex=CreateTexture(fwidth,fheight)
       Else
         tex=update
       End If
       CopyRect 0,0,fwidth,fheight,0,0,FrontBuffer(),TextureBuffer(tex)
       Return tex
     Case 1
       If update = 0 Then
         image=CreateImage(fwidth,fheight)
       Else
         image=update
       End If
       CopyRect 0,0,fwidth,fheight,0,0,FrontBuffer(),ImageBuffer(image)
       Return image
   End Select

End Function
;---------------- end code


It needs some user.decls definitions:


Lines needed in Userlib: User32.decls

FindWindow%( class$,Text$ ):"FindWindowA"
ShowWindow(hwnd%,nCmdShow%)
GetActiveWindow%()
GetDC%(hWnd% )
ReleaseDC%(hWnd%,hDC%)
GetDesktopWindow%()
GetSystemMetrics%(nIndext%)

Lines needed in Userlib: Gdi32.decls
BitBlt%(hDestDC%,X%,Y%,nWidth%,nHeight%,hSrcDC,XSrc,YSrc,dwRop)


I hope its of use, and sorry for the somewhat off topic.

Jim

I *think* the problem is when you do the BitBlt there is no bitmap selected in to the blitzhdc so it doesn't work.
You need to do

bmp=CreateCompatibleBitmap(deskhdc, width, height)
SelectObject(blitzhdc, bmp);

before the bitblt.
But then there's no real reason why CopyRect will work, since it's not obvious what the source for the copy is. :-\

Jim
Challenge Trophies Won:

Paul

@ zawran, that code has the exact same problem as mine. It looks lite the desktop was updating hen i ran the code so i got some black areas.
@jim, the problem is probably there, but ihave tried waht you say(i think) and it doesn't work, same prolem. could you compile an exe of youre c++ program so i can check if that works on my pc? thx, and sry for the offtopic.
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

Paul

OK... found a solution. use the api_keybd_event(44,0,0,0) function to "press" the print screen button. then paste the image to an imagebuffer using the PasteImageFromClipboard() function from here:   http://www.blitzbasic.com/codearcs/codearcs.php?code=1767
I will bite you - http://s5.bitefight.se/c.php?uid=31059
Challenge Trophies Won:

madsravn

Cool effect :) I've gotta try it out . Thanks man ;)

Jim

No probs - great to see you here!

Jim
Challenge Trophies Won:

Jim

Just spotted a slight error.
correction:

int err = GetDIBits(mydc, mybmp, 0, h, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

should be

int err = GetDIBits(mydc, mybmp, 0, 1024, texture, (BITMAPINFO *)&screen_bmi, DIB_RGB_COLORS);

Corrected in original post.

Jim
Challenge Trophies Won: