WiX Heat Pre-build Error - wix

I have a WiX installer that was working fine, but it's been a few months since I worked on it... so, I am not attempting to build the installer (on a reconfigured machine) and now it fails to build every time. I've tried to simplify everything to isolate where it's failing, but I still can't seem to figure out why. Essentially, it looks like it's failing at the pre-build process. I had a length Pre-build Event command, but I've simplified it to the bare essentials. Here's my command:
call “$(WIX)bin\heat.exe” dir "$(SolutionDir)MyProj\bin\Release" -out “$(ProjectDir)MyFiles.wxs”
The error I'm getting is:
call “C:\Program Files (x86)\WiX Toolset v3.10\bin\heat.exe” dir "C:\Users\MyName\Documents\GitHub\MyProj\bin\Release" -out “C:\Users\MyName\Documents\GitHub\MyProj\Installer\MyFiles.wxs”
The filename, directory name, or volume label syntax is incorrect.
The code appears to exit with code 1, which seems to suggest that it's failing to locate a filename or path... however, I've checked the paths that are printed in the output log and the heat.exe application does exists under the C:\Program Files (x86) directory. The directory (dir) it's trying to harvest is properly defined and the output location is as well. So, does anyone know why this is failing?
Update
What's incredibly strange is that the pre-build event command seems to fail even when I simplify the command to try to simply call the heat.exe application (with no other parameters). I tried changing my pre-build event to the following:
call “C:\Program Files (x86)\WiX Toolset v3.10\bin\heat.exe”
As you can see from the attached image, the heat.exe application is indeed located in the directory specified in the build command. Yet, I still get an error saying that the MSBuild failed and exited with code 1. If I check the output log, it says that the, "filename, directory name, or volume label syntax is incorrect". However, I can say that this installer was working properly a few months ago with no changes to the build events... so I really don't know why it wouldn't work now, except that I had to reconfigure my machine and reinstall Windows 10 recently. I downloaded and installed the latest WiX toolset, and would assume that would be everything that is needed. But, this error persists. Any ideas?

This is really dumb but I believe you need to put a \ at the end of your dir IIRC. I think I ran into the same issue at one point. The error is not particularly helpful.
call "$(WIX)bin\heat.exe" dir "$(SolutionDir)MyProj\bin\Release\" -out "$(ProjectDir)MyFiles.wxs"
(I think I was remembering backwards and you need to NOT have the trailing \ in the dir.. sorry)
Just in case you can't get the pre-build event to work, you can also call heat like this (requires editing the wixproj file)
<Target Name="BeforeBuild">
<Exec Command=""$(WIX)bin\heat.exe" dir "$(SolutionDir)MyProj\bin\Release" -out "$(ProjectDir)MyFiles.wxs""/>
</Target>
This is how I call heat in some of the installers I've authored. If this also doesn't work I'm out of ideas for why this doesn't work for you.

I know its a little old question but I've faced the issue and spent hours to notice different qoutes here: “$(WIX)bin\heat.exe”. Replace with straight ones "$(WIX)bin\heat.exe" and enjoy.

Related

How can I obtain few of vc runtime dll's to include in my installer?

I've tried for many hours to find the solution for my problem and couln't find it even here.
So I have that application.exe that I am writing the Wix Toolset installer for it. Unfortunately I have no access to the source code but I hope I can do my task without it.
The problem is that it runs correctly with vc_redist.x64 installed on the end user's machine, but not without it.
What I've tried:
I was trying to run it without those runtimes and got into "couldn't find vcruntime140.dll error"
So I pasted it in the app's folder and tried to move on with dll's and the next error occured as shown in picture:
the application was unable to start correctly (0xc000007b). Click OK to close the application
I've read those runtimes after installation go into eg. "C://Windows/System32"
so I tried to go to that location and
dir > before.txt
and
dir > after.txt
after installing the vc++ runtime.
and copy pasted the files that occured only after the installation.
I tried to use gumpbin.exe from Visual Studio that gave given output:
found some dependencies
and the Dependency Walker gave me kind of similar output.
Dependency Walker output the same libs as direct ones, but also gave imo about hundreds of indirect ones. So I thought copy/pasting all of them is a really hard job without software to help.
I was also thinking about forcing vc_redist.x64.exe to extract files to folder given by me so I could use them for my purpose and the only parameter that looked fine was /layout but it only copied the whole .exe to another folder. Didn't extract it.
My questions is:
is there an easy way of obtaining the vc_redist.x64 libraries so I could author only the needed ones in my installer?
Any help will be appreciated. Thanks in advance!
Edit:
My goal is to secure newbie end users from being unable to run the application when they accidentally uninstall the VC runtime, therefore having vc_redist.exe as prerequisite in bootstrapper is unfortunetely not the case

