2015-10-20 89 views
0

我创建了一个线程,它工作良好时Preview=false,但当我设置Preview=true然后我总是得到一个错误(系统错误代码5访问被拒绝)。德尔福系统错误代码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. 

回答

0

如果看一下供TVCLReport的源代码,其Execute()方法显示当Preview=True基于VCL-UI:

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; 

TRpPreviewControlTScrollBox的。 ShowPreview()是一个帮助函数,它将TRpPreviewControl对象放置在与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线程中可能更容易,并且在忙于生成报告时向用户显示消息。

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

+0

非常感谢你的努力和想法。我很感激。我会试一试,让它知道它是否有效。 – ErenRavenHeart

+0

我无法弄清楚......“dm.rmvFarm.DisplayPreview”,“dm.rmvFarm.OnPreview”未申报。 – ErenRavenHeart

+0

@ErenRavenHeart您可能有另一个ReportManager版本,而不是Remy。或者你没有在你的Uses子句中包含适当的源文件。使用文档。 –