前面几篇文章讲解了Excel开发的几个比较主要的也是比较重要的方面,比如菜单系统Excel对象模型自定义函数RTD函数异步自定义函数用户自定义任务面板等,在实际开发中我们还会遇到各种“千奇百怪”的问题,以及开发中的一些注意事项和技巧等,后面有空我会写文介绍。当我们的Excel外接应用程序开发好了之后,需要给用户使用,这就涉及到了应用程序的安装与部署,本文就简要介绍下Excel项目的安装和部署。

    和一般的.NET 中的Windows Form程序不同,Excel开发通常是一种插件式的开发机制,它需要借宿在Excel上,并通过调用Excel的API来实现特定的业务逻辑。宿主Excel在运行的时候,会根据当前用户以及Excel版本信息,读取注册表特定位置,以查找在本机当前用户下面注册的插件信息,然后逐个加载。这里面就涉及到了和安装部署相关的一些需要考虑的问题了。

一 插件安装部署时需要考虑的问题


Excel在安装部署的时候,需要考虑一些问题:

  • 插件的类型,是Document Level,还是Application Level,是基于VSTO开发还是Shared Add-in技术开发。这个对于安装部署有较大影响。
  • 判断待部署机器的位数,32位和64位机器Excel的插件信息在注册表的位置有所不同,对于64位操作系统,某些内容会写到\Wow6432Node\节点下。
  • 待部署用户的机器上是否安装有Excel,Excel的版本是多少,Excel的位数是多少,如果是安装的Office 2003 是否安装有SP3 补丁,以及补丁版本号是多少。这里需要说明的是,从Office 2010开始,Excel分为32位和64位版本,这两个版本的dll在一般情况下是不能够兼容的,在应用开发中,如果我们的插件决定兼容这两个版本,那么还需要对于不同的目标机器需要分别编译发布相应的dll;如果不兼容,则还需要判断Office的版本
  • 如果是使用.NET 技术开发,需要判断用户机器上是否安装有.NET Framework以及Framework的版本。
  • 如果用户安装的是Excel 2003,如果用到了某些功能,需要判断用户是否安装了相应的补丁,如果没有安装,需要静默安装。
  • 安装完成后,相应的权限设定,比如对于某些目录,需要添加到安全目录,这样Excel在打开自己的带有宏文件的目录时不会提示不安全。

    在部署插件的时候,以上问题在安装部署的时候是需要进行考虑,并通过代码的方式获取的。还有一些条件,比如用户有可能是安装的绿色版或者不完全版的Excel,这些奇奇怪怪的问题我们都需要考虑。 但是如果考虑到了以上条件,插件的安装和部署应该可以达到90%以上。

    要了解Excel插件的安装部署我们需要清楚Excel是如何加载插件的,下面介绍下Excel插件的加载和运行机制。

二 Excel插件的加载及运行机制


    这里以VSTO Add-in为例,Shared Add-in原理和机制类似。

    当我们使用Office开发工具来开发Add-in的时候,我们实际上是创建了一个用托管代码编写的能够被Office加载的程序集(assembly)。程序集加载之后,Add-in就能够响应Office应用程序发起的事件了。Add-in也可以调用Office开放的对象模型来扩展其功能,当然也可以使用.NET 类库中提供的各种功能。

    程序集和Office的Com组件进行交互是通过Office提供的称之为Primary Interop Assembly (PIA)来实现的。

    如果有多个VSTO创建的Add-in部署到了目标机器,在Office启动的时候,每一个Add-in会被加载到各自不同的AppDomain中,这样极大地提高了插件的稳定性,意味着如果有一个Add-in工作不正常,不会影响其他Add-in的功能,其次,当Office应用程序关闭的时候,所有的Add-in的程序集都可以从内存中清除。

    虽然Add-in的程序集是开发中我们最要关注的东西,但是Office在发现和加载我们编写的Add-in的时候,其他几个组件和部分也发挥着重要作用。这对熟悉Add-in的安装和部署有着很重要的作用。

2.1 注册表项

    Excel 通过一系列的注册表项来加载插件。在部署的时候,我们也需要将我们插件的相关信息写入到目标机器的注册表中。通常在Vista及以上版本的Windows中对注册表的操作需要获得管理员权限。

    a) 在部署的时候,我们需要确定是部署到CurrentUser还是LocalMachine节点下。

LocalMachine and Current User in  Register

    一般的软件在安装的时候都会提示该软件是仅适用我,还是所有人。如果是仅适用于我的话,就会将注册表信息保存在CurrentUser下,这样只有该用户登录才能看到该软件;如果是选择所有人的话,就会写到LocalMachine节点下。

    使用Visual Studio创建的Add-in都可以部署到Current user下,但是并不是所有的都可以不会素到Local machine下,这可能和Offfice版本以及Add-in的部署方式有关。

    还有一点需要注意的是,如果应用程序部署到了Local machine下面,那么在Excel插件中不会显示在Add-in外接程序列表中。

Addin was not shown in Local machine

    所以,一般的,我们会将应用程序部署到Current User下。