How do I reference a variable at the command line using light.exe in WiX

I have read references that seem to suggest the ability to reference a bind or WiX variable at the command line (this one being the most obvious). This would give me the ability to add the Assembly Information to the name of the MSI that gets generated. For example,
light.exe ... -out Installer.!(bind.FileVersion.myExe).msi ...
light.exe ... -out Installer.!(wix.BlahInfo).msi ...
There is definitely some validation going on. If the WixVariable ID name is different between the WXS file and the reference in the light.exe command, I get an error:
light.exe : error LGHT0197 : The Windows Installer XML variable !(wix.BlahInfo1) is unknown
If I make sure they match, then the error disappears:
<WixVariable Id="BlahInfo" Value='!(bind.FileVersion.myExe)'/>
light.exe ... -out Installer.!(wix.BlahInfo).msi ...
However, no matter what I try, the resulting MSI file never does a run time variable replacement. Instead, it just adds the !(...) to the file name. As an example my last build produced a file with the following name:
Installer.!(wix.BlahInfo).msi
Is this something that can be done or have I misunderstood the documentation? Thanks.
Light doesn't support bind-time variable references on the command line.
So I reached the same conclusion as Bob. This wasn't acceptable since it introduced too much variability in builds so I solved it a different way. I knew that an executable run at the command line could reference a Windows environment variable at runtime. So all I needed to do was to set an environment variable and reference it and voila:
light.exe ... -out Installer.%BLAH_VERSION%.msi
To make this happen there was quite a bit that needed to get done. To start, my version number is coming from the Assembly Info of a Visual Studio project. The first thing I had to do was make it dynamic so that it created a new one for each build. Changing the last 2 numbers to a * did that:
[assembly: AssemblyVersion("6.4.*")]
The next thing to do was to externalize that number so it could be used elsewhere. Adding this stanza to the end of the csproj did that:
<Target Name="PostBuildMacros">
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="Targets" />
</GetAssemblyIdentity>
<ItemGroup>
<VersionNumber Include="#(Targets->'%(Version)')"/>
</ItemGroup>
</Target>
<PropertyGroup>
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
PostBuildMacros;
</PostBuildEventDependsOn>
<PostBuildEvent>setx BLAH_VERSION #(VersionNumber)</PostBuildEvent>
</PropertyGroup>
Thanks to this stackoverflow post for help.
Of course to reference it, I would need to find a way to get an already opened command prompt to update its references to an environment variable. This proved to be the most difficult, but this stackoverflow post came to the rescue.
So now I have tied it all together using a windows batch script. Essentially, I build the EXE, test it, make sure it is good, run my batch script and I have an MSI file named after the assembly info version that was generated for me.

WiX Heat: Pre-build event fires too early on build server

