CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
+ Reply to Thread
Results 1 to 13 of 13
  1. #1
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610

    Efficient way to grab the screen

    Hi all ! I ve searched the forums for screen capture posts and found one where galathea says the CreateWindowDC API function should do the job given the desktop window handle f.e. This makes perfect sense yes (thanks galathea).

    But will it properly capture the AVI overlays and some other funky effects ? I need an exact whole image of the screen (portion of it) because i am implementing a remote control service.... For this reason i am willing to go to any depth of the WinAPI just to get the image a) fast and b) without holes. DirectX, whatever - i will eat it !

    Am I dreaming ? :-)

  2. #2
    Join Date
    Jul 2003
    Location
    Belgium
    Posts
    10

    getPixel

    You can get the color of a pixel by

    Code:
         static HDC hdcScreen ;
         POINT pt ;
         static COLORREF cr;
         hdcScreen = CreateDC (string_specifying_driver_name, NULL, NULL, NULL) ;
         cr = GetPixel (hdcScreen, pt.x, pt.y) ;
    So... you do do that for every pixel...
    Last edited by Fresny; July 31st, 2003 at 04:16 AM.

  3. #3
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    Yes, thanks. But that would be like the slowest of all the slow ways to do it

  4. #4
    Join Date
    Jun 2003
    Location
    Armenia, Yerevan
    Posts
    637
    Did you try BitBlt() function? I think it will be much faster.

  5. #5
    Join Date
    Dec 2001
    Location
    Dallas, Tx, USA (originally fromIndia)
    Posts
    154

    Efficient way to grab the screen

    BitBlt is the fastest way you could grab a screen, unless i guess you try writing code at the framebuffer level.
    Regards,
    Preetham.
    "All you touch and all you see is all you'll ever be"

  6. #6
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610

    Good input

    Yes looks like BitBlt is fastest. However I will need to access the ARGB data directly, because the image will be coded with a custom PNG encoder, and with BitBlt this will involve one more copying - using the GetDIBits to access the bitmap. Not a crisis but:

    1. Blit bitmaps from display DC to memory DC - BitBlt
    2. Copy memory DC selected bitmap into user supplied buffer - GetDIBits

    ---looks like a lot of copying. I need at least 5 frames per second

    I was thinking to do it the DirectDrawSurface7 way - you can lock the screen pixel data directly without any copying. Do you guys think it is a way to do it ?

    THanks for a lot of good input anyway !!!

  7. #7
    Join Date
    Sep 2002
    Posts
    1,747
    I think DirectDraw is probably the nicest solution for this. You DirectDrawCreateEx your IDirectDraw7 interface, set it up to support your primary surface (SetCooperativeLevel, etc.), and then you can use one of the many ways to actually create your IDirectDrawSurface7 object. The trick here is that you want to have your primary surface represent the one that GDI uses, and there are two commands that allow you access to the GDI primary surface (GetGDISurface and FlipToGDISurface), or if there is a specific DC you know you want access to, use that (unfortunately, I don't have experience with this yet, so I can't give much details). You should then create a back buffer surface as well. Then, you can BltFast from the primary surface to the buffer any time you want to capture the screen and Lock the buffer surface to give you memory access to the actual bitmap bits (which will be in a device dependent format, which you need to parse using the information from the DDSURFACEDESC2 structure returned to you when you lock the surface).

    There was an interesting post in this forum a couple of weeks back by LearnMFC, with several people (including myself) trying to help with a problem very similar. Its title mentioned getting access to a bitmap's bits a particular Hz, so if you find that, maybe it can give some more ideas!
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  8. #8
    Join Date
    Sep 2002
    Location
    Maryland - Fear The Turtle!
    Posts
    7,537
    Originally posted by galathaea
    I think DirectDraw is probably the nicest solution for this. You DirectDrawCreateEx your IDirectDraw7 interface, set it up to support your primary surface (SetCooperativeLevel, etc.), and then you can use one of the many ways to actually create your IDirectDrawSurface7 object. The trick here is that you want to have your primary surface represent the one that GDI uses, and there are two commands that allow you access to the GDI primary surface (GetGDISurface and FlipToGDISurface), or if there is a specific DC you know you want access to, use that (unfortunately, I don't have experience with this yet, so I can't give much details). You should then create a back buffer surface as well. Then, you can BltFast from the primary surface to the buffer any time you want to capture the screen and Lock the buffer surface to give you memory access to the actual bitmap bits (which will be in a device dependent format, which you need to parse using the information from the DDSURFACEDESC2 structure returned to you when you lock the surface).

    There was an interesting post in this forum a couple of weeks back by LearnMFC, with several people (including myself) trying to help with a problem very similar. Its title mentioned getting access to a bitmap's bits a particular Hz, so if you find that, maybe it can give some more ideas!
    I usually use both hand to grab the screen, this due to drunkeness (sp is that a freaking word?) word up bro....

    and andreas was asking what ThreadJacking was..phhhppt...

  9. #9
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    Galathea:


    DirectDraw7 works very fast:

    Code:
    	LPDIRECTDRAW7		lpDD;
    	LPDIRECTDRAWSURFACE7	lpDDSPrimary;
    
    	DirectDrawCreateEx(NULL, (LPVOID*)&lpDD, IID_IDirectDraw7, NULL);
    
    
    	lpDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);
    
    
    	DDSURFACEDESC2 ddsd;
    	memset(&ddsd, 0, sizeof(ddsd));
    
    	ddsd.dwSize	= sizeof(ddsd);
    	ddsd.dwFlags	= DDSD_CAPS;
    
    	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
    	
    	lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL);
    
    
    	lpDDSPrimary->Lock(NULL, &ddsd, DDLOCK_READONLY, NULL);
    	
    	//'ddsd.lpSurface' is a pointer to display memory
    	
    	lpDDSPrimary->Unlock(NULL);
    I forgot to mention that I needed to access ARGB values directly, so this wont get any faster than the code shown.
    There is no copying involved and from there I can go on and apply my imaging to the bitmap i obtained.

    There is one BIG problem though, and as far as I am concerned, it persists on most screen grab solutions out there:

    Namely, the code above and GetDesktopWindow way only work in users desktop. I need my application to service the screen data even when the workstation is locked and no user is present (no user desktop or window station is present).

    If I lock workstation before the program takes effect, my surface gets lost, and any attempts to restore it silently fail although they shamelessly return DD_OK. In other words, I cannot access the physical screen data without a user desktop...

    Any suggestions ?

    P.S. Mick are/were you drunk right now ?

  10. #10
    Join Date
    Sep 2002
    Posts
    1,747
    My first reaction is that a DDI driver hook would be needed (something along the lines maybe of what Feng Yuan shows in his book on Graphics programming?). But that's my response to anything that needs to bypass user security and get to the system. There might be a way to do something with passing an impersonation access token to someone who is handling the screen, but I don't know who is handling the screen then (the SYSTEM account talks to ...?). If you can't gain the appropriate priveleges in user mode, the only way may be with a a driver...
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

  11. #11
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    Originally posted by galathaea
    My first reaction is that a DDI driver hook would be needed (something along the lines maybe of what Feng Yuan shows in his book on Graphics programming?). But that's my response to anything that needs to bypass user security and get to the system. There might be a way to do something with passing an impersonation access token to someone who is handling the screen, but I don't know who is handling the screen then (the SYSTEM account talks to ...?). If you can't gain the appropriate priveleges in user mode, the only way may be with a a driver...
    Thanks for helping me out, I appreciate the hellp very much !!!
    Given that topics this deep are seldom, I REALLY appreciate your response

    The application is a system service not a user process, hence even impersonating a user wont achieve desired effect (servicing a remote user with a screen visuals). In other words, say, I impersonated someone and now posess the credentials required to create and manage objects as if they were managed by him - the user; but my task is rather to simulate physical screen. I leave Windows security intact because if the workstation is locked they will have to unlock it by interacting with screen remotely first.

    I will look onto device drivers if DDI is what I think it is, looks like it will save me, becase user APIs dont

    THanks again, tell me if you have any more input pleaaaaaaaaaaaaaase

    P.S. What is DDI ? Microsoft doesnt tell Do you mean DDK ? Device Driver Development Kit ? I cant find any APIs that interact with drivers....
    Last edited by Amn; August 1st, 2003 at 03:32 PM.

  12. #12
    Join Date
    May 2001
    Location
    Oslo, Norway
    Posts
    610
    While I am burying myself in Windows DDK, is there anybody out there who knows the secret of capturing the screen in system mode with logon screens and all that ?

    Anyone ?

    * Heads on to MSDN for further DDK research *

    * MS is not exactly selfexplanatory *

  13. #13
    Join Date
    Sep 2002
    Posts
    1,747
    The DDI is window's graphics Device Driver Interface. You can find some information at this MSDN introduction, but I admit it isn't really too helpful. Basically, if you need to capture graphics going on in the system that you can't reach in user mode, the only possibility that I can think of is to write a driver hook into the DDI and grab the data from there. The only really good example of this that I know of is from the book by Feng Yuan, which doesn't really go into what would be needed for you, it only shows you how to hook into the interface (it has another one of those low level interception programs that is mainly used to show the reader what is going on behind the scenes). I wish I had actual code to help out, but I haven't really done much along these lines yet. Some of what I do in my job kind of intersects here, but I couldn't give any real details as they are company property. However, I hope this helps you get started!
    */*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/

    "It's hard to believe in something you don't understand." -- the sidhi X-files episode

    galathaea: prankster, fablist, magician, liar

+ Reply to Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts



HTML5 Development Center

Click Here to Expand Forum to Full Width