All access of UI controls must be executed on the UI thread. You'll need to queue or synchronize UI access code onto that main UI thread.
Access Violation when adding multiple lines in a TMemo
-
22-06-2023 - |
Question
It is an old problem which I first encountered when the first firemonkey came out. Now even with XE5 its the same. I can't use TMemo for anything unless each new line is added with a sufficient time delay.
The problem occurs on heavy forms with lots of controls. And if the lines are long enough to be wrapped and contain special characters, the chance increases. If a string contains line breaks then it almost always gets raised.
Doing the same in a form containing only the memo, and the filler thread, doesn't produce any AVs, I think there must be something wrong somewhere else.
The AV originates in TTextSettings, TTextLayout, TText etc.
Legend
TAgStringList : A derived class from TStringlist with logging, conversion to bytes and locking support.
FLogMemo : The visual TMemo.
FDisplayReq : The condition to add log lines into FLogMemo.
BeignRead : inline method to TMREWSync.BeginRead
EndRead : inline method to TMREWync.EndRead
Log Method
procedure TAgStringList.Log
( const APrefixes : Array of String;
const ALogs : Array of String;
const AException : Exception = nil );
var
I : NativeInt;
LogString : String;
begin
LogString := Format ( '[%s]', [FormatDateTime ( 'hh:mm:ss.zzz', Time )] );
for I := 0 to Length ( APrefixes ) - 1 do
LogString := Format ( '%s[%s]', [LogString, APrefixes [I]] );
if Assigned ( AException ) then
LogString := Format ( '%s[%s]', [LogString, AException.ClassName] );
if FDisplayReq then
FLogMemo.Lines.Add ( LogString );
Add ( LogString );
for I := 0 to Length ( ALogs ) - 1 do
begin
if FDisplayReq then
FLogMemo.Lines.Add ( ALogs [I] );
Add ( ALogs [I] );
end;
if Assigned ( AException ) then
begin
if FDisplayReq then
FLogMemo.Lines.Add ( AException.Message );
Add ( AException.Message );
Add ( '' );
end
else
Add ( '' );
end;
Log Thread Method
procedure TAgStringList.LogManager;
var
I : NativeInt;
EndIndex : NativeInt;
begin
BeginRead;
EndIndex := GetCount - 1;
if FLogManager.Tag < EndIndex then
begin
if Assigned ( FLogMemo ) then
begin
FLogMemo.BeginUpdate;
for I := FLogManager.Tag to EndIndex do
FLogMemo.Lines.Add ( Strings [I] );
FLogMemo.EndUpdate;
FLogManager.Tag := GetCount;
end;
SaveToFile ( FLogFileName );
end;
EndRead;
end;
Solution