2015-10-20 102 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子句中包含適當的源文件。使用文檔。 –