Nested variables in Wix - wix

I am creating a WIX template for my projects to ensure a relatively standard layout.
I have defined a variable to reference the Main Application using <?define MainApp="MyApp"?> where MyApp is the name of the referenced project. I then use the MainApp variable to reference the project's properties in the .wxs and .wxi files.
However, I have an issue when referencing nested properties.
$var.($(var.MainApp).ProjectName) expands to "MyApp" without issue.
$var.($(var.MainApp).ProjectDir)Resources\Main.ico expands to $var.(MyApp.ProjectDir)Resources\Main.ico
$var.($(var.MainApp).TargetPath) expands to $var.(ConsoleApplication1.TargetPath)
etc...
My aim is to create a single definition for my main application, thus eliminating a search/replace, which I find clunky.

As you've found, nested preprocessor variables are not supported by the WiX toolset today.

Related

Creating class inside package A of A.B in IntelliJ

I have a maven project in IntelliJ IDE. I have created a package with name event.handlers. After which I created multiple classes inside this package.
There are no classes inside event everything is inside event.handlers.
Now I want to create a java class inside package event.
Is there any way from the IDE I can do that?
Currently, I am manually creating the java file inside the event folder in my code repository.
In the left Project structure pane, there is Settings button, in that please Uncheck, Compact Empty Middle Packages.
The settings will be like
.
Now you will have a tree structure, where you can right-click or (ctrl + enter/ alt + insert) on the package and create the file.
For example,
Try creating a Java Class at src folder named event.NewClass. This will create a NewClass.java inside src/event.
You can create folder with the dot symbol . at creating a Java Class or a Package, or Kotlin File/Class when Type is not File. For example create a Package with name com.company.example at src folder will automatically generate the folders recursively, src/com/company/example, create a Java Class with name com.company.example.AClass will automatically generate a file AClass.java inside the automatically generated folder tree src/com/company/example.
It might be easier to just create the class inside package AB and Refactor > Move to place it inside of A.
It seems that all other answers here are workarounds anyway, so if it's just a one-off, this might be the easiest option.
However, in my case, after doing this I had to "Invalidate Caches and Restart" before IDEA updated the UI properly.

Detecting unused components in Wix in Visual Studio

I'm using wix 3.8 in Visual Studio 2010.
If I have 2 components in a fragment in a wxs file and I only reference one of them in a feature I get an ICE21 error that there are components that are not used.
If I have a wxs file with components where none of the components are part of a feature I get no error, the components are just silently skipped.
Is this the desired behaviour? Is there a way to force an error message in this case?
The reason I'm asking is that I plan to use wix to create an installer where the developers themselves are reponsible for adding new files and components to the installer. It would be nice to have a way to make sure that they (we) didn't forget to include the new components in a feature.
Fragment description from the documentation, I highlighted the part where it should answer your question:
The Fragment element is the building block of creating an installer
database in WiX. Once defined, the Fragment becomes an immutable,
atomic unit which can either be completely included or excluded from a
product. The contents of a Fragment element can be linked into a
product by utilizing one of the many *Ref elements. When linking in a
Fragment, it will be necessary to link in all of its individual units.
For instance, if a given Fragment contains two Component elements, you
must link both under features using ComponentRef for each linked
Component. Otherwise, you will get a linker warning and have a
floating Component that does not appear under any Feature.
So, if any Component is referenced into a Feature then the complete Fragment with all its Components will be pulled into build and give you a warning/error that you have orphan component(s).
In your first case you have two components in a same fragment and you referenced only one and got an error about the second component.
If you have a fragment with many components and you don't reference any of them then Wix will not read that fragment at all.
In your second case all your components are in the same fragment but none of the components are referenced into a Feature therefore there are no errors as that fragment is not used at all.

Windows Store Apps : suppress "Common" folder generation?

I'm writing a Windows Store app, and I'd like to know if it's possible to suppress the generation of the "Common" folder, containing the code from Microsoft, which - imho I do not need.
Any ideas?
Cheers
Common contains StandardStyles.xaml which per App.xaml:
<!--
Styles that define common aspects of the platform look and feel
Required by Visual Studio project and item templates
-->
<ResourceDictionary Source="Common/StandardStyles.xaml"/>
and in StandardStyles.xaml:
<!--
This file contains XAML styles that simplify application development.
These are not merely convenient, but are required by most Visual Studio project and item templates.
Removing, renaming, or otherwise modifying the content of these files may result in a project that
does not build, or that will not build once additional pages are added. If variations on these
styles are desired it is recommended that you copy the content under a new name and modify your
private copy.
-->
That said if you've determined it's not something you'll need just delete it, simpler and less fragile than hacking a T4 template (or whatever mechanism is used) for the code generation.

Unable to delete deployed file during installation with WIX installer

In our WIX installer project, we need to generate a new file, let's call it FileB, based on a deployed file, called FileA in a managed custom action function. In another word, in the component declaration, I declare the FileA. While in a custom action (which happens at commit phase), I need to generate FileB based on FileA. After that, since FileA is no use anymore, I want to delete it in the same custom action.
And here comes the problem: with the default installation folder, which is Program Files, the normal user is not allowed to add file (generate FileB) into this folder in the custom action (I am not 100% sure I am right, but it is the case in my test. And if I install it in another folder, there is no problem at all). So I think I need to give permission of creating file. In order to do that, I add a CreateFolder element to the component which includs FileA. The whole component declaration is something like this:
<Component Id='COMPONENT_NAME' Guid='MY_GUID'>
<!--OTHER FILES IN THE COMPONENT-->
...
<CreateFolder Directory='INSTALLDIR'>
<Permission CreateFile='yes' User='Everyone' GenericAll='yes' Delete='yes'/>
</CreateFolder>
<File Id='MyFileA' Name='FileA' Source='PATH_TO_FILEA' KeyPath='no' >
<Permission GenericAll='yes' User='Everyone' Delete='yes'/>
</File>
</Component>
The component actually belongs to a component group, which resides in INSTALLDIR. The reason there is other files in the same component element is because I want another File to be the keypath, so that deleting FileA would not cause a problem of that. And now the generation of FileB is working fine. But later in the same custom action, I am experiencing the problem when deleting FileA. It just says that ": Access to the path 'DEPLOYMENT_PATH_TO_FILEA' is denied." I thought the problem lies in the FileA declaration, that's why I added the Delete='yes' in the Permission element under File, hoping to make it OK to delete it (although I am not sure whether this means in the installation it is possible to delete). But still I get this error. Can anyone tell me what I did wrong?
Another question is, I really don't know what is the purpose of those CreatFolder elements. For one thing: if the aim is to create the directory structure, I think the (nested)Directory elements already do that. And why to have such element under Component element when most of the time you probably want the directory structure to be separated with component structure(the components just use directory reference to refer to correct directory). Secondly, the default Directory property of CreateFolder is the parent Directory where the component resides in. But it is common that more than one components reside in the same directory, like what I have here: multiple components are in the same component group, whose directory element references to INSTALLDIR. So only one of these components has the CreateFolder element, whose Directory property in my case is the parent directory of all those components. It is really hard to understand this structure. I guess I have some misunderstanding of the CreateFolder element. Can someone enlighten me to usage of CreateFolder? Thanks!
Thanks!
A number of issues to address here. First, you should know that Commit phase custom actions don't execute if rollback is disabled. You should really have an deferred and rollback custom action.
Second, you can't tell MSI to install a file and then go delete it. That's counterproductive and just causes servicing issues down the road. A better solution ( I'm assuming you are using a WiX DTF managed custom action ) is to include FileA as a content item in the custom action project. This will cause the file to exist in the current (temp) directory of the custom action while it execute. You can then generate fileb. For rollback, you can delete fileb.
You'll also need to author a RemoveFile element to teach MSI to delete the file on uninstall. Otherwise it won't since MSI doesn't know anything about fileb created by your out of process custom action.
Otherwise it'd be useful to know what the contents of fileb are. It would be easier to implement if this was an xml file that could be installed as fileb and then transformed using the xml wix extension.

MSBUILD Generate xml documentation file for all projects in solution (without touching the projects)

I'm trying to create the XML documentation for all the projects in the solution even when the option its not checked in the project properties (and this is the key point).
I'm using TFS 2010 SP1 and tried with this "/p:TreatWarningsAsErrors=true /p:GenerateDocumentation=true" in the "MSBuild Arguments" field of my build definition. It doesn't generate anything.
I also tried with /p:DocumentationFile=foo.xml, which it does work but I assuming the file gets overridden by the last compiled project, so I tried using a variable instead but with no luck, I tried with
/p:DocumentationFile=$(Project).xml,
/p:DocumentationFile=$(localProject).xml
/p:DocumentationFile=$(localBuildProjectItem).xml
Is there a way to create the XML documentation for all the projects from within MSBUILD even though the option is not checked in the project?
PS: And yes I already see another thread similar to this but I don't want to modify the projects, that's the whole point of doing it with MSBUILD.
Thanks for your time
I also wanted to achieve this and finally I came up with a solution following these steps:
Create a Directory.Build.props file in the solution root folder.
Set GenerateDocumentationFile property to true.
Set DocumentationFile property.
By default you would use $(OutputPath) and $(AssemblyName) properties to set the documentation file name, like this:
<DocumentationFile>$(OutputPath)$(AssemblyName).xml</DocumentationFile>
But unfortunately this does not work as Directory.Build.props file is processed first hence properties set in .csproj files are unavailable at this point.
Fortunately there is another property that gets the current project name: $(MSBuildProjectName)
The output path by default is the following:
for Web projects: bin\
for other projects: bin\$(Configuration)\, e.g. bin\Debug\
To decide whether a project is a web project or not I used the name of the project which ends either with .Web or .WebApi
So the complete Directory.Build.props file looks like this in my case:
<Project>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- The rest is omitted for clarity. -->
</PropertyGroup>
<PropertyGroup>
<!-- warning CS1591: Missing XML comment for publicly visible type or member -->
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="$(MSBuildProjectName.EndsWith('.Web')) Or $(MSBuildProjectName.EndsWith('.WebApi'))">
<DocumentationFile>bin\$(MSBuildProjectName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="!$(MSBuildProjectName.EndsWith('.Web')) And !$(MSBuildProjectName.EndsWith('.WebApi'))">
<DocumentationFile>bin\$(Configuration)\$(MSBuildProjectName).xml</DocumentationFile>
</PropertyGroup>
</Project>
As you can see there is also a <NoWarn>1591</NoWarn> property set which tells the compiler not to produce warning messages for publicly visible types where XML document is missing.
Hope it helps.
Open your process template (i.e.: $/yourproject/BuildProcessTemplates/DefaultTemplate.xaml)
Scroll down to find the Compile the Project activity.
Add a new variable named DocumentationFile, type=String, scope=Compile the Project
Set its default value to:
String.Format("{0}.XML", System.IO.Path.GetFileNameWithoutExtension(serverBuildProjectItem))
Save changes and scroll down to Run MSBuild for Project activity.
In CommandLineArguments, set the following value:
String.Format("/p:SkipInvalidConfigurations=true {0};DocumentationFile={1}", MSBuildArguments, DocumentationFile)
Check-in the changes and build. This should generate the documentation even if it was not set by the project.