VanGo-VSIX制作

1. 预备知识

  1. 单个基本模版制作: VS自定义项目模版

  2. 多个工程模版制作:Creating project template using VSIX extension for Visual Studio 2012

  3. 自定义VS的MVC的基架: Creating a Custom Scaffolder for Visual Studio

  4. 创建VSPackage:

  5. 制作工程或项目模版的时候还会用到IWizard这个接口,主要控制在模版生成的时候动态的做一些事情: How to: Use Wizards with Project Templates, 当然这个程序集放到必须放到全局缓冲区才能在模版生成的时候调用

  6. Nuget基本概念和使用: https://www.nuget.org/

  7. 全局缓冲区(GAC)本地路径:

    • C:\Windows\Microsoft.NET\assembly\GAC_MSIL
  8. VS插件扩展路径:

    • C:\Users\win7831\AppData\Local\Microsoft\VisualStudio\12.0\Extensions
  9. VS工程运行时临时文件路径:

    • C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files
  10. T4模版基本使用 : 你必须懂的 T4 模板:深入浅出

2. 预备工具

  1. VS开发包(必须) :Visual Studio Software Development Kit (SDK)

  2. 模版制作的VS插件(必须): SideWaffle Template Pack

  3. T4模版调试工具 :tangible T4 Editor 2.3.0

  4. 基于MVC5的基架插件 : Happy Scaffolding for MVC5

  5. Nuget包制作及使用: NuGetPackageExplorer

  6. VS开发者工具,可以在安装目录下找到,具体示版本而定, 里面可以使用下面工具,就不用全世界去找了

    • 本机工具地址: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts\Developer Command Prompt for VS2013
    • 程序集加入全局缓冲区工具: gacutil.exe
    • 程序集生成公钥标记的签名工具 : sn.exe
  7. 打包.NET程序的第三方插件: InstallShield Limited Edition

  8. Wix Toolset 制作安装包工具:

    1. Wix Toolset安装包(必须)
    2. VS2013插件(必须)
    3. 参考: Installing VSIX package via WiX installer
  9. VS 2013压缩脚本插件(必须): Web Essentials 2013.5

3. 工程结构

  1. 工程说明图

[图片上传失败...(image-d1b4fd-1571983320144)]

  1. 工程依赖图

[图片上传失败...(image-e12d1b-1571983320144)]

  1. 新建插件工程

[图片上传失败...(image-4ac5a6-1571983320144)]

4. VanGo.VSIX制作步骤

