我是如何让PowerPoint能够多进程同时导出的

在我们目前的业务开发中,遇到了PPT转PDF的业务需求。如何能够无损并且快速的进行转换,是我们遇到的一个不大不小的问题。

经过各种调查研究,使用C#的COM接口直接操作微软家的Office PowerPoint,让其将PPT文件另存为PDF,是一个比较稳妥,资源消耗也比较小的好办法。

基本的代码如下图所示,很简单。

但是这是个单进程模式,转换效率跟不上,服务器利用率也不高。

怎么办?

多开几个进程不就好了!

于是,我就一口气打开了三个进程,然后……

根本跑不起来……

我在Google上找了找原因,在一个很不起眼的网页写着(原文记不清了,而且我再也没找到那个网页):

PowerPoint不像Word和Excel,PowerPoint只能单进程运行,同时只能执行一项导出指令

大概意思就是说,PowerPoint在进程内部维护了一个导出队列,同时只能有一个文件进行导出,其他的要排队,但是Word和Excel就能多进程运行。

是这样么?我开始了一次不太漫长的追寻之路。

太长不看版结论:是这样的,这项技术称为"MDI多文档窗口程序",但是Word和Excel可以通过命令行参数 "/w" 强行启动多个进程同时执行导出,而PowerPoint只能借助不同用户身份开启多个进程同时导出,详情请搜索“runas”命令。

首先,我去确定下这个“MDI”是如何工作的。

下面文字摘自网络:

多文档界面 (MDI) 允许创建在单个容器窗体中包含多个窗体的应用程序。象 Microsoft Excel 与 Microsoft Word 这样的应用程序就具有多文档界面。

MDI 应用程序允许用户同时显示多个文档,每个文档显示在它自己的窗口中。文档或子窗口被包含在父窗口中,父窗口为应用程序中所有的子窗口提供工作空间。例如:Microsoft Excel 允许创建并显示不同样式的多文档窗口。每个子窗口都被限制在 Excel 父窗口的区域之内。当最小化 Excel 时,所有的文档窗口也被最小化,只有父窗口的图标显示在任务栏中。

比较直观的展示就是:

以上两张图就是开启MDI和关闭MDI的进程展示。可以看到,当开始了MDI时,虽然打开了两个文档,但是实际上只有一个Word进程在工作。当关闭了MDI模式,每个文档都会新建一个Word进程。

微软官方的文档中关于新建Office程序的命令行参数,是这么记录的:

image

但是很遗憾,PowerPoint并不支持这个命令行参数,所有的PPT文档都是在一个PowerPoint进程中打开的。

官方并没有给我们一个方案,那么我们有没有其他的方案去实现单机多个PowerPoint进程呢?

我大概思考了下,有一下几个思路:

  1. 虚拟机

  2. Docker

  3. 沙盒软件(多开软件)

虚拟机

虚拟机采用了虚拟化技术,能够很完美的模拟出一个操作环境,那么就可以完美运行office程序,但是额外的性能消耗很大,单个PowerPoint程序的内存消耗在150M-300M之间,一个虚拟机的消耗能够轻松达到这个数值的五倍之多。本来单机能够支持二十个进程,结果现在只能支持四个,差距太大,不考虑。

Docker

Docker也是虚拟化技术,能够模拟出一套完全隔离的内存空间和系统资源。经过微软官方和Docker开发组长达两年的合作,Docker推出了完美支持windows系统的的docker for windows.

与之前推出的windows版不同,Docker for windows是完全针对于windows的内核开发。可以支持Windows Server和一个比较小的Nano windows镜像。

但是很遗憾,这次我们没法用,因为Docker不支持有UI界面的程序运行。

沙盒/多开软件

这个应该也是Windows使用过程中经常会遇到的软件。尤其是玩游戏的网友,应该都用过各种游戏的多开助手。网游为了限制游戏内资源分布,把握游戏发展进程,往往会限制单机运行客户端的数量,而各种助手又能破解掉这种限制。那么我们能不能使用这种方式去开启多个PowerPoint进程呢?

