Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - BitBlt streikt
HenryHux - Fr 04.02.11 21:16
Titel: BitBlt streikt
Hi,
ich wende mich mal wieder an euch, da ich absolut nicht mehr weiter weiß.
Und zwar habe ich eine ältere Procedur, welche einen Screenshot macht, und diesen schneidet.
So sieht sie aus:
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:
| procedure Screenshot(Bounds:TRect; Links, Rechts, Oben, Unten : Integer; var TBmp : TBitmap); var DeskCanvas: TCanvas; ShotTargetBitmap : TBitmap; Cut : TRect; begin try try Shottargetbitmap := TBitmap.create; ShotTargetbitmap.Width := (Bounds.Right - Bounds.left); ShotTargetbitmap.Height := (Bounds.Right - Bounds.Left);
TBmp:=TBitmap.Create; TBmp.Width := Rechts - Links; TBmp.Height := Unten - Oben;
DeskCanvas := TCanvas.Create; DeskCanvas.Handle := GetDC(0);
Cut.Left := Links; Cut.Top := Oben; Cut.Right := Rechts; Cut.Bottom := Unten;
BitBlt(ShotTargetBitmap.Canvas.Handle, 0 ,0, bounds.Right-bounds.left, bounds.Bottom-bounds.top, DeskCanvas.handle, bounds.Left, bounds.Top,SRCCOPY); BitBlt(TBmp.Canvas.Handle, 0, 0, Cut.Right, Cut.Bottom, ShotTargetBitmap.Canvas.Handle, Cut.Left, Cut.Top, SRCCOPY);
TBmp.savetofile('C:\TBmp2 '+inttostr(Random(50000))+'.bmp'); ShotTargetBitmap.savetofile('C:\TBmp1 '+inttostr(Random(50000))+'.bmp');
finally ReleaseDC(0,DeskCanvas.Handle); FreeAndNil(deskcanvas); FreeAndNil(ShotTargetBitmap); end; except on E : Exception do begin showmessage('Exception in Screenshot : ' + E.Message); FreeAndNil(TBmp); end; end; end; |
Das Problem, welches ich erst kürzlich bemerkt habe ist, dass das fertig geschnittene Bitmap, einfach nur weiß ist.
Zwar richtig geschnitten, aber 0 Inhalt.
Bei ca jedem 6ten bis 7ten Bmp, hat er es aber genau so gemacht wie gewollt, sprich mir Inhalt.
Meiner Meinung nach, müsste es an dem letzten BitBlt liegen, denn alle! abgespeicherten ShotTargetBmps sind richtig.
Zu sagen bleibt, dass keine einzige Exception ausgelöst wurde.
Habe noch ein paar mal sleep() eingebaut, was aber das gleiche, ist also nicht weil die Prozedur zu schnell läuft.
Vielleicht wisst ihr ja was.
Lg
BenBE - Fr 04.02.11 21:25
Was sagt GetLastError?
HenryHux - Fr 04.02.11 21:39
BenBE hat folgendes geschrieben : |
Was sagt GetLastError? |
Der sagt bei jedem mal wo das Bild weiß bleibt 87.
Nur kann ich damit nichts anfangen, laut
http://msdn.microsoft.com/en-us/library/ms681382 ist es ein falcher Parameter.
Doch ich rufe immer die gleichen auf, also wodran könnte es liegen?
lg
jaenicke - Fr 04.02.11 21:43
Naja, fällt dir hier nicht etwas auf... ;-)
HenryHux hat folgendes geschrieben : |
Delphi-Quelltext 1: 2:
| ShotTargetbitmap.Width := (Bounds.Right - Bounds.left); ShotTargetbitmap.Height := (Bounds.Right - Bounds.Left); | |
HenryHux - Fr 04.02.11 21:55
Ok, danke wahr denke auch noch ein Fehler, aber nicht der, den ich suche..
Delphi-Quelltext
1: 2:
| ShotTargetbitmap.Width := (Bounds.Right - Bounds.left); ShotTargetbitmap.Height := (Bounds.Bottom - Bounds.Top); |
Damit ist es genau das gleiche.
Der Aufruf sieht so aus :
Delphi-Quelltext
1:
| Screenshot(Rect(Links,Oben,Links+100,Oben+100),32,43,64,90, TBmp); |
Wobei TBmp dort wo es aufgerufne wird nur lokal deklariert ist und noch nicht mit create erzeugt ist.
Es wird lediglich mit .free am Ende beendet.
Sonst ne Idee wodran es liegen könnte?
Lg
jaenicke - Fr 04.02.11 22:00
Kann es sein, dass du das fälschlicherweise in einem Thread aufrufst?
Und wozu brauchst du überhaupt DeskCanvas? :gruebel:
HenryHux - Fr 04.02.11 22:06
jaenicke hat folgendes geschrieben : |
Kann es sein, dass du das fälschlicherweise in einem Thread aufrufst?
Und wozu brauchst du überhaupt DeskCanvas? :gruebel: |
Gehts auch ohne? o.O
Aber vermutung ist richtig, ist eine Klasse, deren Instanz in einem Thread aufgerufen wird.
Ist dasn Problem?
jaenicke - Fr 04.02.11 22:20
HenryHux hat folgendes geschrieben : |
Wobei TBmp dort wo es aufgerufne wird nur lokal deklariert ist und noch nicht mit create erzeugt ist.
Es wird lediglich mit .free am Ende beendet. |
Äußerst schlechter Stil. Ressourcen sollten immer dort freigegeben werden, wo sie reserviert werden. Und schon gar nicht innerhalb einer Prozedur erzeugt und nach außen gegeben werden.
Und auch die Fehlerbehandlung gehört nach draußen, nicht in die Prozedur.
Außerdem hast du die Ressourcenschutzblöcke falsch angewendet.
Außerdem brauchst du kein var, da eine Bitmap ohnehin schon eine Objektreferenz ist, wenn du es außen erzeugst.
Und zu deinem Cut-Rect: Variablen so im Grunde nur durch andersnamige zu ersetzen, führt höchstens zu Verwirrung...
HenryHux hat folgendes geschrieben : |
jaenicke hat folgendes geschrieben : | Und wozu brauchst du überhaupt DeskCanvas? :gruebel: | Gehts auch ohne? o.O |
Ja, denn du benutzt ja nur den HDC, nicht das Canvas Objekt...
Korrigiert also so ca.:
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:
| procedure Screenshot(Bounds:TRect; Links, Rechts, Oben, Unten : Integer; TargetBmp : TBitmap); var DesktopHandle: HDC; ShotTargetBitmap: TBitmap; begin if not Assigned(TargetBmp) then Exit; Shottargetbitmap := TBitmap.Create; try ShotTargetbitmap.Width := Bounds.Right - Bounds.Left; ShotTargetbitmap.Height := Bounds.Bottom - Bounds.Top; TargetBmp.Width := Rechts - Links; TargetBmp.Height := Unten - Oben;
DesktopHandle := GetDC(0); try BitBlt(ShotTargetBitmap.Canvas.Handle, 0 ,0, bounds.Right-bounds.left, bounds.Bottom - bounds.top, DesktopHandle, bounds.Left, bounds.Top,SRCCOPY); BitBlt(TargetBmp.Canvas.Handle, 0, 0, Rechts, Unten, ShotTargetBitmap.Canvas.Handle, Links, Oben, SRCCOPY);
TargetBmp.savetofile('K:\TBmp2 '+inttostr(Random(50000))+'.bmp'); ShotTargetBitmap.savetofile('K:\TBmp1 '+inttostr(Random(50000))+'.bmp'); finally ReleaseDC(0, DesktopHandle); end; finally FreeAndNil(ShotTargetBitmap); end; end; |
HenryHux hat folgendes geschrieben : |
Aber vermutung ist richtig, ist eine Klasse, deren Instanz in einem Thread aufgerufen wird.
Ist dasn Problem? |
Ja, denn du benutzt eine Leinwand zum Zeichnen. Das geht nicht in einem Thread, sondern nur synchronisiert mit dem Hauptthread.
HenryHux - Fr 04.02.11 23:22
Ok, danke habe jetzt einiges verändert.
Doch habe ich das mit dem Synchronisieren noch nicht ganz hinbekommen.
Ich kenne nur Synchronize und TCriticalSection, muss aber zugeben, dass ich noch nie damit gearbeitet habe.
Mit Synchronize sollte ich die Prozedur ja aufrufen können, aber er macht es nur, wenn ich keine Parameter übergebe.
Muss ich aber. Zumindest kenne ich keinen anderen Weg.
Delphi-Quelltext
1:
| SYNCHRONIZE(Screenshot(Rect(Links,Oben,Links+100,Oben+100),32,43,64,90, TBmp)); |
Das klappt nicht, wäre auch zu einfach gewesen :D
Wie synchronisiere ich sowas am Besten?
Vielleicht ein paar gute Tipps? =)
jaenicke - Fr 04.02.11 23:25
Du musst die Daten unter private als Feld speichern. Dann kannst du eine Methode ohne Parameter synchronisiert aufrufen und darin diese Daten wiederum verwenden um die Screenshot-Prozedur aufzurufen.
HenryHux - Fr 04.02.11 23:41
jaenicke hat folgendes geschrieben : |
Du musst die Daten unter private als Feld speichern. Dann kannst du eine Methode ohne Parameter synchronisiert aufrufen und darin diese Daten wiederum verwenden um die Screenshot-Prozedur aufzurufen. |
:autsch: :autsch:
Da hätte ich selber drauf kommen müssten... Naja
Habe aber noch ein Problem:
Delphi-Quelltext
1:
| Synchronize(Screenshot); |
Wird zu [DCC Fehler] UnCardScanning.pas(158): E2066 Operator oder Semikolon fehlt .
Ich denke, dass ich noch die Instanz oder Ähnliches angeben muss.
Doch
TThread.Synchronize(Screenshot)
[DCC Fehler] UnCardScanning.pas(159): E2389 Auf Protected-Element 'TThread.Synchronize' kann hier nicht zugegriffen werden
jaenicke - Fr 04.02.11 23:58
Eigentlich ist das so schon richtig, schließlich bist du ja schon im Thread. Mich irritiert, dass du die Methode Screenshot synchronisieren willst, obwohl so ja schon die Prozedur eben hieß. Bist du da durcheinander gekommen?
Ich vermute jedenfalls, dass da irgendetwas anderes noch Screenshot heißt als deine Methode...
Sonst: Wie sieht denn der Quelltext dort sonst aus?
HenryHux - Sa 05.02.11 00:06
Ich bin immoment viel am basteln.
Die Procedure Screenshot ist lokal in einer Funktion, die ReadIn heißt.
Und diese ist Bestand von einer Klasse, welche dann in einem Thread aufgerufen wird.
Ist das vlt ein Problem?
jaenicke - Sa 05.02.11 00:11
Das Synchronize gehört in das Execute des Threads.
Theoretisch kannst du die Instanz des Threads mitgeben, aber das wäre nicht gerade sauber...
In neueren Delphiversionen kann man auch außerhalb eines Threads synchronisieren. Aber am besten pack das ins Execute, da gehört es hin. Mit dem private meinte ich das des Threads.
HenryHux - Sa 05.02.11 00:52
Ok, habe es jetzt hinbekommen.
Zwar etwas hässlich, aber es klappt.
Habe einfach die ganze Klasse in den Thread gesteckt, wusste einfach nicht wie ich es sonst machen sollte.
Werde mich dann in nächster Zeit öfter damit beschäftigen müssen, mit Zeit kommt Rat =)
Vielen Dank, jaenicke!
Lg
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!