oleg-shilo / wixsharp

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

Problem installation in %AppData% Wix 4 WPF #1519

Closed grizoood closed 4 weeks ago

grizoood commented 1 month ago

Hello,

I have a problem, I need to copy 2 folders to %AppData% folder.

static void Main()
{
    var project = new ManagedProject("My product");

    project.Scope = InstallScope.perUser;

    project.AddFiles();

    project.GUID = new Guid("6fe30b47-2577-43ad-9095-1861ba25889b");

    //custom set of UI WPF dialogs
    project.ManagedUI = new ManagedUI();

    project.ManagedUI.InstallDialogs.Add<WixSharp_Setup1.WelcomeDialog>()
                                    .Add<WixSharp_Setup1.LicenceDialog>()
                                    .Add<WixSharp_Setup1.FeaturesDialog>()
                                    .Add<WixSharp_Setup1.InstallDirDialog>()
                                    .Add<WixSharp_Setup1.ProgressDialog>()
                                    .Add<WixSharp_Setup1.ExitDialog>();

    project.ManagedUI.ModifyDialogs.Add<WixSharp_Setup1.MaintenanceTypeDialog>()
                                   .Add<WixSharp_Setup1.FeaturesDialog>()
                                   .Add<WixSharp_Setup1.ProgressDialog>()
                                   .Add<WixSharp_Setup1.ExitDialog>();

    project.BuildMsi();
}

static void AddFiles(this ManagedProject project)
{
    string installDir = "AppDataFolder";

    var files = new Dir($@"{installDir}\",
         new Dir($@"My Company 1\My Product\",
            new File("Program.cs")),
         new Dir($@"My Company 2\My Product\",
            new File("Program.cs")));

    project.AddDir(files);
}

The directory is set to : image

I tried adding this:

Compiler.AutoGeneration.InstallDirDefaultId = null;

The folders copy well into %AppData% but in the "InstallDirDialog.xaml" interface I can no longer change the installation directory. image

I tried this but it doesn't work : Compiler.AutoGeneration.InstallDirDefaultId = "AppDataFolder";

Torchok19081986 commented 4 weeks ago

morning, Is button "Change" not available anymore or is grayout ? How do you copy folders into %appdata% - CA or event AfterInstall ? You can try , as opposite, same in Wix v3 from MSI Template for Managed Project. If there is everthing ok, means, v4 somehow doesnt get it. Also look into your output wxs. Does Installdir Id present ?

Best regards, Torchok.

grizoood commented 4 weeks ago

The "Change" button is not grayed out, I meant that now the path is empty.

What I want is to have the folder "C:\Users\{USER_NAME}\AppData\Roaming" in InstallDirDialog interface.

I seem to be unable to set the installation directory to a special folder.

Torchok19081986 commented 4 weeks ago

hm. In your Method Addfiels right ? What about set it from Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) ?

grizoood commented 4 weeks ago

I tried this using InstallDir to force AppDataFolder to be the installation directory because otherwise it takes the first non-special folder in my case: "C:\Users\{USER_NAME}\AppData\Roaming\My Company 1\My Product\"

static void AddFiles(this ManagedProject project)
{
    string installDir = "AppDataFolder";

    var files = new InstallDir($@"{installDir}\",
         new Dir($@"My Company 1\My Product\",
            new File("Program.cs")));

    project.AddDir(files);
}

The directory is displayed correctly in the InstallDirDialog interface but the files are not copied. I really feel like he doesn't like having a special folder like INSTALLDIR.

grizoood commented 4 weeks ago

It's the same problem here (https://github.com/oleg-shilo/wixsharp/issues/865) but I want to be able to have the InstallDir in the InstallDirDialog interface. Indeed if I put this:

Compiler.Auto Generated.InstallDirDefault Id = null;

it works, it installs the files but in the InstallDirDialog interface, the path is empty.

Torchok19081986 commented 4 weeks ago

what about set Id on InstallDir and add it to this line ? line ... new InstallDir(new Id("dirid1")) ... and then Compiler.Auto Generated.InstallDirDefault Id = "dirid1" ?

grizoood commented 4 weeks ago

I don't understand what you want to do?

grizoood commented 4 weeks ago

Same problem, InstallDirDialog path is empty and the files are not installed with :

Compiler.AutoGeneration.InstallDirDefaultId = "DIR";

string installDir = "AppDataFolder";

var files = new InstallDir(new Id("DIR"), $@"{installDir}\",
     new Dir($@"My Company 1\My Product\",
        new File("Program.cs")));

project.AddDir(files);
grizoood commented 4 weeks ago

@oleg-shilo Do you have a tip?

oleg-shilo commented 4 weeks ago

Alex, you started defining the dir structure in the way that is really difficult to follow. Thus when @Torchok19081986 gave you the right advice you could not map it to your code.

Let's step back.....

Problem

Why don't you try to define your project structure in the straightforward way, consistent with the WixSharp samples? And when you have the working solution, you may try to do some trick definitions like project.AddFiles(...).

This is what I did and it worked immediately:


static public void Main()
{
    var project =
        new ManagedProject("MyProduct",
            new Dir(@"%AppData%\My Company\My Product",
                new Dir("SubDirA",
                    new File(@"Files\Bin\MyApp.exe")),
                new Dir("SubDirB",
                    new File(@"Files\Bin\MyApp.cs"))));

    project.ManagedUI = ManagedUI.Default;
    // project.ManagedUI = ManagedUI.DefaultWpf;
    // project.UI = WUI.WixUI_InstallDir;
    project.BuildMsi();
}

InstallDir dialog showed the right folder path. And the files are installed in the correct locations:

image

Thus the simple code above does exactly what you described as your scenario. I suggest you start from this approach.

