[Solved] GetDC(0) only yields primary screen in Windows 10 (Linux is all OK) lazarus / 39-Graphics ---------------------------------------------------------------------- fripster · 2019-01-02 17:46 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 ---------------------------------------------------------------------- Thaddy · 2019-01-02 18:25 Quote from: fripster on January 02, 2019, 06:46:59 pmThe 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. ---------------------------------------------------------------------- ASerge · 2019-01-02 19:15 Quote from: fripster on January 02, 2019, 06:46:59 pmThe 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 · 2019-01-02 22:52 @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://wik i.freepascal.org/Developing_with_Graphics#Taking_a_screenshot_of_the_s creen) 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 ---------------------------------------------------------------------- ASerge · 2019-01-04 11:17 Quote from: fripster on January 02, 2019, 11:52:45 pmI 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_G raphics#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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TLazIntfImage.LoadFromDevice(DC: HDC);var  R: TRect;  RawImage: TRawImage;  DeviceSize: TPoint;begin  GetDeviceSize(DC, DeviceSize);  R := Rect(0,0,DeviceSize.X,DeviceSize.Y);...As you can see, negative coordinates are not taken into account. ---------------------------------------------------------------------- fripster · 2019-01-08 19:05 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Procedure TakeScreenShot(VAR mypic:Graphics.TBitmap);{$IFDEF WINDOWS} var  ScreenDC: HDC;begin  mypic.Width:=Screen.DesktopWidth;  mypic.Height:=Screen.DesktopHeight;  mypic.Canvas.Brush.Color := clWhite;  mypic.Canvas.FillRect(0, 0, mypic.Width, mypic.Height);  ScreenDC:=GetDC(GetDesktopWindow);  BitBlt(mypic.Canvas.Handle, 0, 0, mypic.Width, mypic.Height, ScreenDC, Screen.DesktopLeft, Screen.DesktopTop, SRCCOPY);  ReleaseDC(0, ScreenDC);end;{$ENDIF} {$IFDEF LINUX}var  ScreenDC: HDC;begin  ScreenDC := GetDC(0);  Mypic.LoadFromDevice(ScreenDC);  ReleaseDC(0,ScreenDC);end;{$ENDIF}        This takes a screenshot of all available screens, whatever their positions w.r.t. each other. Fripster ---------------------------------------------------------------------- Manlio · 2022-01-22 20:05 Quote from: fripster on January 08, 2019, 08:05:43 pmI will put it here so that others can benefit from it. Fripster Thank you Fripster for the code, I was looking exactly for that! And here is a method I created, based on your code, with the additional option of taking the screenshot of only a specific monitor: Code: [Select]// Monitor=-1 takes whole composite area, otherwise only specific monitor procedure ScreenshotToFile(Filename: string; Monitor: integer); var   BMP: Graphics.TBitmap; // graphics.TBitmap, not Windows.TBitmap   ScreenDC: HDC;   M: TMonitor;   W, H, X0, Y0: integer; begin   // Initialize coordinates of full composite area   X0 := Screen.DesktopLeft;   Y0 := Screen.DesktopTop;   W  := Screen.DesktopWidth;   H  := Screen.DesktopHeight;   // Monitor=-1 takes entire screen, otherwise takes specific monitor   if (Monitor >= 0) and (Monitor < Screen.MonitorCount) then begin     M  := Screen.Monitors[Monitor];     X0 := M.Left;     Y0 := M.Top;     W  := M.Width;     H  := M.Height;   end;   // prepare the bitmap   BMP := Graphics.TBitmap.Create;   BMP.Width  := W;   BMP.Height := H;   BMP.Canvas.Brush.Color := clWhite;   BMP.Canvas.FillRect(0, 0, W, H);   ScreenDC := GetDC(GetDesktopWindow);   // copy the required area:   BitBlt(BMP.Canvas.Handle, 0, 0, W, H, ScreenDC, X0, Y0, SRCCOPY);   ReleaseDC(0, ScreenDC);   // save to file (possibly to TStream, etc.)   BMP.SaveToFile(Filename);   BMP.Free; end; ---------------------------------------------------------------------- flowCRANE · 2022-01-28 00:47 Attached is a test desktop capture program. Gets an area based on the cursor position — the cursor points to the upper left corner, and the area is the size of the program window. No matter how many screens there are and where the cursor is — it always copies a visible part of the desktop. If the screens have different resolutions, the empty space is filled by the system with black color. However, the content outside the screens is not cleared by the system, so in the program I first fill the entire bitmap in white, and then the visible desktop fragment is copied. In the attached picture you can see all three places — the main monitor (LCD0), an additional monitor (LCD1) and the empty space filled in black, resulting from the difference in resolution of both screens. In the second attachment is a Lazarus project of this program. Tested on Windows10. Have fun. ---------------------------------------------------------------------- Remy Lebeau · 2022-01-28 01:25 Using GetDC() is such an old-school way to do screenshots on Windows  There are more modern APIs available, ie: https://www.codeproject.com/Articles/5051/Various-methods-for- capturing-the-screen https://www.codeproject.com/Articles/607288/Screenshot-using-the- Magnification-library https://blogs.windows.com/windowsdeveloper/2019/09/16/new-ways-to-do- screen-capture/