一. 应用场景

开发一个课件在线学习功能,要求将WORD, EXCEL, PPT类型课件可在线打开学习;最初设想使用第三方office插件,无奈价格太高放弃使用;

我们最终的方案是:利用office自身的另存为功能,在服务器将上传的office文件转化为pdf格式,然后网页打开pdf文件实现在线学习功能;

项目实现方案:新建一个windows自启的service安装在服务器,这个服务里面会建立一个HttpListener,用于监听文件转换的请求,请求来了后交给ServiceHandle处理,ServiceHandle会调用ConvertHelper把指定目录下的office文件转化为pdf,并放在相同目录下,以供在线学习使用;

二. 工具及环境

VS2019

Office:本地开发2016版;服务器2010版

开发环境 win10

服务器环境 windows server 2012 R2

VS开发使用到的nuget包:NetOffice

三. 创建windows server项目

基本按照这个思路开发出一个基础service完全没问题;这里需要提醒下的是:项目的文件路径不要带有空格,否则在执行bat批处理操作时会出现问题。

四. 使用NetOffice实现文件转换

上面只是创建一个服务, 真正转换的核心功能还没开始,这时我们需要利用NetOffice插件;

项目目录:

image.png

利用nuget包管理器安装所需包,这是项目的packages.config文件:

转换核心代码:ConvertHelper.cs

public class ConvertHelper

