Search code examples
c#wixwindows-installerrundll32

Wix custom action shows a error dialog from RunDLL "Access is denied" when installer is ran a second time


Created an installer of a toolkit with a Visual Studio extension as part of it in Wix 3.14. It contains a custom action that searches the local system for installed versions of Visual Studio 2019 and 2022. The custom action is written in managed C# using an open source sample from Microsoft. The first time a user runs the installer it will complete successfully and all is fine. If the user uninstalls and runs again they will get an error dialog from RunDLL stating "There was a problem starting [File path to temp file in temp folder]" and below that message is "Access is denied". This installer is per machine so the installer is running with elevated privileges.

The Wix project uses the WixVSExtension to search for VS2019 with its related folders and my extension fills the VS2022 void. The WixVSExtension never fails and it performs a similar function.

In troubleshooting I have narrowed the error down to when the custom action is invoked. I have observed that the msi removes the temp file when it has completed. At first I thought maybe it was a file name clash. I've watched it using ProcMon and don't get any definitive results to point to a culprit.

I have tried debugging it and stepping into the code and it fails before it ever gets into the code. The fact that it will run successfully the first time through, tells me it is not an obvious coding error. Wondering if there is some type of race condition that is causing this failure. My question is anyone aware of situations like this or have pointers on how I can track down why this error is thrown?

Here's the relevant bits: Custom Action Defintion

<Binary Id="VSLocator" SourceFile="$(env.RD_BINARIES_PATH)\Setup\VSLocator.CA.dll"/>
<CustomAction Id="VSFindInstances2" BinaryKey="VSLocator" DllEntry="VSFindInstances2" Execute="firstSequence"/>

The custom action invoke

<InstallUISequence>
  <Custom Action="VSFindInstances2" After="VSFindInstances"></Custom>
</InstallUISequence>

The custom action C# code:

using System;
using System.Runtime.InteropServices;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.VisualStudio.Setup.Configuration;

namespace VSLocator {
    public class CustomActions {
        private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);

        [CustomAction]
        public static ActionResult VSFindInstances2( Session session ) {
            try {
                session.Log( "VSFindInstances2 Enter" );
                var query = new SetupConfiguration();
                var query2 = (ISetupConfiguration2)query;
                var e = query2.EnumAllInstances();

                var helper = (ISetupHelper)query;

                int fetched;
                var instances = new ISetupInstance[1];
                do {
                    e.Next( 1, instances, out fetched );
                    if ( fetched > 0 ) {
                        PrintInstance( instances[ 0 ], helper, session );
                    }
                }
                while ( fetched > 0 );
            }
            catch ( COMException ex ) when ( ex.HResult == REGDB_E_CLASSNOTREG ) {
                session.Log( "The query API is not registered. Assuming no instances are installed." );
            }
            catch ( Exception ex ) {
                session.Log( $"Error 0x{ex.HResult:x8}: {ex.Message}" );
            }
            return ActionResult.Success;
        }

        private static void PrintInstance( ISetupInstance instance, ISetupHelper helper, Session session ) {
            var instance2 = (ISetupInstance2)instance;
            var state = instance2.GetState();
            session.Log( $"InstanceId: {instance2.GetInstanceId()} ({( state == InstanceState.Complete ? "Complete" : "Incomplete" )})" );


            if ( ( state & InstanceState.Local ) == InstanceState.Local ) {
                var installationVersion = instance.GetInstallationVersion();
                var version = helper.ParseVersion(installationVersion);
                session.Log( $"InstallationVersion: {installationVersion} ({version})" );
                session.Log( $"InstallationPath: {instance2.GetInstallationPath()}" );

                // 32bit only discovery for now, remove this for 64bit too
                var installPath = instance2.GetInstallationPath();

                if ( installPath.Contains("\\Program Files (x86)\\") ) {
                    if ( installationVersion.StartsWith( "16." ) && string.IsNullOrEmpty( session[ "VS2019_ROOT_FOLDER]" ] ) ) {
                        session[ "VS2019_ROOT_FOLDER" ] = installPath;
                    }
                    if ( installationVersion.StartsWith( "17" ) && string.IsNullOrEmpty( session[ "VS2022_ROOT_FOLDER]" ] ) ) {
                        session[ "VS2022_ROOT_FOLDER" ] = installPath;
                    }
                }
            }
        }
    }
}

Here is the section of log where VSFindInstances and VSFindInstances2 is called:

