利用Office Save as PDF or XPS 实现Office批传PDF
由于加班要转换Office文档及CAD为PDF,为了省事因此临时写个批量转换PDF工具。CAD已经有现成的一个叫Convert的工具,那就剩下Office这边的Word,Excel,PowerPoint的转换了。微软在Office 2007已经提供了一个叫save as pdf or xps的插件,但插件只能单个转换。因此网上搜了一下这方面的转换代码,搜来搜去很杂,itext,icreator等等,文档也不是很详细,于是想想微软应该提供了这方面的接口,查阅了一下MSDN,微软确实提供了.NET 调用Office com接口转换PDF的代码,以下简直封装的代码。
准备条件:
Office 12 dll Microsoft.Office.Interop.Word,Microsoft.Office.Interop.Excel.....
save as pdf插件
代码部分:
Word代码
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Core;
using System.Threading;
namespace ConvertToPDF.BaseClass
{
publicclass WordToPDF:OfficeToPDF
{
#region 初始化参数
ApplicationClass wordApplication =null;
Document wordDocument =null;
object paramMissing;
WdExportFormat paramExportFormat;
bool paramOpenAfterExport;
WdExportOptimizeFor paramExportOptimizeFor;
WdExportRange paramExportRange;
int paramStartPage =0;
int paramEndPage =0;
WdExportItem paramExportItem;
bool paramIncludeDocProps;
bool paramKeepIRM;
WdExportCreateBookmarks paramCreateBookmarks;
bool paramDocStructureTags;
bool paramBitmapMissingFonts;
bool paramUseISO19005_1;
object paramReadOnly;
#endregion
public WordToPDF()
{
paramMissing = Type.Missing;
paramExportFormat = WdExportFormat.wdExportFormatPDF;
paramOpenAfterExport =false;
paramExportOptimizeFor = WdExportOptimizeFor.wdExportOptimizeForPrint;
paramExportRange = WdExportRange.wdExportAllDocument;
paramStartPage =0;
paramEndPage =0;
paramExportItem = WdExportItem.wdExportDocumentContent;
paramIncludeDocProps =true;
paramKeepIRM =true;
paramCreateBookmarks = WdExportCreateBookmarks.wdExportCreateWordBookmarks;
paramDocStructureTags =true;
paramBitmapMissingFonts =true;
paramUseISO19005_1 =false;
paramReadOnly =true;
}
publicoverridevoid SaveAsPDF(string paramSourceFilePath, string paramExportFilePath)
{
try
{
object paramSourceDocPath = (object)paramSourceFilePath;
// Open the source document.
wordDocument = wordApplication.Documents.Open(
ref paramSourceDocPath, ref paramMissing, ref paramReadOnly,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing, ref paramMissing, ref paramMissing,
ref paramMissing);
// Export it in the specified format.
if (wordDocument !=null)
wordDocument.ExportAsFixedFormat(paramExportFilePath,
paramExportFormat, paramOpenAfterExport,
paramExportOptimizeFor, paramExportRange, paramStartPage,
paramEndPage, paramExportItem, paramIncludeDocProps,
paramKeepIRM, paramCreateBookmarks, paramDocStructureTags,
paramBitmapMissingFonts, paramUseISO19005_1,
ref paramMissing);
//通知成功
OnFinish(paramSourceFilePath, paramExportFilePath);
Thread.Sleep(1000);
}
catch (Exception ex)
{
OnError(ex, paramSourceFilePath, paramExportFilePath);
try
{
// Close and release the Document object.
if (wordDocument !=null)
{
wordDocument.Close(ref paramMissing, ref paramMissing,
ref paramMissing);
wordDocument =null;
}
}
catch (Exception e)
{
if (wordDocument !=null)
wordDocument =null;
}
}
}
publicoverridevoid Open()
{
wordApplication=new ApplicationClass();
}
publicoverridevoid Close()
{
try
{
// Close and release the Document object.
if (wordDocument !=null)
{
wordDocument.Close(ref paramMissing, ref paramMissing,
ref paramMissing);
wordDocument =null;
}
}
catch (Exception ex)
{
wordDocument =null;
}
try
{
if (wordApplication !=null)
{
wordApplication.Quit(ref paramMissing, ref paramMissing,
ref paramMissing);
wordApplication =null;
}
}
catch (Exception ex)
{
wordApplication =null;
ProcessManager.KillWordProcess();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
}
Excel代码
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Excel;
using Microsoft.Office.Core;
using System.Threading;
namespace ConvertToPDF.BaseClass
{
publicclass ExcelToPDF:OfficeToPDF
{
#region 参数定义
Microsoft.Office.Interop.Excel.ApplicationClass excelApplication =null;
Workbook excelWorkBook =null;
object paramMissing = Type.Missing;
XlFixedFormatType paramExportFormat = XlFixedFormatType.xlTypePDF;
XlFixedFormatQuality paramExportQuality = XlFixedFormatQuality.xlQualityStandard;
bool paramOpenAfterPublish;
bool paramIncludeDocProps;
bool paramIgnorePrintAreas;
object paramFromPage;
object paramToPage;
#endregion
public ExcelToPDF()
{
paramMissing = Type.Missing;
paramExportFormat = XlFixedFormatType.xlTypePDF;
paramExportQuality = XlFixedFormatQuality.xlQualityStandard;
paramOpenAfterPublish =false;
paramIncludeDocProps =true;
paramIgnorePrintAreas =true;
paramFromPage = Type.Missing;
paramToPage = Type.Missing;
}
publicoverridevoid Open()
{
excelApplication =new Microsoft.Office.Interop.Excel.ApplicationClass();
}
publicoverridevoid Close()
{
try
{
// Close the workbook object.
if (excelWorkBook !=null)
{
excelWorkBook.Close(false, paramMissing, paramMissing);
excelWorkBook =null;
}
}
catch (Exception ex)
{
excelWorkBook =null;
}
try
{
// Quit Excel and release the ApplicationClass object.
if (excelApplication !=null)
{
excelApplication.Quit();
excelApplication =null;
}
}
catch (Exception ex)
{
excelApplication =null;
ProcessManager.KillExcelProcess();
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
publicoverridevoid SaveAsPDF(string paramSourceFilePath, string paramExportFilePath)
{
try
{
// Open the source workbook.
excelWorkBook = excelApplication.Workbooks.Open(paramSourceFilePath,
paramMissing, paramMissing, paramMissing, paramMissing,
paramMissing, paramMissing, paramMissing, paramMissing,
paramMissing, paramMissing, paramMissing, paramMissing,
paramMissing, paramMissing);
// Save it in the target format.
if (excelWorkBook !=null)
excelWorkBook.ExportAsFixedFormat(paramExportFormat,
paramExportFilePath, paramExportQuality,
paramIncludeDocProps, paramIgnorePrintAreas, paramFromPage,
paramToPage, paramOpenAfterPublish,
paramMissing);
//完成通知
OnFinish(paramSourceFilePath,paramExportFilePath);
Thread.Sleep(1000);
}
catch (Exception ex)
{
// Respond to the error.
OnError(ex,paramSourceFilePath,paramExportFilePath);
try
{
// Close the workbook object.
if (excelWorkBook !=null)
{
excelWorkBook.Close(false, paramMissing, paramMissing);
excelWorkBook =null;
}
}
catch (Exception e)
{
// Close the workbook object.
if (excelWorkBook !=null)
excelWorkBook =null;
}
}
}
}
}
open打开一个Office进程(Word为Word.exe,Excel为Excel.exe进程,Close关闭此进程)。在转换Word中总会碰到一些意外(有时候是RPC不响应),当进程未正常关闭时则杀死此进程。
另外注意一点,在转换Word过程使用的是只读模式,否进出现意外后会弹出此Word文档副本操作,很麻烦。基类OfficeToPDF提供了事件通知机制,接口IOfficeToPDF提供了事件注册及公用的接口方法SaveAsPDF。事件主要用来控制异常和查看进度。
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConvertToPDF.BaseClass
{
publicclass PDFConvertEventArgs : EventArgs
{
public PDFConvertEventArgs()
{ }
public Exception Exception { set; get; }
publicstring SourceFilePath { set; get; }
publicstring ExportFilePath { set; get; }
}
publicinterface IOfficeToPDF
{
void SaveAsPDF(string paramSourceFilePath, string paramExportFilePath);
event EventHandler<PDFConvertEventArgs> Error;
event EventHandler<PDFConvertEventArgs> Finish;
void Open();
void Close();
}
publicabstractclass OfficeToPDF : IOfficeToPDF
{
#region IOfficeToPDF 成员
publicvirtualvoid SaveAsPDF(string paramSourceFilePath, string paramExportFilePath)
{
thrownew NotImplementedException();
}
publicevent EventHandler<PDFConvertEventArgs> Error;
publicevent EventHandler<PDFConvertEventArgs> Finish;
protectedvoid OnError(Exception ex)
{
if (Error !=null)
{
PDFConvertEventArgs args =new PDFConvertEventArgs();
args.Exception = ex;
Error(this, args);
}
}
protectedvoid OnError(Exception ex, string paramSourceFilePath, string paramExportFilePath)
{
if (Error !=null)
{
PDFConvertEventArgs args =new PDFConvertEventArgs();
args.Exception = ex;
args.SourceFilePath = paramSourceFilePath;
args.ExportFilePath = paramExportFilePath;
Error(this, args);
}
}
protectedvoid OnFinish()
{
if (Finish !=null)
{
PDFConvertEventArgs args =new PDFConvertEventArgs();
Finish(this, args);
}
}
protectedvoid OnFinish(string paramSourceFilePath, string paramExportFilePath)
{
if (Finish !=null)
{
PDFConvertEventArgs args =new PDFConvertEventArgs();
args.SourceFilePath = paramSourceFilePath;
args.ExportFilePath = paramExportFilePath;
Finish(this, args);
}
}
publicvirtualvoid Open()
{
thrownew NotImplementedException();
}
publicvirtualvoid Close()
{
thrownew NotImplementedException();
}
#endregion
}
}
转Word总会出现一些莫名其妙的问题,没办法只增加了一个杀死进程的类
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
namespace ConvertToPDF.BaseClass
{
class ProcessManager
{
//获取程序集
//private static Assembly _reflect = Assembly.Load("ExcelConvert");
[DllImport("kernel32.dll")]
privatestaticextern IntPtr _lopen(string lpPathName, int iReadWrite);
[DllImport("kernel32.dll")]
privatestaticexternbool CloseHandle(IntPtr hObject);
privatestaticint OF_READWRITE =2;
privatestaticint OF_SHARE_DENY_NONE =0x40;
privatestaticreadonly IntPtr HFILE_ERROR =new IntPtr(-1);
///<summary>
/// 判断文是否被占用
///</summary>
///
///
///
///<param name="filePath"></param>
///<returns></returns>
publicstaticbool FileIsUsing(string filePath)
{
bool result =false;
IntPtr vHandle = _lopen(filePath, OF_READWRITE | OF_SHARE_DENY_NONE);
if (vHandle == HFILE_ERROR)
{
result =true;
}
CloseHandle(vHandle);
return result;
}
///<summary>
/// 杀死EXCEL进程
///</summary>
publicstaticvoid KillExcelProcess()
{
KillProcess("Excel");
}
///<summary>
/// 杀死EXCEL进程
///</summary>
publicstaticvoid KillWordProcess()
{
KillProcess("Word");
}
///<summary>
/// 杀死进程
///</summary>
publicstaticvoid KillProcess(string processName)
{
System.Diagnostics.Process[] excelProcess = System.Diagnostics.Process.GetProcessesByName(processName);
foreach (System.Diagnostics.Process process in excelProcess)
{
if (process !=null)
{
process.Kill();
}
}
}
///<summary>
/// 杀死进程
///</summary>
publicstaticbool ProcessIsRun(string processName)
{
bool isRun=false;
System.Diagnostics.Process[] excelProcess = System.Diagnostics.Process.GetProcessesByName(processName);
foreach (System.Diagnostics.Process process in excelProcess)
{
if (process !=null)
isRun =true;
}
return isRun;
}
}
}
看一下简单调用的方式
word.Error +=new EventHandler<PDFConvertEventArgs>(office_Error);
word.Finish +=new EventHandler<PDFConvertEventArgs>(office_Finish);
word.Open();
IOfficeToPDF excel =new ExcelToPDF();
excel.Error +=new EventHandler<PDFConvertEventArgs>(office_Error);
excel.Finish +=new EventHandler<PDFConvertEventArgs>(office_Finish);
excel.Open();
word.SaveAsPDF(sourceFilePath, exportFilePath);
excel.SaveAsPDF(sourceFilePath, exportFilePath);
excel.Close();
word.Close();
代码很简单,忽忙写的,所以就不注释了。另外程序在运行的尽量不要直接关闭(所以我屏掉了关闭等按钮),否则像wordDocumnet这个没正常关闭,下次再转换的时候会引起一些不必要的麻烦。(基本是RPC不响应,估计频率调COM接口的问题,还有就是WORD不停弹只读副本的原因等等)
看下程序的运行效果:
时间关系简单封装后,做了100份批传测试没啥大问题。
现将源码发布出来,WordDocument关闭异常问题还没解决,有知道原因的可以指点或修正回发我一份。