Link to home
Start Free TrialLog in
Avatar of JackJohnsons
JackJohnsons

asked on

Delphi 7: After many BitBlts to bitmap it doesn't change anymore

Hello experts

I wrote a function to find a color on the screen, it uses bitblt then directly accesses the bitmap in memory. it works fine, but when I call the function in a burst (for i := 0 to 10000 i.e.) the bitmap "hangs". When the screen changes the bitmap doesnt change anymore =/ It's certainly not the way of accessing the bitmap because when I draw the bitmap to another canvas, it reflects the old screen.
Anyone who got an idea why?
unit ColourFinder;
 
{$O+}
 
interface
 
uses Windows, Variants, Graphics, Sysutils, Forms;
 
type
  TRGB24 = packed Record
    b,g,r: Byte;
  end;
 
  TRGB24Array = Array [0..MaxInt div SizeOf(TRGB24)-1] of TRGB24;
  PRGB24Array = ^TRGB24Array;
 
var
  SBMP : TBitmap; //Search bitmap
  Scanlines: Array of PRGB24Array; //scanlines
  I: Integer; //for for loop for getting the scanlines
 
function FindColor(var x, y: Integer; color, xs, ys, xe, ye: Integer; ClientDC : HDC): Boolean;
 
implementation
 
function FindColor(var x, y: Integer; color, xs, ys, xe, ye: Integer; ClientDC : HDC): Boolean;
var
  xx, yy: Integer;
  R, G, B: Byte;
begin
 
  R:= color;
  G:= color shr 8;
  B:= color shr 16;
 
  BitBlt(SBMP.Canvas.Handle, xs, ys, xe - xs, ye - ys, ClientDC, xs, ys, SRCCOPY);
 
  for yy:= ys to ye do
    for xx:= xs to xe do
      if(Scanlines[yy][xx].R = R)then if(Scanlines[yy][xx].G = G)then if(Scanlines[yy][xx].B = B)then
      begin
        x:= xx;
        y:= yy;
        Result:= True;
        exit;
      end;
  Result:= False;
  x:= -1;
  y:= -1;
end;
 
initialization
  SBMP := TBitmap.Create; //Create the search bitmap
  SBMP.Width:= Screen.Width;
  SBMP.Height:= Screen.Height;
  SetLength(Scanlines, SBMP.Height);
  SBMP.PixelFormat:= pf24bit;
  for I:= 0 to SBMP.Height - 1 do
    Scanlines[i]:= SBMP.ScanLine[i];
  ClientDC := GetDC(0);
end.

Open in new window

Avatar of BdLm
BdLm
Flag of Germany image

Does your functions fail at the second scan alraey, you nexer get any change of the screen ?


Instead of a loop use a TTimer and scan the desktiop at fixed intervalls
 
BTw:

you read the screen content with  ClientDC := GetDC(0);  inside a unit I guess, this i executed only at program start up,

do something like

procedure TForm1.ReadScreen(sender: TObject);
begin
      //   copy the BMP
       ClientDC := GetDC(0);
     //  run the function
    FindColor(.....)
end;


set the OnTimer.Event to the  Function ReadSCreen(....)

 
Avatar of JackJohnsons
JackJohnsons

ASKER

The loop I use is a simple for loop, for i := 0 to 10000 do FindColor(...
I can't use a TTimer unfortunately, needs to be a real for loop :-(
after how many loops you get the hang up?

can you post the copde with your loop ?


the code is really easy, and it is approx after 1

for i := 0 to 10000 do 
  FindColor(x, y, 255 {red}, 0, 50, 50 GetDC(0));
writeln(inttostr(x));
writeln(inttostr(y));
sleep(5000); //in this time change screen
for i := 0 to 10000 do 
  FindColor(x, y, 255 {red}, 0, 50, 50 GetDC(0));
writeln(inttostr(x));
writeln(inttostr(y));

Open in new window

****  the MainForm **** (test with ~ 100 loops)
unit ColourFinderForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ColourFinder, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }



  SBMP        : TBitmap; //Search bitmap

  I           : Integer; //for for loop for getting the scanlines


  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
     SBMP := TBitmap.Create; //Create the search bitmap  only once !!!!
     SBMP.Width:= Screen.Width;
     SBMP.Height:= Screen.Height;
     SBMP.PixelFormat:= pf24bit;
     {

       ClientDC := GetDC(0);
     }
end;

procedure TForm1.Button1Click(Sender: TObject);
var   i,x,y   : Integer;
begin
  for i := 0 to 1000  do
      begin
      FindColor(SBMP, x, y, 255 {red}, 0, 0, 10, 10,  GetDC(0));

      Edit1.Text :=IntToStr(i)+  ':'  + IntToStr(x) + ':' + IntToStr(y);

      sleep(350);

      self.Repaint;



      end;

end;

end.

******  the new unit *******
 
unit ColourFinder;
 
{$O+}
 
interface
 
uses Windows, Variants, Graphics, Sysutils, Forms;
 
type
  TRGB24 = packed Record
    b,g,r: Byte;
  end;
 
  TRGB24Array = Array [0..MaxInt div SizeOf(TRGB24)-1] of TRGB24;
  PRGB24Array = ^TRGB24Array;
 
 
 