b) Office的版本信息

    Office 2010和Office 2013可以加载HKEY_LOCAL_MACHINE 和HKEY_CURRENT_USER下面的Add-in,要加载HKEY_LOCAL_MACHINE 下面的Add-in需要安装976477补丁。

c) 部署类型

    如果使用ClickOne部署Add-in,add-in只能在Current user下面部署,这是因为ClickOne仅支持在HKEY_CURRENT_USER下面读写注册表信息。如果要使机器上的所有用户都能够使用Add-in,那么需要使用Windows Installer来部署Add-in

2.2 注册表值

    这里以部署到HKEY_CURRENT_USER为例,LOCAL_MACHINE下面类似。

Addin register in HKEY_CURRENT_USER

     一般滴,Excel各产品会在Root\Software\Microsoft\Office\application name\Addins\add-in 下面寻找对应的注册表项。这也是最重要的一个注册表项值,上图列出的是一个我们在之前文章中创建的那个简单的名为YYAddin的VSTO程序。对于Shared Add-in开发的插件,该注册表信息类似,不过也有些区别后面会说明。

    这个节点下面的注册表键值对需要说明一下。

  • Description字段: 类型为REG_SZ,必须,该字段为对该Addin的简要描述,该表述会出现在Opption->Add-Ins菜单中。如下图:

VSTO ADDIN DESCRIPTION

  • FriendlyName,字段类型为REG_SZ,必须。这个实在开发工具->Com加载相中显示的名称。默认是改Addin的Id,如下图。

VSTO ADDIN FRIENDLYNAME

  • LoadBehavior字段REG_DWORD类型,必须。这个字段比较重要,用来指明插件的加载行为和状态 (加载或者卸载),默认为3,表示当应用程序加载时,即加载该插件。其枚举值为http://msdn.microsoft.com/en-us/library/bb386106.aspx#LoadBehavior ,在我们调试程序的时候,如果程序出现异常,通常Excel会将该插件的该项值改为2或者其他非3的值,表示下次请启动的时候不会加载。
  • Manifest,REG_SZ类型,对于VSTO开发的应用程序,该字段必须设定。该字段指明该插件的部署后的程序集清单的位置,可以指定为本机,网络共享,或者一个位于Web服务器上的位置。对于Shared Add-in类型的程序,该字段不必须,他会有另外一套机制来加载插件。

    基本上对于VSTO 应用程序,只需要将以上部分的注册表项写入到目标机器上即可完成安装部署。

2.3 VSTO Runtime

    使用VSTO创建的Add-in程序,终端用户也需要安装VSTO的运行时环境。该运行时环境包含一些非托管组件以及一些托管的程序集。非托管的程序集被加载到Add-in的程序集中。托管程序集提供的对象模型能够使得Add-in代码可以调用Excel开放的API扩展其功能。

2.4 加载逻辑

    当用户打开Office 软件的时候,Office使用部署的程序及清单来定位和加载Add-in的程序集,如下图所示:

Addin work with Office

以VSTO创建的Add-in为例, 步骤如下:

  1. Office应用程序检查位于注册表项中的使用VSTO创建的Addin
  2. 如果找到了Add-in的注册表信息,Office会在家VSTOEE.dll,该dll会加载VSTOLoader.dll.这些都是VSTO 运行时环境中的非托管dll。
  3. VSTOLoader.dll会加载.NET Framework,并启动VSTO运行时环境中的托管代码。
  4. VSTO运行时环境会检查该Add-in的程序集清单,检查是否有更新,有的话下载更新。
  5. VSTO运行时环境会进一步执行一系列安全性检查
  6. 如果Add-in运行运行,VSTO运行时环境会使用部署的程序集清单以及应用程序的清单来检查程序集是否有更新,如果有新的程序集,则运行时会下载最新的程序集到ClickOne的缓存中放到用户机器上。
  7. VSTO运行时环境会创建一个新的应用程序域,然后将Add-in的程序集加载进来。
  8. VSTO运行时环境调用ThisAddIn_Startup方法然后Add-in插件启动。

三 实施


    对于Excel插件的部署,这里分两块介绍,一个是VSTO项目的部署,一个是Com Shared Add-in类型项目的部署。

3.1 VSTO创建的插件的项目部署

    关于VSTO的部署,对于Document Level的项目文件,直接可以创建一个部署项目或者使用ClickOnce部署。非常简单,博客园中,Mr.Brooks同学写过一篇有关VSTO部署的文章 VSTO 学习笔记(十三)谈谈VSTO项目的部署,这里不再赘述了。

    从上图的注册表信息的Manifest可以看出,VSTO项目的程序集清单其实是一个.vsto文件,它是VSTO项目部署时的安装文件,用文本编辑器打开,可以看到他是一个xml文件,包含了VSTO项目的具体信息,如.NET运行时版本,依赖的程序集,数字签名等信息。

