Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C# WiX Custom Actions crash with "Could not load file or assembly" #1447

Closed
ERGeorgiev opened this issue Feb 10, 2024 · 4 comments
Closed

C# WiX Custom Actions crash with "Could not load file or assembly" #1447

ERGeorgiev opened this issue Feb 10, 2024 · 4 comments

Comments

@ERGeorgiev
Copy link

ERGeorgiev commented Feb 10, 2024

I have a C# WiX project, like this (trimmed code):
C# WiX project Main:

public class WixInstaller
{
    public static void Main()
    {
        // Setup Project
        var project = new Project(AppName,
            // Application Dir
            new Dir(@$"%ProgramFiles%\{AppName}",
                // Application Files
                new Files($@"{binPath}\*.*"),
                // Program Menu Exe
                new File($@"{binPath}\{AppName}.exe",
                    new FileShortcut(AppName, @$"%ProgramMenu%\{AppName}") { IconFile = iconPath }))
        );

        // Run After Install
        var runAfterInstallAction = new ElevatedManagedAction(
            CustomActions.RunAfterInstall, Return.check, When.After, Step.InstallFinalize, Condition.NOT_Installed) 
        { 
            Execute = Execute.immediate 
        };
        project.AddAction(runAfterInstallAction);

        Compiler.BuildMsi(project, System.IO.Path.Combine(_solutionDirectory, fileName));
    }
}

The custom action:

public class CustomActions
{
    [CustomAction]
    public static ActionResult RunAfterInstall(Session session)
    {
        try
        {
            // This pattern in necessary to catch exceptions relating to missing dlls.
            Action(session);
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
        }

        return ActionResult.Success;

        static void Action(Session session)
        {
            using Microsoft.Win32.TaskScheduler.TaskService ts = new();
        }
    }
}

When the custom action is executed, it errors out in Could not load file or assembly Microsoft.Win32.TaskScheduler version..... I am not sure how to fix this. There's a lot of guides available online, but seems like there's nothing on a WiX C# project, even on WiX's actual documentation. Seems like I need to add a dll file referenced by the action, but the C# project doesn't seem to have similar functionality.

  • I tried project.AddBinary(), but it didn't fix the issue.
  • I tried setting the custom action's actionAssembly to the required binary with no luck (couldn't find it, seems like no CA file was being created)
  • Making a separate project for customActions
  • project.DefaultRefAssemblies.Add(typeof(TaskScheduler).Assembly.Location);
  • Specifying actionAssembly typeof(CustomActions).Assembly.Location
@oleg-shilo
Copy link
Owner

The correct way of embedding CA dependencies is to add them with project.DefaultRefAssemblies.Add.
This will ensure that the MakeSfxCA packages them with your CA assembly. So you have done it right.

Is there any chance that you are embedding an x64 version of assembly (check it in the assembly file). Because if you are then it cannot load to MSI runtime that is always a x86 CPU.

If it does not help then I can only suggest the debugging. Isolate your working code in a separate method and call it from the CA body. Before the call subscribe for the AppDomain.CirrentDomain.ResolveAssembly event. Then fire the assertion on the entry in CA (see wiki for debugging steps). This will tell you what are the other dependencies that are missing.

@oleg-shilo
Copy link
Owner

oleg-shilo commented Feb 11, 2024

I just tested and it seems to work just fine:

image

image

image

@ERGeorgiev
Copy link
Author

project.DefaultRefAssemblies.Add(@".\bin\Debug\net472\Microsoft.Win32.TaskScheduler.dll"); for me throws
System.IO.DirectoryNotFoundException: 'Could not find a part of the path 'C:\Users\user\Projects\VisualStudio\project\project.Installer\bin\Debug\net472\bin\Debug\net472\Microsoft.Win32.TaskScheduler.dll'.'

What worked:
project.DefaultRefAssemblies.Add(@".\Microsoft.Win32.TaskScheduler.dll");

Thank you! I am unsure why my original code was not working:
project.DefaultRefAssemblies.Add(typeof(TaskScheduler).Assembly.Location);, I assume the Location does not hold the actual .dll, but it did build the msi so I assume it did.

@oleg-shilo
Copy link
Owner

Yep, the Assembly.Location property can be empty. Though I always try to use it as it is so convenient :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants