关于使用PdfCreator .NET COM包装器打印Excel工作表及旧版本适配的技术问询
PDFCreatorHelper 优化与PDF Creator 2.0+兼容指南
嘿,针对你手里的旧版PDFCreatorHelper类,我整理了使用优化和新版本兼容的具体方案,咱们一步步来看:
首先先贴出你提供的现有代码片段,方便对照:
public class PDFCreatorHelper { //全局声明 private clsPDFCreator _pdfcreator = null; public string CreatedFile { get; private set; } public bool ActiveXError { get { return _ActiveXError; } } private bool _ActiveXError = false; private void _pdfcreator_eError() { MessageBox.Show("PDF Cre..."); }
一、现有工具类的使用优化建议
1. 完善资源生命周期管理
旧版代码最大的问题是没处理clsPDFCreator这个ActiveX控件的资源释放,长期运行容易导致内存泄漏和ActiveX资源占用。建议实现IDisposable接口,主动清理COM资源:
public class PDFCreatorHelper : IDisposable { private clsPDFCreator _pdfcreator = null; public string CreatedFile { get; private set; } public bool ActiveXError { get; private set; } public PDFCreatorHelper() { try { _pdfcreator = new clsPDFCreator(); _pdfcreator.eError += _pdfcreator_eError; } catch (Exception ex) { ActiveXError = true; // 这里换成日志记录比弹框更友好,非UI场景也能用 // Logger.Error("Failed to initialize PDFCreator ActiveX", ex); } } private void _pdfcreator_eError() { ActiveXError = true; // 别硬编码弹窗了,改成事件通知或者抛出具体异常,灵活度更高 // OnErrorOccurred?.Invoke("PDF Creator runtime error"); } // 实现IDisposable,确保COM资源被释放 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing && _pdfcreator != null) { _pdfcreator.Close(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_pdfcreator); _pdfcreator = null; } } ~PDFCreatorHelper() { Dispose(false); } }
2. 增强错误处理与灵活性
- 移除硬编码的
MessageBox.Show:弹窗在后台服务或控制台程序里完全没用,改成事件回调或者抛出自定义异常,让调用方决定如何处理错误。 - 补充日志记录:只靠
ActiveXError标志很难排查问题,建议加入日志框架(如Serilog、NLog)记录错误详情。
3. 参数化核心逻辑
把Excel文件路径、工作表名称、输出PDF路径这些做成方法参数,不要硬编码,让工具类更通用:
public bool PrintExcelSheetToPdf(string excelFilePath, string sheetName, string outputPdfPath) { if (ActiveXError || _pdfcreator == null) return false; try { // 这里用Office Interop处理Excel打印,记得也要释放Excel的COM资源 var excelApp = new Microsoft.Office.Interop.Excel.Application(); var workbook = excelApp.Workbooks.Open(excelFilePath); var worksheet = workbook.Sheets[sheetName]; // 指定PDF Creator打印机 excelApp.ActivePrinter = "PDFCreator"; worksheet.PrintOut(OutputFileName: outputPdfPath); CreatedFile = outputPdfPath; // 清理Excel资源 workbook.Close(false); System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); return true; } catch (Exception ex) { ActiveXError = true; // 记录错误日志 return false; } }
二、PDF Creator 2.0+ 版本兼容方案
PDF Creator 2.0之后彻底弃用了旧的clsPDFCreator ActiveX接口,改用全新的COM API(命名空间PDFCreator.COM),以下是适配步骤:
1. 引用新版本COM组件
在项目的“添加引用”→“COM”列表里找到PDFCreator COM Library(新版本名称可能略有不同),添加引用到项目中。
2. 替换旧的ActiveX对象
用PDFCreatorApplication和Printer类代替旧的clsPDFCreator,示例代码:
using PDFCreator.COM; public class PDFCreatorNewHelper : IDisposable { private PDFCreatorApplication _pdfApp; private Printer _pdfPrinter; public string CreatedFile { get; private set; } public bool InitializationError { get; private set; } public PDFCreatorNewHelper() { try { _pdfApp = new PDFCreatorApplication(); _pdfApp.Initialize(); _pdfPrinter = _pdfApp.Printer; // 可以指定PDF Creator的配置文件,比如"Default" _pdfPrinter.DefaultProfile = "Default"; } catch (Exception ex) { InitializationError = true; // 记录初始化错误日志 } } public bool PrintExcelSheetToPdf(string excelFilePath, string sheetName, string outputPdfPath) { if (InitializationError || _pdfApp == null) return false; try { var excelApp = new Microsoft.Office.Interop.Excel.Application(); var workbook = excelApp.Workbooks.Open(excelFilePath); var worksheet = workbook.Sheets[sheetName]; // 用PDF Creator的实际打印机名称 excelApp.ActivePrinter = _pdfPrinter.Name; // 打印到PDF Creator队列 worksheet.PrintOut(); // 等待打印作业完成,新版本必须等作业结束才能保存 var job = _pdfApp.Jobs.Last; while (!job.IsFinished) { System.Threading.Thread.Sleep(100); } // 保存生成的PDF到指定路径 job.SaveAs(outputPdfPath); CreatedFile = outputPdfPath; // 清理资源 job.Release(); workbook.Close(false); System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); return true; } catch (Exception ex) { InitializationError = true; // 记录错误日志 return false; } } public void Dispose() { if (_pdfApp != null) { _pdfApp.Shutdown(); System.Runtime.InteropServices.Marshal.ReleaseComObject(_pdfApp); _pdfApp = null; } if (_pdfPrinter != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(_pdfPrinter); _pdfPrinter = null; } } }
3. 关键注意事项
- 权限配置:打开PDF Creator的设置,找到“COM访问”选项并开启,同时确保你的应用程序有足够权限(比如管理员权限,避免UAC拦截)。
- 打印机名称:不要硬编码打印机名称,通过
_pdfPrinter.Name获取正确的名称,避免环境差异导致的问题。 - 作业状态等待:新版本的打印作业需要等待完成后才能保存,否则会出现文件未生成或损坏的情况。
三、额外优化建议
- 摆脱Office Interop依赖:如果不想部署Office组件,可以改用EPPlus、NPOI等开源库读取Excel内容,再用iTextSharp或PdfSharp生成PDF,减少部署复杂度。
- 批量处理支持:增加批量打印多个工作表或多个Excel文件的方法,提高处理效率。
- 配置文件驱动:把PDF Creator的打印机名称、默认配置文件等参数存入appsettings.json或配置文件,避免硬编码,方便环境切换。
内容的提问来源于stack exchange,提问作者Vojtěch Dohnal