事实上是可以的,我这里测试使用的是windows最著名的沙盒软件 Sandboxie

将PowerPoint添加到Sandboxie中,然后点击运行,我们就可以惊喜的发现,任务管理器中出现了两个PowerPoint的进程。

这时候,我思考的问题是:Why?

为什么没有通过虚拟化技术,也能够骗过PowerPoint的识别,开启出两个进程呢?

先让我们来看看这两个程有什么区别。我这里使用了 **ProcessExplorer **软件来查看进程的详细信息。

左边是沙盒启动的进程,右边是正常启动的进程。

可以看到,两个进程启动的文件,运行目录,命令行参数之类的基本信息都完全一样,但是有两个地方不同:

1. 父进程ID

沙盒启动的进程,父进程id是一个不存在的进程,而正常启动的进程,父进程是window桌面进程 explorer.exe。

2. 启动用户名

沙盒启动的进程,用户名是匿名用户Anonymous,而正常启动的进程,用户名就是我们当前登陆的用户名。

事出有异必有妖,那么导致两个进程独立运行的原因,肯定就因为以上两个原因中的一个。

我使用了HideTools(一款能够修改进程信息的软件),修改了正常打开的PowerPoint程序的父进程id,如下图。

那么当我又正常打开了一个PowerPoint程序,会不会产生三个独立运行的进程呢?

事实证明,并没有。

那么,我们几乎能够确定,让PowerPoint能够多进程同时执行的关键点,就在于“打开程序的用户不同”上。

其实到了这里,我们大概能明白这是怎么一回事了。作为经常在Linux下开发程序的服务器端人员,这时候才想起来这么一回事,其实是有点羞愧的。

Linux下的权限管理和进程分配使用非常广泛,服务器程序的用户一般都是www-data,php-fpm的用户是php,管理员使用root账户,开发人员使用对文件拥有只读权限的dev账户等等。不同的用户,可访问和可分配的资源都是相互独立。互不干扰的。

而同样的,windows下也有着一套用户管理和访问限制体系。

在Linux下,我们可以使用sudo切换进程的执行用户,而在windows下,我们可以使用runas命令去达到同样的效果。

RUNAS 用法:
RUNAS [/noprofile | /profile] [/env] [/savecred | /netonly] /user:<UserName> program

RUNAS使用示例:
runas /noprofile /user:mymachine\administrator cmd
说明:使用本机上的Administrator管理员身份执行CMD,/noprofile为不加载该用户的配置信息。

runas /profile /env /user:mydomain\admin “mmc %windir%\system32\dsa.msc”
说明:使用本机上的admin身份扫行msc控制台。 /profile为指定加载用户配置文件。 /env 表示使用当前环境。

runas /env /user:user@domain.microsoft.com “notepad \”my file.txt\””
说明:使用域用户身份运行,并指定使用notepad打开my file.txt文档。

实际应用实例:
@echo off
runas /user:Administrator /sa “C:\Program Files\Internet Explorer\iexplore.exe”
说明:以管理员身份运行IE浏览器。

像这样,我们将命令保存为批处理后,只要在用户电脑上运行这个批处理(第一次输入管理员密码),以后用户只要双击该文件就可会以管理员身份执行命令中所指定的程序了。

那么我们只需要在服务器上预先建立几个账户,甚至可以在程序中动态创建,然后分配到一个合适权限的组(比如一个ppt用户组,只开放一个转换文件夹的读写权限),然后使用runas 命令,就能达到多进程同时执行,同时导出的效果。

还是最开始我们使用的四行代码,打包成exe文件,

然后在shell中使用runas,如下图,换几个用户多执行几次。

这里要指定命令行参数 /profile 加载用户配置文件,不然默认分配的内存是不够启动PowerPoint程序的。

然后~ BOOM!

我们成功启动了多个发布进程,并且都在正常发布。

由于runas必须手动输入密码,我们可以使用sanur等windows下的管道工具,或者指定rnas 的/savecred选项,做到免密启动。

如果有c#的编程基础,可以使用c#的Process类,指定进程启动信息StartInfo的username和password,就可以不使用这种命令行方式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容