在 Delphi Web 服务器后面使用快速报告生成 PDF
我有一个 Delphi Web 服务器,提供一些 Web 服务*。 其中之一应该生成并返回 PDF 报告。
PDF 创建是通过 QReport 完成的,然后使用 ExportToFilter 过程将其导出为 PDF 文件。
当从应用程序内部调用时,该例程工作正常,但当在 TIdTCPServer 后面调用时,它会挂起并且永远不会完成。 调试它,我得到了挂点:
(注意:我现在在家,我没有源代码。我会尝试尽可能准确地重现 Quickrpt.pas 的源代码) .
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
AProgress := TQRFormProgress.Create(Application); // Hangs on this line
AProgress.Owner := QReport;
if ShowProgress then AProgress.Show;
QReport.Client := AProgress;
...
在网上搜索,我在 本页 (1)建议将ShowProgress设置为False,并编辑代码,使其在ShowProgress设置为false时不创建进度表(显然,这是由于QReport不是线程安全的)。
所以,我编辑了代码,现在我有了:
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
if ShowProgress then
begin
AProgress := TQRFormProgress.Create(Application);
AProgress.Owner := QReport;
AProgress.Show;
QReport.Client := AProgress
end;
...
现在,报告出来了。 但随后服务出现无效指针异常(我无法跟踪)。 对服务的调用成功完成,但是当我关闭服务**时,它再次开始抱怨无效指针异常,然后出现“MyServer 已提交无效操作,必须关闭”Windows 消息,然后又出现几次,然后只是指针异常,然后出现错误 216(据我所知,与 Windows 访问权限有关)。
谢谢!
更新(1 月 5 日):感谢 Scott W. 的 答案。 确实,经过一番研究,我发现了另一个建议,即只有主线程才能访问某些组件。 因此,我将 QR 码设置回正常状态,并从 TThread 内的 Synchronize 调用中调用 main 方法(这样主线程就会处理它)。 但我仍然遇到同样的错误。
您提到您能够使用 QR 4 生成 PDF 作为服务。也许这就是为什么它对我不起作用,因为我使用的是 QR 3。另一方面,您没有提到您是否在背后执行此操作TIdTCPServer(这是我的情况,提供 Web 服务)或者如果您自行运行它(例如,在批处理过程中)。
有人知道我的二维码版本是否有问题吗? 谢谢!
* 在 Windows XP SP2 上运行 Delphi 7 和 QuickReport 3。 该服务器基于 Indy。
** 我有两个版本的服务器:Windows 应用程序和 Windows 服务。 两者都调用相同的内部逻辑,并且两个版本都会出现问题。
更新(3月8日):毕竟,我的问题是我的打印例程在另一个dll中,并且默认的内存管理模块有点蹩脚。 将我的 .dpr 的第一次使用设置为 ShareMem 会使用 Borland 的实现覆盖内存管理模块,并解决了我的问题。
uses
ShareMem, ...
I have a Delphi web server providing some web services*. One of them is supposed to generate and return a PDF report.
The PDF creation is done with a QReport that is then exported into a PDF file with the ExportToFilter procedure.
The routine works fine when called from within an application, but when called behind a TIdTCPServer, it hangs and never finishes. Debugging it, I got tho the hanging point:
(note: I'm home right now and I don't have the source code. I'll try to reproduce quickrpt.pas' source as accurrate as I can remember).
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
AProgress := TQRFormProgress.Create(Application); // Hangs on this line
AProgress.Owner := QReport;
if ShowProgress then AProgress.Show;
QReport.Client := AProgress;
...
Searching the web, I found in this page (1) the suggestion to set ShowProgress to False, and edit the code so that it does not create the progress form when ShowProgress is set to false (apparently, this is due to QReport not being threadsafe).
So, I edited the code, and now I have this:
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
if ShowProgress then
begin
AProgress := TQRFormProgress.Create(Application);
AProgress.Owner := QReport;
AProgress.Show;
QReport.Client := AProgress
end;
...
Now, the report comes out. But then the service gets to an Invalid Pointer Exception (which I can't trace). Following calls to the service complete successfully, but when I shut down the service** it starts whining again with Invalid Pointer Exceptions, then the "MyServer has commited an invalid action and must be closed" windows message, then again a couple of times more, then just the pointer exception, then comes to error 216 (which as far as I could find out, is related to Windows access permissions).
Thanks!
Update (jan 5): Thanks Scott W. for your answer. Indeed, after some research, I found another suggestion that only the main thread can access some components. So I set the QR code back to normal and called the main method from a Synchronize call inside a TThread (so that way the main thread would handle it). But I still get the same error.
You mention you were able to generate PDF as a service with QR 4. Maybe that's why it's not working for me, since I'm using QR 3. On the other hand, you don't mention if you're doing that behind a TIdTCPServer (which is my case, providing web services) or if you run it by itself (for instance, during a batch process).
Anybody knows whether my QR version might be the problem? Thanks!
* Running Delphi 7 and QuickReport 3 on a Windows XP SP2. The server is based on Indy.
** I have two versions of the server: a Windows application and a Windows Service. Both call the same inner logic, and the problem occurs with both versions.
Update (mar 8): After all, my problem was that my printing routine was in another dll, and the default memory management module is somewhat crappy. Setting the first uses of my .dpr to be ShareMem overrides the memory management module with Borland's implementation, and solved my problem.
uses
ShareMem, ...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我猜测
QReport.Client
在代码中稍后的某个地方使用,并且修改后的代码不再将其分配给 AProgress,最终会出现错误。您确定必须修改 QuickReport 源吗? 我在 Windows 服务中使用 QuickReport 生成 PDF 文件,然后附加到电子邮件中,一切正常,无需修改 QR 源。 我不记得必须进行哪些设置,但它是使用 Delphi 6 和 QR 4.06 完成的。
I'm guessing that
QReport.Client
is used somewhere later in the code, and with your modified code no longer assigning it to AProgress, you end up with an error.Are you sure that you have to modify the QuickReport source? I have used QuickReport in a Windows Service to generate a PDF file and then attach to email message and all worked fine without having to modify the QR source. I don't recall exactly which settings had to be made, but it was done with Delphi 6 and QR 4.06.