{

public static void ConvetToPdf(string sourcePath, string targetPath)

{

if (!File.Exists(sourcePath))

{

throw new Exception(string.Format("文件{0}不存在", sourcePath));

}

if (File.Exists(targetPath))

{

throw new Exception(string.Format("目标文件{0}已存在", targetPath));

}

LogHelper.Info("开始转换:" + Path.GetFileName(sourcePath));

var targetDirectory = Path.GetDirectoryName(targetPath);

if (!Directory.Exists(targetDirectory))

{

Directory.CreateDirectory(targetDirectory);

}

var ext = Path.GetExtension(sourcePath).ToLower();

if (ext == ".ppt" || ext == ".pptx")

{

ConvertPptToPdf(sourcePath, targetPath);

}

else if (ext == ".doc" || ext == ".docx")

{

ConvertDocumentToPdf(sourcePath, targetPath);

}

else if (ext == ".xls" || ext == ".xlsx")

{

ConvertExcelToPdf(sourcePath, targetPath);

}

else

{

LogHelper.Info("{0}不支持转换pdf", sourcePath);

return;

}

if (File.Exists(targetPath))

{

LogHelper.Info("转换成功:" + Path.GetFileName(sourcePath));

}

else

{

LogHelper.Info("转换失败:" + Path.GetFileName(sourcePath));

}

}

///

/// 转换ppt文件到pdf文件(不支持超时终止)

///

///

///

private static void ConvertPptToPdf(string sourcePath, string targetPath)

{

NetOffice.PowerPointApi.Application application = null;

NetOffice.PowerPointApi.Presentation presentation = null;

var cts = new CancellationTokenSource();

var thread = new Thread(() =>

{

try

{

application = new NetOffice.PowerPointApi.Application();

presentation = application.Presentations.Open(sourcePath, true, NetOffice.OfficeApi.Enums.MsoTriState.msoTrue, false);

presentation.SaveCopyAs(targetPath, NetOffice.PowerPointApi.Enums.PpSaveAsFileType.ppSaveAsPDF);

}

catch (Exception ex)

{

if (ex.InnerException != null && ex.InnerException is ThreadAbortException)

{

LogHelper.Info("ConvertPptToPdf: {0}操作超时", Path.GetFileName(sourcePath));

}

else

{

LogHelper.Error(ex, "ConvertPptToPdf: {0}出现异常", Path.GetFileName(sourcePath));

}

}

finally

{

if (presentation != null)

{

presentation.Close();

presentation = null;

}

if (application != null)

{

application.Quit();

application.Dispose();

application = null;

}

//killProccess("POWERPNT");

}

});

cts.Token.Register(() =>

{

thread.Abort();

});

cts.CancelAfter(Program.MaxThreads * 1000);

thread.Start();

thread.Join();

GC.Collect();

GC.WaitForPendingFinalizers();

}

///

/// 转换word文件到pdf文件(支持超时终止)

///

///

///

private static void ConvertDocumentToPdf(string sourcePath, string targetPath)

{

NetOffice.WordApi.Application application = null;

NetOffice.WordApi.Document document = null;

var cts = new CancellationTokenSource();

var thread = new Thread(() =>

{

try

{

application = new NetOffice.WordApi.Application();

document = application.Documents.Open(sourcePath);

document.ExportAsFixedFormat(targetPath, NetOffice.WordApi.Enums.WdExportFormat.wdExportFormatPDF);

}

catch (Exception ex)

{

if (ex.InnerException != null && ex.InnerException is ThreadAbortException)

{

LogHelper.Info("ConvertDocumentToPdf: {0}操作超时", Path.GetFileName(sourcePath));

}

else

{

LogHelper.Error(ex, "ConvertDocumentToPdf: {0}出现异常", Path.GetFileName(sourcePath));

}

}

finally

{

if (document != null)

{

document.Close();

document = null;

}

if (application != null)

{

application.Quit();

application.Dispose();

application = null;

}

//killProccess("WINWORD");

}

});

cts.Token.Register(() =>

{

thread.Abort();

});

cts.CancelAfter(Program.MaxThreads * 1000);

thread.Start();

thread.Join();

GC.Collect();

GC.WaitForPendingFinalizers();

}

private static void ConvertExcelToPdf(string sourcePath, string targetPath)

{

NetOffice.ExcelApi.Application application = null;

NetOffice.ExcelApi.Workbook wookbook = null;

var cts = new CancellationTokenSource();

var thread = new Thread(() =>

{

try

{

application = new NetOffice.ExcelApi.Application();

wookbook = application.Workbooks.Open(sourcePath);

wookbook.ExportAsFixedFormat(NetOffice.ExcelApi.Enums.XlFixedFormatType.xlTypePDF, targetPath);

}

catch (Exception ex)

{

if (ex.InnerException != null && ex.InnerException is ThreadAbortException)

{

LogHelper.Info("ConvertExcelToPdf: {0}操作超时", Path.GetFileName(sourcePath));

}

else

{

LogHelper.Error(ex, "ConvertExcelToPdf: {0}出现异常", Path.GetFileName(sourcePath));

}

}

finally

{

if (wookbook != null)

{

wookbook.Close();

wookbook = null;

}

if (application != null)

{

application.Quit();

application.Dispose();

application = null;

}

//killProccess("EXCEL");

}

});

cts.Token.Register(() =>

{

thread.Abort();

});

cts.CancelAfter(Program.MaxThreads * 1000);

thread.Start();

thread.Join();

GC.Collect();

GC.WaitForPendingFinalizers();

}

public static void CleanProccess()

{

LogHelper.Info("CleanProccess Start");

killProccess("WINWORD");

killProccess("EXCEL");

LogHelper.Info("CleanProccess Finish");

}

private static void killProccess(string appName)

{

// Store all running process in the system

Process[] runingProcess = Process.GetProcesses();

for (int i = 0; i < runingProcess.Length; i++)

{

// compare equivalent process by their name

if (string.Equals(runingProcess[i].ProcessName, appName, StringComparison.OrdinalIgnoreCase))

{

try

{

// kill running process

runingProcess[i].Kill();

LogHelper.Info("Kill {0} [{1}]", appName, runingProcess[i].Id);

}

catch (Exception ex)

{

if (ex is System.InvalidOperationException)

{

//进程已经关闭

}

else

{

LogHelper.Error(ex, "Kill {0} [{1}] Error", appName, runingProcess[i].Id);

}

}

}

}

}

}

ServiceListener监听http请求,端口号默认8091;

public ServiceListener()

{

_stop = new ManualResetEvent(false);

_idle = new ManualResetEvent(false);

_busy = new Semaphore(Program.MaxThreads, Program.MaxThreads);

_listener = new HttpListener();

_listenerThread = new Thread(HandleRequests);

}

