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

installDir variable erased depending on ManagedProject structure #1579

Closed Fiinleyyy closed 2 months ago

Fiinleyyy commented 4 months ago

Hi, I think I found a bug or feature (depending who you ask ;)) which most likely isn't intended. In AfterInstall I am accessing the installDir variable as string installDir = eventArgs.Session.Property("INSTALLDIR"); If the installer is uninstalling or installing, acessing the install dir variable is not a problem.

However as soon as I change my project structure of my ManagedProject having two directories which aren't subdirectories the installDir variable can not be accessed during uninstall!

´var project = new ManagedProject("Example", new Dir(ExampleDir), new Dir("Example1", new Dir("Example2", new Files(ExampleFiles))), new WixSharp.File(ExampleFile2)), new WixSharp.File(ExampleFile3))));´

works fine: image

var project = new ManagedProject("Example", new Dir(ExampleDir, new WixSharp.File(ExampleFile2)), new Dir(ExampleDir), new Dir("Example1", new Dir("Example2", new Files(ExampleFiles))));

while the above code has problems finding the installDir during uninstall. It's weird since there are no problems during install, only uninstall. image

I'm very sure this is not intended.

oleg-shilo commented 4 months ago

Seems to be working for me:

var project =
    new ManagedProject("Example",

    new Dir(@"C:\My Company\My Product",
            new Dir("Example1",
                new File("program.cs"))),

        new Dir(@"C:\test",
            new Dir("Example1",
                new Dir("Example2",
                    new File("program.cs")))));

