Системная ошибка Delphi, код 5, доступ запрещен
Я создал тему, и она хорошо работает, когда Preview=false
, но когда я установил Preview=true
тогда я всегда получаю ошибку (системная ошибка с кодом 5, доступ запрещен).
Я хочу создать поток отчета, потому что на его создание уходит более 10 секунд.
Может кто-нибудь объяснить, что происходит?
procedure TReportThread1.Execute;
begin
if ReportBUFFER = 1 then begin
dm.rmvFarm.Filename := reportpath + 'aoc.rep';
dm.rmvFarm.Report.Params.Items[0].Value := Thread_StartOfTheDayR1;
dm.rmvFarm.Report.Params.Items[1].Value := Thread_EndOfTheDayR1;
dm.rmvFarm.Report.Params.Items[2].Value := currentusr;
dm.rmvFarm.Preview := true;
dm.rmvFarm.Execute;
ReportThread1.free;
end;
end.
1 ответ
Если вы посмотрите на исходный код TVCLReport
, его Execute()
метод отображает пользовательский интерфейс на основе VCL, когда Preview=True
:
type
TVCLReport=class(TCBaseReport)
private
prcontrol:TRpPreviewControl;
...
end;
function TVCLReport.Execute:boolean;
var
...
begin
inherited Execute;
...
try
if Preview then
begin
prcontrol:=TRpPreviewControl.Create(nil);
try
prcontrol.Report:=Report;
Result:=ShowPreview(prcontrol,Title);
finally
prcontrol.free;
end;
end
else
begin
...
end;
TRpPreviewControl
происходит от TScrollBox
, ShowPreview()
это вспомогательная функция, которая помещает TRpPreviewControl
объект на заказ TForm
объект (TFRpPreview
), который отображается с ShowModal()
, Интерфейсы на основе VCL не являются поточно-ориентированными и не могут использоваться вне контекста основного потока пользовательского интерфейса. Как вы видете, TVCLReport.Execute()
не предоставляет никакой возможности синхронизироваться с основным потоком пользовательского интерфейса, поэтому Preview=True
НЕ безопасно использовать в рабочем потоке.
Если вы хотите позвонить TVCLReport.Execute()
в рабочем потоке, но отображать его предварительный просмотр в поточно-ориентированном виде, одним из возможных решений будет изменение исходного кода для TVCLReport
выставить функциональность предварительного просмотра таким образом, чтобы вы могли вызвать его с помощью TThread.Synchronize()
Например:
type
TVCLReportPreviewEvent = procedure(Sender: TObject; var VResult: Boolean) of object;
TVCLReport=class(TCBaseReport)
private
prcontrol:TRpPreviewControl;
...
public
OnPreview: TVCLReportPreviewEvent;
function DisplayPreview: Boolean;
end;
function TVCLReport.Execute:boolean;
var
...
begin
inherited Execute;
...
try
if Preview then
begin
if Assigned(OnPreview) then
OnPreview(Self, Result)
else
Result := DisplayPreview;
end
else
begin
...
end;
function TVCLReport.DisplayPreview: Boolean;
begin
prcontrol:=TRpPreviewControl.Create(nil);
try
prcontrol.Report:=Report;
Result := ShowPreview(prcontrol, Title);
finally
prcontrol.free;
end;
end;
procedure TReportThread1.Execute;
begin
if ReportBUFFER = 1 then begin
dm.rmvFarm.Filename := reportpath + 'aoc.rep';
dm.rmvFarm.Report.Params.Items[0].Value := Thread_StartOfTheDayR1;
dm.rmvFarm.Report.Params.Items[1].Value := Thread_EndOfTheDayR1;
dm.rmvFarm.Report.Params.Items[2].Value := currentusr;
dm.rmvFarm.Preview := true;
dm.rmvFarm.OnPreview := DisplayPreviewInMainThread;
dm.rmvFarm.Execute;
ReportThread1.free;
end;
end;
procedure TReportThread1.DisplayPreviewInMainThread(Sender: TObject; var VResult: Boolean);
begin
TThread.Synchronize(nil,
procedure
begin
VResult := dm.rmvFarm.DisplayPreview;
end
);
end;
Хотя, если создание вашего отчета действительно занимает много времени, есть вероятность, что предварительный просмотр также займет много времени. Если это так, то это решение не принесет вам ничего полезного. Может быть проще просто оставить TVCLReport
в главном потоке пользовательского интерфейса и отображать сообщение пользователю, пока он занят созданием отчета.
Вам просто нужно попробовать и посмотреть, что получится.