MSI (c) (2C:30) [17:53:54:639]: Doing action: VSFindInstances
Action 17:53:54: VSFindInstances. 
Action start 17:53:54: VSFindInstances.
MSI (c) (2C:30) [17:53:54:648]: Creating MSIHANDLE (1) of type 790542 for thread 21040
MSI (c) (2C:48) [17:53:54:649]: Invoking remote custom action. DLL: C:\Users\ADM-JI~1.COR\AppData\Local\Temp\MSI3E90.tmp, Entrypoint: FindInstances
MSI (c) (2C:84) [17:53:54:651]: Cloaking enabled.
MSI (c) (2C:84) [17:53:54:651]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (2C:84) [17:53:54:651]: Connected to service for CA interface.
MSI (c) (2C!18) [17:53:54:772]: Creating MSIHANDLE (2) of type 790541 for thread 35864
MSI (c) (2C!18) [17:53:54:772]: Creating MSIHANDLE (3) of type 790531 for thread 35864
VSFindInstances:  Entering VSFindInstances in C:\Users\ADM-JI~1.COR\AppData\Local\Temp\MSI3E90.tmp, version 3.14.5722.0
MSI (c) (2C!18) [17:53:54:772]: Closing MSIHANDLE (3) of type 790531 for thread 35864
MSI (c) (2C!18) [17:53:54:810]: PROPERTY CHANGE: Adding VS2019_ROOT_FOLDER property. Its value is 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise'.
MSI (c) (2C!18) [17:53:54:823]: PROPERTY CHANGE: Adding VS2019_IDE_MODELING_PROJECTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:823]: PROPERTY CHANGE: Adding VS2019_IDE_VWD_PROJECTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:823]: PROPERTY CHANGE: Adding VS2019_IDE_VSTS_TESTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:824]: PROPERTY CHANGE: Adding VS2019_IDE_FSHARP_PROJECTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:825]: PROPERTY CHANGE: Adding VS2019_IDE_VB_PROJECTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:825]: PROPERTY CHANGE: Adding VS2019_IDE_VCSHARP_PROJECTSYSTEM_INSTALLED property. Its value is '1'.
MSI (c) (2C!18) [17:53:54:826]: Closing MSIHANDLE (2) of type 790541 for thread 35864
MSI (c) (2C:48) [17:53:54:827]: Closing MSIHANDLE (1) of type 790542 for thread 21040
Action ended 17:53:54: VSFindInstances. Return value 1.
MSI (c) (2C:30) [17:53:54:828]: Doing action: VSFindInstances2
Action 17:53:54: VSFindInstances2. 
Action start 17:53:54: VSFindInstances2.
MSI (c) (2C:30) [17:53:54:832]: Creating MSIHANDLE (4) of type 790542 for thread 21040
MSI (c) (2C:9C) [17:53:54:833]: Invoking remote custom action. DLL: C:\Users\ADM-JI~1.COR\AppData\Local\Temp\MSI3F3D.tmp, Entrypoint: VSFindInstances2
CustomAction VSFindInstances2 returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
MSI (c) (2C:9C) [17:53:58:307]: Closing MSIHANDLE (4) of type 790542 for thread 21040
Action ended 17:53:58: VSFindInstances2. Return value 3.
MSI (c) (2C:30) [17:53:58:309]: Doing action: FatalError
Action 17:53:58: FatalError. 
Action start 17:53:58: FatalError.
Action 17:53:58: FatalError. Dialog created

Solution

  • I cloned your repos and ran the MSI a few times and I'm not able to reproduce your problem. The CA fires each time I install it. Note I do see the SfxCA lines I expected to see. I don't see this in yours.

    Have you tested this on multiple machines especially clean VM snapshots? I suspect your have an environmental issue that is crashing DTF and causing your CA to not fire. If you can find the root cause it and it looks like DTF could be improved I would create an issue with WiX.

    === Verbose logging started: 4/8/2022 8:49:31 Build type: SHIP UNICODE 5.00.10011.00 Calling process: C:\WINDOWS\system32\msiexec.exe === MSI (c) (08:E0) [08:49:31:374]: Doing action: VSFindInstances2 MSI (c) (08:E0) [08:49:31:374]: Note: 1: 2205 2: 3: ActionText Action 8:49:31: VSFindInstances2. Action start 8:49:31: VSFindInstances2. MSI (c) (08:08) [08:49:31:380]: Invoking remote custom action. DLL: C:\Users\cxp5196\AppData\Local\Temp\MSI920B.tmp, Entrypoint: VSFindInstances2 SFXCA: Extracting custom action to temporary directory: C:\Users\cxp5196\AppData\Local\Temp\MSI920B.tmp-
    SFXCA: Binding to CLR version v4.0.30319 Calling custom action VSLocator!VSLocator.CustomActions.VSFindInstances2 VSFindInstances2 Enter InstanceId: 97a9f9ed (Complete) InstallationVersion: 17.1.32210.238 (4785081009963246) InstallationPath: C:\Program Files\Microsoft Visual Studio\2022\Enterprise Action ended 8:49:31: VSFindInstances2. Return value 1.

    === Verbose logging started: 4/8/2022 8:49:46 Build type: SHIP UNICODE 5.00.10011.00 Calling process: C:\WINDOWS\system32\msiexec.exe ===

    Action 8:49:47: VSFindInstances2. Action start 8:49:47: VSFindInstances2. MSI (c) (90:B8) [08:49:47:088]: Invoking remote custom action. DLL: C:\Users\cxp5196\AppData\Local\Temp\MSICF62.tmp, Entrypoint: VSFindInstances2 SFXCA: Extracting custom action to temporary directory: C:\Users\cxp5196\AppData\Local\Temp\MSICF62.tmp-
    SFXCA: Binding to CLR version v4.0.30319 Calling custom action VSLocator!VSLocator.CustomActions.VSFindInstances2 VSFindInstances2 Enter InstanceId: 97a9f9ed (Complete) InstallationVersion: 17.1.32210.238 (4785081009963246) InstallationPath: C:\Program Files\Microsoft Visual Studio\2022\Enterprise Action ended 8:49:47: VSFindInstances2. Return value 1.