如何正确实施我的安装程序 [英] How do I implement my Installer correctly

查看:28
本文介绍了如何正确实施我的安装程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个安装程序,它会自动更新已安装的组件.因此,我创建了一个安装程序项目,具有以下设置:

I'm trying to create an installer, which automagically updates the installed component. Therefore I have created an installer-project, with following settings:

  • 产品代码:{9835AE3C-1CED-4FC6-85E1-D2DC8093E9F4}
  • 产品名称:Foo
  • 升级代码:{02FD8E1A-A552-47AE-BDAA-F165702DE8DC}
  • 版本:1.2.002

当我更改我的 Version 属性时,会生成一个新的 ProductCode(按照我的理解,产品的分组是通过 UpgradeCode 并且特定版本绑定到ProductCode).

When I change my Version-attribute, a new ProductCode gets generated (how I understood, the grouping on the product is done via UpgradeCode and the specific version is bound to ProductCode).

我的自定义操作如下所示:

My Custom-Actions look like this:

Sooo ... 这里有我的安装程序类:

Sooo ... here we have my installer-class:

[RunInstaller(true)]
// my .cs-file
public partial class Installer : System.Configuration.Install.Installer
{
    public Installer()
    {
        this.InitializeComponent();
    }

    protected override void OnAfterInstall(System.Collections.IDictionary savedState)
    {
        base.OnAfterInstall(savedState);

        using (var serviceController = new ServiceController(Settings.Service.Name))
        {
            serviceController.Start();
            serviceController.WaitForStatus(ServiceControllerStatus.Running);
        }
    }

    protected override void OnBeforeUninstall(System.Collections.IDictionary savedState)
    {
        base.OnBeforeUninstall(savedState);

        using (var serviceController = new ServiceController(Settings.Service.Name))
        {
            serviceController.Stop();
            serviceController.WaitForStatus(ServiceControllerStatus.Stopped);
        }
    }
}


// my designer
partial class Installer
{
    private ServiceInstaller ServiceInstaller;
    private ServiceProcessInstaller ServiceProcessInstaller;

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary> 
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Component Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.ServiceProcessInstaller = new System.ServiceProcess.ServiceProcessInstaller();
        this.ServiceInstaller = new System.ServiceProcess.ServiceInstaller();
        // 
        // ServiceProcessInstaller
        // 
        this.ServiceProcessInstaller.Account = System.ServiceProcess.ServiceAccount.LocalService;
        this.ServiceProcessInstaller.Password = null;
        this.ServiceProcessInstaller.Username = null;
        // 
        // ServiceInstaller
        // 
        this.ServiceInstaller.ServiceName = "Foo";
        this.ServiceInstaller.StartType = System.ServiceProcess.ServiceStartMode.Automatic;

    }

    #endregion
}

初始安装不是问题 - 一切正常(安装、自动启动等).但是,当我尝试安装具有相同 UpgradeCode 但不同 ProductCode 的新 .msi 包时,安装程​​序失败并显示错误 1001:指定的服务已经存在" - 其中让我相信,没有调用任何卸载处理程序(或调用)并且 UpgradeCode/Productcode-magic 不起作用......
所以,我的问题是:处理(或应该处理)卸载的路径(覆盖)在哪里?什么是正确的实现?

The initial installation is not the problem - everything works fine (installation, automatic start, ...). But when I try to install a new .msi-package with the same UpgradeCode but different ProductCode, the installer fails with "Error 1001: The specified service already exists" - which makes me believe, that any uninstall-handler (or invocation) is not being called and that the UpgradeCode/Productcode-magic does not work ...
So, my question: Where is the path (overriding) which handles (or should handle) the uninstallation? What would be the correct implementation?


HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer:Logging 的设置是 iwemv - 输出@ pastebin(实际上,我的场景中的代码与此处的问题不同).
正如我们在第 161ff 行看到的,找到了以前的版本:

edit:
Setting of HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows\Installer:Logging is iwemv - output @ pastebin (actually I have different codes in my scenario as in my question here).
as we see in line 161ff, the previous version is found:

MSI (c) (50:04) [10:03:31:319]: Doing action: AppSearch
Aktion gestartet um 10:03:31: AppSearch.
MSI (c) (50:04) [10:03:31:319]: Note: 1: 2262 2: AppSearch 3: -2147287038 
Aktion beendet um 10:03:31: AppSearch. Rückgabewert 1.
MSI (c) (50:04) [10:03:31:319]: Doing action: FindRelatedProducts
Aktion gestartet um 10:03:31: FindRelatedProducts.
MSI (c) (50:04) [10:03:31:319]: PROPERTY CHANGE: Adding PREVIOUSVERSIONSINSTALLED property. Its value is '{C4C4318A-2F89-416B-A48C-76BD035EB52B}'.
Aktion beendet um 10:03:31: FindRelatedProducts. Rückgabewert 1.