public void Start()

{

var url = String.Format(@"http://localhost:{0}/", Program.ListenerPort); // Port=8091

LogHelper.Info("Listenning Start:" + url);

_listener.Prefixes.Add(url);

_listener.Start();

_listenerThread.Start();

}

五. 系统调用http服务,转换文件

public void ConvertToPdf(string serviceUrl, string sourcePath, string pdfPath)

{

var url = $"{serviceUrl}?srcPath={sourcePath}&tarPath={pdfPath}";

using (var webClient = new WebClient())

{

var result = webClient.DownloadString(url);

}

}

至此,开发完毕,本地开发完成;

六. 本地测试功能

注册服务,执行注册服务.bat

启动服务,执行启动服务.bat

查看服务运行情况

image.png

但是测试转换时遇到了问题,日志错误为 "Office 检测到该文件有问题。为帮助保护您的计算机,此文件无法打开。":

2020-05-02 09:04:22:248 Info [Thread9] 开始转换:a10a54166224453abdd8d4b809f15449.ppt

2020-05-02 09:04:25:379 Exception [Thread10] ConvertPptToPdf: a10a54166224453abdd8d4b809f15449.ppt出现异常 Exception:

System.Runtime.InteropServices.COMException (0x80004005): See inner exception(s) for details. ---> System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.Runtime.InteropServices.COMException: Presentations.Open : Office 检测到该文件有问题。为帮助保护您的计算机,此文件无法打开。

--- 内部异常堆栈跟踪的结尾 ---

在 System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)

在 System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)

在 NetOffice.Invoker.MethodReturn(COMObject comObject, String name, Object[] paramsArray)

在 NetOffice.Invoker.MethodReturn(COMObject comObject, String name, Object[] paramsArray)

在 NetOffice.PowerPointApi.Presentations.Open(String fileName, Object readOnly, Object untitled, Object withWindow)

在 LMS.DocumentConvertService.ConvertHelper.LMS.DocumentConvertService\Service\ConvertHelper.cs:行号 75

2020-05-02 09:04:33:477 Info [Thread9] 转换失败:a10a54166224453abdd8d4b809f15449.ppt

我才用了其中2种较简单解决方案:

修改代码,在ProjectInstaller.cs中ProjectInstaller类中重载OnAfterInstall

[RunInstaller(true)]

public partial class ProjectInstaller : System.Configuration.Install.Installer

{

public ProjectInstaller()

{

InitializeComponent();

}

protected override void OnAfterInstall(IDictionary savedState)

{

try

{

base.OnAfterInstall(savedState);

System.Management.ManagementObject myService = new System.Management.ManagementObject(

string.Format("Win32_Service.Name='{0}'", this.serviceInstaller1.ServiceName));

System.Management.ManagementBaseObject changeMethod = myService.GetMethodParameters("Change");

changeMethod["DesktopInteract"] = true;

System.Management.ManagementBaseObject OutParam = myService.InvokeMethod("Change", changeMethod, null);

}

catch (Exception)

{

}

}

}

SC程序修改, 允许与桌面进行交互

用批处理的方式实现,加入如下命令到>启动服务.bat文件中

sc config MonitorService type=interact type=own

至此,本地开发环境转换服务成功运行。

接下来准备上服务器!!

