http://blog.youkuaiyun.com/mcai4gl2/article/details/7294625
前一阵子做了一个生成报表的小project,生成的报表是关于股价的记录。没有什么现成的包和第三方程序给我们用,听说WPF渲染的页面可以之间存成PDF,不过只是道听途说,没敢真正实践,最后还是用了自己以前搞过的方法,Office Interop,在一个word文档中插入很多placeholder搞成template,然后用C#代码动态把PlaceHolder变成数据,然后保存。这个方法其实挺强大,不过有几个限制和不爽的地方。第一,程序运行的机器上要有Office安装,word是必须的,如果要生成图的话,还需要Excel. 第二,.NET Office Interop本质上还是COM的封装,性能和稳定性就不能太苛求了。第三,Office Interop搞起来还是挺烦的。抱怨了半天,不过这个方法还是可行的。不过最后要求生成PDF形式的报表,但是Office没有PDF生成的支持,这怎么办?想起自己每每需要生成PDF文件的时候直接用PDFCreator虚拟打印机就可以了,查了一下,果然,PDFCreator有COM API. 这下问题解决了。
在C#中如何调用PDFCreator生成PDF文件呢?
第一步:安装PDFCreator (这个好像是废话)
第二步:创建C#项目,加入PDFCreator.exe COM引用
第三步:参见如下代码:
- public override void Process(ITask task, int index)
- {
- if (!File.Exists(Path.Combine(FromLocation, FromFilename)))
- {
- throw new FileNotFoundException("File: " + Path.Combine(FromLocation, FromFilename) + " does not exists");
- }
- Monitor.Enter(lockObject);
- clsPDFCreator creator = null;
- try
- {
- creator = new clsPDFCreator();
- creator.eError += new __clsPDFCreator_eErrorEventHandler(creator_eError);
- creator.eReady += new __clsPDFCreator_eReadyEventHandler(creator_eReady);
- String paramters = "/NoProcessingAtStartup";
- if (!creator.cStart())
- {
- throw new Exception("Cannot launch PDFCreator. Error: " + Error);
- }
- var opt = creator.cOptions;
- opt.UseAutosave = 1;
- opt.UseAutosaveDirectory = 1;
- opt.AutosaveDirectory = this.ToLocation;
- opt.AutosaveFormat = 0;
- opt.AutosaveFilename = this.ToFilename;
- creator.cOptions = opt;
- creator.cClearCache();
- creator.cDefaultPrinter = "PDFCreator";
- if (!creator.cIsPrintable(Path.Combine(FromLocation, FromFilename)))
- {
- throw new Exception("File: " + Path.Combine(FromLocation, FromFilename) + " is not printable.");
- }
- creator.cPrintFile(Path.Combine(FromLocation, FromFilename));
- creator.cPrinterStop = false;
- Ready = false;
- var duration = new TimeSpan(0, 0, 0, TimeoutInSec);
- DateTime lastCheck = DateTime.Now;
- DateTime startTime = lastCheck;
- while (!Ready && ((lastCheck - startTime) < duration))
- {
- System.Threading.Thread.Sleep(500);
- lastCheck = DateTime.Now;
- }
- creator.cPrinterStop = true;
- Thread.Sleep(1000);
- creator.cClose();
- if (!Ready)
- {
- throw new Exception("PDF creation failed. This maybe due to timeout.");
- }
- }
- finally
- {
- Monitor.Exit(lockObject);
- }
- }
- void creator_eReady()
- {
- this.Ready = true;
- }
- void creator_eError()
- {
- Error = creator.cError.Description;
- }
代码很好懂,自己很懒,没有把代码重新写成一个Project,直接把Project中的代码贴上了,大家要用的话,还要稍微修改一下。要说的一点是PDFCreator不支持多线程,所以如果程序本身是多线程的话,需要在代码中增加一个锁机制,保证PDF生成的调用是单线程的。还有打印机的名字用的是默认值,没有修改,不过这些问题是难不倒各位看官的。