第 272 行调用@客户端

line 272 invocation @ client

MSI (c) (50:04) [10:03:31:413]: Switching to server: TARGETDIR="C:\Program Files (x86)\MyCompany\Foobar\" ALLUSERS="1" PREVIOUSVERSIONSINSTALLED="{C4C4318A-2F89-416B-A48C-76BD035EB52B}" VSDNETURLMSG="Dieses Setup erfordert die Version 4.0 von .NET Framework. Installieren Sie .NET Framework, und führen Sie Setup erneut aus. .NET Framework kann über das Internet bezogen werden. Möchten Sie es jetzt beziehen?" VSDNETMSG="Dieses Setup erfordert die Version 4.0 von .NET Framework. Installieren Sie .NET Framework, und führen Sie Setup erneut aus." CURRENTDIRECTORY="D:\Foo\Release" CLIENTUILEVEL="0" CLIENTPROCESSID="5200" USERNAME="MyCompany Support" COMPANYNAME="MyCompany GmbH" SOURCEDIR="D:\Foo\Release\" ACTION="INSTALL" EXECUTEACTION="INSTALL" ROOTDRIVE="D:\" INSTALLLEVEL="1" SECONDSEQUENCE="1"  ADDLOCAL=DefaultFeature  

第 313 行调用@服务器

line 313 invocation @ server

MSI (s) (A4:6C) [10:03:41:219]: Command Line: TARGETDIR=C:\Program Files (x86)\MyCompany\Foobar\ ALLUSERS=1 PREVIOUSVERSIONSINSTALLED={C4C4318A-2F89-416B-A48C-76BD035EB52B} VSDNETURLMSG=Dieses Setup erfordert die Version 4.0 von .NET Framework. Installieren Sie .NET Framework, und führen Sie Setup erneut aus. .NET Framework kann über das Internet bezogen werden. Möchten Sie es jetzt beziehen? VSDNETMSG=Dieses Setup erfordert die Version 4.0 von .NET Framework. Installieren Sie .NET Framework, und führen Sie Setup erneut aus. CURRENTDIRECTORY=D:\Foo\Release CLIENTUILEVEL=0 CLIENTPROCESSID=5200 USERNAME=MyCompany Support COMPANYNAME=MyCompany GmbH SOURCEDIR=D:\Foo\Release\ ACTION=INSTALL EXECUTEACTION=INSTALL ROOTDRIVE=D:\ INSTALLLEVEL=1 SECONDSEQUENCE=1 ADDLOCAL=DefaultFeature ACTION=INSTALL 

sooo ... 操作是安装,而不是更新/卸载/...?!

sooo ... action is install, and not update/uninstall/...?!

推荐答案

既然你问得正确",你应该知道 InstallUtil 自定义操作是一个可怕的反模式,你正在重新发明轮子,为 MSI 已经支持的东西编写代码.您还应该知道 Visual Studio 部署项目在很多方面都很糟糕(在这种情况下,不会暴露 MSI 安装和控制服务的能力),它们在 VS11 的下一个版本中被删除.

Since you asked "correctly" you should know that InstallUtil custom actions are a horrible antipattern and you are reinventing the wheel by writing code to things MSI already supports natively. You should also know that Visual Studio Deployment projects are horrible in so many ways ( in this case not exposing MSI's ability to install and control services ) that they are removed in the next release of VS11.

一些背景:(你的就是 a 和 c 的例子)

Some background: ( Yours is an example of a and c )

Zataoca:自定义操作(通常)是承认失败.

现在我给您的建议是摆脱自定义操作并改用 WiX 合并模块.这个概念是将包含您的服务 EXE 的组件分解为合并模块,然后让您的 VDPROJ 使用合并模块.(从控制台应用程序中取出一个类并将其移动到库中,然后使用 ILDASM 将库合并回控制台应用程序,如果您愿意的话).使用 Windows Installer XML 创作合并模块,因为 1) 它实际上公开了 ServiceInstall 和 ServiceControl 表,2) 它是 FOSS.

Now my advice to you is to get rid of the custom action and use a WiX merge module instead. The concept is to factor the component that has your service EXE into a merge module and then have your VDPROJ consume the merge module. ( Take a class out of a console app and move it into library and then use ILDASM to merge the library back into the console app if you will ). Use Windows Installer XML to author the merge module because 1) it actually exposes the ServiceInstall and ServiceControl tables and 2) it's FOSS.

使用 Windows Installer XML 增强 InstallShield - Windows 服务

您生成的 MSI 会更简单/更清晰,并且您的 1001 错误消息会神奇地消失,因为 MSI 正在为您工作.

Your resultant MSI will be much simpler / cleaner and your 1001 error messages will magically go away because MSI is doing the work for you.

这篇关于如何正确实施我的安装程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