function FindColor(sBMP:  TBitMap; var x, y: Integer; color, xs, ys, xe, ye: Integer; ClientDC : HDC): Boolean;
 
implementation
 
function FindColor(sBMP:  TBitMap; var x, y: Integer; color, xs, ys, xe, ye: Integer; ClientDC : HDC): Boolean;
var
  xx, yy, i : Integer;
  R, G, B: Byte;
  Scanlines   : Array of PRGB24Array; //scanlines
begin
 
 
  SetLength(Scanlines, SBMP.Height);
 
  for I:= 0 to SBMP.Height - 1 do
       Scanlines[i]:= SBMP.ScanLine[i];
 
 
 
  R:= color;
  G:= color shr 8;
  B:= color shr 16;
 
  BitBlt(SBMP.Canvas.Handle, xs, ys, xe - xs, ye - ys, ClientDC, xs, ys, SRCCOPY);
 
  for yy:= ys to ye do
    for xx:= xs to xe do
      if(Scanlines[yy][xx].R = R)then if(Scanlines[yy][xx].G = G)then if(Scanlines[yy][xx].B = B)then
      begin
        x:= xx;
        y:= yy;
        Result:= True;
        exit;
      end;
  Result:= False;
  x:= -1;
  y:= -1;
end;
 
initialization
 
end.
 

Open in new window

is your problem solved ?
best
It didn't fix my problem :(
can you complete thsi code 90 % finished ?
unit Unit_screenfunctions;
{************************
 *   http://www.experts-exchange.com/Programming/Editors_IDEs/Delphi/Q_23631004.html?cid=238#a22298541
 ************************}
 
interface
 
 
uses   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;
 
 
 
       procedure  ScreenShot(MyDC: TBitMap);
       procedure  GetColorValue(xpos, ypos: Integer; var R,g,b, mean :  integer; Bit  : TBitMap);
       function   FindColor(x_min,x_max,y_min,y_max,r,g,b, Bit : TBitMap) : boolean;
 
implementation
 
 
 
procedure ScreenShot(MyDC: TBitMap);
var
  c: TCanvas;
  r: TRect;
begin
  c := TCanvas.Create;
  c.Handle := GetWindowDC(GetDesktopWindow);
  try
    r := Rect(0, 0, Screen.Width, Screen.Height);
    MyDC.Width := Screen.Width;
    MyDC.Height := Screen.Height;
    MyDC.Canvas.CopyRect(r, c, r);
  finally
    ReleaseDC(0, c.Handle);
    c.Free;
  end;
end;
 
function   FindColor(x_min,x_max,y_min,y_max,r,g,b, Bit : TBitMap) : boolean;
var     i,j   :   Integer;
        mean  :   Integer;
begin
     for i:= x_min to x_max do
          for j:=y_min to y-max do
             begin
                //
                 GetColorValue(i,j,r,g,b,mean
             end;
 
end;
 
 
{*************************************************************************************
 *   CThis Returns the r,g,b  value for a given x_pos, y_pos inside a Bitmap
 *
 *
 *************************************************************************************}
procedure GetColorValue(xpos, ypos: Integer; var R,g,b, mean :  integer; Bit  : TBitMap);
type
  PixArray = Array [1..3] of Byte;
var
  p     : ^PixArray;
  h,w   : Integer;
 
begin
 
  Bit.PixelFormat := pf24bit;
 
  if (ypos <= Bit.Height-1)   and (xpos <= Bit.Width-1) then
 
    begin
    p:= Bit.ScanLine[ypos];
    For w:=0 to xpos do
    begin
      mean := ( (round(p^[1]) + round(p^[2]) + round(p^[3])) div 3);
      r := p^[1];
      g := p^[2];
      b := p^[3];
      Inc(p);
    end;
  end;
end;
 
 
end.

Open in new window

the main form code ...
unit Unit_screenEE;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, Unit_screenfunctions;
 
type
  TForm1 = class(TForm)
    CaputureScreenButton: TButton;
    Image1: TImage;
    Edit1: TEdit;
    Edit2: TEdit;
    CheckColorButton: TButton;
    Edit3: TEdit;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure CaputureScreenButtonClick(Sender: TObject);
    procedure CheckColorButtonClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    SBMP : TBitmap;
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
     SBMP := TBitmap.Create; //Create the search bitmap  only once !!!!
     SBMP.Width:= Screen.Width;
     SBMP.Height:= Screen.Height;
     SBMP.PixelFormat:= pf24bit;
end;
 
 
procedure TForm1.CaputureScreenButtonClick(Sender: TObject);
begin
 
      ScreenShot(SBMP);
 
      Image1.Picture.Bitmap.assign(SBMP);
end;
 
 
 
 
procedure TForm1.CheckColorButtonClick(Sender: TObject);
var    x,y   :   Integer;
       r,g,b, mean :   Integer;
begin
    x:= StrToInt (Edit1.text);
    y:= StrToInt (Edit2.text);
 
    GetColorValue(x,y, r,g,b,mean,SBMP);
 
    Edit3.Text := IntToStr(r)+':'+ IntToStr(g)+':'+ IntToStr(b)+':'+IntToStr(mean);
end;
 
end.

Open in new window

here is the complete project ...
ASKER CERTIFIED SOLUTION
Avatar of BdLm
BdLm
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial