Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Implementing multi-monitor screenshots

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I have been doing a lot of work lately with taking screenshots (for a remote desktop system) and just stumbled across a problem while I'm trying to implement support for multiple monitors. While taking the screenshot is OK, the method I'm using to draw the cursor only presumes 1 screen. If I position the pointer on an additional screen (when taking a screenshot of that additional screen), the cursor does NOT show. I move the pointer to the main screen and it shows (of course in the wrong spot because it's the wrong screen).

My code is entirely below. When specifying MonitorID, 0 = entire screen (all monitors), 1 = main screen, 2 = additional screen..... etc.....

I just need to determine the correct X/Y position of the pointer according to which screen is currently active.

Code:
procedure DrawScreenCursor(var Bmp: TBitmap; const MonitorID: Integer);
var
  R: TRect;   
  CursorInfo: TCursorInfo;
  Icon: TIcon;
  IconInfo: TIconInfo;
begin
  R:= Bmp.Canvas.ClipRect;
  Icon:= TIcon.Create;
  try
    //MonitorID: 0=ALL screens, 1=MAIN screen, 2=ADDITIONAL screen, etc....
    CursorInfo.cbSize:= SizeOf(CursorInfo);
    if GetCursorInfo(CursorInfo) then
    if CursorInfo.Flags = CURSOR_SHOWING then
    begin
      Icon.Handle:= CopyIcon(CursorInfo.hCursor);
      if GetIconInfo(Icon.Handle, IconInfo) then
      begin
        //Draw cursor image on screenshot image
        Bmp.Canvas.Draw(
          CursorInfo.ptScreenPos.x - Integer(IconInfo.xHotspot) - R.Left,
          CursorInfo.ptScreenPos.y - Integer(IconInfo.yHotspot) - R.Top,
          Icon
        );
      end;
    end;
  finally
    Icon.Free;
  end;
end;
       
function TakeScreenshot(var bmp: TBitmap; MonitorNumber: Integer): Boolean;
const
  CAPTUREBLT = $40000000;
var
  DesktopCanvas: TCanvas;
  DC: HDC;
  Left, Top: Integer;
begin
  Result := False;
  if (MonitorNumber > Screen.MonitorCount) then
  Exit;
  DC:= GetDC(0);
  try
    if (DC = 0) then
    Exit;
    if (MonitorNumber = 0) then begin
      Bmp.Width := Screen.DesktopWidth;
      Bmp.Height := Screen.DesktopHeight;
      Left := Screen.DesktopLeft;
      Top := Screen.DesktopTop;
    end else begin
      Bmp.Width := Screen.Monitors[MonitorNumber-1].Width;
      Bmp.Height := Screen.Monitors[MonitorNumber-1].Height;
      Left := Screen.Monitors[MonitorNumber-1].Left;
      Top := Screen.Monitors[MonitorNumber-1].Top;
    end;
    DesktopCanvas := TCanvas.Create;
    try
      DesktopCanvas.Handle := DC;
      Result := BitBlt(
        Bmp.Canvas.Handle,
        0,
        0,
        Bmp.Width,
        Bmp.Height,
        DesktopCanvas.Handle,
        Left,
        Top,
        SRCCOPY or CAPTUREBLT
      );
      Result:= True;
    finally
      DesktopCanvas.Free;
    end;
  finally
    if (DC <> 0) then
    ReleaseDC(0, DC);
  end;
end;

function ScreenShot(Bmp: TBitmap; const DrawCursor: Boolean;
  const Quality: TPixelFormat; const Monitor: Integer): Bool;
begin
  Result:= TakeScreenshot(Bmp, Monitor);
  if Result then
    if DrawCursor then
      DrawScreenCursor(Bmp, Monitor);
end;

JD Solutions
 
Multiple Monitor API Reference

It looks like you need to relate the window in question to the monitor and then translate it to something the functions you are using can understand.

This example Microsoft gives should point you in a good direction.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top