I'm expriencing some weird problems in one of my projects. What is the most strange is that this only happens in this project and I can't recreate it in another.
Luckilly this is a tiny project (intended to provide an answer to one of the questions here on SO - still not finished) so I managed to figure out that it has to do something with destroying of TImage component I have placed on my form at design time and set a BMP image to it also at design time.
The AV I get is: Project Project1.exe raised exception class $C0000005 with message 'acces violation at 0x00407430: read of adress 0xfffffffc'.
Last three Call stacks are:
Vcl.Graphics.TBitmapCanvas.Destroy
Vcl.Graphics.TCanvasDestroy
System.TObject.Free
Also Delphi puts me in System.pas unit in TObbject.Free method on line "Destroy".
procedure TObject.Free;
begin
if Self <> nil then
{$IFDEF AUTOREFCOUNT}
__ObjRelease;
{$ELSE}
Destroy;
{$ENDIF}
end;
Value of Self at this time is shown only as ().
But why this AV only happens if I store some data into my multidimensional array.
I can create and set the size of the multidimensional array at runtime and everyting is fine. But as soon as I change data of some items in this multidimensional array I get AV when closing my application.
Here is my full source code:
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TSubImage = record
LeftBound: Integer;
RightBound: Integer;
TopBound: Integer;
BottomBound: Integer;
end;
TForm2 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
Image1: TImage;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
SubImages: Array of TSubImage;
implementation
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var X,Y,I: Integer;
RegionMask: Array of Array of Integer;
begin
SetLength(RegionMask,Image1.Width+1,Image1.Height+1);
for Y := 0 to Image1.Height do
begin
for X := 0 to Image1.Width do
begin
if Image1.Canvas.Pixels[X,Y] <> clFuchsia then
begin
//Check left pixel
if X > 0 then
begin
if RegionMask[X-1,Y] <> 0 then
begin
RegionMask[X,Y] := RegionMask[X-1,Y];
//Check to se if pixel X position is leftwards to subimages left bound
if Subimages[RegionMask[X,Y]].LeftBound > X then
//Move subimage left bound to match pixel X position
Subimages[RegionMask[X,Y]].LeftBound := X;
//Check to se if pixel X position is rightwards to subimages right bound
if Subimages[RegionMask[X,Y]].RightBound < X then
//Move subimage right bound to match pixel X position
Subimages[RegionMask[X,Y]].RightBound := X;
//Check to se if pixel Y position is upwards to subimages top bound
if Subimages[RegionMask[X,Y]].TopBound > Y then
//Move subimage top bound to match pixel Y position
Subimages[RegionMask[X,Y]].TopBound := Y;
//Check to se if pixel Y position is downwards to subimages bottom bound
if Subimages[RegionMask[X,Y]].BottomBound < Y then
//Move subimage bottom bound to match pixel Y position
Subimages[RegionMask[X,Y]].BottomBound := Y;
end;
end;
//Check top pixel
if Y > 0 then
begin
if RegionMask[X,Y-1] <> 0 then
begin
RegionMask[X,Y] := RegionMask[X,Y-1];
//Check to se if pixel X position is leftwards to subimages left bound
if Subimages[RegionMask[X,Y]].LeftBound > X then
//Move subimage left bound to match pixel X position
Subimages[RegionMask[X,Y]].LeftBound := X;
//Check to se if pixel X position is rightwards to subimages right bound
if Subimages[RegionMask[X,Y]].RightBound < X then
//Move subimage right bound to match pixel X position
Subimages[RegionMask[X,Y]].RightBound := X;
//Check to se if pixel Y position is upwards to subimages top bound
if Subimages[RegionMask[X,Y]].TopBound > Y then
//Move subimage top bound to match pixel Y position
Subimages[RegionMask[X,Y]].TopBound := Y;
//Check to se if pixel Y position is downwards to subimages bottom bound
if Subimages[RegionMask[X,Y]].BottomBound < Y then
//Move subimage bottom bound to match pixel Y position
Subimages[RegionMask[X,Y]].BottomBound := Y;
end;
end;
//Create new region
if RegionMask[X,Y] = 0 then
begin
SetLength(SubImages,Length(SubImages)+1);
//If I comment out this line no exception is raised on closing the from
RegionMask[X,Y] := Length(SubImages);
//Set subimage initial bounds which are coordinates of one pixel
//since we created new region for this pixel
SubImages[RegionMask[X,Y]].LeftBound := X;
SubImages[RegionMask[X,Y]].RightBound := X;
SubImages[RegionMask[X,Y]].TopBound := Y;
SubImages[RegionMask[X,Y]].BottomBound := Y;
end;
end;
end;
end;
Form2.Caption := IntToStr(Length(SubImages)-1);
for I := 0 to Length(Subimages)-1 do
begin
ListBox1.Items.Add(IntToStr(SubImages[I].LeftBound)+','+
IntToStr(SubImages[I].RightBound)+','+
IntToStr(SubImages[I].TopBound)+','+
IntToStr(SubImages[I].BottomBound));
end;
SetLength(RegionMask,0,0);
RegionMask := nil;
end;
end.
You've got a one-off error in these lines. Consider the first time you add an element to SubImages. The length of SubImages is 1, but the only element in the array is SubImages[0]. You set RegionMask[X,Y] to 1, and then use that value to index the array. So you are trying to access one item beyond the end of the array.
SetLength(SubImages,Length(SubImages)+1);
RegionMask[X,Y] := Length(SubImages);
SubImages[RegionMask[X,Y]].LeftBound := X;