对于初学着来说,很多都是非常细小的步骤或者配置的问题,这里不做详细的每一步的制作,细节太多,但是上面的预备知识中有步骤需要一步一步做的例子,这非常有用,本人也是基于上面别人的资料来做的,下面的步骤只是针对自己制作过程中的大步骤以及自己遇到的问题的总结

  1. VSIX: 首先得了解VanGo平台的模版都是VS的插件,VS可以通过各种插件来扩展功能, 这里有一些VSIX的概念,下图展示,VSIX是一个标准的VS插件安装包类型,不同的基于VSIX的工程从本质上来说只是默认生成VS框架设计的指定模式,包括默认引用的程序集, 定义各种插件的配置文件,以什么样的形式导入VS而已,VanGo平台中就用到下面四种不同的工程实现
    [图片上传失败...(image-f0f424-1571983320144)]

  2. ProjectTemplate: VanGo插件安装最基本的就是模版制作,分为ProjectTemplate和ItemTemplate,他们的工程结构类似,实现原理相同,只是VSIX引入的时候区分,VS才能在不同时候使用不同模版,他们都基于一个重要的文件类型(.vstemplate),这个文件定义了模版的基本信息,参考MSDN, 下图显示VanGo平台下的VanGo.ProjectTemplate.vstempalte文件,注意里面safeprojectname类似的模版参数,VS这样定义可以在生成模版时根据具体用户输入信息等定义模版内容,而且模版参数可以在模版文件的任何位置使用,参考MSDN

    [图片上传失败...(image-e99956-1571983320144)]

    1. 自己遇到的坑,上图中的safeprojectname.Application这个模版参数,在传入VanGoProject.Application.vstemplate模版后所有的safeprojectname成了上面的值,比如用户输入Test, 工程名就为Test.Application,而模版中的所有safeprojectname不是Test而是Test.Application(Stackoverflow Issue),要高版本才支持,可是我升级了还是不能用CopyParameters这个参数,替代方法,使用向导WIzard在进入模版前拦截,手动又把safeprojectname改回来
      public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
      {
      
          if (replacementsDictionary.ContainsKey("$safeprojectname$"))
          {
              string[] tempName = replacementsDictionary["$safeprojectname$"].Split('.');
              replacementsDictionary["$safeprojectname$"] = tempName[0];
          }
      }
      
    2. 一个工程导出为模版的时候会自动生成.vstemplate这个文件,这样比较方便,不用每一个文件添加,但是生成的模版一定是不符合我们的要求的,需要自己更改, 模版的基本信息,哪些文件名需要生成时重命名,哪些文件可以用模版参数进行替换等等,需要耐心修改,下面只是示例
      <Folder Name="Shared" TargetFolderName="Shared">
        <ProjectItem ReplaceParameters="true" TargetFileName="_Layout.cshtml">_Layout.cshtml</ProjectItem>
        <ProjectItem ReplaceParameters="true" TargetFileName="_Layout.js">_Layout.js</ProjectItem>
        <ProjectItem ReplaceParameters="true" TargetFileName="Error.cshtml">Error.cshtml</ProjectItem>
      </Folder>
      <ProjectItem ReplaceParameters="true" TargetFileName="$safeprojectname$WebViewPageBase.cs">VanGoProjectWebViewPageBase.cs</ProjectItem>
      <ProjectItem ReplaceParameters="true" TargetFileName="web.config">web.config</ProjectItem>
      
  3. TemplateWizard: 模版文件是静态的,怎么在模版生成时动态控制模版生成,就要用到模版向导,基本逻辑是这样的:

    1. 新建Wizard向导工程,继承IWizard接口,实现方法,注意IWizard定义的方法的使用及调用顺序,其次重要的是EnvDTE的使用,这个理解为运行时VS的一个实例对象,这样就可以对VS和模版为所欲为了,参考GitHub: 例子

    2. 为向导程序集增加签名并生成PublicTokenKey(只是程序集签名的一个缩写标识而已,用来作为gac中的唯一标识,相当于GUID)

    3. 模版.vstemplate文件中指定用程序集作为向导,这里用到了PublicTokenKey来引用

    4. 把向导程序集放入GAC中,下面显示详细步骤

      签名步骤
      [图片上传失败...(image-6bdfb6-1571983320144)]
      引用方式
      [图片上传失败...(image-ff4808-1571983320144)]
      GAC路径
      [图片上传失败...(image-b82d8e-1571983320144)]

    5. 替代放入GAC中方法 : 今天思考为什么一定要把TemplateWizard放入gac中,这样的话VSIX不能把程序集添加到GAC中,还要重新做一个MSI之类的安装包,参考Visual Studio Extension Deployment,最后发现VSIX中把TemplateWizard按照Assembly的assets加载进来,在创建模版时同样可以引用到此程序集,参考 How to properly embed a custom wizard assembly in VSIX template project in VS 2013?,这样感觉非常完美,就不用通过命令行把程序集添加到GAC中了

    6. vstemplate中的WizardExtension中使用IWizard的dll扩展中replacementsDictionary所有值, 调用方法dll和值的情况如下:

      1. 注意: 在下面值中我修改了一个值和添加了一个值, 但是在接下来的application的模版生成中这些变化没有带到application里面, 说明两者之间是独立的,不能跨项目传值, 即使在父模版下面多个子模版也是不行的, 改变的值只能在当前模版内的工程里用
      <WizardExtension>
          <Assembly>VanGoTemplateWizard, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=270c7df44e506ac1</Assembly>
          <FullClassName>VanGoTemplateWizard.WebChildWizard</FullClassName>
      </WizardExtension>
      
      WebChildWizard: 键: $guid1$值: 01e6bc37-1f12-4a53-8a8f-b81b20baedc6
      
      // 中间有10个guid,省略
      
      WebChildWizard: 键: $guid10$值: 7e18b938-e50a-4326-9c4b-51cc5490d3fe
      
      WebChildWizard: 键: $time$值: 2/24/2017 10:05:17 AM
      
      WebChildWizard: 键: $year$值: 2017
      
      WebChildWizard: 键: $username$值: win7831
      
      WebChildWizard: 键: $userdomain$值: win7831-PC
      
      WebChildWizard: 键: $machinename$值: WIN7831-PC
      
      WebChildWizard: 键: $clrversion$值: 4.0.30319.36373
      
      WebChildWizard: 键: $registeredorganization$值: ChangeValue(自己改的值,原来为空)
      
      WebChildWizard: 键: $runsilent$值: False
      
      WebChildWizard: 键: $wizarddata$值: (vstempalte中自己定义的WizardData下面的所有信息包含于此)
          <packages repository="extension" repositoryId="VanGo.VSIX..5b483547-33a7-44d5-a6f0-bc859b449cfa" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
          <package id="Antlr" version="3.5.0.2" />
          <package id="Castle.Core" version="3.3.3" />
          <package id="Castle.Core-log4net" version="3.3.3" />
          <package id="Castle.LoggingFacility" version="3.3.0" />
          ... ...
      
      WebChildWizard: 键: $solutiondirectory$值: c:\users\win7831\documents\visual studio 2013\Projects\VanGoWeb7\
      
      WebChildWizard: 键: $projectname$值: VanGoWeb7
      
      WebChildWizard: 键: $safeprojectname$值: VanGoWeb7
      
      WebChildWizard: 键: $currentuiculturename$值: en-US
      
      WebChildWizard: 键: $installpath$值: C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE
      
      WebChildWizard: 键: $specifiedsolutionname$值: 
      
      WebChildWizard: 键: $exclusiveproject$值: False
      
      WebChildWizard: 键: $destinationdirectory$值: c:\users\win7831\documents\visual studio 2013\Projects\VanGoWeb7\VanGoWeb7\VanGoWeb7
      
      WebChildWizard: 键: $targetframeworkversion$值: 4.5.1
      
      WebChildWizard: 键: AddValue值(自己添加的值): 8ae594fd-d6c4-46e9-9053-6a043ae0b82d
      
  4. Scaffolder: 基于MVC的基架或脚手架,在VSIX引用中属于MEF,同样也会被放入到全局缓冲区,我们可以在GAC的路径中看到他,但是这个是VSIX安装时自动拷贝进去的,所以才会有上面替代gac的思考,VanGo.Scaffolder是基于Sidewaffle插件新建的插件工程,可以快速开发基于MVC的基架,基本逻辑实现如下

    1. 继承微软的基架代码工厂类CodeGeneratorFactory, 定义代码生成的信息CodeGeneratorInformation, 创建代码生成实例

    2. 继承CodeGenerator, 在覆盖方法中创建UI控件, 代码生成具体控制

    3. UI中使用WPF的MVVM来绑定变量,代码生成中使用T4模版来实现模版的生成

    4. 自己遇到的坑: 在生成模版的时候,由于需求要生成嵌套的模版,基于T4模版不能实现,所以只好手动获取DTE实例,再自己写入文件流的方式来动态的添加嵌套模版,这种方法虽然不规范,但也是无奈之举,相当于只有一个cshtml页面用到了标准的T4模版,T4模版的好处相当于在模版中无障碍使用c#,实现动态生成模版的效果,就如上面的ProjectTempalte中的Wizard的功能,十分酷炫,也是MVC生成模版的标准形式,简单示例如下:

      <#@ template language="C#" HostSpecific="True" #>
      <#@ output extension=".cshtml" #>
      <#@ include file="Imports.include.t4" #>
      <#
      // The following chained if-statement outputs the file header code and markup for a partial view, a view using a layout page, or a regular view.
      if(IsPartialView) {
      #>
      <#
      } else if(IsLayoutPageSelected) {
      #>
      @{
          ViewBag.Title = "<#= ViewName#>";
      <#
      if (!String.IsNullOrEmpty(LayoutPageFile)) {
      #>
          Layout = "<#= LayoutPageFile#>";
      <#
      }
      #>
      }
      <h2>欢迎使用VanGo平台</h2>
      <h2><#= ViewName#></h2>
      <#
      } else {
      #>
      @{
          Layout = null;
      }
      <!DOCTYPE html>
      <html>
      <head>
          <meta name="viewport" content="width=device-width" />
          <title><#= ViewName #></title>
      </head>
      <body>
      <#
          PushIndent("    ");
      }
      #>
      <#
      if(!IsPartialView && !IsLayoutPageSelected) {
      #>
      <div> 
      </div>
      <#
      }
      #>
      <#
      // The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
      #>
      <#
      if(!IsPartialView && !IsLayoutPageSelected) {
          ClearIndent();
      #>
      </body>
      </html>
      <#
      }
      #>
      
    5. VanGo.Scaffolder类图关系
      [图片上传失败...(image-12f4c8-1571983320144)]

  5. NuGet: 专门写一下,因为自己花了太多时间去了解它的使用,以及依赖方法,在模版中继承Nuget包,自己制作nuget包,自己被坑的地方也很多,大致有如下

    1. 吐槽: 在制作模版是要了解工程依赖的nuget包关系, 这些nuget包有来自package的包,有来自.net本来就有的包,也有奇葩的本来.net就有的包,但是mvc5需要高版本还是什么原因又依赖于package中下载的,一团乱麻,导致我做了一张依赖关系图, 更坑的是很多library的名字和package中文件夹的名字不一样,十分想骂人,这就算了, 各种library名字看着很重复,多个s,少个s,不同工程中的nuget包依赖的版本不一样,但是在web的工程中的web.config又可以指定老版本统一调用某一个版本,各种模版建好后library程序集加载错误的bug,真是想骂人,一个感觉哪里都有nuget,哪里的nuget都不一样,因为一个依赖System.Runtime的库在模版制作好后就是加载报错,排查了一个星期左右,连微软都说这是.net的bug,下了补丁还是不行,改IIS的运行时还是不行, 清理工程运行时缓存还是不行, 最后发现在模版生成的时候, 在web.config中因为我在csproj文件中引用了此类库,不知什么时候多加了一个运行时Assembly的标签,导致的奇葩报错,真是要跪了,吐槽归吐槽,还是总结一下在制作VISX中需要用到nuget的地方以及注意事项
      [图片上传失败...(image-725b3b-1571983320145)]
    2. csproj文件使用nuget: 因为是基于MVC的工程制作的ProjectTempalte,所以在依赖的地方全是标准的nuget依赖方法,类库都放在packages文件夹下,这是nuget生成的标准文件夹,如下所示,指定了路径的Refernece就是nuget还原的包,而没指定的则是.net中自带的程序集,指定工程版本会引用到不同的位置,就像gac一样的,还要注意MSbuild文件类型中Reference下面的标签使用,参考Common MSBuild Project Items
      1. Include: 指定依赖的程序集,包含Version,Culture,PublicKeyToken,一般同一个公司的PublicKeyToken是一样的,不会由于版本升级而变
      2. SpecificVersion: 指定为true的代表告诉project指定加载这个version的程序集,如果为false,则会去package文件夹下寻找相似可代替的程序集,版本不同没关系,只要程序集名字一样就行,唉,这真是,为了编译成功,什么都不顾了..
      3. Private: 这个和工程中Properties中的copy local对应,true则表示会拷贝到最终的bin下的生成路径中去,false则不会拷贝,注意当没有这个标签的时候默认值是true
      4. HintPath: 依赖的程序集的相对路径
        <Reference Include="System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
            <Private>True</Private>
            <SpecificVersion>False</SpecificVersion>
            <HintPath>..\..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
        </Reference>
        <Reference Include="System.ComponentModel.Composition" />
        <Reference Include="System.Data.DataSetExtensions" />
        <Reference Include="System.Net.Http" />
        <Reference Include="System.Net.Http.Formatting, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
            <SpecificVersion>False</SpecificVersion>
            <HintPath>..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll</HintPath>
        </Reference>
        <Reference Include="System.Runtime.Caching" />
        
    3. packages.config生成nuget信息: 当用nuget还原工程中依赖的包时,换原好的包就会在pacakge.config中记录还原的包的信息,一开始都是我自己手动加进去的,too young, too simple,这里面的信息是根据.csproj文件里面的依赖信息生成的
      1. id: 这是Reference中的程序集名字
      2. version: 同version
      3. targetFramework: 这取决于新建的工程的.net版本,不是此程序集的版本...
      <?xml version="1.0" encoding="utf-8"?>
      <packages>
          <package id="Antlr" version="3.5.0.2" targetFramework="net452" />
          <package id="Castle.Core" version="3.3.3" targetFramework="net452" />
          <package id="VanGo" version="0.1.0.0" targetFramework="net452" />
      </packages>
      
    4. vstemplate中的nuget: 标准的MVC模版生成后会把nuget包全部加载完成,VanGo平台的模版也同样要实现这个功能,不过目前都是本地的nuget包生成的依赖关系,实现的逻辑是
      1. 在vstemplate中的WizardData中加入pacakges的标签包含依赖的包,这里的repositoryId是引用此模版的VSIX的Product ID,里面定义pakcage的每个包信息,只需提供程序集名字和version即可

        <WizardData>
            <packages repository="extension" repositoryId="VanGo.VSIX..5b483547-33a7-44d5-a6f0-bc859b449cfa">
                <package id="Castle.Core" version="3.3.3"/>
                <package id="Castle.Core-log4net" version="3.3.3"/>
                <package id="Castle.LoggingFacility" version="3.3.0"/>
                <package id="Castle.Windsor" version="3.3.0"/>
                <package id="Castle.Windsor-log4net" version="3.3.0"/>
                <package id="Newtonsoft.Json" version="8.0.2" />
                <package id="System.Collections.Immutable" version="1.1.36.0"/>
                <package id="Nito.AsyncEx" version="3.0.1"/>
                <package id="log4net" version="1.2.10"/>
        
                <package id="VanGo" version="0.1.0.0"/>
                <package id="VanGo.Core" version="0.1.0.0"/>
                <package id="VanGo.Application" version="0.1.0.0"/>
                <package id="VanGo.Web.Api" version="0.1.0.0"/>
            </packages>
        </WizardData>
        
      2. 在VSIX中新建文件夹为packages, 这里用.nupkg的nuget包来引用,这是nuget包的格式,经过加密的二进制文件,我们可以用NuGet Package Explorer制作自己的nuget包,也可以发布到nuget galllery上面

        注意: 这里的每个nupkg包的properties必须把Build Action为Content, 然后Include in Visx设置为true
        [图片上传失败...(image-86d0f5-1571983320145)]

        NuGet Package Explorer
        [图片上传失败...(image-cd6b72-1571983320145)]

  1. VSPackage制作

    参考: VS2013在右键菜单添加命令插件开发

    1. vsct文件解析
    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <!--这两个文件位于: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VSSDK\VisualStudioIntegration\Common\Inc-->
      <!--用于定义目标菜单的guid和id值-->
    <Extern href="stdidcmd.h"/>
    <Extern href="vsshlids.h"/>
    <!--定义包的Guid-->
    <Commands package="guidVanGo_VSP_ShortCutsPkg">
     <Groups>
          <!--Group元素定义了目标菜单的guid和id-->
          <Group guid="guidVanGo_VSP_ShortCutsCmdSet" id="MyMenuGroup" priority="0">
            <!--定义了将命令添加到主菜单(guidSHLMainMenu) 里面的Edit(IDM_VS_MENU_EDIT)下面-->
            <!--guid和id的值已经在stdidcmd.h和vsshlids.h(C:\Program Files (x86)\Microsoft Visual Studio 12.0\VSSDK\VisualStudioIntegration\Common\Inc)这两个文件里定义了,而这两个文件已经在vsct文件的开头就已经使用Extern元素引入了,所以就不需要我们再去定义了-->
            <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>        
          </Group>
          <Group guid="guidVanGo_VSP_ShortCutsCmdSet1" id="MyMenuGroup1" priority="0">
            <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN"/>
          </Group>
        </Groups>
        <!--菜单命令使用Button元素来表示的-->
         <Buttons>
         <!--Button元素的guid和id属性是该命令的唯一标识, 这两个属性值分别在项目的Guids.cs和PkgCmdID.cs文件里定义了-->
          <!--priority表示命令在目标菜单的排列优先级-->
          <Button guid="guidVanGo_VSP_ShortCutsCmdSet" id="cmdidVanGoShortCuts" priority="0" type="Button">        
            <!--Parent子元素表示要将我们的命令添加到哪个菜单下面,如工具、帮助、右键菜单, id属性的值是Group元素的id属性值-->
            <Parent guid="guidVanGo_VSP_ShortCutsCmdSet" id="MyMenuGroup" />
            <!--Icon元素是命令前的小图标,其属性值是在GuidSymbol元素定义的-->
            <Icon guid="guidImages" id="bmpPic1" />
            <!--控制命令动态显示-->
            <CommandFlag>DynamicVisibility</CommandFlag>
            <!--动态更改显示文本-->
            <CommandFlag>TextChanges</CommandFlag> 
            <Strings>
              <!--定义了命令的显示字符串, 动态更改所以没有默认值-->
              <ButtonText></ButtonText>
            </Strings>        
          </Button>
          <!--服务切换快捷命令-->
          <Button guid="guidVanGo_VSP_ShortCutsCmdSet1" id="cmdidVanGoShortCuts1" priority="1" type="Button">
            <Parent guid="guidVanGo_VSP_ShortCutsCmdSet1" id="MyMenuGroup1" />
            <Icon guid="guidImages" id="bmpPic1" />
            <CommandFlag>DynamicVisibility</CommandFlag>
            <CommandFlag>TextChanges</CommandFlag>
            <Strings>
              <ButtonText></ButtonText>
            </Strings>
          </Button>
          
        </Buttons>
        <Bitmaps>
          <Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
        </Bitmaps>
      </Commands>
      <!--在Commands标签后面可以指定上面命令同时显示在多个地方-->
       <CommandPlacements>
        <!--同时显示在html的代码编辑框中-->
        <CommandPlacement guid="guidVanGo_VSP_ShortCutsCmdSet" id="MyMenuGroup" priority="0">
          <Parent guid="HtmlEditorWindowLibra" id="IDMX_HTML_SOURCE"/>
        </CommandPlacement>
        <CommandPlacement guid="guidVanGo_VSP_ShortCutsCmdSet1" id="MyMenuGroup1" priority="1">
          <Parent guid="HtmlEditorWindowLibra" id="IDMX_HTML_SOURCE"/>
        </CommandPlacement>
      </CommandPlacements>
      <!--命令绑定快捷键-->
      <KeyBindings>
        <!--暂时没找到cshtml的editor的ID, 所以这个应该是全局的, 或者用guidVSStd97全局的guid-->
        <KeyBinding guid="guidVanGo_VSP_ShortCutsCmdSet" id="cmdidVanGoShortCuts" editor="guidHtmlEditor" key1="VK_F1" mod1="Alt"/>
        <KeyBinding guid="guidVanGo_VSP_ShortCutsCmdSet1" id="cmdidVanGoShortCuts1" editor="guidVSStd97" key1="VK_F8" mod1="Alt"/>
      </KeyBindings>
      <!--定义上面所有使用的变量-->
       <Symbols>
        <!--定义包的guid-->
        <GuidSymbol name="guidVanGo_VSP_ShortCutsPkg" value="{b799221e-83d6-4548-9031-7959470b18ce}" />
        <!--html中的guid-->
        <GuidSymbol name="guidHtmlEditor" value="{8b382828-6202-11d1-8870-0000f87579d2}"></GuidSymbol>
        
        <!-- This is the guid used to group the menu commands together -->
        <GuidSymbol name="guidVanGo_VSP_ShortCutsCmdSet" value="{79e392eb-e4f9-45c6-8438-153a71eb7b67}">
          <IDSymbol name="MyMenuGroup" value="0x1020" />
          <IDSymbol name="cmdidVanGoShortCuts" value="0x0100" />
        </GuidSymbol>
    
        <GuidSymbol name="guidVanGo_VSP_ShortCutsCmdSet1" value="{42839474-CBBD-4AB9-94F1-1DF7BAEC07B4}">
          <IDSymbol name="MyMenuGroup1" value="0x1021" />
          <IDSymbol name="cmdidVanGoShortCuts1" value="0x0101" />
        </GuidSymbol>
            <!--代码段里右键-->
        <GuidSymbol name="guidVanGo_VSP_CodeWindowRightClickCmdSet" value="{D309F791-903F-11D0-9EFC-00A0C9AA004F}">
          <IDSymbol name="rightID" value="1037" />
        </GuidSymbol>
    
        <!--html的代码里-->
        <GuidSymbol name="HtmlEditorWindowLibra" value="{78F03954-2FB8-4087-8CE7-59D71710B3BB}">
          <IDSymbol name="IDMX_HTML_SOURCE" value="1"/>
        </GuidSymbol>
            <GuidSymbol name="guidImages" value="{b92f9878-7b88-4b19-a41a-2b1ea51355c6}" >
          <IDSymbol name="bmpPic1" value="1" />
          <IDSymbol name="bmpPic2" value="2" />
          <IDSymbol name="bmpPicSearch" value="3" />
          <IDSymbol name="bmpPicX" value="4" />
          <IDSymbol name="bmpPicArrows" value="5" />
          <IDSymbol name="bmpPicStrikethrough" value="6" />
        </GuidSymbol>
      </Symbols>
      </CommandTable>
    
    1. EnvDTE: 是最核心的程序集,所有后续要讲到的东西都归于它名下.

    2. MSDN上对它的介绍:

    EnvDTE 是包含 Visual Studio 内核自动化的对象和成员的用程序集包装的 COM 库。 在 EnvDTE80、EnvDTE90、 EnvDTE90a 和 EnvDTE100 命名空间中包含更改和新功能。

    1. EnvDTE80、90、100按照数字,越大的表示越新,因为Visual Stuido有好多版本,不同的版本会提供新的功能,而这几个版本的 EnvDTE 正是对应了这些更新,不同的版本只是在功能上做了补充,并没有谁能替代谁的关系,比如editPoint2 比 editPoint 可能多了某些新特性,当你要使用这些新特性的时候,就应该使用editPoint2,否则还是使用 editPoint。
  2. DTE对象: 在 Visual Studio 中, DTE 对象是自动化模型中的顶级对象,通过操作DTE对象可以获取对 Visual Studio 的控制,比如你可以得到当前活动的文档、活动的窗口、活动的项目、查找与替换、向解决方案中添加文件、执行预定义命令、录制宏等。

