Entwickler-Ecke

Algorithmen, Optimierung und Assembler - "Systemressourcen erschöpft" bei Erstellung von Sc


CarstenSchmidt - Fr 29.07.05 09:56
Titel: "Systemressourcen erschöpft" bei Erstellung von Sc
Moin!

Mein Programm sucht nacheinander zwei Fenster nach Caption, holt das Fenster in den Vordergrund und macht ein Screenshot. Dieser Vorgang wird alle Minute wiederholt. Den Code dazu habe ich aus dem Forum. Obwohl ich mir sicher bin, dass ich alle Handles wieder freigebe, wächst der Speicherbedarf des Programms langsam aber stetig an bis ich nach ein paar Tagen die Meldung bekommen "Systemressourcen erschöpft" und das Programm nicht weitermachen will.

Kann mir jemand sagen, wie ich an den Übeltäter komme oder wo mein Fehler im Code ist?

Danke und Gruß
Carsten



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
procedure SwitchToThisWindow(h1: hWnd; x: bool); stdcall;
  external user32 Name 'SwitchToThisWindow';
         {x = false: Size unchanged, x = true: normal size}

function FormularSaveScreenShot(FileName: String; h : hWnd): Boolean;
var
  Rec: TRect;
  iWidth, iHeight: Integer;
  JpegImg: TJpegImage;
  bmp : TBitmap;
begin
JpegImg := TJpegImage.Create;
bmp := TBitmap.Create;
  with bmp do try
    GetWindowRect(h, Rec);
    iWidth  := Rec.Right - Rec.Left;
    iHeight := Rec.Bottom - Rec.Top;
    Width := iWidth;
    Height := iHeight;
    BitBlt(Canvas.Handle, 00, iWidth, iHeight, GetWindowDC(h), 00, SRCCOPY);
    Result := True;
//    try SaveToFile(Filename) except Result := False end;
    JpegImg.assign(bmp);
    try JpegImg.SaveToFile(Filename) except Result := False end;
  finally
    ReleaseDC(h, GetWindowDC(h));
    Free;
    JpegImg.Free;
  end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  h1,h2 : hwnd;
  time  :Tdatetime;
begin
if edit1.Text > '' then
 begin
 h1 := findwindow(nil, PCHAR(edit1.text));
 if h1 = 0 then exit;
 SwitchToThisWindow(h1, True);
 sleep(2000);
 time := now;
 FormularSaveScreenShot(edit1.text+'.jpg',h1);
 label1.Caption := formatdatetime('dd.mmmm. hh:nn:ss', time);
 label6.Caption := inttostr(strtoint(label6.Caption)+1);
 end;
if edit2.Text > '' then
 begin
 h2 := findwindow(nil, PCHAR(edit2.text));
 if h2 = 0 then exit;
 SwitchToThisWindow(h2, True);
 sleep(2000);
 time := now;
 FormularSaveScreenShot(edit2.text+'.jpg',h2);
 label2.Caption := formatdatetime('dd.mmmm. hh:nn:ss', time);
 label6.Caption := inttostr(strtoint(label6.Caption)+1);
 end;
releasedc(h1,findwindow(nil, PCHAR(edit1.text)));
releasedc(h2,findwindow(nil, PCHAR(edit2.text)));
end;



Ich benutze Win XP/2k mit Dephi 2005 Prof.


Stefan.Buchholtz - Fr 29.07.05 10:12
Titel: Re: "Systemressourcen erschöpft" bei Erstellung vo
user profile iconCarstenSchmidt hat folgendes geschrieben:
Moin!

Mein Programm sucht nacheinander zwei Fenster nach Caption, holt das Fenster in den Vordergrund und macht ein Screenshot. Dieser Vorgang wird alle Minute wiederholt. Den Code dazu habe ich aus dem Forum. Obwohl ich mir sicher bin, dass ich alle Handles wieder freigebe, wächst der Speicherbedarf des Programms langsam aber stetig an bis ich nach ein paar Tagen die Meldung bekommen "Systemressourcen erschöpft" und das Programm nicht weitermachen will.

Kann mir jemand sagen, wie ich an den Übeltäter komme oder wo mein Fehler im Code ist?

Danke und Gruß
Carsten

Ich benutze Win XP/2k mit Dephi 2005 Prof.