project.AfterInstall += (SetupEventArgs e) =>
{
    try
    {
        MessageBox.Show(e.Session.Property("INSTALLDIR"));
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
};

project.BuildMsi();

image WixSharp Setup18.zip

I have attached the sample. I suggest you run it and see if it behaves the same way in your environment. Is there something that you do during the install?

Fiinleyyy commented 4 months ago

Odd. Your code works fine for me while my project seems to fail on two different environments. I'll stop making up example project structure code and just post mine:

var project = new ManagedProject("Example",
                /*new Dir(TargetDir, 
                    new Files(featureA, sourceDirA),
                    new Files(featureB, sourceDirB)),*/
                new Dir(TempDir + @"\exampletemp",
                    new Dir("src",
                        new Dir("PX.Example",
                            new Files(featureExample, Path.Combine(sourceExample, @"PX.Example\*.*"))),
                        new Dir("PX.Example.Services",
                            new Files(featureExample, Path.Combine(sourceExample, @"PX.Example.Services\*.*")))),
                    new Dir("scripts",
                        new WixSharp.File(featureExample, Path.Combine(sourceExample, "services.json"))),
                    new WixSharp.File(featureExample, Path.Combine(sourceExample, "example.ps1")),
                    new WixSharp.File(featureExample, Path.Combine(sourceExample, "utils.psm1")))); 

As soon as I add the code that's commented AfterInstall can't find installDir during uninstall. I removed all the code during install so it can't be anything during install, problem still remains. It occurs when I change it to the given project structure

oleg-shilo commented 4 months ago

The only problem is that you can run the sample I shared with you and I cannot run code you shared. So I can only guess by analysing your code.

So... you might be triggering the problem by the specific value you pass in TempDir. The easiest way to troubleshoot it it to take the working code (e.g. the one that I shared) and start converting it in "yours" by modifying it step by step. And see which step starts triggering the problem:

Fiinleyyy commented 4 months ago

When I try to replace TempDir with the absolute path I am getting the error: error WIX0346: The Directory/@Name attribute's value, 'C:\Temp', is not a valid relative lo ng name because it contains illegal characters. Legal relative long names contain no more than 260 characters and must contain at least one non-period character. Any character except for the follow may be used: ? | > < : / * ".

oleg-shilo commented 4 months ago

My suggestion was very different. I suggested using a working sample and modifying it until it breaks. You are modifying the one that is already broken.

Muniwedesu commented 2 months ago

so this is probably related to the issue i have encountered - if you set InstallDir value to any wix-constant (i.e. InstallDir("%AppDataFolder%)), then it will set INSTALLDIR variable to "E:\AppDataFolder\" and everything will be copied there if that tome exists <- that always happens even if you have other folders inside InstallDirs added as Dir/Dir[]. However, if you create as InstallDir("%AppDataFolder%/Any/Other/Path/Fragments"), then it will correctly create folder structure. The .wxs files are generated as:


<Directory Id="TARGETDIR" Name="SourceDir">
      <!-- in this case INSTALLDIR will be set to "E:\AppDataFolder" -->
      <Directory Id="INSTALLDIR" Name="AppDataFolder">

        <Component Id="Component.INSTALLDIR.EmptyDirectory" Guid="219b74b8-e3aa-4806-9a09-3e79798d0e16">
          <CreateFolder />

          <RegistryKey Root="HKCU" Key="Software\WixSharp\Used">
            <RegistryValue Value="0" Type="string" KeyPath="yes" />
          </RegistryKey>
        </Component>

      </Directory>

      <Component Id="TARGETDIR" Guid="219b74b8-e3aa-4806-9a09-3e79ca1a8fa7" KeyPath="yes">
        <CreateFolder />
        <RemoveFolder Id="TARGETDIR" On="uninstall" />
      </Component>

    </Directory>
</Directory>
<Directory Id="TARGETDIR" Name="SourceDir">
     <!-- in that case folder structure is created correctly -->
      <Directory Id="AppDataFolder" Name="AppDataFolder">
        <Directory Id="INSTALLDIR" Name="Any">

          <Component Id="Component.INSTALLDIR.EmptyDirectory" Guid="4a92aa5d-777f-48dd-b803-a20ba0b5d68f">
            <CreateFolder />
            <RemoveFolder Id="INSTALLDIR" On="uninstall" />

            <RegistryKey Root="HKCU" Key="Software\WixSharp\Used">
              <RegistryValue Value="0" Type="string" KeyPath="yes" />
            </RegistryKey>
          </Component>

        </Directory>
      </Directory>
</Directory>

To reproduce:

           var project1 = new Project("name")
                .AddDir(new InstallDir("%AppDataFolder%"));
            project1.BuildMsi();

            var project2 = new Project("name 2")
                .AddDir(new InstallDir(@"%AppDataFolder%\Any\"));
            project2.BuildMsi();
oleg-shilo commented 2 months ago

Will investigate it on weekend

oleg-shilo commented 2 months ago

The problem is caused by the auto-assignment of the INSTALLDIR id to the root directory. This assignment is required for custom UI to understand which directory to show in the InstallDir dialog.

Your case is unusual as you are installing directly to one of the standard directories, like in AppDataFolder. What is, technically speaking, an anti-pattern. That's why you need to avoid installing it to AppDataFolder and instead install it in AppDataFolder/subdir. Or, if you indeed need to install inside of standard dir, disable INSTALLDIR id assignment even by impacting installdir selection dialog. Most likely it is what you want to do.

BTW, you probably missed the warning that was generated for you:
image

It tells you what you did wrong and it also tells you how to fix it. In your case Compiler.AutoGeneration.InstallDirDefaultId = null; will do the trick.

Muniwedesu commented 2 months ago

@oleg-shilo oh, I see, thank you for the thorough explanation. The intent was to mark something as the base installation directory and put the other dirs inside it (like if there were multiple installdirs), but it seems that I completely misunderstood why INSTALLDIR is needed.

oleg-shilo commented 2 months ago

One thing that I was wrong about is the warning message. It is indeed generated if one uses this code:

var project = new Project("name", 
                  new Dir("%AppDataFolder%"));
project.BuildMsi();

However, the warning is not generated if the code is like this:

var project = new Project("name", 
                  new InstallDir("%AppDataFolder%"));
project.BuildMsi();

Simply because it's interpreted as your conscious decision to overwrite the standard dir. So actually you did not see it.

However, a better dev experience would be to show the warning always. And the user can choose to act on or ignore it.

Will change it in the next release.