旧文件夹的msisettargetPatha在升级时以1315失败(无法写入指定文件夹)

发布于 2025-01-24 16:38:05 字数 4392 浏览 2 评论 0原文

序言

我们已更改了产品的默认安装文件夹,但是我们现有客户端需要在升级上保留旧的安装路径。 更新:独立msimsm模块是用Wix构建的。但是,整个项目是使用Wix MSM S模块构建的。因此,应在两种项目类型(WIX和InstallShield)中重复使用自定义。

选择的解决方案

由于installdir目录表中的输入已更改,因此我需要在自定义期间找到已安装产品的路径并修改installdir行动。

这是sopitoldPathonUpgrade自定义代码的一部分,该代码是在Costfinalize之后立即执行的:

        guid_str_t guidBuffer{};
        auto bufferLenght = DWORD(guidBuffer.size());

        constexpr const auto propUpgradingProduct = "UPGRADING_PRODUCT";

        UINT res = MsiGetPropertyA(hInstall,
            propUpgradingProduct,
            guidBuffer.data(),
            &bufferLenght);

        if (ERROR_SUCCESS != res)
            throw std::runtime_error(std::string("Failed to get property \"") +
                propUpgradingProduct + 
                "\", Error: " +
                getLastError());

        logMessage(std::string() + __func__ + ": current INSTALLDIR = \"" + getCurrentInstallDir() + "\"");

        const auto& oldPath = getPathByGUID(guidBuffer);
        logMessage(std::string() + __func__ + ": setting INSTALLDIR to old path: \"" + oldPath + "\"");

        constexpr const auto installFolderIdentifier = "INSTALLDIR";
        res = MsiSetTargetPathA(hInstall, installFolderIdentifier, oldPath.c_str());

        if (ERROR_SUCCESS != res)
            throw std::runtime_error(std::string("Failed to set INSTALLDIR on an product update. Error: ") +
                getLastError());

这是Wix定义:

<Fragment>
  <CustomAction Id="AssignOldPathOnUpgrade"
                BinaryKey="DLServiceCA"
                DllEntry="AssignOldPathOnUpgrade"
                Execute="immediate"
                Impersonate="no"
                Return="check" />
  <Binary Id="DLServiceCA" SourceFile="$(var.DLServiceCA.TargetPath)" />
</Fragment>

和Wix installexecutesequence

      <Custom Action="AssignOldPathOnUpgrade" After="CostFinalize">
          UPGRADING_PRODUCT
      </Custom>

问题:问题

。 CUSTIOMACTION因msisettargetPatha返回error_directory带有安装程序的内部错误1315代表无法写入指定文件夹

  1. 如果升级安装是由管理员组成员的用户运行的:启动UAC后不久要求高程。 1315当调用soprionoldPathonupgrade时出现错误。
  2. 如果升级安装是使用管理特权(作为管理员)运行的,则升级是成功的,并且将新版本复制到旧路径。
  3. 以前的升级具有相同的(硬编码)安装目录,因为旧升级目录是由UAC高程(第一个方案)启动的旧升级

dirctory组件

的所有先前版本的WIX项目都通过installDir通过组件 andiss pripiliges:

<Fragment>
    <?if $(sys.BUILDARCH) = x86?>
      <?define INSTALLDIRComponent.Id = "{155AB3A7-0160-419D-AC7D-7BA88AF6E938}" ?>
    <?elseif $(sys.BUILDARCH) = x64?>
      <?define INSTALLDIRComponent.Id = "{E2186CCC-A834-4F37-B58C-F55A11E9E5DD}" ?>
    <?endif?>

    <Component Directory="INSTALLDIR"
               Id="INSTALLDIRComponent"
               Guid="$(var.INSTALLDIRComponent.Id)"
               Location="local"
               Win64="$(var.Win64)" >

      <CreateFolder>
        <Permission User="Administrators" GenericAll="yes"/>
        <Permission User="Everyone" Read="yes" GenericRead="yes"/>
      </CreateFolder>
    </Component>
</Fragment>

结论

  1. 我如何解决此错误解决问题(没有某些疯狂的休息性解决方法)?用户必须能够像使用Previos版本一样进行UAC高程的升级。
  2. installDir是硬编码时,为什么可以将(使用UAC高程)升级到旧路径,而1315当调用msisettargetPatha时出现错误?

更新

MsisettArgetPath如果仅读取选定目录,则会失败。

当我启用读取 用户组的权限时,msisettargetPatha成功。但是,它从来没有启用用户,因此在调用mSisettArgetPatha的电话之间切换此prsight 是不是一个选项


更新2

允许UAC进行安装后,我发现的是,当前用户的MSI过程是 升高的:

因此,我认为它不代表管理员行动(但是, hummy 管理员组的成员组的成员),因此许可 Write 不适用于虚拟在未提升的上下文中。
当路径被硬编码时,为什么它成功将文件复制到目录? - 我想这是因为复制是由系统执行的。这是一个猜测。

Preface