Ich denke, der Device Context ist das Problem:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
function FormularSaveScreenShot(FileName: String; h : hWnd): Boolean;  
var  
  Rec: TRect;  
  iWidth, iHeight: Integer;  
  JpegImg: TJpegImage;  
  bmp : TBitmap;  
  dc: HDC;
begin  
  JpegImg := TJpegImage.Create;  
  bmp := TBitmap.Create;  
  with bmp do try  
    GetWindowRect(h, Rec);  
    iWidth  := Rec.Right - Rec.Left;  
    iHeight := Rec.Bottom - Rec.Top;  
    Width := iWidth;  
    Height := iHeight;  
    dc := GetWindowDC(h);
    BitBlt(Canvas.Handle, 00, iWidth, iHeight, dc00, SRCCOPY);  
    Result := True;  
    JpegImg.assign(bmp);  
    try JpegImg.SaveToFile(Filename) except Result := False end;  
  finally  
    ReleaseDC(h, dc);  
    Free;  
    JpegImg.Free;  
  end;  
end;


Stefan


CarstenSchmidt - Fr 29.07.05 10:26

Sehr schön, danke.

Aber was mache ich dagegen? Ich habe mit handles und Device Contexten keine Erfahrung.

Gruß
Carsten


Stefan.Buchholtz - Fr 29.07.05 10:35

user profile iconCarstenSchmidt hat folgendes geschrieben:
Sehr schön, danke.

Aber was mache ich dagegen? Ich habe mit handles und Device Contexten keine Erfahrung.

Gruß
Carsten


Probier es mal mit den Änderungen, die ich gemacht habe, aus - so firm bin ich in dem Thema auch nicht, deswegen bin ich mir nicht sicher, ob es das war. Meiner Meinung nach musst du genau den Device Context, den du mit GetWindowDC geholt hast, auch mit ReleaseDC wieder freigeben. Nochmal GetWindowDC auf das gleiche Fentser aufrufen und den dann releasen tut es denke ich nicht.

Wenn es das nicht war, versuch mal mit MemProof (http://www.automatedqa.com/downloads/memproof/) herauszufinden, was für ein Objekt nicht wieder freigegeben wird. Das könnte dir einen Hinweis geben, wo der Fehler liegt.

Stefan


Tastaro - Fr 29.07.05 10:43

Das Bitmap ist das Problem.
Zu nem Bmp := tbitmap.create; gehört dann auch irgendwann ein Bmp.free, das in dem Code fehlt.

Beste Grüße
Tastaro


Stefan.Buchholtz - Fr 29.07.05 11:10

user profile iconTastaro hat folgendes geschrieben:
Das Bitmap ist das Problem.
Zu nem Bmp := tbitmap.create; gehört dann auch irgendwann ein Bmp.free, das in dem Code fehlt.

Beste Grüße
Tastaro


Nein, das Free steht ja im finally-Abschnitt - wegen dem with bmp do try bezieht sich dieses Free auf das bmp. Sowas ist nicht offensichtlich, weswegen in in den Programmierrichtlinien der Firma, in der ich arbeite, die with-Anweisung schlicht verboten wurde - die steht bei uns auf etwa gleicher Stufe wie goto.

Stefan


CarstenSchmidt - Fr 29.07.05 11:39

Danke für die Tipps. Ich werde es heute abend mal ausprobieren.

Carsten


hallo - Fr 29.07.05 11:43

Also Delphi hat mit dem Speicher teilweiße Probleme!
Deswegen würde ich das Programm welches den Screenshot macht, per Timer und Shellexecute aufrufen, und gleich danach wieder beenden!


CarstenSchmidt - Fr 29.07.05 18:11

Danke, das war wahrscheinlich die Lösung. Im Nachhinein ist es eigentlich logisch. Wenn ich das Handle release (tschuldigung, ich meine, wenn ich den Griff freigebe oder loslasse), indem ich einen neuen Griff anfasse:


Delphi-Quelltext
1:
    ReleaseDC(h, GetWindowDC(h));                    


muss natürlich ein Griff immer festgehalten werden. Mit der vorherigen Definition des Griffes und der folgenden Freigabe eben desselben


Delphi-Quelltext
1:
2:
dc := GetWindowDC(h);  
ReleaseDC(h, dc);


passiert das nicht. Bei 2000 Aufrufen der Screenshot Prozedur hatte ich so nur einen Speicherzuwachs von 4 Byte.

Danke für die Hilfe

Carsten