精华内容
下载资源
问答
  • 需要打开别人的 msi 安装包,在此基础上, 编辑,修改,增加,替换文件,以及重新打包等等, 怎么搞,谢谢。
  • [Wix] 搞了这么久才知道Wix怎么装 IntelliSense for WiX .wxs files 昨天看了一点Rob.的演讲,看到他在VS.NET里面写XML可以自动感知,很想实现一下。今天找到了:...

    IntelliSense for WiX .wxs files

    昨天看了一点Rob.的演讲,看到他在用VS.NET里面写XML可以自动感知,很想实现一下。今天找到了:
    http://weblogs.asp.net/sweinstein/archive/2004/08/31/223461.aspx

    I recently started looking into WiX as a replacement tool to create the install kit for NatLink and Vocola. It's not that I want to make life more difficult, but Visual Studio .Net setup projects don't support features.

    WiX of course does.

    The problem is that Visual Studio, by default, doesn't recognize .wxs files as XML. The fix for that is the following

    1) 在注册表中增加:

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\Editors\{C76D83F8-A489-11D0-8195-00A0C91BBEE3}\Extensions]
    "wxs"=dword:00000028

    2) 从 WiX/doc 目录复制文件 wix.xsd 和 wixloc.xsd 到

    C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\schemas\xml\

    and provided you reference the WiX namespace at http://schemas.microsoft.com/wix/2003/01/wi you'll get IntelliSense too.

    posted on Tuesday, August 31, 2004 2:53 PM

    posted on 2004-10-18 09:56 浙林龙哥 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/huqingyu/archive/2004/10/18/53552.html

    展开全文
  • Wix 安装部署教程(九) --WPF做安装界面 原文:Wix 安装部署教程(九) --WPF做安装界面 经常安装PC端的应用,特别是重装系统之后,大致分为两类。一类像QQ,搜狗输入法这样的。分三步走的:第一个...
    原文:Wix 安装部署教程(九) --用WPF做安装界面

          经常安装PC端的应用,特别是重装系统之后,大致分为两类。一类像QQ,搜狗输入法这样的。分三步走的:第一个页面可以自定义安装路径和软件许可。第二个页面显示安装进度条,第三个页面推荐其他应用。先不管人家怎么实现的,我们先回顾一下。

         QQ:

               

          再一个就是分六步或七步走的,如QQ影音:欢迎界面,用户许可,安装组件,安装目录,安装进度,安装完成,有七步的,一般会多一些软件推荐。当然还有其他的,比如是基于ClickOnce打包的,就一个界面,一个进度条。没有安装目录选择,这一般不是商业软件。先说第二种,上一步下一步的有很多第三方的打包工具,比较有名的有InstallShield,setupfactory等,看似有了图形化的操作界面,做简单的还可以,但是要是有一些自定义的部分就比较麻烦,因为你没地方改,比如你要在一个安装包中去静默的触发另一个安装包悄悄的安装,而且这些还是商业化的。开源的WIX,基于XML文件配置的方法来打包应用。Wix的基本打包(6,7个步骤),可以出门左拐可以看我之前的教程。接下来要说的,是基于WIX的Bootstrapper工程用WPF接入安装界面。

        WIX是基于BootstrapperCore.dll提供UI扩展的,你可以使用WPF,也可以使用Winform作为安装界面。而这里先不得不先说其中的两个对象。一个是Engine,它提供了最根本的安装方法,如Detect,Plan,Apply和Quit等,另外一个就是引导对象BootstrapperApplication,他提供了安装相关事件,设置窗体对象等。这为我们自定义界面的时候控制安装包提供了基础。

        一、工程准备

       1)新建一个Bootstrapper工程。

        

       新建完成之后会有一个Bundle.wxs文件,里面包含你要安装的msi文件和依赖组件比如.net4.0.  

    <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension"  xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"  xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
      <Bundle Name="WIXTest" Version="1.1.1.0" Manufacturer="Delta" UpgradeCode="{51C1EB78-C0D2-4C30-803C-8D7993CB38A5}"    Compressed="yes"    >
    
        <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense"   /> 
    
         
        <WixVariable Id="WixMbaPrereqLicenseUrl" Value=""/>
        <WixVariable Id="WixMbaPrereqPackageId" Value=""/>
       
    
        <Chain DisableRollback='yes'>
          <PackageGroupRef Id="Netfx4Full"  />
              <MsiPackage Id="DIAView" SourceFile="D:\TestWix\bin\Debug\zh-cn\TestWix.msi" Compressed="yes"  DisplayInternalUI="yes" >
                 </MsiPackage>
        </Chain>
      </Bundle>
    
      <Fragment>
        <util:RegistrySearchRef Id="NETFRAMEWORK40"/>
        <PackageGroup Id="Netfx4Full">
          <ExePackage
              Id="Netfx4FullExe"
              Cache="no"
              Compressed="yes"
              PerMachine="yes"
              Permanent="yes"
              Vital="yes"
              SourceFile="$(var.Dia)dotNetFx40_Full_x86_x64.exe"
              InstallCommand="/q /norestart "
              DetectCondition="NETFRAMEWORK40"
              DownloadUrl="http://go.microsoft.com/fwlink/?LinkId=164193"/>
        </PackageGroup>
      </Fragment>
    </Wix>
    View Code

      最终的EXE还是通过这个工程来生成的。MsiPackage的ID 后面可以用来检测当前电脑是否安装了这个软件。

    二、创建WPF界面程序。

      1).创建一个C# Library工程CustomBA,引用BootstrapperCore.dll 及 WPF相关dll

      BootstrapperCore在你安装的wix安装目录中就能找到。比如我使用的wix3.8,路径就是C:\Program Files (x86)\WiX Toolset v3.8\SDK\BootstrapperCore.dll

      

      另外一个就是Prism 组件,这个可以通过Nuget安装。

     

    但这个有点嫌多,其实工程只使用到了属性更改通知和命令。可以使用wix源码中的两个对象。如此就不必引用上面的Prism

    RelayCommand

     public class RelayCommand : ICommand
        {
            private readonly Action<object> execute;
            private readonly Predicate<object> canExecute;
    
            public RelayCommand(Action<object> execute)
                : this(execute, null)
            {
            }
    
            public RelayCommand(Action<object> execute, Predicate<object> canExecute)
            {
                this.execute = execute;
                this.canExecute = canExecute;
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            [DebuggerStepThrough]
            public bool CanExecute(object parameter)
            {
                return this.canExecute == null ? true : this.canExecute(parameter);
            }
    
            public void Execute(object parameter)
            {
                this.execute(parameter);
            }
        }
    View Code

    PropertyNotifyBase

      public abstract class PropertyNotifyBase : INotifyPropertyChanged
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="PropertyNotifyBase"/> class.
            /// </summary>
            protected PropertyNotifyBase()
            {
            }
    
            /// <summary>
            /// Raised when a property on this object has a new value.
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
    
            /// <summary>
            /// Warns the developer if this object does not have a public property with the
            /// specified name. This method does not exist in a Release build.
            /// </summary>
            /// <param name="propertyName">Property name to verify.</param>
            [Conditional("DEBUG")]
            [DebuggerStepThrough]
            public void VerifyPropertyName(string propertyName)
            {
                // Verify that the property name matches a real, public, instance property
                // on this object.
                if (null == TypeDescriptor.GetProperties(this)[propertyName])
                {
                    Debug.Fail(String.Concat("Invalid property name: ", propertyName));
                }
            }
    
            /// <summary>
            /// Raises this object's PropertyChanged event.
            /// </summary>
            /// <param name="propertyName">The property that has a new value.</param>
            protected virtual void OnPropertyChanged(string propertyName)
            {
                this.VerifyPropertyName(propertyName);
    
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (null != handler)
                {
                    PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
                    handler(this, e);
                }
            }
        }
    View Code

    使用方法差别不大。 

     2)可以建立如下的文件目录,配合WPF的MVVM。

     

    3)增加配置文件,以让Burn使用新的程序集。必须命名为BootstrapperCore.config ,也可以从C:\Program Files (x86)\WiX Toolset v3.8\SDK 目录下拷贝一个版本。

    <?xml version="1.0" encoding="utf-8" ?>
    <!--
      <copyright file="BootstrapperCore.config" company="Outercurve Foundation">
        Copyright (c) 2004, Outercurve Foundation.
        This software is released under Microsoft Reciprocal License (MS-RL).
        The license and further copyright text can be found in the file
        LICENSE.TXT at the root directory of the distribution.
      </copyright>
    -->
    <configuration>
        <configSections>
            <sectionGroup name="wix.bootstrapper" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperSectionGroup, BootstrapperCore">
                <section name="host" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.HostSection, BootstrapperCore" />
            </sectionGroup>
        </configSections>
        <startup useLegacyV2RuntimeActivationPolicy="true">
            <supportedRuntime version="v4.0" />
            <supportedRuntime version="v2.0.50727" />
        </startup>
        <wix.bootstrapper>
            <!-- Example only. Use only if the startup/supportedRuntime above cannot discern supported frameworks. -->
            <!--
            <supportedFramework version="v4\Client" />
            <supportedFramework version="v3.5" />
            <supportedFramework version="v3.0" />
            -->
            <!-- Example only. Replace the host/@assemblyName attribute with assembly that implements BootstrapperApplication. --> 
            <host assemblyName="AssemblyWithClassThatInheritsFromBootstrapperApplication" />
        </wix.bootstrapper>
    </configuration>
    View Code

     修改为:

    <?xml version="1.0" encoding="utf-8" ?>
     <configuration>
        <configSections>
            <sectionGroup name="wix.bootstrapper" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.BootstrapperSectionGroup, BootstrapperCore">
                <section name="host" type="Microsoft.Tools.WindowsInstallerXml.Bootstrapper.HostSection, BootstrapperCore" />
            </sectionGroup>
        </configSections>
        <startup useLegacyV2RuntimeActivationPolicy="true">
            <supportedRuntime version="v4.0" />
        </startup>
        <wix.bootstrapper>
          <host assemblyName="CustomBA">
            <supportedFramework version="v4\Full" />
            <supportedFramework version="v4\Client" />
          </host>
        </wix.bootstrapper>
    </configuration>

    CustomBA.dll,BootstrapperCore.config 和 Microsoft.Practices. Prism.dll(如果使用了) 都会拷贝到bootstrapper项目中去。

     4)修改Assemblyinfo

     增加:

    [assembly: BootstrapperApplication(typeof(CustomBootstrapperApplication))]
    [assembly: AssemblyTitle("CustomBA")]
    CustomBootstrapperApplication 是我们接下来要创建的一个对象,Bundle会调用它的Run方法,这是整个安装包的起点。

     5)创建WPF对象。

        根据MVVM模式,我们分别创建Model,ViewModel和View 以及一些辅助的对象。

        1.Model-->BootstrapperApplicationModel

      public class BootstrapperApplicationModel
        {
            private IntPtr hwnd;
            public BootstrapperApplicationModel( BootstrapperApplication bootstrapperApplication)
            {
                BootstrapperApplication = bootstrapperApplication;
               
                hwnd = IntPtr.Zero;
            }
    
            public BootstrapperApplication BootstrapperApplication
            {
                get;
                private set;
            }
            
            public int FinalResult { get; set; }
            
            public void SetWindowHandle(Window view)
            {
                hwnd = new WindowInteropHelper(view).Handle;
            }
            
            public void PlanAction(LaunchAction action)
            {
                BootstrapperApplication.Engine.Plan(action);
            }
            
            public void ApplyAction()
            {
                BootstrapperApplication.Engine.Apply(hwnd);
            }
            
            public void LogMessage(string message)
            {
                BootstrapperApplication.Engine.Log(LogLevel.Standard, message);
            }
    
            public void SetBurnVariable(string variableName, string value)
            {
                BootstrapperApplication.Engine.StringVariables[variableName] = value;
            }
        }

     从代码看是包装了Engine的方法,设置窗口,PlanAction,ApplyAction,LogMessage以及设置变量等。

    PlanAction是做一个任务准备,例如安装,卸载,修复或者更改。而ApplyAction就是执行这个任务。当UI上的按钮点击时,我们调用PlanAction方法,传递我们要执行的任务。Plan完成之后,再会触发ApplyAction。最后一点就是FinalResult 属性。我们用来存储引导程序结束后Burn引擎返回的状态码 。

      2.ViewModel-->InstallViewModel

     这是一个重要的交互对象。InstallState 安装状态,UpdateState 更新状态,Command用来处理用户在安装界面的操作,在构造函数里进行初始化。然后就是事件订阅。

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Input;
    using Microsoft.Tools.WindowsInstallerXml.Bootstrapper;
    
    namespace CustomBA.ViewModels
    {
        public class InstallViewModel : PropertyNotifyBase
        {
            public enum InstallState
            {
                Initializing,
                Present,
                NotPresent,
                Applying,
                Cancelled,
                Applied,
                Failed,
            }
    
            public enum UpdateState
            {
                Unknown,
                Initializing,
                Checking,
                Current,
                Available,
                Failed,
            }
    
            /// <summary>
            /// 记录状态
            /// </summary>
            private InstallState state;
            public UpdateState updatestate;
    
            /// <summary>
            /// 需要显示在WPFWindow
            /// </summary>
            private string message;
            private BootstrapperApplicationModel model;
            private string _packageId = string.Empty;
            private bool canceled;
            private Dictionary<string, int> executingPackageOrderIndex;
            private string username;
            private int progress;
            private int cacheProgress;
            private int executeProgress;
            private Version _version = new Version("2.0.0.0");
            private bool _installEnabled;
            private int progressPhases=1;
            private bool isUnstalling=false;
            #region Command
            /// <summary>
            /// 执行安装命令
            /// </summary>
            public ICommand InstallCommand { get; private set; }
            public ICommand UninstallCommand { get; private set; }
            public ICommand CancelCommand { get; private set; }
            public ICommand LaunchNewsCommand { get; private set; }
            private ICommand repairCommand;
    
            public ICommand RepairCommand
            {
                get
                {
                    return this.repairCommand ?? (this.repairCommand = new RelayCommand(param =>
                        model.PlanAction(LaunchAction.Repair) 
                     , param => State == InstallState.Present));
                }
            }
    
            #endregion 
    
            #region 属性
            public string Message
            {
                get
                {
                    return message;
                }
                set
                {
                    if (message != value)
                    {
                        message = value;
                        OnPropertyChanged("Message");
                    }
                }
            }
    
            public InstallState State
            {
                get
                {
                    return state;
                }
                set
                {
                    if (state != value)
                    {
                        state = value;
                        Message = "Status: " + state;
                        OnPropertyChanged("State");
                        Refresh();
                    }
                }
            }
    
            public string PackageId
            {
                get { return _packageId; }
                set
                {
                    if (_packageId != value)
                    {
                        _packageId = "packid:" + value;
                        OnPropertyChanged("PackageId");
                    }
                }
            }
            public bool Canceled
            {
                get
                {
                    return this.canceled;
                }
    
                set
                {
                    if (this.canceled != value)
                    {
                        this.canceled = value;
                        OnPropertyChanged("Canceled");
                    }
                }
            }
            public Version Version
            {
                get
                {
                    return _version;
                }
            }
    
            public string Username
            {
                get
                {
                    return this.username;
                }
                set
                {
                    this.username = value;
                    this.model.SetBurnVariable("Username", this.username);
                }
            }
    
         
    
            public int Progress
            {
                get
                {
                    if (isUnstalling)
                    {
                        return progress*2;
                    }
                    return this.progress;
                }
                set
                {
                    this.progress = value;
                    OnPropertyChanged("Progress");
                    OnPropertyChanged("Persent");
                }
            }
    
            private string _info;
    
            public string Info
            {
                get
                {
                    if(string.IsNullOrEmpty(_info))
                    _info= InstallEnabled ? "安装中..." : "进行中...";
                    return _info;
                }
                set
                {
                    _info = value;
                    OnPropertyChanged("Info");
                }
            }
    
            public string Persent
            {
                get { return Progress + "%"; }
            }
    
            public bool InstallEnabled
            {
                get { return State == InstallState.NotPresent; }
            }
    
            public bool UninstallEnabled
            {
                get { return UninstallCommand.CanExecute(this); }
            }
    
            public bool CancelEnabled
            {
                get { return  State == InstallState.Applying; }
            }
    
            public bool ExitEnabled
            {
                get { return this.State != InstallState.Applying; }
            }
    
            public bool ProgressEnabled
            {
                get { return this.State == InstallState.Applying; }
            }
    
            /// <summary>
            /// 先不管
            /// </summary>
            public bool IsUpToDate
            {
                get { return true; }
            }
            public bool RepairEnabled
            {
                get { return this.RepairCommand.CanExecute(this); }
            }
    
            public bool CompleteEnabled
            {
                get { return State == InstallState.Applied; }
            }
    
            public int  Phases
            {
                get
                {
                    return progressPhases;
                }
            }
    
            private string _installText = "Uninstall";
            public string InstallText
            {
                get
                {
                    return _installText;
                }
                set
                {
                    _installText = value;
                    OnPropertyChanged("InstallText");
                }
            }
    
            public string RepairText
            {
                get { return _repairText; }
                set { _repairText = value; }
            }
    
            private bool _lableback=true;
            private string _repairText = "Repair";
    
            public bool LabelBack
            {
                get
                {
                    return _lableback;
                }
                set
                {
                    _lableback = value;
                    OnPropertyChanged("LabelBack");
                }
            }
    
            #endregion 
    
            #region 构造函数
            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="_model"></param>
            public InstallViewModel(BootstrapperApplicationModel _model)
            {
                model = _model;
                executingPackageOrderIndex = new Dictionary<string, int>();
                
                State = InstallState.Initializing;
                //处理由bootstrapper触发的事件
                WireUpEventHandlers();
                //初始化命令 第一个参数是命令要触发的方法,第二个匿名函数是命令执行的条件
                InstallCommand = new RelayCommand(param => model.PlanAction(LaunchAction.Install), param => State == InstallState.NotPresent);
    
                UninstallCommand = new RelayCommand(param =>
                {
                    model.PlanAction(LaunchAction.Uninstall);
                    isUnstalling = true;
                }, param => State == InstallState.Present);
    
                CancelCommand = new RelayCommand(param =>
                {
                    model.LogMessage("Cancelling...");
                    if (State == InstallState.Applying)
                    {
                        State = InstallState.Cancelled;
                    }
                    else
                    {
                        CustomBootstrapperApplication.Dispatcher.InvokeShutdown();
                    }
                }, param => State != InstallState.Cancelled);
    
    
                model.BootstrapperApplication.DetectComplete += DetectComplete;
    
    
    
    
                //进度条相关事件绑定
                //this.model.BootstrapperApplication.CacheAcquireProgress +=
                //(sender, args) =>
                //{
                //    this.cacheProgress = args.OverallPercentage;
                //    this.Progress = (this.cacheProgress + this.executeProgress) / 2;
                //};
                //this.model.BootstrapperApplication.ExecuteProgress +=
                //(sender, args) =>
                //{
                //    this.executeProgress = args.OverallPercentage;
                //    this.Progress = (this.cacheProgress + this.executeProgress) / 2;
                //};
                model.BootstrapperApplication.CacheAcquireProgress += CacheAcquireProgress;
                model.BootstrapperApplication.ExecuteProgress += ApplyExecuteProgress;
                model.BootstrapperApplication.ExecuteMsiMessage += ExecuteMsiMessage;
                model.BootstrapperApplication.PlanBegin += PlanBegin;
                model.BootstrapperApplication.PlanPackageComplete += PlanPackageComplete;
                model.BootstrapperApplication.Progress += ApplyProgress;
                model.BootstrapperApplication.CacheComplete += CacheComplete;
            }
    
            #endregion
    
            private void DetectComplete(object sender, DetectCompleteEventArgs e)
            {
                if (LaunchAction.Uninstall == CustomBootstrapperApplication.Model.Command.Action)
                {
                    CustomBootstrapperApplication.Model.Engine.Log(LogLevel.Verbose, "Invoking automatic plan for uninstall");
                    CustomBootstrapperApplication.Plan(LaunchAction.Uninstall);
                }
                else if (Hresult.Succeeded(e.Status))
                {
                    if (CustomBootstrapperApplication.Model.Engine.EvaluateCondition("NETFRAMEWORK35_SP_LEVEL < 1"))
                    {
                        string message = "WiX Toolset requires the .NET Framework 3.5.1 Windows feature to be enabled.";
                        CustomBootstrapperApplication.Model.Engine.Log(LogLevel.Verbose, message);
    
                        if (Display.Full == CustomBootstrapperApplication.Model.Command.Display)
                        {
                            CustomBootstrapperApplication.Dispatcher.Invoke((Action)delegate()
                            {
                                MessageBox.Show(message, "DIAView", MessageBoxButton.OK, MessageBoxImage.Error);
                                if (null != CustomBootstrapperApplication.View)
                                {
                                    CustomBootstrapperApplication.View.Close();
                                }
                            }
                            );
                        }
    
                        State = InstallState.Failed;
                        return;
                    }
                }
                else
                {
                    State = InstallState.Failed;
                }
            }
    
            #region 方法
            private void CacheAcquireProgress(object sender, CacheAcquireProgressEventArgs e)
            {
                lock (this)
                {
                    this.cacheProgress = e.OverallPercentage;
                    this.Progress = (this.cacheProgress + this.executeProgress) / this.Phases;
                    e.Result = Canceled ? Result.Cancel : Result.Ok;
                }
            }
            private void ApplyExecuteProgress(object sender, ExecuteProgressEventArgs e)
            {
                lock (this)
                {
    
                    this.executeProgress = e.OverallPercentage;
                    this.Progress = (this.cacheProgress + this.executeProgress) / 2; // always two phases if we hit execution.
    
                    if (CustomBootstrapperApplication.Model.Command.Display == Display.Embedded)
                    {
                        CustomBootstrapperApplication.Model.Engine.SendEmbeddedProgress(e.ProgressPercentage, this.Progress);
                    }
    
                    e.Result =  Canceled ? Result.Cancel : Result.Ok;
                }
            }
    
            /// <summary>
            /// 这个方法 会在Detect中被调用
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void DetectPackageComplete(object sender, DetectPackageCompleteEventArgs e)
            {
                PackageId = e.PackageId;
                //对应的是MsiPackage Id="DIAView"
                if (e.PackageId.Equals("DIAView", StringComparison.Ordinal))
                {
                    State = e.State == PackageState.Present ? InstallState.Present : InstallState.NotPresent;
                }
            }
    
    
            private void PlanBegin(object sender, PlanBeginEventArgs e)
            {
                lock (this)
                {
                    if (InstallEnabled)
                    {
                        this.progressPhases = (LaunchAction.Layout == CustomBootstrapperApplication.Model.PlannedAction) ? 1 : 2;
                    }
                    else
                    {
                        LabelBack = false;
                    }
                    InstallText = "";
                    RepairText = "";
                    OnPropertyChanged("Phases");
                    OnPropertyChanged("InstallEnabled");
                    OnPropertyChanged("InstallText");
                    OnPropertyChanged("RepairText");
                    this.executingPackageOrderIndex.Clear();
                }
            }
            private void PlanPackageComplete(object sender, PlanPackageCompleteEventArgs e)
            {
                if (ActionState.None != e.Execute)
                {
                    lock (this)
                    {
                        Debug.Assert(!this.executingPackageOrderIndex.ContainsKey(e.PackageId));
                        this.executingPackageOrderIndex.Add(e.PackageId, this.executingPackageOrderIndex.Count);
                    }
                }
            }
    
            /// <summary>
            /// PlanAction 结束后会触发这个方法
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void PlanComplete(object sender, PlanCompleteEventArgs e)
            {
                if (State == InstallState.Cancelled)
                {
                    CustomBootstrapperApplication.Dispatcher.InvokeShutdown();
                    return;
                }
                State = InstallState.Applying;
                model.ApplyAction();
            }
            /// <summary>
            /// ApplyAction 开始 
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void ApplyBegin(object sender, ApplyBeginEventArgs e)
            {
                State = InstallState.Applying;
                OnPropertyChanged("ProgressEnabled");
                OnPropertyChanged("CancelEnabled");
            }
            /// <summary>
            /// 安装
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void ExecutePackageBegin(object sender, ExecutePackageBeginEventArgs e)
            {
                if (State == InstallState.Cancelled)
                {
                    e.Result = Result.Cancel;
                }
            }
    
            private void ExecuteMsiMessage(object sender, ExecuteMsiMessageEventArgs e)
            {
                lock (this)
                {
                    if (e.MessageType == InstallMessage.ActionStart)
                    {
                        this.Message = e.Message;
                    }
    
                    e.Result = Canceled ? Result.Cancel : Result.Ok;
                }
            }
            private void CacheComplete(object sender, CacheCompleteEventArgs e)
            {
                lock (this)
                {
                    this.cacheProgress = 100;
                    this.Progress = (this.cacheProgress + this.executeProgress) / this.progressPhases;
                }
            }
            /// <summary>
            /// 卸载
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void ExecutePackageComplete(object sender, ExecutePackageCompleteEventArgs e)
            {
                if (State == InstallState.Cancelled)
                {
                    e.Result = Result.Cancel;
                }
            }
            /// <summary>
            /// Apply结束
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected void ApplyComplete(object sender, ApplyCompleteEventArgs e)
            {
                model.FinalResult = e.Status;
                State = InstallState.Applied;
                isUnstalling = false;
                OnPropertyChanged("CompleteEnabled");
                OnPropertyChanged("ProgressEnabled");
               // CustomBootstrapperApplication.Dispatcher.InvokeShutdown();
            }
    
            private void ApplyProgress(object sender, ProgressEventArgs e)
            {
                lock (this)
                {
                    e.Result =  Canceled ? Result.Cancel : Result.Ok;
                }
            }
            /// <summary>
            /// 刷新命令状态 从而改变UI是否使能
            /// </summary>
            private void Refresh()
            {
                CustomBootstrapperApplication.Dispatcher.Invoke(
                (Action)(() =>
                {
                    //((RelayCommand)InstallCommand).CanExecute(this);
                    //.RaiseCanExecuteChanged();
                    //((RelayCommand)UninstallCommand)
                    //.RaiseCanExecuteChanged();
                    //((DelegateCommand)CancelCommand)
                    //.RaiseCanExecuteChanged();
                }));
            }
            /// <summary>
            /// 事件订阅
            /// </summary>
            private void WireUpEventHandlers()
            {
                model.BootstrapperApplication.DetectPackageComplete += DetectPackageComplete;
    
                model.BootstrapperApplication.PlanComplete += PlanComplete;
    
                model.BootstrapperApplication.ApplyComplete += ApplyComplete;
    
                model.BootstrapperApplication.ApplyBegin += ApplyBegin;
    
                model.BootstrapperApplication.ExecutePackageBegin += ExecutePackageBegin;
    
                model.BootstrapperApplication.ExecutePackageComplete += ExecutePackageComplete;
    
            }
            #endregion
    
    
        }
    }
    View Code

    在构造函数内部,WireUpEventHandlers方法里面的事件订阅处理的是安装的状态。其他就是处理安装进度。安装进度是由两部分组成的,CacheAcquireProgress 和ExecuteProgress,基于二者完成的进度平均得到当前的安装进度。Wix3.6书中的代码如下:

         this.model.BootstrapperApplication.CacheAcquireProgress +=
                (sender, args) =>
                {
                    this.cacheProgress = args.OverallPercentage;
                    this.Progress = (this.cacheProgress + this.executeProgress) / 2;
                };
                this.model.BootstrapperApplication.ExecuteProgress +=
                (sender, args) =>
                {
                    this.executeProgress = args.OverallPercentage;
                    this.Progress = (this.cacheProgress + this.executeProgress) / 2;
                };

    我按照wix3.8中WixBA的源码调整了下。卸载的时候常数是1而不是2.

     3.在Views中新建一个InstallView.Xaml 。

     我们先做一个简单的。只有几个按钮。最后的界面如下(美观度先不考虑,;-)): 只有安装,卸载和取消三个按钮,再加一个进度条和一个消息提示。

    XAML:

      <Grid>
              <StackPanel>
                <Label Content="{Binding Message}" />
                <Button Command="{Binding InstallCommand}">Install</Button>
                <Button Command="{Binding UninstallCommand}">Uninstall</Button>
                <Button Command="{Binding CancelCommand}">Cancel</Button>
                <Label VerticalAlignment="Center">Progress:</Label>
                <Label Content="{Binding Progress}" />
                <ProgressBar Width="200" Height="30" Value="{Binding Progress}" Minimum="0" Maximum="100" />
            </StackPanel>
        </Grid>

    CS:

     public InstallView(InstallViewModel viewModel)
            {
                this.InitializeComponent();
                this.DataContext = viewModel;
                this.Closed += (sender, e) =>
                viewModel.CancelCommand.Execute(this);
            }

    4.入口对象CustomBootstrapperApplication。

      public class CustomBootstrapperApplication:BootstrapperApplication
        {
            public static Dispatcher Dispatcher { get; set; }
            static public DiaViewModel Model { get; private set; }
            static public InstallView View { get; private set; }
         
            protected override void Run()
            {
                Model = new DiaViewModel(this);
                Dispatcher = Dispatcher.CurrentDispatcher;
                var model = new BootstrapperApplicationModel(this);
                var viewModel = new InstallViewModel(model);
                View = new InstallView(viewModel);
                model.SetWindowHandle(View);
                this.Engine.Detect();
                View.Show();
                Dispatcher.Run();
                this.Engine.Quit(model.FinalResult);
            }
        }
    重载了Run方法,是UI的主要入口函数,它会被Burn引擎调用,Dispatcher 用于UI和后台线程直接通信。它提供了Invoke方法,我们可以用来更新UI控件的状态。而这里的Model相当于一个辅助对象。
      public class DiaViewModel
        {
            private Version _version;
            private const string BurnBundleInstallDirectoryVariable = "InstallFolder";
            private const string BurnBundleLayoutDirectoryVariable = "WixBundleLayoutDirectory";
    
            public DiaViewModel(BootstrapperApplication bootstrapper)
            {
                Bootstrapper = bootstrapper;
                Telemetry = new List<KeyValuePair<string, string>>();
            }
    
            /// <summary>
            /// Gets the bootstrapper.
            /// </summary>
            public BootstrapperApplication Bootstrapper { get; private set; }
    
            /// <summary>
            /// Gets the bootstrapper command-line.
            /// </summary>
            public Command Command { get { return Bootstrapper.Command; } }
    
            /// <summary>
            /// Gets the bootstrapper engine.
            /// </summary>
            public Engine Engine { get { return Bootstrapper.Engine; } }
    
            /// <summary>
            /// Gets the key/value pairs used in telemetry.
            /// </summary>
            public List<KeyValuePair<string, string>> Telemetry { get; private set; }
    
            /// <summary>
            /// Get or set the final result of the installation.
            /// </summary>
            public int Result { get; set; }
    
            /// <summary>
            /// Get the version of the install.
            /// </summary>
            public Version Version
            {
                get
                {
                    if (null == _version)
                    {
                        Assembly assembly = Assembly.GetExecutingAssembly();
                        FileVersionInfo fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
    
                        _version = new Version(fileVersion.FileVersion);
                    }
    
                    return _version;
                }
            }
    
            /// <summary>
            /// Get or set the path where the bundle is installed.
            /// </summary>
            public string InstallDirectory
            {
                get
                {
                    if (!Engine.StringVariables.Contains(BurnBundleInstallDirectoryVariable))
                    {
                        return null;
                    }
    
                    return Engine.StringVariables[BurnBundleInstallDirectoryVariable];
                }
    
                set
                {
                    Engine.StringVariables[BurnBundleInstallDirectoryVariable] = value;
                }
            }
    
            /// <summary>
            /// Get or set the path for the layout to be created.
            /// </summary>
            public string LayoutDirectory
            {
                get
                {
                    if (!Engine.StringVariables.Contains(BurnBundleLayoutDirectoryVariable))
                    {
                        return null;
                    }
    
                    return Engine.StringVariables[BurnBundleLayoutDirectoryVariable];
                }
    
                set
                {
                    Engine.StringVariables[BurnBundleLayoutDirectoryVariable] = value;
                }
            }
    
            public LaunchAction PlannedAction { get; set; }
    
            /// <summary>
            /// Creates a correctly configured HTTP web request.
            /// </summary>
            /// <param name="uri">URI to connect to.</param>
            /// <returns>Correctly configured HTTP web request.</returns>
            public HttpWebRequest CreateWebRequest(string uri)
            {
                var request = (HttpWebRequest)WebRequest.Create(uri);
                request.UserAgent = String.Concat("WixInstall", Version.ToString());
                return request;
            }
        }
    View Code
     
    model.SetWindowHandle(view);  
    这个方法会控制wpf窗口,在Burn 引擎安装或卸载的时候会用到。
    this.Engine.Detect();
    它会让Burn去检查是否bundle已经安装,这样当窗口显示出来的时候,我们需要知道是显示一个安装按钮还是一个卸载按钮。show方法会显示WPF窗口,接着我们调用了
    Dispatcher.Run()
    它会一直执行到Dispatcher关闭或遇到任务取消,关闭窗口我们可以调用Dispatcher的InvokeShutdown方法。
    Engine.Quit
    会优雅的退出bootstrapper 进程。而不是直接kill。
     
    5.更改配置
      以上wpf这边就是已经准备好,现在就需要告诉Bootstrapper工程。
     首先我们需要引用CustomBA这个工程,以及相关的dll
       
     然后修改Bundle中的BootstrapperApplicationRef,使用payload相当于是把CustomBA下面的DLL都copy过来。但如果没有使用prism,就可以将其全部拿掉。
     <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost">
          <Payload SourceFile="$(var.CustomBA.TargetDir)CustomBA.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)BootstrapperCore.config" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.Composition.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.Interactivity.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.Mvvm.Desktop.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.Mvvm.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.PubSubEvents.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.Prism.SharedInterfaces.dll" />
          <Payload SourceFile="$(var.CustomBA.TargetDir)Microsoft.Practices.ServiceLocation.dll" />
        </BootstrapperApplicationRef>

    然后再编译运行,就ok了。 运行一下安装包,wpf界面出来,有点小激动,比起xml配置的界面还是要好多了,主要是给了各种可能。

    三、界面优化

     当然,上面的界面还不能满足我们的胃口,我就先把WIXBA的界面抓过来了。

    修改了下安装界面。明白了安装步骤和事件控制,怎么折腾界面那都是你自己的事情了。这个界面也不是很好,进度条不显示的时候纠结显示些别的什么。

      安装前:                                                                             卸载中:

             

    <Window x:Class="CustomBA.Views.InstallView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            WindowStartupLocation="CenterScreen"
        WindowStyle="None"
        AllowsTransparency="True"
        Background="{x:Null}"
        Width="400"
        Height="400">
        <Window.Resources>
            <ResourceDictionary Source="Styles.xaml"    />
        </Window.Resources>
    
        <Grid>
            <Rectangle MouseLeftButtonDown="Background_MouseLeftButtonDown" Fill="{StaticResource BackgroundBrush}"/>
            <Grid VerticalAlignment="Stretch" Margin="15">
                <Grid.RowDefinitions>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"/>
                    <RowDefinition Height="1*"  />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="1*" />
                </Grid.ColumnDefinitions>
                <Button Grid.Row="0" Grid.ColumnSpan="2" Background="#33CCFF"   />
                <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource StatusTextStyle}" Padding="12 0  0 0" >stoneniqiu</TextBlock>
                <TextBlock Grid.Row="0"  Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource StatusTextStyle}" HorizontalAlignment="Right"  Text="{Binding Version}"/>
                <TextBlock Grid.ColumnSpan="2"  Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50" Foreground="White" IsHitTestVisible="False">YourSoft</TextBlock>
    
                <Label Grid.Row="2" Grid.Column="0"  Margin="3"  Grid.ColumnSpan="3" Background="#33CCFF"  ></Label>
    
    
                <Grid Grid.Row="2" Grid.Column="0" ColumnSpan="3" >
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions> 
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <ProgressBar Grid.Row="0" Margin="4" VerticalAlignment="Bottom"  Grid.Column="0"   Grid.ColumnSpan="3"  Width="350" Height="8" Value="{Binding Progress}" Minimum="0" Maximum="100" 
                                 Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" />
                    <Label Grid.Row="1"   Grid.Column="0" Background="#33CCFF" Foreground="White"  Margin="3"  Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"   Content="{Binding Info}"  ></Label>
                    <Button Grid.Row="1" Grid.Column="1" Click="ButtonBase_OnClick" Content="" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" ></Button>
                    <Label  Grid.Row="1" Grid.Column="2"  Background="#33CCFF"  Foreground="White" Margin="3"   Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"  HorizontalContentAlignment="Right"  Content="{Binding Persent}"   />
                </Grid>
    
    
    
                <!-- Install -->
                <Button Grid.Row="1" Grid.ColumnSpan="3" Tag="安装"  Grid.Column="0"  Command="{Binding InstallCommand}" Visibility="{Binding InstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Content="Install" />
                <Image Grid.Row="1" Grid.Column="2" Source="..\resources\gear.png"  Visibility="{Binding InstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    
                <Label Grid.Row="1" Grid.Column="0" Margin="3" Grid.ColumnSpan="3" Background="#33CCFF"   Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" ></Label>
                
                <!--<TextBlock Grid.Row="2"   Grid.ColumnSpan="3" Style="{StaticResource StatusTextStyle}"  Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Text="{Binding Message}"/>-->
                <Image Grid.Row="1" Grid.Column="2" Source="..\resources\gear.png"   Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">
                    <Image.RenderTransform>
                        <RotateTransform x:Name="ProgressRotateTransform" Angle="1"/>
                    </Image.RenderTransform>
                    <Image.Triggers>
                        <EventTrigger RoutedEvent="Image.Loaded">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="ProgressRotateTransform" Storyboard.TargetProperty="Angle" From="0.0" To="360.0" Duration="0:0:4" RepeatBehavior="Forever"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Image.Triggers>
                </Image>
                <!-- Uninstall -->
                <Button Grid.Row="1" Grid.Column="0"  Command="{Binding UninstallCommand}" Visibility="{Binding UninstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Content="{Binding InstallText}" />
                <!--<Image Grid.Row="1" Grid.Column="0" Source="..\resources\gear.png"  Visibility="{Binding UninstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"/>-->
    
                <Image Grid.Row="1" Grid.Column="0" Source="..\resources\gear.png"   Visibility="{Binding UninstallEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">
                    <Image.RenderTransform>
                        <RotateTransform x:Name="UpdateRotateTransform" Angle="1"/>
                    </Image.RenderTransform>
                    <Image.Triggers>
                        <EventTrigger RoutedEvent="Image.Loaded">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="UpdateRotateTransform" Storyboard.TargetProperty="Angle" From="0.0" To="360.0" Duration="0:0:4" RepeatBehavior="Forever"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </Image.Triggers>
                </Image>
                
    
                <!-- Repair -->
                <Button Grid.Row="1" Grid.ColumnSpan="2" Grid.Column="1"  Command="{Binding RepairCommand}" Visibility="{Binding RepairEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"  Content="Repair"  />
                <Image Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Source="..\resources\wrench.png"   Visibility="{Binding RepairEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    
                <!-- Complete -->
                <Button Grid.Row="1" Grid.ColumnSpan="3"  Grid.Column="0"  IsEnabled="False" Visibility="{Binding CompleteEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">Complete</Button>
                <Image Grid.Row="1" Grid.Column="2" Source="..\resources\gear.png"   Visibility="{Binding CompleteEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"/>
    
    
                <TextBlock Grid.Row="1" Grid.Column="0"  Grid.ColumnSpan="3" Style="{StaticResource StatusTextStyle}"  Visibility="{Binding ProgressEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Text="{Binding Message}"/>
    
    
                
                <!-- Failed -->
                <!--<Button Grid.Row="1" Grid.ColumnSpan="3" Grid.Column="0" Background="#33CCFF"   Command="{Binding TryAgainCommand}" Visibility="{Binding TryAgainEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">Failed. Try Again?</Button>
                <TextBlock Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="60" Foreground="White" IsHitTestVisible="False"    Visibility="{Binding TryAgainEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">X</TextBlock>-->
    
    
    
                <!-- Cancel -->
                <Button Grid.Row="0" Grid.Column="2"  Visibility="{Binding CancelEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" Command="{Binding CancelCommand}">Cancel</Button>
                <TextBlock Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="60" Foreground="White" IsHitTestVisible="False"   Visibility="{Binding CancelEnabled, Converter={StaticResource BooleanToVisibilityConverter}}">X</TextBlock>
    
                <!-- Exit -->
                <Button Grid.Row="0" Grid.Column="2"  Visibility="{Binding ExitEnabled, Converter={StaticResource BooleanToVisibilityConverter}}"  Name="Exit" Click="Exit_OnClick"  >Exit</Button>
                <Image Grid.Row="0" Grid.Column="2" Source="..\resources\exit.png"  Visibility="{Binding ExitEnabled, Converter={StaticResource BooleanToVisibilityConverter}}" />
    
            </Grid>
    
            <!--<StackPanel>
                <Label Content="{Binding Message}" />
                <Label Content="{Binding PackageId}" />
                <Button Command="{Binding InstallCommand}">Install</Button>
                <Button Command="{Binding UninstallCommand}">Uninstall</Button>
                <Button Command="{Binding CancelCommand}">Cancel</Button>
                <Label VerticalAlignment="Center">Username:</Label>
                <TextBox Text="{Binding Username}" Margin="10"  MinWidth="150" />
                <Label VerticalAlignment="Center">Progress:</Label>
                <Label Content="{Binding Progress}" />
                <ProgressBar Width="200" Height="30" Value="{Binding Progress}" Minimum="0" Maximum="100" />
            </StackPanel>-->
        </Grid>
    
    
    </Window>
    View Code

     

     小结: 以上就是整个过程,基本走通了,但还没有达到最终目的。要制作想QQ那样三步的安装界面,还有2个关键比较重要的问题没有解决。

     1.使用了wpf界面后,bundle无法再先安装.net . 这意味着要在我们的wpf界面之前安装.net(不然wpf界面跑不起来),用wix3.9编译,会给出提示界面。但安装.net失败。

     2.用户选择路径问题,原本我们是通过msi的安装界面来让用户选择安装路径,但现在msi的安装界面就显得有些多余。但这是两个工程,如何把安装界面传递过去。也是个问题。

     这两个问题解决后,我会在后面的博客中更新。那样才算完整。

     

      需要的demo的留邮箱,觉得可以的就点个赞~

      参考资料:

     1.书 Wix3.6:A Develop's Guide to Windows Installer XML

     2.源码:wix3.8  

     

    posted on 2018-05-18 09:19 NET未来之路 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/lonelyxmas/p/9054562.html

    展开全文
  • 但是我们一直还是在调试的项目中来做的,怎么能够让我们做的这个状态机设计器能够提供给其它人使用呢,在这一节,我们就来做一个安装程序,这样在只安装了VS.NET的机器上,不用安装SDK就可以使用我们的设计器了....

      我们到现在为止已经对Vs.net  dsl的基础知识进行了介绍,并且一步一步的完成了我们的状态机设计器的设计,在上一节结合T4模板生成了代码.但是我们一直还是在调试的项目中来做的,怎么能够让我们做的这个状态机设计器能够提供给其它人使用呢,在这一节,我们就来做一个安装程序,这样在只安装了VS.NET的机器上,不用安装SDK就可以使用我们的设计器了.
        VS.NET DSL专门提供了针对DSL的安装项目,我们直接基于这个项目来制作我们的安装程序:
        1.首先,向我们的解决方案中添加一个Dsl 安装项目,从项目类型中选择Extensibility—Domain Specific Language Setup:
           2010-3-13 12-16-44

        2. 我们可以看到在生成的项目中, 还是由很多tt文件, 其实dsl的安装是基于开源项目wix,不过在一般情况下,我们不需要手动去修改wix文件,不过如果一旦有特殊的需求,现有的这种机制是很难满足的. 我们来介绍一下这种安装机制:
           当我们向这个解决方案中添加DSL setup项目时,它会自动的寻找Dsl项目和DslPackage项目,并自动添加对这两个项目的引用,然后根据这两个项目中生成自己的元数据文件InstallerDefinition.dslsetup,我们来看一下这个文件:

    隐藏行号 复制代码
    1. <installerDefinition xmlns="http://schemas.microsoft.com/VisualStudio/2005/DslTools/InstallerDefinitionModel" 
    2. productUrl="InsertProductUrlHere"
    3. defaultDirectoryName="LanguageSm"
    4. productVersion="1.0.0"
    5. requiresCSharp="true"
    6. requiresVisualBasic="true"
    7. productCode="326b807c-a6da-43ac-9d29-f75cf060622a"
    8. upgradeCode="cc04b782-48c3-49c5-a60e-eda39258bfaa"
    9. localeId="1033">
    10.     <dslPackage name="LanguageSm" project="DslPackage" assemblyPath="Company.LanguageSm.DslPackage.dll" registryRoot="SOFTWARE\Microsoft\VisualStudio\9.0">
    11.         <fileExtensions>
    12.             <fileExtension name="mydsl5" extension="mydsl5" descriptionKey="FileDescription" hasIcon="true" iconId="0"/>
    13.         </fileExtensions>
    14.         <supportingAssemblies>
    15.             <supportingAssembly name="Dsl" project="Dsl" assemblyPath="Company.LanguageSm.Dsl.dll"/>
    16.         </supportingAssemblies>
    17.     </dslPackage>
    18.     <licenseAgreement filePath="Files\EULA.rtf" isEmbedded="true" />
    19.     <supportingFiles>
    20.         <supportingFile name="Readme" filePath="Files\Readme.htm" installShortcut="true" shortcutIconPath="Resources\ReadmeShortcut.ico" openAfterInstall="true" />
    21.     </supportingFiles>
    22.     <vsItemTemplates>
    23.         <vsItemTemplate localeId="1033" targetDirectories="CSharp" project="DslPackage" templatePath="CSharp\1033\LanguageSm.zip"/>
    24.         <vsItemTemplate localeId="1033" targetDirectories="VisualBasic" project="DslPackage" templatePath="VisualBasic\1033\LanguageSm.zip"/>
    25.     </vsItemTemplates>
    26.     <dslSchemas>
    27.         <dslSchema project="Dsl" filePath="GeneratedCode\LanguageSmSchema.xsd"/>
    28.     </dslSchemas>
    29. </installerDefinition>

             (1).根结点installerDefinition下面是全局的定义,包括产品URL,目录名称,版本,是否在安装需要vs.net安装c#或者是BisualBasic等,在这里我们注意需要把requireVisualBasic设置为false.
             (2).dslPackge结点是对我们的dsl的一些注册信息,这些信息都来自于我们的DslDefinition.dsl文件,不过我们这里可以对这些信息进行一些修改.
             (3).licenseAgreement  许可协议文件,这会在安装过程中显示出来.
             (4).supportingFiles, 需要复制到安装目录的文件列表
             (5).vsItemTemplates   项目项模板,是在项目中新增项的时候的,而不是说我们生成代码的tt模板,也不是说新增项目的模板 , localeId是区域id,你可以根据你的vs.net语言版本改成2052
          
        下面再来看一下生成的其它几个文件:
         2010-3-14 10-51-48

         Main.wxs       这是wix的主文件,控制整个安装流程,包括对以下几个部分的引用.
         Files.wxs       需要在安装目录创建的目录结构和文件  包括dll和附属文件
         Registry.wxs    注册项信息,需要写入注册表的项
         UI.wxs          安装界面
         string.wxs     被其它部分使用的语言的键值对,如果需要多语言支持,可以再添加对应语言的文件,比如string_zh-cn.wxs
         
         除了string.wxs文件,其它的几个文件都是由tt文件生成的,不要手动去修改,即使修改了重新转换模板时也会被覆盖掉.
         3.我们暂时不需要做一些高级功能,现在先重新生成模板,然后编译整个安装项目:

    隐藏行号 复制代码
    1.    D:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Wix\candle.exe -dConfiguration=Debug -out obj\Debug\ -w0 -v Files.wxs Registry.wxs Main.wxs UI.wxs 
    2.    D:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Wix\light.exe -b F:\NET\Projects\LanguageSm\LanguageSmSetup -loc Strings.wxl -out bin\Debug\LanguageSm.msi -sa -w0 -v obj\Debug\Files.wixobj obj\Debug\Registry.wixobj obj\Debug\Main.wixobj obj\Debug\UI.wixobj  


        可以看到其实是调用了sdk中附带的wix的candle命令来生成. 编译完成后,在setup项目下的debug目录下面,可以找到生成的exe文件,我们点击安装:

        2010-3-14 11-38-25 
        接下来就是许可协议rtf文件的内容,同意后点下一步:
        2010-3-14 11-38-48
        这一步选择我们的安装目录:
        2010-3-14 11-39-09 
        选择完目录后,直接下一步,直接到完成安装,我们新建一个类库项目,添加项时就会看到我们的LanguageSm:
        2010-3-14 12-30-43

       添加后我们就可以和我们调试项目的时候一样进行状态机的设计了.不过生成代码的功能暂时还没有加进来.
        4.不过当你把这个生成的安装文件给没有安装过Visual stuido.net SDK的机器安装后,你会发现,没有作用,要让dsl能够直接在vs.net上安装,你还必须要有自己的PLK(Package Load Key).
          (1)登陆vsx的网站http://msdn.microsoft.com/zh-cn/vsx/cc655795(en-us).aspx,左下角的就是plk的注册信息,这些信息来源于你的DslDefinition.dsl的根结点的属性:
       2010-3-14 12-46-39

          (2)填写完这些信息完,点击生成PLK,会生成一串的字母.然后打开DslPackage项目下面的VSPackage.resx文件,添加一个键为1的字符串资源,值就是生成的PLK GUID.
      2010-3-14 13-17-35
          (3)打开DslPackage项目GeneratedCode文件夹下面的Package.tt文件,将下面这句用来加载PLK的属性标记的注释去掉:

    隐藏行号 复制代码
    1. /// [VSShell::ProvideLoadKey("Standard", Constants.ProductVersion, Constants.ProductName, Constants.CompanyName, 1)]

           (4)保存文件,重新转换模板,再编译dslsetup项目生成exe文件,这次就可以直接在未安装sdk的机器上安装使用了.

       5. 即使你可能觉得Dsl setup安装项目还是很强大的,不过我还是需要说明以下几点:
           (1)使用wix结合t4制作dsl安装项目,虽然简单,但是有失灵活性,如果你想扩展在使用现有的这种方式会有些麻烦除非你脱离开T4,就直接使用wix来完成.
           (2)使用wix,就是把注册表操作,复制文件操作,多语言处理,安装界面和流程处理等通过它特有的xml和扩展机制来实现,你完全可以不用这种机制,不用dsl setup项目,而使用自己的安装方式.  比如直接新建普通的安装项目或者是使用installshiled.
           (3)很高兴的看到,在vs 2010中的关于dsl的安装已经不使用wix了,而是通过新的扩展管理器来加载.

     
    代码下载

     

    参考资源
          1. Visual Stuido DSL 工具特定领域开发指南
          2. DSL Tools Lab     http://code.msdn.microsoft.com/DSLToolsLab  系列教程  [本系列的入门案例的主要参考]

    作者:孤独侠客似水流年
    出处:http://lonely7345.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    分类: .NET

    本文转自孤独侠客博客园博客,原文链接:http://www.cnblogs.com/lonely7345/archive/2010/03/16/1686765.html,如需转载请自行联系原作者
    展开全文
  • 如何才能可以? ``` <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> *" Name="补丁安装程序" Language="1033" Codepage ="1252" Version="1.0.0.0" Manufacturer="AAA有限公司" UpgradeCode=...
  • 前段时间心血来潮想建一个个人网站,调研了一圈,试用了 Weebly、Wix、Squarespace 等等产品,感觉都没有办法满足我的奇葩需求……最终还是觉得 GitHub Pages 是最好的——自由、免费、流量够用,目前的访问速度也还...

    3bcec58d740e4d1a008cbd2f00383862.png

    前段时间心血来潮想建一个个人网站,调研了一圈,试用了 Weebly、Wix、Squarespace 等等产品,感觉都没有办法满足我的奇葩需求……最终还是觉得 GitHub Pages 是最好的——自由、免费、流量够用,目前的访问速度也还不错,完美!

    GitHub Pagespages.github.com
    6426110e87e503615a20d10f7d22db03.png

    曾经还想用 GitHub Pages + Jekyll 的方式做,这样的话,之后可以用 markdown 来更新文章,一劳永逸。但是作为一个不会敲代码的设计,Jekyll 我真的搞不明白,安装各种工具的流程就失败了 (ಥ_ಥ)

    最终选择了用 html 模板做静态页面……后续更新的话,改 html 文件里的文章内容就行了,也没有很麻烦嘛~(自我安慰)

    这种建站方式大概是最简单的,全程不到十分钟,建好之后你可以根据自己的需求随意修改模板的内容和样式(当然,改到什么程度取决于你看得懂多少 html 和 css 的代码了……)

    这个教程会写得非常通俗简单小白,开发大佬不要嘲我哈~

    前期准备

    1. 安装一个 GitHub 的客户端,用来同步云端和本地的文件:GitHub Desktop
      可能有些大佬喜欢用终端同步?本小白还是喜欢可视化操作……这个网站打不开的话就找一下网盘版吧,应该也不少。
    2. 下载一个 html 的模板。这里安利一个网站:HTML5 UP,有几十个模板,质量都非常高,响应式设计,还都有二级页面,后续魔改一下也是可以满足五花八门的样式需求的。

    大致的流程

    1. 注册一个 GitHub 帐号,并建一个 GitHub Pages 的仓库
    2. 用 GitHub 客户端将仓库拉到本地
    3. 把 html 的模板文件放到对应的本地文件夹里
    4. 用 GitHub 客户端把本地文件夹同步到云端的仓库

    第一步:新建一个 GitHub Pages 的仓库

    • 点击网页右上角的「New repository」

    e52a0fb7f66909b7d7ce393991ed6fe0.png
    • 填写仓库名,格式必须是「你的 http://username.github.io」才能被识别

    76c010f9785e864c88f7d1858938da82.png
    • 建好后,进入仓库最后一个 tab「Settings」,在「GitHub Pages」那一栏点「Choose a theme」选一个默认的网页模板。这里随便选一个就行,反正后面会被其他模板替换掉,系统提供的模板都很简陋。

    56481922944fba25eb0c5b596eba6d57.png

    选完默认模板其实网站就创建好可以访问了,回到 Settings 的时候就会看到你的网站域名啦~

    这个时候你的仓库根目录下会有两个文件:_config.yml、index.html(这是网站的默认首页)

    299a6462c38a8d032f43ffe44431ea8b.png

    ba8eebccb2baf702d14720f690c1b0ef.png

    第二步:用 GitHub 客户端将仓库拉到本地

    • 安装好 GitHub 客户端后,登录你的帐号。然后克隆仓库,把刚刚建好的仓库文件夹拉到本地。

    279c101848d9de25eeab153e58619b8b.png

    0772d0a502a8394e558f934a22de8e28.png

    第三步:添加模板文件

    • 将下载好的模板文件解压,然后把里面的所有文件挪到你刚刚克隆到本地的文件夹中。index.html 直接替换,原来文件夹中的 _config.yml 就放那儿不用管它……

    5a89b21174bd198dd261a80d37f361c8.png

    最后一步:将文件夹内容同步到云端仓库

    • 这是打开 GitHub 客户端,已经可以看到好几项变动了,点击「Commit to master」,然后点击「Push origin」,等待几分钟就完成同步了。

    2f919c74bb6b730ff758a47928828f99.png

    4aa29b0cb83f8cffaff76d213262aee7.png

    再次访问个站链接,已经是新模板的样式啦~

    我这里随便选了 html5 up 的第一个模板,就是下图的样子。不过这个仓库是我为了写教程建的,已经删掉了,所以现在访问不了啦……

    5a10f8de559265a08e234d0d3f6d0d55.png

    最后简单介绍一下后续会常用的文件:

    • assets/css 里面都是网页的样式文件啦,后续要调整页面设计,也是这些文件改得最多。
    • index.html 上面提到了,是首页文件,首页的内容都在这个文件里改。
    • 你可以在根目录下新建一个文件夹放文章内容的 html,方便管理。

    之后有时间的话,会再写篇文章介绍一下我魔改网页样式的野路子吧,在这里就不赘述了。

    展开全文
  • 前段时间心血来潮想建一个个人网站,调研了一圈,试用了 Weebly、Wix、Squarespace 等等产品,感觉都没有办法满足我的奇葩需求……最终还是觉得 GitHub Pages 是最好的——自由、免费、流量够用,目前的访问速度也还...
  • WordPress、Drupal、Magento、Shopify、Joomla、Squarespace、Wix这么多外贸建站程序如何选择?一灯今天就给你最终答案,评测标准主要依托以下两个方面:灵活性:能跟上谷歌算法的更新,开箱即。开源...
  • wix toolset 失败 error CNDL0044 : The Class element’s ForeignServer or Server attribute was not found; one of these is required. C:\Program Files (x86)\WiX Toolset v3.11\bin>light.exe -ext ...
  • 但是,其实这些建站工具鱼龙混杂,很多都又丑又难,审美也不到位,导致网站显得很乱。所以一定要选择一个靠谱的建站平台,这样才能节省时间,快速建站。国外比较出名的有wordpress, wix, strikingly, 国内有上线了...
  • 大家一定想知道怪物的Appr值是怎么算出来的吧?其实有更简单的办法! 首先大家要准备好两个主角:SQL数据库与看wix软件(为什么要用看wix软件,因为这个软件查看...已知Appr值的情况下怎么用wix软件快速准确查看Mon-x(1~
  • 我们可以参考Wix或其他的安装程序,但是对于Electron应用更好的打包程序是Squirrel。毕竟某些著名的VisualStudioCode和Slack的客户端应用就是这个框架来打包和更新的。现在我来告诉你怎么创建一个基于Electron的...
  • 枸杞的由来和技术栈

    2021-01-02 15:11:32
    <code>ant-design</code> 和 <code>react-native-community</code> 以及 <code>wix</code> 三个组织产出的代码都靠谱,而且多数仓库都有人在维护。 但我对 React Native 的未来还是看好的。在去年的八月份&#...
  • WIX:setb S1_CD4052_9 setb S0_CD4052_10 SETB TR0 ACALL WII SJMP WIENE WII:CLR C MOV A,R4 SUBB A,R1 MOV R4,A MOV A,R5 SUBB A,R2 MOV R5,A MOV A,R6 SUBB A,#0 MOV R6,A RET WTR:JNB 0AH,TRA ...

空空如也

空空如也

1 2
收藏数 21
精华内容 8
关键字:

wix怎么用