Search code examples
wixshell-extensionswix3.11

WiX: How to restart Windows Explorer to install / uninstall a shell extension


I am trying to write a WiX installer that includes a managed icon shell extension (using SharpShell). I've finally figured out how to register it via Wix (I couldn't get the SharpShell registration manager to work whenn called via WiX).

During installation, the following dialog appears:

enter image description here

If I select "Ignore", the icon shell extension is successfully installed and Window Explorer picks up the change immediately. I'm not sure which files that its detecting as "In Use".

During uninstall, the following dialog appears:

Close applications prompt

If you select the "Automatically close and attempt to restart" option, it closes Windows Explorer, but it does not restart at the end of the installation. I have to manually restart it via task manager.

WiX Fragment Definition

The WiX fragment that defines the shell extension installation is shown below:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util='http://schemas.microsoft.com/wix/UtilExtension'>
    <!-- This fragment was originally generated using heat with the following command line:
            "$(WIX)bin\heat.exe" dir "$(SolutionDir)Icon ShellExtension\bin\$(ConfigurationName)" -dr IconShellExtensionDIR -cg IconShellExtension -var var.IconShellExtension.TargetDir -fips -g1 -gg -sfrag -srd -suid -template fragment -t "$(ProjectDir)AssemblyFileFilter.xslt" -out "$(ProjectDir)Fragments\IconShellExtension.wxs"
         
         It was then subsequently manually modified, as file associations are defined in a different component the default icon entry had to be removed.
    -->
    <Fragment>
    <DirectoryRef Id="IconShellExtensionDIR">
      <Component Id="IconShellExtension.dll" Guid="D609F6F2-52FB-4153-8D6A-3E2B7F8C4647">
        <Class Id="{A1C3600C-F3E5-300E-8167-541C62083DAA}" Context="InprocServer32" Description="IconShellExtension.UaProjectIconHandler" ThreadingModel="both" ForeignServer="mscoree.dll">
          <ProgId Id="IconShellExtension.UaProjectIconHandler" Description="UA Project File Icon Handler" />
        </Class>
        <util:RestartResource ProcessName="explorer.exe"/>
        <File Id="IconShellExtension.dll" KeyPath="yes" Source="$(var.IconShellExtension.TargetDir)\IconShellExtension.dll" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}" Value="" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32\1.0.0.0" Name="Class" Value="IconShellExtension.UaProjectIconHandler" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32\1.0.0.0" Name="Assembly" Value="IconShellExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e9ad08f31c5e4fb" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32\1.0.0.0" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32\1.0.0.0" Name="CodeBase" Value="file:///[#IconShellExtension.dll]" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32" Name="Class" Value="IconShellExtension.UaProjectIconHandler" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32" Name="Assembly" Value="IconShellExtension, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e9ad08f31c5e4fb" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32" Name="RuntimeVersion" Value="v4.0.30319" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="CLSID\{A1C3600C-F3E5-300E-8167-541C62083DAA}\InprocServer32" Name="CodeBase" Value="file:///[#IconShellExtension.dll]" Type="string" Action="write" />
        <RegistryValue Root="HKCR" Key="UserAppProject\ShellEx\IconHandler" Value="{a1c3600c-f3e5-300e-8167-541c62083daa}" Type="string" Action="write" />
        <RegistryValue Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Explorer" Name="GlobalAssocChangedCounter" Value="1" Type="integer" Action="write" />
      </Component>
      <Component Id="SharpShell.dll" Guid="174E147D-4744-492F-BC5C-F00DAA4925AA">
        <File Id="SharpShell.dll" KeyPath="yes" Source="$(var.IconShellExtension.TargetDir)\SharpShell.dll" />
      </Component>
    </DirectoryRef>
  </Fragment>
  <Fragment>
    <ComponentGroup Id="IconShellExtension">
      <ComponentRef Id="IconShellExtension.dll" />
      <ComponentRef Id="SharpShell.dll" />
    </ComponentGroup>
  </Fragment>
</Wix>

Goal

I want the installer to be able to install or uninstall without prompting the user about files in use, and it just auto close and restart Windows Explorer during the process. My understanding is that's what the restart manager allows, and the WixUtils RestartResource tag should do this for me.

Any help would be appreciated!

UPDATE

I have tried various different combinations of properties and attempted to remove/disable the FilesInUse dialog.

I tried setting the following combination of properties as suggested in this post:

    <Property Id="MSIRMSHUTDOWN" Value="2"/>
    <Property Id="MSIDISABLERMRESTART" Value="0"/>
    <Property Id="MSIRESTARTMANAGERCONTROL" Value="0"/>

This performed the restart of explorer.exe during uninstall, once the uninstall sequence was completed (although the length of time the explorer was shutdown for was lengthy). However, I found that when I attempt to reinstall, it displayed the FilesInUse dialog again.

I found a solution that worked for me which I will post as the accepted answer.


Solution

  • The best solution that seemed to work and did not display any unwanted dialogs was to remove the MSIRMSHUTDOWN and MSIDISABLERMRESTART properties and set the following property:

        <!-- The following setting seems to suppress any restart dialogs -->
        <Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable"/>
    

    This cleanly added or removed my shell extension. The only issue is that the shell extension remained active until I rebooted (as this was an Icon Shell Extension only, then this was acceptable to me).