Wix安装包制作

  1. 安装包安装时错误原因
    1. 插件安装过了, VSIX插件需要卸载
    2. customAction中有异常也会报错

模版更改流程

  1. 直接在工程模版中更改文件, 注意文件的build Action要设置为Content内容
  2. 如果增加或删除了文件或文件夹,在工程模版中的.csproj文件中要更新保持文件结构的一致性, 这保证生成模版后的文件结构正确
  3. 同时在.vstemplate的文件中也要更新保持一致性, 这保证在编译打包模版的时候能正确的找到文件

自定义UI

wix本身自带有一套UI,使用这些UI我们可以满足大多数的安装界面要求,你可以决定到底使用哪种WixUI:

  1. WixUI_Mondo 包含WixUI附带的全部用户界面:welcome界面,许可协议,安装类型(经典、自定义、完全),部件定制(安装类型自定义),浏览目标目录,磁盘消耗,同时也包含维护模式的界面;
  2. WixUI_FeatureTreeWixUI_Mondo的区别就是不能选择安装类型,许可协议界面之后直接到了部件定制界面;
  3. WixUI_InstallDir 不会出现选择安装类型和自定义部件的界面,许可协议之后会进入到选择安装目录界面
  4. WixUI_Minimal 简化的安装界面,在欢迎和许可协议后会自动安装,不能自定义部件和安装路径
  5. WixUI_AdvancedWixUI_Minimal 相似,可以一键直接安装,也允许定义部件和安装路径
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容