Recent

Author Topic: [Solved] GetDC(0) only yields primary screen in Windows 10 (Linux is all OK)  (Read 2311 times)

fripster

  • Newbie
  • Posts: 3
Dear All,

I am working on a simple screenshotting tool that continuously screenshots a screen and then publishes the picture to a webserver. The problem i find is that using the example code from the Lazarus site (which uses getDC(0) to get the device context) does not work under Windows 10. It gets me a screenshot allright, but only shows the primary screen. This should not happen as GetDC(0) normally should yield the complete virtual desktop, including all screens. The same code works perfectly under Linux (Debian with XFCE) and shows all screens.
I have searched the net a lot (even tried TBGRABitmap, same result) and have not found this error anywhere.
Can any of you please point me in the right direction?

Thanks!

Fripster
« Last Edit: January 08, 2019, 08:06:29 pm by fripster »

Thaddy

  • Hero Member
  • *****
  • Posts: 9158
Re: GetDC(0) only yields primary screen in Windows 10 (Linux is all OK)
« Reply #1 on: January 02, 2019, 07:25:58 pm »
The problem i find is that using the example code from the Lazarus site (which uses getDC(0) to get the device context) does not work under Windows 10. It gets me a screenshot allright, but only shows the primary screen. This should not happen as GetDC(0) normally should yield the complete virtual desktop, including all screens.
I do not know what you have been smoking Tripster, but  GetDc(0) is a Windows API call in the first place and it is proxied for other platforms in Lazarus for convenience.
It gives you a device handle to the primary screen. If the Linux behavior gives you a full virtual screen then the Linux implementation is not correct.
Your assumption is plain wrong.
« Last Edit: January 02, 2019, 07:29:22 pm by Thaddy »
also related to equus asinus.

ASerge

  • Hero Member
  • *****
  • Posts: 1411
Re: GetDC(0) only yields primary screen in Windows 10 (Linux is all OK)
« Reply #2 on: January 02, 2019, 08:15:11 pm »
The problem i find is that using the example code from the Lazarus site (which uses getDC(0) to get the device context) does not work under Windows 10.
I only have one monitor, so I can't check. But judging by the articles on the Internet, GetDC(0) gives the entire virtual screen. Perhaps in your utility you forget that the additional monitor may have negative coordinates relative to the primary.

fripster

  • Newbie
  • Posts: 3
Re: GetDC(0) only yields primary screen in Windows 10 (Linux is all OK)
« Reply #3 on: January 02, 2019, 11:52:45 pm »
@Aserge: you are right. GetDC(0) gets the entire virtual screen. I know about the negative numbers, but if i just perform a Tbitmap.SaveToFile function as a test then all screens should be visible in the resulting .bmp file. This only works under Linux (even if the call would be wrong, which I doubt: please see here: http://wiki.freepascal.org/Developing_with_Graphics#Taking_a_screenshot_of_the_screen) but not under Windows ... I think it is strange.

@Thaddy: I do not smoke, and I am sober thank you. For your information and entertainment, please see here: https://stackoverflow.com/questions/14715527/getdcnull-gets-primary-monitor-or-virtual-screen
« Last Edit: January 02, 2019, 11:56:27 pm by fripster »

ASerge

  • Hero Member
  • *****
  • Posts: 1411
Re: GetDC(0) only yields primary screen in Windows 10 (Linux is all OK)
« Reply #4 on: January 04, 2019, 12:17:01 pm »
I know about the negative numbers, but if i just perform a Tbitmap.SaveToFile function as a test then all screens should be visible in the resulting .bmp file. ...please see here: http://wiki.freepascal.org/Developing_with_Graphics#Taking_a_screenshot_of_the_screen) but not under Windows ... I think it is strange.
An old example, before the mass use of multiple monitors. As i see in intfgraphics.pas:
Code: Pascal  [Select]
  1. procedure TLazIntfImage.LoadFromDevice(DC: HDC);
  2. var
  3.   R: TRect;
  4.   RawImage: TRawImage;
  5.   DeviceSize: TPoint;
  6. begin
  7.   GetDeviceSize(DC, DeviceSize);
  8.   R := Rect(0,0,DeviceSize.X,DeviceSize.Y);
  9. ...
As you can see, negative coordinates are not taken into account.

fripster

  • Newbie
  • Posts: 3
Okay... After some asking around and Googling a lot I finally found how it needs to be done. I will put it here so that others can benefit from it.
Code: Pascal  [Select]
  1. Procedure TakeScreenShot(VAR mypic:Graphics.TBitmap);
  2. {$IFDEF WINDOWS}
  3.  var
  4.   ScreenDC: HDC;
  5. begin
  6.   mypic.Width:=Screen.DesktopWidth;
  7.   mypic.Height:=Screen.DesktopHeight;
  8.   mypic.Canvas.Brush.Color := clWhite;
  9.   mypic.Canvas.FillRect(0, 0, mypic.Width, mypic.Height);
  10.   ScreenDC:=GetDC(GetDesktopWindow);
  11.   BitBlt(mypic.Canvas.Handle, 0, 0, mypic.Width, mypic.Height, ScreenDC, Screen.DesktopLeft, Screen.DesktopTop, SRCCOPY);
  12.   ReleaseDC(0, ScreenDC);
  13. end;
  14. {$ENDIF}
  15.  
  16. {$IFDEF LINUX}
  17. var
  18.   ScreenDC: HDC;
  19. begin
  20.   ScreenDC := GetDC(0);
  21.   Mypic.LoadFromDevice(ScreenDC);
  22.   ReleaseDC(0,ScreenDC);
  23. end;
  24. {$ENDIF}      
   

This takes a screenshot of all available screens, whatever their positions w.r.t. each other.

Fripster
« Last Edit: January 08, 2019, 11:09:16 pm by fripster »