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

Cannot build .net 8 example project #1574

Closed Davidvanluijk closed 3 months ago

Davidvanluijk commented 4 months ago

I'm trying to build an installer project with .net 8. I'm following https://github.com/oleg-shilo/wixsharp/blob/wix-v4-master/Source/src/NET-Core/Sample/. It doesn't compile however, the error that occurs is:

0>wix.exe: Error WIX0144 : The extension 'C:\MyInstaller\My Product.wxs' could not be loaded because of the following reason: Could not load file or assembly 'C:\MyInstaller\My Product.wxs'. Format of the executable (.exe) or library (.dll) is invalid.

Please advice how to fix this. I'm trying to get it compiled with .net 8 to use it with AOT custom actions, but I'm already stuck with simply compiling it.

Thanks in advance.

My csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0-windows</TargetFramework>
    <LangVersion>latest</LangVersion>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="WixSharp.Core" Version="2.2.0" />
    <PackageReference Include="WixSharp.Msi.Core" Version="2.2.0" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="wix\" />
  </ItemGroup>
  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="cd .\&#xD;&#xA;set ide=true&#xD;&#xA;dotnet &quot;$(TargetPath)&quot;" />
  </Target>
</Project>

My program.cs:

using WixSharp;

namespace MyInstaller
{
    public class Program
    {
        public static void Main()
        {
            var project =
                new Project("My Product",
                    new Dir(@"%ProgramFiles%\My Company\My Product",
                        new File("program.cs")));
            project.PreserveTempFiles = true;
            project.UI = WUI.WixUI_ProgressOnly;
            project.BuildMsi();
        }
    }
}
oleg-shilo commented 4 months ago

I have checked and the sample in repo has a project structure problem but not the one that you described. I have fixed it but to ensure that you can compile I have attached a fresh completely isolated sample. WinFormsApp2.zip

oleg-shilo commented 4 months ago

But of course, the most reliable way to do this is to use Visual Studio template:

image

Davidvanluijk commented 4 months ago

Thank you for your fast response. I can't seem to build the sample zip you send me. I unpacked it, removed everything expect the csproj and the program.cs and ran the following commandline from a commandprompt in the folder: dotnet build WinFormsApp2.csproj --configuration Release

This produces the same error (log attached). Is there a link to a specific Wix version that needs to be configured / added? log.txt

Davidvanluijk commented 4 months ago

I notice there is a My Product.wxs in my root directory where there is an msi in yours. I made a dir listing after build (too big for upload), maybe that helps. dir.txt

oleg-shilo commented 4 months ago

From the log it's clear the CA dll is built successfully. So, you are failing to build the msi. Meaning that you most likely will have the same problem if you try to build trivial .NET Framework targeting WixSharp project.

It seems that in your environment, you have problems with executing the wix.exe command (part of the VS project build).

You can troubleshoot it by changing the build command to project.BuildMsiCmd();. After that VS build will produce the Build_My Product.cmd batch file.

This batch file is all you need to build the msi. It has no dependency on either WixSharp or VS/MSBuild. YOu can use it to troubleshoot and see what is missing. Most likely some of the WiX tools.

Davidvanluijk commented 4 months ago

Nice option, that really helps! The resulting cmd doesn't work out of the box, I need to modify a couple of things:

I couldn't figure out how to influence wixsharp in such a way that it would generated correctly though.

oleg-shilo commented 4 months ago

Removal of -ext "" as it seems as if this causes the wxs to be interpreted as extension instead of a wxs file. I can also add a pathname to an extension dll, as long as it's not empty it seems

The content of your batch file is invalid. This empty string after "" needs to be the name of the extension. And this is the primary cause of all the problems. Everything else is just symptoms. I would like to understand why, in your environment, the same project generates a different output (batch file). This is how the correct batch file looks like:

echo off
C:\Users\user\.dotnet\tools\wix.exe build -sw1026 -sw1076 -sw1079 -sw1149  -ext "WixToolset.UI.wixext"  "C:\Users\user\source\repos\WinFormsApp2\WinFormsApp2\My Product.wxs"  -o "C:\Users\user\source\repos\WinFormsApp2\WinFormsApp2\My Product.msi"

I think you might have a problem with the WixToolset.UI.wixext not being installed in your environment. You can check it by executing the following code that most likely returns null in your case:

