If TPicture.Graphic is stored elsewhere then the "elsewhere" becomes invalid when it's reassigned using the setter (its address changes). Using assign(), .Graphic address does not vary.
However i'd like to see a reduced code that reproduces the problem. With his sample it's hard to say if it's relevant or not.
ok lets break things down a bit
Pass the component reference by value not by reference even if value changes the original graphic is not lost.
procedure TPicture.SetGraphic(Value: TGraphic);
var
NewGraphic: TGraphic;
ok: boolean;
begin
if (Value=FGraphic) then exit;
if the value passed is FGraphic then don't waste time and cpu.
NewGraphic := nil;
ok := False;
NewGraphic is a local variable and the above section initializes the values.
try
if Value <> nil then
begin
NewGraphic := TGraphicClass(Value.ClassType).Create;
If the value is not nil make sure that a new graphic of the same class (also known as image type) is created
NewGraphic.Assign(Value);
since the same image type has been created the assign procedure does not convert the passed graphic (eg it does not convert a png to a bmp)
NewGraphic.OnChange := @Changed;
NewGraphic.OnProgress := @Progress;
end;
set some internal management values nothing to do with the assignment process.
FGraphic.Free;
free the old graphic. so far the value parameter has not changed at all and no leaks happened.
FGraphic := NewGraphic; //!\ new heap address /!\
fgraphic at this point has an invalid reference so make sure it has a valid one.
Changed(Self);
ok := True;
raise the appropriate events and invalidate the needed objects.
finally
// this try..finally construction will in case of an exception
// not alter the error backtrace output
if not ok then
NewGraphic.Free;
in case of an exception cleanup things of course if the exception happens after the fgraphic.free line then we left the component in an invalid unrecoverable state.
end;
end;
That is what I see here there is no leak or memory corruption and certainly there is no orphaned reference. An invalid reference in the FGraphic might come up depending on the exception and the position it happened and can be solved easily by using the freeandnil function instead of calling free directly or by using the interlockedexchange to set the value to nil before freeing the fgraphic.
Since the program has a lot of try finally and I assume the same amount or more of empty "try except" blocks the actual exception is lost and we do not know what to look for.
I am with you that this seems a lot like a buffer overrun or some other kind of memory corruption which happens long before the process reaches the specified procedure but the error is silenced instead of showing it to the end user.
PS:
I sometimes become extremely thick headed, if thats the case here too I expect some smacking around to get me started again.