服务器将office转pdf文件,Windows服务-Office转PDF文件相关推荐

  1. 管理服务器没有响应怎么办,win10启动windows服务显示服务没有响应控制功能怎么解决...

    有win10旗舰版64位系统用户在启用windows服务的时候,显示服务没有响应控制功能的提示,只是系统出错导致的,有很多用户遇到这种问题的时候不知道要怎么解决的,那么在win10系统里遇到这种问题的 ...

  2. Windows向Linux自动传输文件,Windows向虚拟机Linux传输文件方法

    在Windows中装了个centOS,进行文件操作时,把mv写成了rm,然后就悲剧了.. 赶紧从网上找来文件的具体内容,然后由Windows向Linux挂载共享文件夹. 具体做法: 在Windows中 ...

  3. linux下find查找带有指定权限的文件(windows下编译的源代码文件)

    find -type f -perm -o=x 查找用户在windows下编译的源代码文件 转载于:https://blog.51cto.com/axlrose/1357610

  4. 蓝牙文件传输服务linux,openwrt蓝牙文件传输

    openwrt支持: USB Supprot------------------------------- kmod-usb-ohci kmod-usb-uhci kmod-usb-storage-e ...

  5. 怎样搜索计算机文档,怎么样快速搜索电脑文件 Windows系统秒搜电脑文件

    不知大家有没有遇到过这样的情况,当电脑里储存的文件越来越多的时候,就会经常找不到需要用到的文件放在什么地方,遇到急需该文件却又忘了放在什么位置的时候是最气的!而如果我们使用Windows自身的全盘搜索 ...

  6. 微软服务器搭建ngrok,ngrok搭建(Windows服务端+Windows客户端)

    1.go环境搭建(需要Linux系统) 1)下载源码,可以在http://www.golangtc.com/download 2)将其解压到/usr/local目录下: tar -C /usr/loc ...

  7. 怎么快速搜索服务器里的文件,Windows中快速搜索指定文件夹

    Windows自带的记事本因方便小巧常被大家使用,但记事本的"状态栏"和"自动换行"却是对冤家,当你通过菜单栏开启"自动换行"... Win ...

  8. 【windows服务】将windows服务打包成安装文件

    1.在解决方案下添加一个Setup Project 如果没有安装文件则用下面的地址下载后安装:https://visualstudioclient.gallerycdn.vsassets.io/ext ...

  9. linux 定时传送文件,Windows与Linux之间定时文件传输

    需要的朋友点击链接,这里有更详细的实现过程 一.获取WinSCP windows上装上Winscp程序,使用这个程序通过sftp协议把本地的文件传输到linux服务器上. winscp下载链接 二.编 ...

最新文章

  1. python基础教程书-7本Python必读的入门书籍
  2. 迈向成功的关键在于执行(摘自李开复博士的《做最好的自己》)
  3. SpringMVC深度探险(二) —— SpringMVC概览
  4. 解决spring配置c3p0连接池,tomcat无法正常启动
  5. 15.4.1 杠杆利用类型参数推断
  6. Taro+react开发(51) 数组对象和数组得处理
  7. s3c2440的内存管理机制
  8. html扩展xhtml在线,告别html,迎来xhtml
  9. 鲲鹏迁移第一批吃螃蟹的人,践行技术国际化
  10. 三星Galaxy S22系列零部件开始量产:搭载骁龙898 最早1月亮相
  11. 中国大陆物联网驶入快车道 台商抢上车
  12. scrum 11.27
  13. access字段类型varchar_Access SQL语句创建表对应的数据类型名称
  14. 在国内使用DNS服务器的一个对比分析
  15. 寒假刷刷算法题(13)
  16. OC5021B降压型恒流驱动控制芯片,关断时间可调
  17. 豆瓣是用python开发的吗_Google、知乎、豆瓣、网易都在用Python Web开发!
  18. Visual Paradigm创建Java类图时如何绘制实线箭头?
  19. 1688搜索店铺列表 API
  20. vpc经典网络区别_阿里云经典网络与VPC网络互通的实现

热门文章

  1. Zookeeper Watch监听
  2. linux查看当前用户终端,Linux----基本命令的使用(vi命令,查看文件内容,显示进程,切换用户等)...
  3. python ide如何运行_ide - 如何运行Python程序?
  4. 总结计算机语言的基本元素,认识程序设计中基本元素教案.doc
  5. 方幂序列 c+~+_C ++编程中的Trigraph序列
  6. 合并排序算法排序过程_外部合并排序算法
  7. java list过滤重复的数据_List 去除重复数据的 5 种正确姿势!
  8. android 网络程序下载,Android之网络文件下载
  9. 北京soul_Soul高智商情侣,机器人博士邂逅科技记者,跨越1200公里来相爱
  10. Java PushbackReader mark()方法与示例