Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor verschoben (https://www.delphipraxis.net/204850-der-screenshot-zeigt-den-mauszeiger-nicht-wenn-er-auf-den-zweiten-monitor-verschoben.html)

flashcoder 6. Jul 2020 20:41

Delphi-Version: 5

Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor verschoben
 
Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor verschoben wird

Ich habe in letzter Zeit viel mit Screenshots (für ein Remotedesktopsystem) gearbeitet und bin gerade auf ein Problem gestoßen, während ich versuche, die Unterstützung für mehrere Monitore zu implementieren. Während das Aufnehmen des Screenshots in Ordnung ist, setzt die Methode, mit der ich den Cursor zeichne, nur 1 Bildschirm voraus. Wenn ich den Zeiger auf einem zusätzlichen Bildschirm positioniere (wenn ich einen Screenshot dieses zusätzlichen Bildschirms mache), wird der Cursor NICHT angezeigt. Ich bewege den Zeiger auf den Hauptbildschirm und es wird angezeigt (natürlich an der falschen Stelle, weil es der falsche Bildschirm ist).

Mein Code ist ganz unten.

Delphi-Quellcode:
program Test;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Windows,
  vcl.Graphics,
  SysUtils;

function GetCursorInfo2: TCursorInfo;
var
  hWindow: HWND;
  pt: TPoint;
  dwThreadID, dwCurrentThreadID: DWORD;
begin
  Result.hCursor := 0;
  ZeroMemory(@Result, SizeOf(Result));
  if GetCursorPos(pt) then
  begin
    Result.ptScreenPos := pt;
    hWindow := WindowFromPoint(pt);
    if IsWindow(hWindow) then
    begin
      dwThreadID := GetWindowThreadProcessId(hWindow, nil);
      dwCurrentThreadID := GetCurrentThreadId;
      if (dwCurrentThreadID <> dwThreadID) then
      begin
        if AttachThreadInput(dwCurrentThreadID, dwThreadID, True) then
        begin
          Result.hCursor := GetCursor;
          AttachThreadInput(dwCurrentThreadID, dwThreadID, False);
        end;
      end
      else
        Result.hCursor := GetCursor;
    end;
  end;
end;

procedure TakeScreenshot(var Bmp: TBitmap; WndHdc: HDC; Width, Height, Left, Top: Integer);
const
  CAPTUREBLT = $40000000;
var
  DesktopCanvas: TCanvas;
  MyCursor: TIcon;
  CursorInfo: TCursorInfo;
  IconInfo: TIconInfo;
  DC: HDC;
begin
  DC := GetDC(WndHdc);
  try
    if (DC = 0) then
      Exit;
    Bmp.Width := Width;
    Bmp.Height := Height;
    DesktopCanvas := TCanvas.Create;
    try
      DesktopCanvas.Handle := DC;
      BitBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, DesktopCanvas.Handle, Left, Top, SRCCOPY or CAPTUREBLT);
      MyCursor := TIcon.Create;
      try
        CursorInfo := GetCursorInfo2;
        if CursorInfo.hCursor <> 0 then
        begin
          MyCursor.Handle := CursorInfo.hCursor;
          GetIconInfo(CursorInfo.hCursor, IconInfo);
          Bmp.Canvas.Draw(CursorInfo.ptScreenPos.X - IconInfo.xHotspot, CursorInfo.ptScreenPos.Y - IconInfo.yHotspot, MyCursor);
        end;
      finally
        MyCursor.ReleaseHandle;
        MyCursor.Free;
      end;
    finally
      DesktopCanvas.Free;
    end;
  finally
    if (DC <> 0) then
      ReleaseDC(0, DC);
  end;
end;

function EnumDisplayMonitors(dc: HDC; rect: PRect; EnumProc: pointer; lData: Integer): Boolean; stdcall; external user32 name 'EnumDisplayMonitors';

type
  TMonInfo = record
    h: THandle;
    DC: HDC;
    R: TRect;
  end;