WixTools.FindWixExtensionDll("WixToolset.UI.wixext");

WixSharp does install the extension if it's not found. And I suspect for some reason it fails. If t is the case then you can install the extension manually:

wix.exe extension add -g WixToolset.UI.wixext

But I am still puzzled as to why WixSharp fails when it executes the very same shell command to install the extension.


I will still cover the rest of your points...

Removal of as that seems to be a Wix3 element

Not sure I read it the same way. The link you shared only says the UIRef is available since WiX3 and in WiX4 you will need to ensure using WiX extensions. Even more. The very next section specifically show WiX4 example with the use of UIRef element.

In your case you had to remove this element because you removed the extension from the wixi.exe command (your first bullet point).

Change the CustomAction2 result to be ActionResult.Success as otherwise the installer never finishes successfully

Correct. This is the sample that I prepared for you to demonstrate that you can build the project, start MSI and get CA execution but not pollute your system with the installation. Thus, in the sample, I abort the installation after the CA execution is over.

Normally you would only need the create the project form VS project template without this trick.

Davidvanluijk commented 4 months ago

Hi Oleg,

Once again, thank you for the fast response. I'll try it out once I return to the office in a couple of weeks.

King regards, David

Op za 6 jul 2024 13:05 schreef Oleg Shilo @.***>:

Removal of -ext "" as it seems as if this causes the wxs to be interpreted as extension instead of a wxs file. I can also add a pathname to an extension dll, as long as it's not empty it seems

The content of your batch file is invalid. This empty string after "" needs to be the name of the extension. And this is the primary cause of all the problems. Everything else is just symptoms. I would like to understand why, in your environment, the same project generates a different output (batch file). This is how the correct batch file looks like:

echo offC:\Users\user.dotnet\tools\wix.exe build -sw1026 -sw1076 -sw1079 -sw1149 -ext "WixToolset.UI.wixext" "C:\Users\user\source\repos\WinFormsApp2\WinFormsApp2\My Product.wxs" -o "C:\Users\user\source\repos\WinFormsApp2\WinFormsApp2\My Product.msi"

I think you might have a problem with the WixToolset.UI.wixext not being installed in your environment. You can check it by executing the following code that most likely returns null in your case:

WixTools.FindWixExtensionDll("WixToolset.UI.wixext");

WixSharp does install the extension if it's not found. And I suspect for some reason it fails. If t is the case then you can install the extension manually:

wix.exe extension add -g WixToolset.UI.wixext

But I am still puzzled as to why WixSharp fails when it executes the very same shell command to install the extension.

I will still cover the rest of your points...

Removal of as that seems to be a Wix3 element

Not sure I read it the same way. The link you shared only says the UIRef is available since WiX3 and in WiX4 you will need to ensure using WiX extensions. Even more. The very next section https://wixtoolset.org/docs/fourthree/faqs/#converting-custom-wixui-dialog-sets specifically show WiX4 example with the use of UIRef element.

In your case you had to remove this element because you removed the extension from the wixi.exe command (your first bullet point).

Change the CustomAction2 result to be ActionResult.Success as otherwise the installer never finishes successfully

Correct. This is the sample that I prepared for you to demonstrate that you can build the project, start MSI and get CA execution but not pollute your system with the installation. Thus, in the sample, I abort the installation after the CA execution is over.

Normally you would only need the create the project form VS project template without this trick.

— Reply to this email directly, view it on GitHub https://github.com/oleg-shilo/wixsharp/issues/1574#issuecomment-2211739108, or unsubscribe https://github.com/notifications/unsubscribe-auth/AUQEKABELYRQYIX4QUMSC4LZK7FORAVCNFSM6AAAAABKG6DXWCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJRG4ZTSMJQHA . You are receiving this because you authored the thread.Message ID: @.***>

Davidvanluijk commented 4 months ago

I was able to test the suggestion you send today, here are my results:

  1. I couldn't use the methods you are referring to because they were internal to Wixsharp
  2. When I execute wix.exe extension add WixToolset.UI.wixext/4.0.4 -g and build the cmd file I got the correct location after -ext, so that worked as expected. It also build the MSI correctly now.
  3. When I execute wix.exe extension remove WixToolset.UI.wixext/4.0.4 -g afterwards the folder is removed completely and wixsharp errors out on DirectoryNotFound (see below exception stack trace). This is not really an issue for me, just letting you know.
  4. When I execute wix.exe extension add WixToolset.UI.wixext -g nothing seems to happen: no feedback, no files appearing on my system, it just silently does nothing. Since there is so little feedback I haven't got any clues to investigate why this happens.