I'm harvesting a directory for my Visual Studio solution.
It works on my local system so far probably because the project build order is being respected.
When I run the installer on a build server it finds the right directory but it has not been created at the time of building the setup file. It throws a HEAT5052 error saying The directory 'a:\b\c' could not be found.
Is there any way to "wait" until or to execute the heat command after all project references are built?
OK so I've spent hours to figure out how to fire Heat AFTER all references are resloved. I only found solutions for the <PreBuildEvent> and <PostBuildEvent> using the Heat command line and the BeforeBuild and AfterBuild targets.
So I found all kind of targets inside the wix2010.targets file located in my
Program files (x86)\MSBuild\Microsoft\Wix\ folder. It contains a target called AfterResolveReferences and it does exactly that. So here's my code I ended up with (in case someone is interested):
<Target Name="AfterResolveReferences">
<HeatDirectory
ToolPath="$(WixToolPath)"
OutputFile="Product.Binaries.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
Transforms="Filter.xslt"
Directory="$(HarvestFolder)"
DirectoryRefId="MY_FOLDER"
ComponentGroupName="Binaries"
GenerateGuidsNow="true"
SuppressRootDirectory="true"
SuppressRegistry="true"
PreprocessorVariable="var.App.TargetDir">
</HeatDirectory>
</Target>
I had the same problem and it was solved by combining the accepted answer and this answer to ensure that my post build event, which was copying files, always runs:
<RunPostBuildEvent>Always</RunPostBuildEvent>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
Also, my build server was using the MSBuild command line, and I used this answer to locate my local MSBuild.exe so I could test my changes locally without having to push to the build server.

Installshield Build Automation

I have seen many solutions for automating my InstallShield build, but I am having issues with each one. I am using InstallShield Professional 2013. Sorry for the lengthy question, but I am clueless on which direction to go to solve my issues.
1) IsCmdBld.exe - I have a script that runs and will build my installer. BUT, when the installer runs, I get an error message that says "The System Administrator has set policies to prevent this installation". I am not sure why this is happening, but I do not get the same error message if I build the installer through the designer. EDIT: Here is my command (%guid% is a Guid I generate to set the Product Code):
for /f %%i in ('"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\uuidgen.exe"') do set guid=%%i
"C:\Program Files (x86)\InstallShield\2013 SP1 SAB\System\ISCmdBld.exe" -p "MyInstaller.ism" -r SingleImage -y "1.0.0.13" -z ProductCode=%guid%
2) InstallShield Automation Interface - I have followed numerous examples and tutorials on this, but all end in the same result. When I call the following code:
var project = new ISWiAuto20.ISWiProject();
I get this error:
Unable to cast COM object of type 'System.__ComObject' to interface type
'ISWiAuto20.ISWiProject'. This operation failed because the QueryInterface call
on the COM component for the interface with IID '{872D23A7-C18D-468C-895D-1CF027E4FBB1}'
failed due to the following error: Library not registered.
(Exception from HRESULT: 0x8002801D (TYPE_E_LIBNOTREGISTERED)).
3) MsBuild.exe - Running MsBuild on my InstallShield project file yields this error:
error NSB4025: The project file could not be loaded. Invalid character in the
given encoding. Line 1, position 1
The choice between these approaches (when they all work) largely depends on the build system you are trying to integrate with. If you're using a batch or makefile approach, IsCmdBld.exe is probably the easiest starting point. If you're using Visual Studio and TFS or MSBuild, you'll probably have more luck there, as it will report errors in a way the build system can understand. (Other than that, they're fundamentally similar.) If you need to make tweaks to the project before you build it, the automation layer can either augment or replace the other approaches.
But in your case you say they all don't work. What have you done to diagnose why? Here are the first steps I'd take for each of those symptoms:
IsCmdBuild built setups yielding an error that the IDE-build ones do not. First identify what the problem really is. Look in a verbose log for more information. Build both ways with the .msi available and compare the results with MsiDiff. Make sure you've tested elevated. Depending on what you find, it may be something to address in the project, the build process, or a bug in InstallShield.
Automation Interface yields TYPE_E_LIBNOTREGISTERED. First off, if this is the IDE machine, consider repairing the installation. If it's a standalone-build machine, ditto. If it's a standalone-build machine that didn't use the installation, you should, or at least you should ensure the dependencies are present and that the automation interface is registered. Secondly, as Christopher Painter noted, InstallShield is a 32-bit product so it must be invoked from a 32-bit context. If you're calling, say, CScript to run a .vbs file, make sure you're using C:\Windows\SysWow64\CScript.exe.
MSBuild NSB4025. The comment from stijn is largely correct - you can't call MSBuild on the .ism file (while it can be xml instead of binary, it's not MSBuild-compatible). However you can create a .isproj file that can work correctly. Save the project in Visual Studio, or copy <InstallShield>\Support\0409\MSBuild.xml to (ProjectName).isproj and tweak its contents; call MSBuild on the resulting .isproj file. Odds are strong this will have approximately the same results as IsCmdBuild, as the build portion is largely shared.
Using MSBuild doesn't follow the exact order of the Project files specified in the solution .sln file.
The best option is to use devenv.exe
And sometimes, devenv doesn't return exact return status, so I kept an exe to scan the log file for the success code.
https://devopsdiaryblog.wordpress.com/2017/12/20/devenv-return-code-issue/
And for iscmdbuild.exe, better to use commandline as it is the suggested one from flexera.

How can I execute programs in my %PATH% with MSBuild?

Note: I'm using Mercurial as an example here, because that's what I'm trying to get to work with MSBuild right now.
But the problem is not limited to Mercurial, it happens with every external program that is somewhere in my %PATH% variable (I tried the same with PowerShell, for example).
So I didn't put the Mercurial tag on this question on purpose, because this is not about Mercurial!
What I actually want to do:
I want my build script to get the current revision number from my Mercurial repository and store it in a file.
The simplest way to do this from the command line is:
hg id -i >rev.txt
Mercurial is installed on my machine and the installation folder is in my %PATH% variable.
So I can run this line from anywhere on my machine (directly from the command line, or from a batch file), and it just works.
The problem occurs when I try to run this line from my build script.
I change the BeforeBuild (or AfterBuild) section of my .csproj file as follows:
<Target Name="AfterBuild">
<Exec Command="hg id -i >rev.txt"/>
</Target>
When I compile my solution with Visual Studio, it works and the rev.txt file is created in the folder where my .csproj is.
But when I compile the exact same solution from the command line with MSBuild, the build fails with the following error message:
The command "hg id -i >rev.txt" exited with code 9009.
I googled "msbuild code 9009" and found some solutions, but all of them propose to provide the full path to the executable.
When I do this, the build succeeds with MSBuild as well.
But this is not an acceptable solution for me, because I can't be sure that everyone using my project (including the build server) has installed Mercurial in the exact same folder.
That's exactly what %PATH% is for...
The same happens when I put the <Exec Command="... line directly into the build script.
If I specify the path to the executable, it works.
If I don't specify the path, it doesn't.
Is there any trick to make MSBuild execute programs in my %PATH% variable without specifying the complete folder?
EDIT:
#leppie:
Output redirection:
You mean the fact that I save the output of my command in a text file inside the command , instead of just running hg id -i as a command and using an output parameter or something like that to get the output?
Doesn't make any difference...the error is the same when I omit >rev.txt.
Command line args:
No, it throws the same error, even if I shorten the command to just hg (without any parameters).
Don't forget: if I run the exact same Exec command in the exact same .csproj file from Visual Studio, or if I just provide the path to the .exe file in the command, everything works.
So IMO output redirection and command line args can't be the problem.
Have you tried this extension pack for mercurial/msbuild?
http://msbuildhg.codeplex.com/documentation
Seems to have a task for returning revision id, which is what your trying to achieve no?
<HgVersion LocalPath="$(MSBuildProjectDirectory)" Timeout="5000">
<Output TaskParameter="Revision" PropertyName="AssemblyRevision" />
</HgVersion>
Okay, I found the solution.
I have to admit, it was a classic case of PEBKAC :-)
I'll explain it anyway, maybe it will help someone who made the same mistake:
Basically everything I have tried (plus what James Woolfenden suggested in his answer) would have been worked...if only the batch file that I use to run the build script wouldn't have looked like this:
path="%windir%\Microsoft.net\Framework\v4.0.30319"
msbuild build.proj
Yes, exactly.
I'm editing the %PATH% variable for the duration of this batch file, and I'm overwriting it with the path to MSBuild instead of just appending it.
So when my build script tries to call Mercurial, it can't find it anymore because its location is not in the %PATH% variable anymore.
No idea why I didn't see this before.
The correct way would be to append the MSBuild path, leaving the other paths intact:
path=%path%;%windir%\Microsoft.net\Framework\v4.0.30319