var
  MonList: array of TMonInfo;

function MonitorEnumProc(hMonitor: THandle; hdcMonitor: HDC; lprcMonitor: DWORD; dwData: Integer): Boolean; stdcall;
var
  I, Width, Height, Left, Top: Integer;
  Bmp: TBitmap;
begin
  I := High(MonList) + 1;
  SetLength(MonList, I + 1);
  MonList[I].h := hMonitor;
  MonList[I].DC := hdcMonitor;
  MonList[I].R := PRect(lprcMonitor)^;

  Left := PRect(lprcMonitor)^.Left;
  Top := PRect(lprcMonitor)^.Top;
  Width := PRect(lprcMonitor)^.Width;
  Height := PRect(lprcMonitor)^.Height;

  Bmp := TBitmap.Create;
  try
    TakeScreenshot(Bmp, hdcMonitor, Width, Height, Left, Top);
    Bmp.SaveToFile('C:\Screen' + IntToStr(I + 1) + '.bmp');
  finally
    Bmp.Free;
  end;

  Result := True;
end;

procedure Main;
var
  S: string;
  I: Integer;
begin
  Writeln('Number of monitors: ' + IntToStr(High(MonList) + 1) + #13#10);
  Writeln('-----------------');
  for I := 0 to High(MonList) do
    with MonList[I] do
    begin
      S := #13#10 + 'Handle: ' + IntToStr(h) + #13#10 + 'Dc: ' + IntToStr(DC) + #13#10 + 'Size: ' + IntToStr(R.Right) + 'x' + IntToStr(R.Bottom) + #13#10;
      Writeln(S);
      Writeln('-----------------');
    end;
end;

begin
  try
    EnumDisplayMonitors(0, nil, Addr(MonitorEnumProc), 0);
    Main;
    Writeln(#13#10 + 'Connected: ' + IntToStr(GetSystemMetrics(SM_CMONITORS)) + #13#10);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Sinspin 7. Jul 2020 13:59

AW: Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor versch
 
Hallo,

Du fotografierst den Cursor mit? Würde es nicht auch gehen die Fotos ohne den Cursor zu machen und ihn dann selber lokal zu zeichnen? Position und Status kann man ja abfragen.

himitsu 7. Jul 2020 14:04

AW: Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor versch
 
Nee, und das macht er ja schon (siehe TakeScreenshot),
also er macht ein Foto, schaut wo die Maus rumschwirrt und was für einen Zeiger die hat und malt sie auch auf das Bild drauf. :zwinker:


Man könnte nun mit dem Debugger schauen ob die Position simmt und ob auch ein Bild des Zeigers ausgelesen wurde.
Für Letzteres könnte man testweise auch mal mit einer festen Position den Zeiger auf's Bild malen
und für Ersteres entweder ein Ersatzbild oder z.B. zuerst einen Punkt/Kreis an die Stelle und dann darauf den Zeiger.

Sinspin 7. Jul 2020 16:18

AW: Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor versch
 
Zitat:

Zitat von himitsu (Beitrag 1469034)
Nee, und das macht er ja schon (siehe TakeScreenshot),
also er macht ein Foto, schaut wo die Maus rumschwirrt und was für einen Zeiger die hat und malt sie auch auf das Bild drauf. :zwinker:

Das passiert wenn man zu faul zum Lesen ist. :shock:

Das ist ja richtig Clever den aktuellen Cursor als Bild auszulesen. Ich würde ihn aber erst nach dem übertragen aufs Bild malen, sicher machst Du das hier nur zum Testen.

Ist auf dem zweiten Monitor eine andere DPI Einstellung oder Zoom/Lesehilfe aktiviert?
Wie groß ist die Abweichung von der erwarteten Position?

flashcoder 8. Jul 2020 06:00

AW: Der Screenshot zeigt den Mauszeiger nicht, wenn er auf den zweiten Monitor versch
 
Gelöst!:-D Danke an alle.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:25 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz