Delphi系统错误代码5访问被拒绝

时间:2015-10-20 03:15:11

标签: multithreading delphi reportmanager

我创建了一个线程,它在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 个答案:

答案 0 :(得分:0)

如果您查看TVCLReport的源代码,其Execute()方法会在Preview=True时显示基于VCL的用户界面:

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源自TScrollBoxShowPreview()是一个帮助函数,可将TRpPreviewControl对象放到与TForm一起显示的自定义TFRpPreview对象(ShowModal())上。基于VCL的UI不是线程安全的,不能在主UI线程的上下文之外使用。如您所见,TVCLReport.Execute()没有为您提供与主UI线程同步的任何机会,因此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留在主UI线程中可能更容易,并且在忙于生成报告时向用户显示消息。

你只需要尝试一下,看看会发生什么。