We have changed the default installation folder for a product, but there is a requirement from our existing clients to preserve the old installation path on an upgrade. Update: standalone msi and msm modules are built with Wix. However, the whole project is built with InstallShield using Wix msms modules. So the CustomAction should be reusable in both project types (Wix and InstallShield).

Chosen solution

Since the INSTALLDIR entry in a Directory table has changed, I need to find the path of the installed product and modify INSTALLDIR during a custom action.

This is a part of AssignOldPathOnUpgrade CustomAction's code, which is executed right after CostFinalize:

        guid_str_t guidBuffer{};
        auto bufferLenght = DWORD(guidBuffer.size());

        constexpr const auto propUpgradingProduct = "UPGRADING_PRODUCT";

        UINT res = MsiGetPropertyA(hInstall,
            propUpgradingProduct,
            guidBuffer.data(),
            &bufferLenght);

        if (ERROR_SUCCESS != res)
            throw std::runtime_error(std::string("Failed to get property \"") +
                propUpgradingProduct + 
                "\", Error: " +
                getLastError());

        logMessage(std::string() + __func__ + ": current INSTALLDIR = \"" + getCurrentInstallDir() + "\"");

        const auto& oldPath = getPathByGUID(guidBuffer);
        logMessage(std::string() + __func__ + ": setting INSTALLDIR to old path: \"" + oldPath + "\"");

        constexpr const auto installFolderIdentifier = "INSTALLDIR";
        res = MsiSetTargetPathA(hInstall, installFolderIdentifier, oldPath.c_str());

        if (ERROR_SUCCESS != res)
            throw std::runtime_error(std::string("Failed to set INSTALLDIR on an product update. Error: ") +
                getLastError());

Here is the Wix definition:

<Fragment>
  <CustomAction Id="AssignOldPathOnUpgrade"
                BinaryKey="DLServiceCA"
                DllEntry="AssignOldPathOnUpgrade"
                Execute="immediate"
                Impersonate="no"
                Return="check" />
  <Binary Id="DLServiceCA" SourceFile="$(var.DLServiceCA.TargetPath)" />
</Fragment>

And Wix InstallExecuteSequence:

      <Custom Action="AssignOldPathOnUpgrade" After="CostFinalize">
          UPGRADING_PRODUCT
      </Custom>

The Problem

The CustiomAction fails due to MsiSetTargetPathA returning ERROR_DIRECTORY with Installer's internal error 1315 which stands for Unable to write to the specified folder.

  1. If the upgrade installation is run by a user who is a member of Administrators group: shortly after launch UAC asks for elevation. And 1315 error occurres when AssignOldPathOnUpgrade is invoked.
  2. If the upgrade installation is run with the administrative priviliges (Run as Administrator), the upgrade is successfull and the new version is copied to the old path.
  3. Previous upgrades that had the same (hardcoded) default directory for installation as the old one are successful when launched by a user with UAC elevation (the 1st scenario).

Dirctory component

The Wix project for all the previous versions creates the INSTALLDIR via a Component and assigns priviliges:

<Fragment>
    <?if $(sys.BUILDARCH) = x86?>
      <?define INSTALLDIRComponent.Id = "{155AB3A7-0160-419D-AC7D-7BA88AF6E938}" ?>
    <?elseif $(sys.BUILDARCH) = x64?>
      <?define INSTALLDIRComponent.Id = "{E2186CCC-A834-4F37-B58C-F55A11E9E5DD}" ?>
    <?endif?>

    <Component Directory="INSTALLDIR"
               Id="INSTALLDIRComponent"
               Guid="$(var.INSTALLDIRComponent.Id)"
               Location="local"
               Win64="$(var.Win64)" >

      <CreateFolder>
        <Permission User="Administrators" GenericAll="yes"/>
        <Permission User="Everyone" Read="yes" GenericRead="yes"/>
      </CreateFolder>
    </Component>
</Fragment>

Conclusion

  1. How can I solve the problem with this error (without some insanelly convoluted workarounds)? User must be able to do an upgrade with UAC elevation just like with previos versions.
  2. Why is it possible to upgrade (with UAC elevation) to an old path when INSTALLDIR is hardcoded, but 1315 error occurres when MsiSetTargetPathA is called?

Update

The documentation says:

MsiSetTargetPath fails if the selected directory is read only.

When I enable Read permission for Users group, MsiSetTargetPathA succeeds. But it is not ever enabled for Users, so toggling this prmission between calls to MsiSetTargetPathA is not an option.


UPDATE 2

After allowing UAC to proceed with installation I found out, that the msi process from the current user is not elevated:
enter image description here

Hence, I think it does not act on behalf of an Administrator (however, dummy is a member of Administrators group), so the Permission to Write does not apply to dummy in an unelevated context.
Why does it successfully copy files to the directory when the path is hardcoded? - I guess it is because the copying is performed by the SYSTEM. This is a guess though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

妥活 2025-01-31 16:38:05

You should be using SetDirectory to change the directory path. If you really need to run custom code to get the previous path, then it should set a new property and then a SetDirectory should set the directory to the value using that new property.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文