如何在 WIX 中为目录分配路径值? [英] How to assign path value to Directory in WIX?

查看:24
本文介绍了如何在 WIX 中为目录分配路径值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的 WIX 项目中,我有一个类似这样的目录结构:

<Directory Id="INSTALLLOCATION" Name="FolderName">...</目录><Directory Id="MYDIRECTORY" Name="SomeDifferentDirectory">...</目录></目录>

这里INSTALLLOCATION代表我的程序的安装文件夹,但是我想另外创建一个安装目录之外的目录,例如,D:\MyFolder1\MyFolder2,从上面的例子中,我如何将此值分配给 MYDIRECTORY 以便在安装完成后创建它?

解决方案

我没有时间测试下面列出的选项,但它们应该是可行的技术可能性.希望其中一种选择会令人满意.

但是,首先:我不喜欢这种设置二级顶级目录的方法 - 真的需要吗?你能解释一下这个场景吗?也许有更可靠的方法?

请参阅底部的替代方案?"部分,了解我认为比摆弄"目录属性更好的方法.如果我是你,我会读这个替代方案?"第一部分 - 也许它可以为您节省很多麻烦?

但第一部分涉及各种技术选项来完成您的要求:

<小时>

设置目录属性

有很多方法可以设置目录属性,这让我很头疼.正如我所说,我没有时间测试这些选项 - 发布未经测试的建议总是很生气,但您似乎可以帮助自己提供一些建议:

  1. 上面看到的浏览按钮仅适用于指定了 ConfigurableDirectory 属性指向自定义目录属性的功能(忽略上面屏幕截图中的 C:\ 条目- 只是一个小问题):

    <Feature Id="ProductFeature" Title="MinimalShortcutTester" Level="1"><ComponentGroupRef Id="ProductComponents"/></功能><!-- 一个可配置的目录功能--><Feature Id="FeatureDirectory" Title="FeatureDirectory" ConfigurableDirectory="MYCUSTOMDIR"><!-- 你的东西在这里--></功能>

    以及 WiX 源中的其他位置,实际可配置目录:

    <!-- 必须更改的模型 GUID,自定义目标目录不适用于自动 GUID --><Component Id="MyFile.exe" Guid="{00000000-0000-0000-0000-000000000000}" Feature="FeatureDirectory"><File Source="C:\SourceControl\MyFile.exe"/></组件></目录>

    我会使用一个额外的自定义操作来很好地默认这个 MYCUSTOMDIR 目录,或者检查用户所做的选择的有效性.这并不完全是直截了当的,但必须在每种情况下处理.

    再想一想,我可能会使用 set property custom action 将 MYCUSTOMDIR 目录默认为 PersonalFolder 的子文件夹,然后允许用户覆盖它安装.现在您必须回读用户对修改和修复(以及其他安装模式)的选择,否则您将默认为 PersonalFolder 以及您在其他安装模式中指定的任何子文件夹.您可以在注册表中保留用户文件夹选择,然后使用 AppSearch(我认为大多数专业人士的偏好)读回它,或者在自定义操作中完成所有操作.在所有安装模式下使这项工作正常进行可能具有挑战性.做好测试.

    技术挑战:如果您在注册表中为 MYCUSTOMDIR 保留原始文件夹选择并使用 AppSearch 读取它,您必须确保调整您的设置属性自定义操作(用于将默认值设置为 MYCUSTOMDIR 如果未设置值),以便在该属性已具有从注册表中检索到的值时它不会运行.不是火箭科学,但可以很巧妙地做到正确 - 并且对所有安装模式下的测试都很挑剔.如果您依赖标准构造而不是自定义操作,一旦您了解所涉及的活动部件",您通常会受益 - 首先您默认首次安装,因为尚未设置任何值(除非通过命令行设置值),然后您允许它在 GUI 中(或通过命令行)被覆盖,然后在安装过程中保留在注册表中,在下次启动时(修复、修改、自我修复、升级、补丁),你读回持久化的值,不要让通过条件等设置默认值...

    为了安全保存链接:Wix:禁用内置对话框中的控件.

    <小时>

    替代方案?

    如上所述,通过更好地理解替代方案,通常可以避免这些二级顶级目录层次结构.

    检查替代方案的一些问题:

    • 哪些文件会进入这个二级顶级文件夹?数据文件?数据库?
    • 此类文件夹通常用于存放数据文件,有时使用的文件夹对于每个用户都是唯一的(即不是共享文件夹).例如我的文档".
      • 在这些情况下,我喜欢让应用程序在启动时创建文件夹(将对此类文件夹进行写访问),然后将每个用户所需的任何文件从安装在某处的只读模板副本复制到该文件夹​​中在 %ProgramFiles% 下.
      • MSI 不适用于部署用户配置文件.我在这里写了一些问题的摘要:从管理员配置文件在当前用户配置文件上创建文件夹和文件.通常不清楚如何引用多次部署的计数文件,每个用户一次.
      • 我多次重复这个建议,但有时处理用户配置文件部署确实是一场噩梦.非常常见的问题:(1) 意外的数据覆盖/重置,(2) 无法将用户配置文件复制到位,(3) 意外卸载修改后的文件(读取:用户数据),(4)无法可靠地覆盖现有文件 - 同样的问题往往会重复发生.
    • 当然也有可能因为其他原因需要这样一个顶级文件夹,但我敢打赌,它将填充用户数据或用户可修改的文件.这准确吗?

    In my WIX project I have a directory structure something like this:

    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="INSTALLLOCATION" Name="FolderName">
       ...
      </Directory>
      <Directory Id="MYDIRECTORY" Name="SomeDifferentDirectory">
       ...
      </Directory>
    </Directory>
    

    Here INSTALLLOCATION represents the installation folder of my program, but I want to additionally create another directory that is outside the installation directory, for example, D:\MyFolder1\MyFolder2, from the example above how can I assign this value to MYDIRECTORY so that it will be created after installation completes?

    解决方案

    I don't have time to test the options I list below, but they should be viable, technical possibilities. Hopefully one of the options will be satisfactory.

    But, first of all: I dislike this approach of setting secondary, top-level directories - is it really needed? Can you explain the scenario? Maybe there is a more reliable way?

    See the "Alternatives?" section towards the bottom for what I deem to be a better approach than to "fiddle around" with directory properties. If I were you I would read this "Alternatives?" section first - maybe it saves you a whole lot of trouble?

    But the first section deals with various technical options to do what you ask:


    Setting a Directory Property

    There are many ways to set a directory property, off the top of my head. As I said, I haven't had time to test these options - and it is always mad to post untested advice, but you seem like someone who can help yourself with some pointers:

    1. AppSearch - you can search the system for a specific file or registry entry and set the directory property to the path found (if any).
      • Very often the path you need can be found this way - and reliably too in the sense that it is a built-in feature (and hence better tested than any custom construct from yourself).
      • You can add a custom action as well to verify that the directory found is valid - if need be. Such "verify data" custom actions can be made pretty safe since they don't change the system - but they can still cause unexpected runtime failures if you are not careful and allow them to return error codes or abort the setup.
    2. A Set Property Custom Action (Custom Action Type 51). Just set the path to something like [ROOTDRIVE]MyFolder.
      • If someone would do that I would fail the package for quality reasons (it is technically possible, but ROOTDRIVE may switch to point to a different path depending on disk space available on each drive - not good at all).
      • Know about the possibility, look for it, fix it if you find it. Don't use it. Seductive the dark side is.
      • Ironically, if I am honest, setting something to [WindowsVolume]MyFolder - may actually work, but I don't like it personally. I want nothing installed to a top-level folder on the system drive in the first place.
      • I believe WiX has the SetDirectory Element for this "set property" purpose. I think it does all the custom action work for you. Some auto-magic. I am however not sure if this feature allows PUBLIC PROPERTIES to be overridden from the command line?
      • If you set something to D:\MyFolder you have to be aware that this path could at some point be missing unexpectedly (drive removed from system, new drive added (?), new DVD drive added (?), drive letter manually changed, etc...).
        • This is beyond normal "set property" actions - it is essentially "hard-coding" (see issue 5 below). Hard coding is never acceptable - for any package with generalized distribution.
        • I would prefer to target PersonalFolder (My Documents) and then redirect this to D:\ in Windows itself. I believe Windows will then assign a new value to PersonalFolder if it can't be found on boot. Windows Installer will then still be able to enumerate the target folders and not just get stuck or crash.
    3. Set directory as a feature directory exposed in the custom dialog in the installer GUI.

      • Mad to suggest since I have never used it, but it is an viable option I think - but requires significant testing in all installation modes (install, repair, self-repair, uninstall, modify, patching, et...) to make sure it works as desired.
        • Quick update: I did a smoke test, it works, but it is not trivial to do I would say. See mock up GUI sample and some WiX snippets in next section below.
      • This involves adding a separate feature for the components set to this feature directory. Then you set the ConfigurableDirectory attribute of the FeatureElement in your WiX source equal to the PUBLICPROPERTY holding the directory path.
      • You should now be able to set this directory from the WiX GUI if you use the dialog set Mondo (<UIRef Id="WixUI_Mondo" />) - from the "Custom" dialog. There is a step-by-step sample using Visual Studio to update a WiX source file to use Mondo here: WiX installer msi not installing the Winform app created with Visual Studio 2017.
      • The GUI selection you make (directory) will be assigned to the property you specified as the ConfigurableDirectory for the feature.
      • Somehow you must set the directory property to something meaningful for a silent install - when the GUI is skipped - or you could abort installation if nothing is defined for the property on the command line.
      • I would check for a valid directory while at it and protect against generalized lunacy such as installing to the system folder, installing straight to C:\, installing into existing folders for other products, etc... - "...users are amazingly creative when it comes to exercising a system in unexpected ways" - Grady Booch - words to live by, and what a cool name - and hair - :-).
    4. A regular, immediate mode custom action (not a set property custom action) which sets a property with a call to Session.Property = "SomeValue" somewhere in the code. Each type of custom action type does this "property set" slightly differently (custom action types: VBScript, C++, DTF / C#, etc... See documentation from Advanced Installer for how this can be done).

      • I am always telling people to avoid custom actions, and it is definitely true for read-write custom actions: Why is it a good idea to limit the use of custom actions in my WiX / MSI setups?.
      • I do, however, use read-only custom actions set to suppress errors and not return errors that roll back the setup when needed. This allows you some power to inspect the system as you see fit to determine what to set to the property in question.
      • Crucially such immediate mode read-only custom actions require no rollback feature since they make no system changes, they don't run elevated either, and most of them "live in the GUI sequence" and are used to get data and settings from the user - or checking various conditions and states of the target system - just inspecting things (they are often also needed in the silent install sequence if the GUI is skipped).
      • Remember that the GUI sequence is skipped in silent installation mode, so your custom action must live in both sequences. You can condition it to run only once though.
    5. Some people even hard code paths in the property table, or using a set property custom action to assign C:\ to a property at runtime - not at all acceptable. This will break - it is merely a question of time. On computers without a C:\ drive it will not install at all - for starters.

      • Not sure if such a property, set in the property table would be overridden during directory resolution and costing - I have never bothered to try - it is not a solution and I just want to state that to prevent its use.

      • A set property custom action assigning C:\ or similar to a property will appear to work, but will blow up in unexpected ways. Guaranteed.

      • Again: if you can help it, don't deploy to a separate, top-level folder.

    6. I have heard some people - in corporate, standardized environments - use an environment variable to define such installation folders. I have never used it for production, never tried it for testing and don't like it as an option.

    Keep in mind that public properties can be set at the command prompt - and hence potentially override whatever logic you add to set it yourself. Maybe add a custom action to check for values coming in from the command line, and either accept it or abort the setup if it is wrong.


    WiX-installer With Configurable Feature Directory

    Here is the GUI screenshot of a WiX installer with configurable feature directory:

    The browse button seen above is only available for features that has the ConfigurableDirectory attribute specified pointing to a custom directory property (ignore the C:\ entry in the screenshot above - just a hiccup):

    <!-- A standard feature -->
    <Feature Id="ProductFeature" Title="MinimalShortcutTester" Level="1">
       <ComponentGroupRef Id="ProductComponents" />
    </Feature>
    
    <!-- A configurable directory feature -->
    <Feature Id="FeatureDirectory" Title="FeatureDirectory" ConfigurableDirectory="MYCUSTOMDIR">
            <!-- your stuff here -->
    </Feature>
    

    And elsewhere in the WiX source, the actual configurable directory:

    <Directory Id="MYCUSTOMDIR">
         <!-- Mock-up GUID that MUST be changed, custom target directories do not function with auto-GUIDs -->
         <Component Id="MyFile.exe" Guid="{00000000-0000-0000-0000-000000000000}" Feature="FeatureDirectory">
             <File Source="C:\SourceControl\MyFile.exe" />
         </Component>    
    </Directory>
    

    I would use an extra custom action to default this MYCUSTOMDIR directory well, or to inspect the choice made by the user for validity. This is not entirely straight forward, but must be dealt with in each case.

    On second thought, I might use a set property custom action to default the MYCUSTOMDIR directory to a sub-folder of PersonalFolder, then allow the user to override it on install. Now you have to read back the user choice on modify and repair (and other installation modes), or else you will default to PersonalFolder and whatever sub-folder you specified in other installation modes. You can persist the user folder selection in the registry, and read it back using AppSearch (the preference of most of the pros I think) or do it all in a custom action. It can be challenging to make this work right in all installation modes. Do test well.

    Technical challenge: if you persist your original folder selection for MYCUSTOMDIR in the registry and read it back with AppSearch, you must make sure to condition your set property custom action (used to set a default value to MYCUSTOMDIR if no value is set) so that it does not run if the property already has a value retrieve from the registry. Not rocket science, but can be fiddly to get right - and be nitpicking about testing in all installation modes. If you rely on standard constructs and not custom actions you generally benefit once you understand "the moving parts" involved - first you default on first install since no value is set yet (unless a value is set via the command line), then you allow it to be overridden in the GUI (or by command line), then you persist in the registry during installation, on next launch (repair, modify, self-repair, upgrade, patch) you read back the persisted value and don't let the default value be set via condition, etc...

    Throwing in a link for safe-keeping: Wix : Disable control in built-in dialog.


    Alternatives?

    As stated above these secondary top-level directory hierarchies may often be avoided by a better understanding of alternatives.

    Some questions to check for alternatives:

    • What files are going to this secondary top-level folder? Data files? Databases?
    • Often such folders are for data files, and sometimes the folder used is unique for each user (i.e. not a shared folder). For example "My Documents".
      • In these cases I like to have the application create the folder on launch (there will be write access to such a folder), and then copy whatever files are required to the folder for each user from read-only template copies installed somewhere under %ProgramFiles%.
      • MSI is not great for deployment of user-profile files. I wrote a summary of some of the issues here: Create folder and file on Current user profile, from Admin Profile. It is not generally clear how to reference count files deployed many times, once per user.
      • I repeat this advice too many times, but it really is a nightmare to deal with userprofile file deployment at times. Very common problems: (1) unexpected data overwrite / reset, (2) failing to copy the userprofile files in place, (3) unexpected uninstall of modified files (read: user data), (4) unable to overwrite existing files reliably - the same problems tend to repeat.
    • It is of course also possible for such a top-level folder to be needed for other reasons, but my bet is that it will be filled with user-data or user-modifiable files. Is this accurate?

    这篇关于如何在 WIX 中为目录分配路径值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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