Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Screenshot via Handle (https://www.delphipraxis.net/115626-screenshot-via-handle.html)

meg91 15. Jun 2008 12:11


Screenshot via Handle
 
Hallo,
ich habe eine Funktion geschrieben, die es ermöglicht einen Screenshot von einem Programm zu machen, welches ich über einen Handle ausfindig gemacht habe. Es soll kein richtiger Screenshot enstehen, sondern nur eine Durchschnittsfarbe berechnet werden.
Soweit funktioniert das auch, nur wenn man den Taskmanager öffnet, kann man zusehen, wie der Speicherverbrauch meines Programms kontinuierlich ansteigt, bis sich mein ganzer PC aufhängt. Die IDE sag dazu auch nichts mehr, weil die dabei auch den Dienst versagt :(
Es muss an diesem Stück Code liegen, weil sobald ich diese Prozedure nicht benutze alles ganz normal funktioniert
Delphi-Quellcode:
var
  h_window: HWND; //das ist das Fenster welches gescannt werden soll

procedure HandleToPix2();
var
  //h_desktop: THandle;
  i_tmp_x, i_tmp_y: Integer;
  i_gesRed, i_gesGreen, i_gesBlue: Integer;
  bRed, bGreen, bBlue: Byte;
  //b_tmp: TBitmap;
  //c_tmp: TCanvas;
  c_color: TColor;
  r_window: TRect;
  i_width, i_height: Integer;
  PixelColor: Integer;
  ha_window: THandle;
const
  c_aspectorato = (4/3);
  //c_aspectorato = (16/9);
  c_vertical = 7;
begin
  try
    //ha_window := GetWindowDC(h_window);
    ha_window := GetDC(h_window);

    GetWindowRect(ha_window , r_window);

    i_width := r_window.Right - r_window.Left;
    i_height := r_window.Bottom - r_window.Top;

    i_gesBlue := 0;
    i_gesGreen := 0;
    i_gesRed := 0;

    for i_tmp_x := 1 to round(c_aspectorato*c_vertical) do
    begin
      for i_tmp_y := 1 to c_vertical do
      begin
        PixelColor := GetPixel(ha_window, r_window.Left + round((i_width / (c_aspectorato*c_vertical))*i_tmp_x), r_window.Top + round((i_height/c_vertical)*i_tmp_y));
        bBlue := GetBValue(PixelColor);
        bGreen := GetGValue(PixelColor);
        bRed := GetRValue(PixelColor);

//        c_color := c_tmp.Pixels[round((i_width / (c_aspectorato*c_vertical))*i_tmp_x), round((i_height/c_vertical)*i_tmp_y)];
//        bBlue := GetBValue(c_color);
//        bGreen := GetGValue(c_color);
//        bRed := GetRValue(c_color);

        rgb_threshold(bRed, bGreen, bBlue);

        i_gesBlue := i_gesBlue + bBlue;
        i_gesGreen := i_gesGreen + bGreen;
        i_gesRed := i_gesRed + bRed;
      end;
    end;

    //Werte ausgeben
    changeRGB(Round(i_gesRed / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesGreen / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesBlue / (round(c_aspectorato*c_vertical)*c_vertical)));
  finally
    ReleaseDC(h_window, ha_window);
  end;
end;
wahrscheinlich vergesse ich irgendwo etwas wieder freizugeben oder mein Zugriff auf die Handles ist falsch.
Sieht jemand den Fehler, ich komm einfach nicht drauf

gruß
markus

rollstuhlfahrer 15. Jun 2008 17:36

Re: Screenshot via Handle
 
HI Markus,

1. du willst die Durchschnittsfarbe eines Fensters herausfinden. Warum benützt du dazu das Bildschirm-Seitenverhältniss? Ich schlage schrittweises Abtasten ohne Seitenverhältniss vor.
2. Redmond kennt weder rgb_threshold noch changeRGB.
3. wo ich doch grade von Seitenverhältniss spreche:
Delphi-Quellcode:
    changeRGB(Round(i_gesRed / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesGreen / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesBlue / (round(c_aspectorato*c_vertical)*c_vertical)));
Mit deiner rechnerei kann da (glaub ich mal so ganz einfach) nichts rauskommen. Ich tippe, es müsste so heißen:
Delphi-Quellcode:
    changeRGB(Round(i_gesRed / (i_width*i_height)),
              Round(i_gesGreen / (i_width*i_height)),
              Round(i_gesBlue / (i_width*i_height)));
Die Schleifen sind davon natürlich auch betroffen:
Delphi-Quellcode:
    for i_tmp_x := 1 to i_width do
    begin
      for i_tmp_y := 1 to i_heigth do
      begin
Sonstige Speicherfehler kann ich keine entdecken. Falls du wirklich nicht weiterkommst, mach mal einen Schrittweisen durchgang und such das Speicherloch oder häng mal FastMM rein.
Was natürlich auch sein kann, ist, dass du zu viel Speicher durch zu große Zahlen belegst. Nimm für i_gesRed, i_gesGreen, i_gesBlue mal Int64, um einen größeren Bereich abzudecken.

Bernhard

meg91 22. Jun 2008 21:21

Re: Screenshot via Handle
 
mein Problem ist nicht die Berechnung, die funktioniert perfekt. Es muss irgendwas mit den Handles zu tun habe, da ich exakt die gleiche Funktion verwende um einen Screenshot vom kompletten Desktop auszuwerten, also GetDC

hier mal eine aktualisierte Version, die aber nach wie vor, das Problem des Speicherverbrauchs hat
Delphi-Quellcode:
procedure HandleToPix(h_handle: HWND);
var
  i_tmp_x, i_tmp_y: Integer;
  i_gesRed, i_gesGreen, i_gesBlue: Integer;
  bRed, bGreen, bBlue: Byte;
  c_tmp: TCanvas;
  c_color: TColor;
  r_window: TRect;
  i_width, i_height: Integer;
  p_window: ^HWND;
const
  c_aspectorato = (4/3);
  //c_aspectorato = (16/9);
  c_vertical = 7;
begin
  c_tmp := TCanvas.Create;

  p_window := @h_handle;

  try
    c_tmp.Handle := GetWindowDC(p_window^);
    //c_tmp.Handle := GetDC(p_window^);

    GetWindowRect(p_window^, r_window);

    i_width := r_window.Right - r_window.Left;
    i_height := r_window.Bottom - r_window.Top;

    //c_tmp.BrushCopy(Rect(0,0,i_width, i_height), GetWindowDC(h_handle), Rect(0,0,i_width, i_height));

    BitBlt(c_tmp.Handle, 0, 0, i_width, i_height, GetWindowDC(h_handle), 0, 0, SRCCOPY);

    i_gesBlue := 0;
    i_gesGreen := 0;
    i_gesRed := 0;

    for i_tmp_x := 1 to round(c_aspectorato*c_vertical) do
    begin
      for i_tmp_y := 1 to c_vertical do
      begin
        c_color := c_tmp.Pixels[round((i_width / (c_aspectorato*c_vertical))*i_tmp_x), round((i_height/c_vertical)*i_tmp_y)];
        bBlue := GetBValue(c_color);
        bGreen := GetGValue(c_color);
        bRed := GetRValue(c_color);

        rgb_threshold(bRed, bGreen, bBlue);

        i_gesBlue := i_gesBlue + bBlue;
        i_gesGreen := i_gesGreen + bGreen;
        i_gesRed := i_gesRed + bRed;
      end;
    end;

    //Werte ausgeben
    changeRGB(Round(i_gesRed / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesGreen / (round(c_aspectorato*c_vertical)*c_vertical)),
              Round(i_gesBlue / (round(c_aspectorato*c_vertical)*c_vertical)));
  finally
    ReleaseDC(p_window^, c_tmp.Handle);
    freeandnil(c_tmp);
  end;

  //BitBlt(c_tmp.Handle, 0, 0, b_tmp.Width, b_tmp.Height, GetWindowDC(h_window), 0, 0, SRCCOPY);
  //BitBlt(c_tmp.Handle, 0, 0, i_width, i_height, GetWindowDC(h_window), 0, 0, SRCCOPY);
end;

SirThornberry 22. Jun 2008 21:42

Re: Screenshot via Handle
 
nicht der Fehler aber eine riesen Unschönheit:
Delphi-Quellcode:
try
  ha_window := GetDC(h_window);
finally
  ReleaseDC(h_window, ha_window);
end;
Du rufst also ReleaseDC für das Fenster auch auf wenn bei der Funktion die Exception geworfen wird und somit die Werte unbestimmt sind.
So sollte es sein:
Delphi-Quellcode:
Ressource_anfordern();
try
  //mit Ressource arbeiten
finally
  Ressource_freigeben();
end;

meg91 22. Jun 2008 21:59

Re: Screenshot via Handle
 
das mit dem sauberen Programmieren war eine gute Idee 8)

Habe mir nochmal meine Prozedur angeschaut und speichere jetzt den HDC zwischen
Delphi-Quellcode:
ha_window := GetWindowDC(h_window);
...und siehe da, auf einmal läuft alles

Danke

gruß
markus


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:15 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