VSTO FILE DETAIL

    该文件默认会使用Visual Studio Tools For Office Execution Engine打开,该组件包含在该组件包含于Visual Studio Tools For Office 运行时,因此客户端若要运行VSTO程序,还需要安装Visual Studio Tools For Office 运行时环境。Visual Studio 2010 Tools for Office Runtime 可以在这里下载。实际上,如果客户机器上安装了VSTO运行时环境,只需要把编译好的debug目录拷贝到目标机器,部署的时候,只需双击.vsto这个文件就可以完成安装和部署。

Install VSTO USING VSTORT

    如果将插件作为单独的产品发布,以上安装部署没有任何问题。但是很多时候,插件是作为产品的一部分发布的。所以我们需要一种更灵活的方式来对项目进行部署。插件的部署在本质上就是对注册表项的读写,了解这一点就很容易了。下面就简要介绍一下如何通过手动写入注册表信息的方式部署VSTO项目。

    如前所述,Excel加载插件是通过查找特定注册表位置来加载的,所以我们只需要在这些位置写入注册表信息即可。以部署我们的YYAddin为例,首先找到开发机上Visual Studio为我们创建好的注册表项,然后右键导出。保存为注册表类型后缀为.reg的文件。

deploy vsto using register

    用记事本打开该reg文件。这个文件就是该Add-in在注册表项中的所有内容了。我们在实际部署的时候,可以创建一个exe文件,获取用户的系统位数,和安装目录,修改该文件中的跟路径,以及Manifest路径,然后再动态生成一份该文件,导入到目标机器即可以完成安装和部署。

VSTO REGEDIT FILE

3.2 Com SharedAddin创建的插件的项目部署

    和VSTO开发的插件不同,使用Shared Add-in开发的插件实际上是一个Com组件,除了在Root\Software\Microsoft\Office\application name\Addins\add-in 下面有相应的信息之外,在ClassRoot中还有一些信息,这里以我们在前面文章中创建的名为YYSharedAddin的项目为例。先看看在Excel节点下的注册表信息:

SharedAddin register in excel

    部署的方法和VSTO相同,只需要将该注册表项导出,然后写入到目标机器即可。但是这只是第一步。细心的读者会发现和VSTO项目相比,缺少了Manifest这个键值对,Excel仅仅只要有一个名为YYSharedAddin.Connect 的插件需要加载,但是这个插件的程序集在哪里呢?我们接着在注册表中搜索YYSharedAddin.Connect。可以看到如下结果。

SharedAddin register in excel class root 2

SharedAddin register in excel class root

   其中ProgId的值为YYSharedAddin.Connect ,这个ProgId以及 该节点的Guid即为我们在创建Shared Add-in的时候人为指定的。如下图:

SharedAddin Project     在前面的文章中讲过,要编译Shared Add-in以及我们使用类库编写的UDF函数,RTD函数以及CTP,这些其实都是Com组件,需要管理员权限运行Visual Studio,并且在项目的属性->编译选项中选中注册为Com组件。如下图:

SharedAddin Register for Com interop 

    Visual Studio在编译和调试的时候实际上是帮我们调用了一下指令:

    regasm " D:/YYUDF/YYAddIn/YYSharedAddin/bin/Debug/YYSharedAddin.dll " /codebase /s

    该语句即可将相关的注册表信息写入到注册表项中去了。这样连同之前导入的注册表,使用Shared Add-in创建的加载项的部署就完成了。

3.3 其它相关模块的部署

    除了我们的主程序之外,通常我们使用Com组件方式写的UDF函数,RTD函数,以及CTP等,也都需要写入到注册表中,最简单的方法和上面一样,直接使用微软提供的Regasm工具,读取程序集中的元数据,并将所需的项添加到注册表中。在部署的时候我们只需要将regasm这个工具打包一起发布,然后安装的时候调用该命令即可。

    还有一个问题,就是如果您是使用的.NET 2.0开发的Shared Add-in程序,目标机器上安装的是Office 2003,那么需要注意的是,Excel 2003 和Word 2003 可能在加载使用.NET 2.0创建的插件的时候可能会出现问题,因此,需要安装名为office2003-KB907417-FullFile-ENU.exeextensibilityMSM.msi的Office补丁。所以在部署的时候,需要判断用户的Excel版本,以及该版本是否已经安装了该补丁,如果没有,需要首先静默安装此补丁。

四 结语


    Excel插件的安装和部署是比较重要的一个环节,由于和传统的Windows Form应用程序不同,作为一种寄宿的插件,它需要往注册表中写入东西。本文首先介绍了Excel加载插件的步骤,Excel插件的注册表组成部分。随后介绍了使用VSTO和Shared Add-in创建插件的部署方式及注意事项。原理都是类似,就是往注册表里面写入注册信息。对于Shared Add-in创建的插件,除了写入必要的注册表信息之外,还需要使用regasm来将dll注册为COM可见,其实也就是通过工具来帮助我们往注册表里写入信息。使用类库方式开发的UDF函数,RTD函数以及CTP都需要使用regasm的方式注册,才能在Excel中进行调用。最后介绍了在Office 2003中要使用插件必须要安装的两个补丁,完成了这些步骤,您开发的插件基本上就可以部署到绝大部分的目标机器上了。

    希望本文对您了解Excel插件的加载机制和安装部署有所帮助。