I understand this works by installing extensions, but I am wondering if it's possible to also support using this extension from a packagereference in the csproj. When I add to my csproj, the dll is available in the nuget folder without having to install anything. Would it be possible to add support to locate the dll there? Or am I missing an important part in how this Wix tooling and extensions works? In principal WixSharp could add the dependencies as package to itself if they are needed for building?

Stacktrace for point 2, in case you need it: Unhandled exception. System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Users\dvl.wix\extensions\WixToolset.UI.wixext'. at System.IO.Enumeration.FileSystemEnumerator1.CreateDirectoryHandle(String path, Boolean ignoreNotFound) at System.IO.Enumeration.FileSystemEnumerator1.Init() at System.IO.Enumeration.FileSystemEnumerable1..ctor(String directory, FindTransform transform, EnumerationOptions options, Boolean isNormalized) at System.IO.Enumeration.FileSystemEnumerableFactory.UserDirectories(String directory, String expression, EnumerationOptions options) at System.IO.Directory.InternalEnumeratePaths(String path, String searchPattern, SearchTarget searchTarget, EnumerationOptions options) at System.IO.Directory.GetDirectories(String path, String searchPattern, EnumerationOptions enumerationOptions) at WixSharp.CommonTasks.WixTools.FindWixExtensionDll(String name, String version) at WixSharp.CommonTasks.WixTools.EnsureWixExtension(String name, String version) at WixSharp.Compiler.<>c.<GenerateWixCommand>b__46_1(String dll) at System.Linq.Enumerable.SelectEnumerableIterator2.ToArray() at WixSharp.Extensions.JoinBy(IEnumerable1 strings, String separator, Func2 selector) at WixSharp.Compiler.GenerateWixCommand(WixProject project, String wxsFile) at WixSharp.Compiler.BuildCmd(Project project, String path, OutputType type) at WixSharp.Compiler.BuildMsiCmd(Project project, String path) at WixSharp.Compiler.BuildMsiCmd(Project project) at WixSharp.Project.BuildMsiCmd(String path) at Program.

$(String[] args) in C:\Temp\WinFormsApp2\Program.cs:line 16

oleg-shilo commented 3 months ago

You are right. I overlooked that FindWixExtensionDll is internal.

I just made it public so it will be available for troubleshooting.

Now, about the extension package. WiX team implemented deployment of the extensions by using NuGet mechanism but opted for the alternative non-nuget location. This location is where WixSharp is trying to find the extension files.

However, the is a simple way to redirect the extension probing algorithm to the location of your choice (e.g. nuget dir). Thus you can install the nuget package by any means and then set

WixTools.WixExtensionsDir =@"%userprofile%\.nuget\packages".ExpandEnvVars();

WixSharp will find the extension in a new location. Currently WixTools.WixExtensionsDir is also internal but I made it public and it will be available in the next release.


The solution I described will work for any cases, even including bringing extensions manually without nuget.

Though I like your idea about checking nuget packages by default so I will also extend the probing approach to check both wixextensions and nuget folders always.

oleg-shilo commented 3 months ago

Done. The fix will be available in the very next release (over weekend)

Davidvanluijk commented 3 months ago

Thank you for the fast response, I'll test the new release once I have the chance!

oleg-shilo commented 3 months ago

This is an example of the customization options:

WixTools.SignTool = @"tools\signtool.exe";
WixTools.MakeSfxCA = @"tools\WixToolset.Dtf.MakeSfxCA.exe";
WixTools.Heat = @"tools\heat.exe";
WixTools.DtfWindowsInstaller = @"tools\WixToolset.Dtf.WindowsInstaller.dll";
WixTools.WixToolsetMbaCore = @"tools\WixToolset.Mba.Core.dll";
WixTools.SfxCAx64 = @"tools\x64\SfxCA.dll";
WixTools.SfxCAx86 = @"tools\x86\SfxCA.dll";
WixTools.WixExtensionsDir = @"%userprofile%\.nuget\packages";