oleg-shilo / wixsharp

Framework for building a complete MSI or WiX source code by using script files written with C# syntax.
MIT License
1.12k stars 175 forks source link

Extracting a zip file during installation #1615

Closed kipamgs closed 1 month ago

kipamgs commented 3 months ago

I'm trying to extract a zip file during the installation problem. I have either one of 2 problems thus the installation fails:

  1. CustomAction.Execute is set to Execute.immediate

    • The custom action is executed before the installation directory is created
  2. The custom action is executed deffered.

    • I can't access the zip file.

Questions:

  1. How can I set the custom action to be executed after the installation directory is created? (I need to extract the zip before services are started. I tried e.g. When.Before, Step.StartServices without success)
  2. How can I access files on a deffered custom action?
  3. Or is there a better way to do this?

I am adding the zip and custom action like this:

project.AddBinary(new Binary(new Id("Python"), @"python310.zip"));

            project.AddProperty(new Property("ZIP_FILE", "Python")); // For immediate execution
            project.AddProperty(new Property("EXTRACT_DIR", "NOT_SET")); // For immediate execution

project.AddAction(new ElevatedManagedAction(CustomActions.ExtractZip, Return.check, When.After, Step.InstallFiles, Condition.NOT_Installed)//, Sequence.InstallExecuteSequence)
            {
                UsesProperties = "ZIP_FILE=Python, EXTRACT_DIR=[INSTALLDIR]",
                //Execute = Execute.immediate,
                Impersonate = false,
            });
        [CustomAction]
        public static ActionResult ExtractZip(Session session)
        {          
            string targetPath = session.Property("INSTALLDIR"); 
            string filename = session.Property("ZIP_FILE");

            try
            {
                using (MemoryStream ms = new MemoryStream(session.ReadBinary(filename)))
                {
                    using (ZipArchive zip = new ZipArchive(ms))
                    {
                        zip.ExtractToDirectory(targetPath);
                    }
                }

            }
            catch (Exception ex)
            {
                session.Log("Error extracting ZIP file: " + ex.Message);
                return ActionResult.Failure;
            }

            return ActionResult.Success;
        }
Zerpico commented 3 months ago

The correct way to get the INSTALLDIR variable (in ElevatedManagedAction ) would be more like this:

session.CustomActionData["INSTALLDIR"]
kipamgs commented 2 months ago

For now i found another approach that is working:

  1. Add the zip file to the project and install it
  2. Extract the installed zip
  3. Delete the zip file after extraction

However it would still be nice if there is a way to access files added with project.AddBinary in a deffered custom action if that is possible with wix. I guess this is not possible because deffered actions are executed in another process?

Torchok19081986 commented 2 months ago

morning, we had same issue and found our solution in BA Installer. One of our workers share code

[CustomAction]
    public static ActionResult ExtractFile(Session session)
    {
        session.Log("Begin ExtractFile");

        // Retrieve the binary stream from the MSI package
        var binaryData = session.Database.ExecuteScalar("SELECT `Data` FROM `Binary` WHERE `Name`='MyEmbeddedFile'") as Stream;

        if (binaryData != null)
        {
            // Define the path where the extracted file will be saved
            string outputFilePath = Path.Combine(Path.GetTempPath(), "extractedFile.ext");

            using (var fileStream = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
            {
                binaryData.CopyTo(fileStream);
            }

            session.Log($"File extracted to {outputFilePath}");

            // If needed, execute the extracted file or do something with it
            // For example, start the file or use it in further operations
        }
        else
        {
            session.Log("Failed to find the embedded binary file.");
            return ActionResult.Failure;
        }

        session.Log("End ExtractFile");

        return ActionResult.Success;
    }