C# 从 .NET 服务打印
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7990/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Printing from a .NET Service
提问by Chris Marasti-Georg
I am working on a project right now that involves receiving a message from another application, formatting the contents of that message, and sending it to a printer. The technology of choice is C# windows service. The output could be called a report, I suppose, but a reporting engine is not necessary. A simple templating engine, like StringTemplate, or even XSLT outputting HTML would be fine. The problem I'm having is finding a free way to print this kind of output from a service. Since it seemsthat it will work, I'm working on a prototype using Microsoft's RDLC, populating a local report and then rendering it as an image to a memory stream, which I will then print. Issues with that are:
我现在正在从事一个项目,该项目涉及从另一个应用程序接收消息、格式化该消息的内容并将其发送到打印机。选择的技术是 C# windows 服务。我想,输出可以称为报告,但不需要报告引擎。一个简单的模板引擎,比如 StringTemplate,甚至 XSLT 输出 HTML 都可以。我遇到的问题是找到一种免费的方式来打印这种服务的输出。由于它似乎可以工作,因此我正在使用 Microsoft 的 RDLC 制作原型,填充本地报告,然后将其作为图像呈现到内存流中,然后我将进行打印。与此有关的问题是:
- Multi-page printing will be a big headache.
- Still have to use PrintDocument to print the memory stream, which is unsupported in a Windows Service (though it may work - haven't gotten that far with the prototype yet)
- If the data coming across changes, I have to change the dataset and the class that the data is being deserialized into. bad bad bad.
- 多页打印将是一个大麻烦。
- 仍然必须使用 PrintDocument 来打印内存流,这在 Windows 服务中是不受支持的(尽管它可能有效 - 原型还没有那么远)
- 如果遇到的数据发生变化,我必须更改数据集和数据被反序列化成的类。坏坏坏。
Has anyone had to do anything remotely like this? Any advice? I already posted a question about printing HTML without user input, and after wasting about 3 days on that, I have come to the conclusion that it cannot be done, at least not with any freely available tool.
有没有人必须像这样远程做任何事情?有什么建议吗?我已经发布了一个关于在没有用户输入的情况下打印 HTML 的问题,在浪费了大约 3 天之后,我得出的结论是它无法完成,至少不能使用任何免费提供的工具完成。
All help is appreciated.
感谢所有帮助。
EDIT: We are on version 2.0 of the .NET framework.
编辑:我们使用 .NET 框架的 2.0 版。
采纳答案by Vaibhav
Trust me, you will spend more money trying to search/develop a solution for this as compared to buying a third party component. Do not reinvent the wheel and go for the paid solution.
相信我,与购买第三方组件相比,您会花更多的钱尝试为此搜索/开发解决方案。不要重新发明轮子并寻求付费解决方案。
Printing is a complex problem and I would love to see the day when better framework support is added for this.
打印是一个复杂的问题,我很想看到为此添加更好的框架支持的那一天。
回答by TheSmurf
This may not be what you're looking for, but if I needed to do this quick&dirty, I would:
这可能不是你要找的,但如果我需要快速而肮脏地做这个,我会:
- Create a separate WPF application (so I could use the built-in document handling)
- Give the service the ability to interact with the desktop (note that you don't actually have to show anything on the desktop, or be logged in for this to work)
- Have the service run the application, and give it the data to print.
- 创建一个单独的 WPF 应用程序(这样我就可以使用内置的文档处理)
- 为服务提供与桌面交互的能力(请注意,您实际上不必在桌面上显示任何内容,也无需登录即可使用)
- 让服务运行应用程序,并为其提供要打印的数据。
You could probably also jigger this to print from a web browser that you run from the service (though I'd recommend building your own shell IE, rather than using a full browser).
您可能还可以通过从服务中运行的 Web 浏览器来进行打印(尽管我建议您构建自己的 shell IE,而不是使用完整的浏览器)。
For a more detailed (also free) solution, your best bet is probably to manually format the document yourself (using GDI+ to do the layout for you). This is tedious, error prone, time consuming, and wastes a lot of paper during development, but also gives you the most control over what's going to the printer.
对于更详细(也是免费)的解决方案,最好的办法可能是自己手动设置文档格式(使用 GDI+ 为您进行布局)。这很乏味、容易出错、耗时,并且在开发过程中会浪费大量纸张,但同时也让您可以最大程度地控制打印机的内容。
回答by Yann Trevin
Printing from a Windows service is really painful. It seems to work... sometimes... but finally it craches or throws an exception from time to time, without any clear reason. It's really hopeless. Officially, it's even not supported, without any explanation, nor any proposal for an alternate solution.
从 Windows 服务打印真的很痛苦。它似乎工作......有时......但最终它不时崩溃或抛出异常,没有任何明确的原因。真是没希望了。官方甚至不支持,没有任何解释,也没有任何替代解决方案的建议。
Recently, I have been confronted to the problem and after several unsuccessful trials and experimentations, I came finally with two viable solutions:
最近,我遇到了这个问题,经过几次不成功的尝试和实验,我终于找到了两个可行的解决方案:
- Write your own printing DLL using the Win32 API (in C/C++ for instance), then use it from your service with P/Invoke (works fine)
- Write your own printing COM+ component, then uses it from your service. I have chosen this solution with success recently (but it was third party COM+ component, not own written) It works absolutely fine too.
- 使用 Win32 API(例如在 C/C++ 中)编写您自己的打印 DLL,然后通过 P/Invoke 从您的服务中使用它(工作正常)
- 编写您自己的打印 COM+ 组件,然后从您的服务中使用它。我最近成功地选择了这个解决方案(但它是第三方 COM+ 组件,不是自己编写的)它也非常好用。
回答by Chris Marasti-Georg
I think we are going to go the third party route. I like the XSL -> HTML -> PDF -> Printer flow... Winnovative's HTML to PDFlooks good for the first part, but I'm running into a block finding a good PDF printing solution... any suggestions? Ideally the license would be on a developer basis, not on a deployed runtime basis.
我认为我们将走第三方路线。我喜欢 XSL -> HTML -> PDF -> 打印机流程... Winnovative 的HTML to PDF在第一部分看起来不错,但我在寻找一个好的 PDF 打印解决方案时遇到了障碍...有什么建议吗?理想情况下,许可证应基于开发人员,而不是基于已部署的运行时。
回答by Joel Lucsy
Printing from a service is a bad idea. Network printers are connected "per-user". You can mark the service to be run as a particular user, but I'd consider that a bad security practice. You might be able to connect to a local printer, but I'd still hesitate before going this route.
从服务打印是一个坏主意。网络打印机是“按用户”连接的。您可以将服务标记为以特定用户身份运行,但我认为这是一种糟糕的安全做法。您也许可以连接到本地打印机,但在走这条路之前我仍然犹豫不决。
The best option is to have the service store the data and have a user-launched application do the printing by asking the service for the data. Or a common location that the data is stored, like a database.
最好的选择是让服务存储数据,并让用户启动的应用程序通过向服务请求数据来进行打印。或者数据存储的公共位置,如数据库。
If you need to have the data printed as regular intervals, setup a Task event thru the Task Scheduler. Launching a process from a service will require knowing the user name and password, which again is bad security practice.
如果您需要定期打印数据,请通过任务计划程序设置任务事件。从服务启动进程需要知道用户名和密码,这又是一种糟糕的安全做法。
As for the printing itself, use a third-party tool to generate the report will be the easiest.
至于打印本身,使用第三方工具生成报告将是最简单的。
回答by Douglas Anderson
To answer your first question, this can be fairly straight forward depending on the data. We have a variety of Service-based applications that do exactly what you are asking. Typically, we parse the incoming file and wrap our own Postscript or PCL around it. If you layout is fairly simple, then there are some very basic PCL codes you can wrap it with to provide the font/print layup you want (I'd be more then happy to give you some guidance here offline).
要回答您的第一个问题,根据数据,这可能相当简单。我们有各种基于服务的应用程序,可以完全满足您的要求。通常,我们解析传入的文件并在其周围包裹我们自己的 Postscript 或 PCL。如果您的布局相当简单,那么您可以使用一些非常基本的 PCL 代码将其包装起来以提供您想要的字体/打印布局(我很乐意在此离线为您提供一些指导)。
One you have a print ready file you can send it to a UNC printer that is shared, directly to a locally installed printer, or even to the IP of the device (RAW or LPR type data).
如果您有打印就绪文件,您可以将其发送到共享的 UNC 打印机、直接发送到本地安装的打印机,甚至发送到设备的 IP(RAW 或 LPR 类型数据)。
If, however, you are going down the PDF path, the simplest method is to send the PDF output to a printer that supports direct PDF printing (many do now). In this case you just send the PDF to the device and away it prints.
但是,如果您要使用 PDF 路径,最简单的方法是将 PDF 输出发送到支持直接 PDF 打印的打印机(现在很多都支持)。在这种情况下,您只需将 PDF 发送到设备并打印出来。
The other option is to launch Ghostscriptwhich should be free for your needs (check the licensing as they have a few different version, some GNU, some GPL etc.) and either use it's built in print function or simply convert to Postscript and send to the device. I've used Ghostscript many times in Service apps but not a huge fan as you will basically be shelling out and executing a command line app to do the conversion. That being said, it's a stable app that does tend to fail gracefully
另一种选择是启动Ghostscript,它应该可以免费满足您的需要(检查许可,因为它们有几个不同的版本、一些 GNU、一些 GPL 等),并使用它内置的打印功能或简单地转换为 Postscript 并发送到装置。我已经在服务应用程序中多次使用 Ghostscript,但不是一个超级粉丝,因为您基本上会掏出并执行命令行应用程序来进行转换。话虽如此,它是一个稳定的应用程序,它确实容易优雅地失败
回答by Nick
I've done it. It's a pain in the A*s. The problem is that printing requires that GDI engine to be in place, which normally means that you have to have the desktop, which only loads when you're logged in. If you're attempting to do this from a Service on a Server, then you normally aren't logged in.
我已经做到了。这是A * s的痛苦。问题是打印需要 GDI 引擎到位,这通常意味着您必须拥有桌面,它仅在您登录时加载。如果您尝试从服务器上的服务执行此操作,那么你通常没有登录。
So first you can't run as the normal service user, but instead as a real user that has interactive login rights. Then you have to tweak the service registry entries (I forget how at the moment, would have to find the code which I can do tonight if you're really interested). Finally, you have to pray.
因此,首先您不能以普通服务用户的身份运行,而是以具有交互式登录权限的真实用户身份运行。然后你必须调整服务注册表项(我现在忘记了如何,如果你真的感兴趣,必须找到我今晚可以做的代码)。最后,你必须祈祷。
Your biggest long term headache will be with print drivers. If you are running as a service without a logged in user, some print drivers like to pop up dialogs from time to time. What happens when your printer is out of toner? Or out of paper? The driver may pop up a dialog that will never be seen, and hold up the printer queue because nobody is logged in!
您最大的长期头痛将是打印驱动程序。如果您在没有登录用户的情况下作为服务运行,某些打印驱动程序喜欢不时弹出对话框。当您的打印机没有碳粉时会发生什么?还是没纸了?驱动程序可能会弹出一个永远不会看到的对话框,并因为没有人登录而阻塞打印机队列!
回答by Omar Kooheji
If you can output to post script some printers will print anything that gets FTPed to a certain directory on them.
如果您可以输出到发布脚本,一些打印机将打印任何通过 FTP 传输到其上某个目录的内容。
We used this to get past the print credits that our university exposed on us, but if your service outputs to a ps then you can just ftp the ps file to the printer.
我们使用它来克服我们的大学向我们公开的打印信用,但是如果您的服务输出到 ps,那么您只需将 ps 文件 ftp 到打印机即可。
回答by Omar Kooheji
In answer to your question about PDF printing, I have not found an elegant solution. I was "shell" ing out to Adobe which was unreliable and required a user to be logged in at all times. To fix this specific problem, I requested that the files we process (invoices) be formatted as multi-page Tiff files instead which can be split apart and printed using native .NET printing functions. Adobe's position seems to be "get the user to view the file in Adobe Reader and they can click print". Useless.
在回答您关于 PDF 打印的问题时,我还没有找到一个优雅的解决方案。我正在“外壳”到 Adobe,这是不可靠的,并且要求用户始终登录。为了解决这个特定问题,我要求将我们处理的文件(发票)格式化为多页 Tiff 文件,而不是使用本机 .NET 打印功能将其拆分和打印。Adobe 的立场似乎是“让用户在 Adobe Reader 中查看文件,然后他们可以单击打印”。无用。
I am still keen to find a good way of producing quality reports which can be output from the web server...
我仍然渴望找到一种生成可以从 Web 服务器输出的质量报告的好方法......
回答by John Rusk
Printing using System.Drawing.Printing is not supported by MS, as per Yann Trevin's response. However, you might be able to use the new, WPF-based, System.Printing (I think)
根据 Yann Trevin 的回复,MS 不支持使用 System.Drawing.Printing 进行打印。但是,您也许可以使用新的、基于 WPF 的 System.Printing(我认为)