Explanations

This is just to clear any possible misunderstanding but not a suggestion to do anything from the below content.

When developer defines the installation folder tree he/she needs somehow indicate to all possible UI types (MSI/WiX, WixSharp.Forms, WixSharp.WPF) which specific folder needs to be treated as the root installation folder that is displayed in the InstallDir dialog.

The id of that folder needs to be passed to the dialog orchestrator.

If you do not specify Ditr.Id (as in your case). WixSharp will automatically nominate one based on the best guess of your intention. You can always check what id was generated and which dir it was assigned to by analysing the generated wxs files in your project wix subfolder.

The autogenerated ID value will be the one that is configured via Compiler.Auto Generated.InstallDirDefault The default value is INSTALLDIR and it's almost never ever you need to change it.

Marking the Dir as install Dir can be done by setting the Dir.IsInstallDir property to true. The same outcome can be achieved by instantiating a special version of Dir class InstallDir , which sets this property during its instantiation

. . .

Since you asked about setting Did ID @Torchok19081986 suggested new InstallDir(new Id("dirid1"))...

oleg-shilo commented 4 weeks ago

What I described above is also covered in this section: https://github.com/oleg-shilo/wixsharp/wiki/Deployment-scenarios#installation-directory

grizoood commented 4 weeks ago

Hi @oleg-shilo,

I just want to have the AppData folder as InstallDir but when I do that, the files don't install.

static public void Main()
{
    var project =
        new ManagedProject("MyProduct",
            new Dir(@"%AppData%",
                new Dir("SubDirA",
                    new File(@"Files\Bin\MyApp.exe")),
                new Dir("SubDirB",
                    new File(@"Files\Bin\MyApp.cs"))));

    project.ManagedUI = ManagedUI.Default;
    // project.ManagedUI = ManagedUI.DefaultWpf;
    // project.UI = WUI.WixUI_InstallDir;
    project.BuildMsi();
}

Try this example, you will see that SubDirA and SubDirB folders are not installing

oleg-shilo commented 4 weeks ago

Alex, I do think that your deployment definition is problematic.

If you look at the wxs of the sample I gave you you will see that the AppData folder is a special folder that even has a special annotation in WiX API:

<StandardDirectory Id="AppDataFolder">
      <Directory Id="My20Company" Name="My Company">

Treating a special system folder as your installation directory is questionable. Installation dir is something that you can create (on installation) and delete (on uninstallation). It's definitely not your plan for AppData. Even though the system has some defence against user removing sys dirs.

If you look at your code wxs you will see that the special folder AppDir is completely screwed:

image

So who knows what is happening there?

The solution is to introduce at least a single folder that you are creating in AppData. It is a common convention that all vendors follow. You do not deploy your files to the root but to a folder that somehow represents your product.

new Dir(@"%AppData%/MyAppDataRoot",
    new Dir("SubDirA",
    . . .   

This will solve your problem.

grizoood commented 4 weeks ago

@oleg-shilo ,

In fact my problem is the following, I developed several addins for the Autodesk Revit application:

Let's take this example, I have 3 applications which each have their WixSharp msi

MyApp1 MyApp2 MyApp3

My installation folders: C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2025\MyApp1 => contains the source files of MyApp1 for 2025 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2024\MyApp1 => contains the source files of MyApp1 for 2024 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2023\MyApp1 => contains the source files of MyApp1 for 2023

C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2025\MyApp2 => contains the source files of MyApp2 for 2025 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2024\MyApp2 => contains the source files of MyApp2 for 2024 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2023\MyApp2 => contains the source files of MyApp2 for 2023

C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2025\MyApp3 => contains the source files of MyApp3 for 2025 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2024\MyApp3 => contains the source files of MyApp3 for 2024 C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2023\MyApp3 => contains the source files of MyApp3 for 2023

I wanted to group my support folders (these folders contain resources for programs, XML files, JSON, etc.) in one place to avoid copying them to each folder (2025, 2024, 2023), so I created a new MyCompany\Support directory.

C:\Users{USERNAME}\AppData\Roaming\MyCompany\Support\MyApp1\ (file used by MyApp1 2025, 2024, 2023) C:\Users{USERNAME}\AppData\Roaming\MyCompany\Support\MyApp2\ (file used by MyApp2 2025, 2024, 2023) C:\Users{USERNAME}\AppData\Roaming\MyCompany\Support\MyApp3\ (file used by MyApp3 2025, 2024, 2023)

If I match SubDirA => C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2025\MyApp1 SubDirB=> C:\Users{USERNAME}\AppData\Roaming\MyCompany\Support\MyApp1\

Isn't it possible to do that?

grizoood commented 4 weeks ago

@oleg-shilo, I await your response, thank you

grizoood commented 4 weeks ago

I close, thk.

oleg-shilo commented 4 weeks ago

Sorry Alex, I was busy with some other conversation in this and other projects.

If I match SubDirA => C:\Users{USERNAME}\AppData\Roaming\Autodesk\Revit\Addins\2025\MyApp1
SubDirB=> C:\Users{USERNAME}\AppData\Roaming\MyCompany\Support\MyApp1\ Isn't it possible to do that?

While installing in these folders is possible but you will open a can of worms with respect of MSI side effects I described earlier. And solving them is problematic due to the MSI (not Wix#) constraints.

If I was you I would introduce a single root folder to bring your scenario to the traditional deployment model:

SubDirA => C:\Users{USERNAME}\AppData\Roaming\AutodeskSupport\Revit\Addins\2025\MyApp1
SubDirB => C:\Users{USERNAME}\AppData\Roaming\AutodeskSupport\MyCompany\Support\MyApp1