Setting Wix icon when advertise is set to no - wix

Seems like I'm forever asking questions about Wix.
This should be the last, and it's just a polishing one.
I'm wanting my associated files to have an icon to go with them, but in my ProgId element, the advertise is not specified which I assume defaults to no.
Therefore in the wix documentation, it states:
For an advertised ProgId, the Id of an Icon element. For a non-advertised ProgId, this is the Id of a file containing an icon resource.
I'm not understanding how this works at all. Do I set up a folder that contains the icon and reference it with IconIndex? This is the part of the .wxs I'm working with.
<Component Id ="MyApp.exe" Guid="{GUID-HERE}">
<File Id="MyApp.exe" KeyPath="yes" Source="$(var.MyApp.TargetDir)MyApp.exe" />
<ProgId Id ="MyAppProgID" Description="MyApp data files" Icon ="Logo.ico" IconIndex="0">
<Extension Id ="myapp" ContentType="application/myapp">
<Verb Id ="open" Command="open" TargetFile="MyApp.exe" Argument=""%1""/>
</Extension>
</ProgId>
<Icon Id="Logo.ico" SourceFile="$(var.MyApp.TargetDir)\Icon\Logo.ico"/>
I'm struggling to find any examples or proper documentation on a lot of the ProgId functionality for wix.
Thanks in advance

You need to change the Icon element to File and remove IconIndex
<Component Id ="MyApp.exe" Guid="{GUID-HERE}">
<File Id="MyApp.exe" KeyPath="yes" Source="$(var.MyApp.TargetDir)MyApp.exe" />
<File Id="Logo.ico" Source="$(var.MyApp.TargetDir)\Icon\Logo.ico"/>
<ProgId Id ="MyAppProgID" Description="MyApp data files" Icon ="Logo.ico">
<Extension Id ="myapp" ContentType="application/myapp">
<Verb Id ="open" Command="open" TargetFile="MyApp.exe" Argument=""%1""/>
</Extension>
</ProgId>

Related

PYRO0243 while building patch

I had the following "Reg2015" component in RTM in which I forgot to assign KeyPath:
<DirectoryRef Id="INSTALLLOCATION">
<Component Id="Reg2015" Guid="{xxx}" Win64="no" >
<RegistryKey Root="HKLM" Key="SOFTWARE\Mine" >
<RegistryValue Name="RefCount" Value="1" Type="integer" />
<RegistryValue Name="Name" Value="Mine" Type="string" Action="write" />
</RegistryKey>
</Component>
...
</DirectoryRef>
To prepare the patch, I changed "RefCount" to "2" and added to patch wxs.
Now PYRO.EXE complains like this:
error PYRO0243: Component 'Reg2015' has a changed keypath in the transform 'C:\Patch\Patch.Wixmst'. Patches cannot change the keypath of a component.
error PYRO0260: Product '{xxx}': Table 'CreateFolder' has a new row 'INSTALLLOCATION/Reg2015' added. This makes the patch not uninstallable.
I understand since there was no "KeyPath", its KeyPath defaulted to INSTALLLOCATION, but didn't know that component ID was considered as a directory.
(1) Can someone explain why?
(2) Is there any way to pass PYRO errors?
(3) For my next major release, if I add "KeyPath" to any of "RegistryValue" element, like
<RegistryValue Name="RefCount" Value="1" Type="integer" KeyPath="yes" />
should I be able to change "RefCount" to 2 in the future patch?
Thanks.
I think WiX selected Refcount as the keypath for the component - that's what the docs say. " If KeyPath is not set to 'yes' for the Component or for a child Registry value or File, WiX will look at the child elements under the Component in sequential order and try to automatically select one of them as a key path. Allowing WiX to automatically select a key path can be dangerous because adding or removing child elements under the Component can inadvertantly cause the key path to change, which can lead to installation problems. " You could verify that by looking in the MSI file with Orca to see what the Component table says about it.
So changing the keypath value probably resulted in that issue. It would be better to set another registry item (or create a new one) in the component to be the keypath.

How to modify XML file with wix toolset

I have XML file that include a next content:
<!--<appcache appCacheType="None" />-->
<appcache appCacheType="SingleClient" defaultExpiration="3600"/>
On installation patch i need to change this content in XML file to:
<appcache appCacheType="None" />
<!--<appcache appCacheType="SingleClient" defaultExpiration="3600"/>-->
What is a better way to do it?
Thanks.
I tried (in vain) to use the MSI Community Extensions for this purpose, but wasn't able to get them up and running.
I ended up using the util:XmlFile-tag from the Util-extension that works flawlessly.
Add the namespace of the Util-extension to your source-file in the Wix-element:
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
Then use it as sub-element of a related component. In your case you want to delete an attribute and change the value of another one. The following should do the trick, just adjust the XPath in the ElementPath-attribute to the one that matches your tag (in the example it updates the appcache-tag which has an attribute appCacheType with the value SingleClient) and the filekey of the XML-file:
<Component Id="myComponentToUpdateTheXmlFile" ... >
<!-- Removing the defaultExpiration-attribute first -->
<util:XmlFile Id="UpdateAppCacheTag" Action="deleteValue" ElementPath="//appcache[\[]#appCacheType='SingleClient'[\]]/#defaultExpiration" File="[#MyConfigFile.xml]" SelectionLanguage="XPath" Sequence="1" Name="defaultExpiration" />
<!-- Now updating the value -->
<util:XmlFile Id="UpdateAppCacheTag" Action="setValue" ElementPath="//appcache[\[]#appCacheType='SingleClient'[\]]/#appCacheType" File="[#MyConfigFile.xml]" SelectionLanguage="XPath" Sequence="2" Value="None" />
</Component>
Be sure to add the Util-extension also on the commandline when invoking candle and light:
<candle or light command line> ... <parameters> ... -ext <PathToWiXExtensions>\WixUtilExtension.dll
If you want to do this only during e.g. patching, then add the appropriate condition for this component.

Wix modify an existing ini file

I was trying to modify an .ini file in Wix
If it does not exists, the msi does not complete....
how do I check for this
I really want to modify it
Yes I looked at other stackoverflow questions/answers and on google
I was trying this...
<Component Id="TestIni" Guid="*">
<CreateFolder />
<IniFile Id="Ini1"
Action="createLine"
Directory="INSTALLLOCATION"
Section="Test"
Name="Minimal.ini"
Key="TestKey"
Value="TestValue" />
<IniFile Id="Ini2"
Action="createLine"
Directory="WindowsFolder"
Section="Test"
Name="Minimal.ini"
Key="TestKey"
Value="WindowsFolder TestValue" />
</Component>
Use Action="addLine" or Action="addTag" if you want to modify an existing value.
You could use the FileSearch element to set a property and then use this property in a condition.

How to create single RegistryKey and refer to it from many RegistryValue's?

I created a RegistryKey and a RegistryValue nested inside this RegistryKey. Later I created another RegistryValue - not nested inside whatever RegistryKey in WiX's XML scheme. But I want to this second RegistryValue be inside the first RegistryKey actually after the installation complete. So I want to refer from many RegistryValue's to a single RegistryKey. How to do it?
It also requires that various registry values will be inside various components, so I can't put all the registry values inside a single registry key within the WiX scheme.
The example is presented below.
<Component>
<RegistryValue
Root="HKLM"
Name="ShortcutInstalled"
Key="SetupAndAccessoryData1"
Type="integer"
Value="1"
KeyPath="yes"
/>
</Component>
<Component>
<RegistryKey
Id="SetupAndAccessoryData1"
Action="createAndRemoveOnUninstall"
Key="SOFTWARE\$(var.Manufacturer)\$(var.ProductName)\SetupAndAccessoryData"
Root="HKLM"
>
<RegistryValue
Type="string"
Name="InstallDirectory"
Value="[ProductDirectory]"
KeyPath="yes"
>
</RegistryValue>
</RegistryKey>
</Component>
For now I must fill the Key attribute of the ShortcutInstalled RegistryValue with the same data as in the Key attribute at the RegistryKey. But I don't want to copy and paste it because of refactoring difficulties. I just want to refer to the same registry key. What is the best approach to gain it?
The RegistryKey element is mostly provided for convenience when you have many RegistryValue elements to nest under a single key. However, it is not necessary to use RegistryKey element since RegistryValue can provide the full path as well. Your example above could also be written like:
<Component>
<RegistryValue
Root="HKLM"
Key="SOFTWARE\$(var.Manufacturer)\$(var.ProductName)\SetupAndAccessoryData"
Name="ShortcutInstalled"
Value="1"
Type="integer" />
</Component>
<Component>
<RegistryValue
Id="SetupAndAccessoryData1"
Root="HKLM"
Key="SOFTWARE\$(var.Manufacturer)\$(var.ProductName)\SetupAndAccessoryData"
Name="InstallDirectory"
Value="[ProductDirectory]"
Type="string" />
</RegistryValue>
</Component>
It's mostly a matter of preference. Alternatively, if you need to refer to the same registry key in many Components then you could use a preprocessor variable to store the common part of the path, then use it across many RegistryValue elements. For example, we could modify the above to look like:
<?define CommonReg = "SOFTWARE\$(var.Manufacturer)\$(var.ProductName)\SetupAndAccessoryData" ?>
<Component>
<RegistryValue
Root="HKLM"
Key="$(var.CommonReg)"
Name="ShortcutInstalled"
Value="1"
Type="integer" />
</Component>
<Component>
<RegistryValue
Id="SetupAndAccessoryData1"
Root="HKLM"
Key="$(var.CommonReg)"
Name="InstallDirectory"
Value="[ProductDirectory]"
Type="string" />
</RegistryValue>
</Component>

Reading DWORD values from registry using WiX's RegistrySearch

I've created an installer with WiX and am trying to preserve an existing DWORD registry entry during a repair installation of my product. To store the existing values, I am using the following WiX fragment;
<Property Id="PreserveMySetting" Secure="yes">
<RegistrySearch Id="FindExistingMySetting"
Root="HKLM"
Key="Software\!(loc.ProductManufacturer)\!(loc.ProductName)"
Name="MySetting"
Type="raw"
Win64="no" />
</Property>
I then set this later on using a component driven by the saved value.
The problem is, the registry search returns the DWORD as a "Formatted" string, e.g.;
#1
Instead of just
1
This means that when my component sets the registry entry, it is created as a REG_SZ with the value "#1", even though I've indicated that it should be an integer;
<Component Id="MySettingKey"
Guid="{76C4B14C-14BC-42E1-91F0-75C9F2A20EC8}">
<RegistryValue Id="MySetting"
Action="write"
Name="MySetting"
Value="[PreserveMySetting]"
Type="integer"
KeyPath="yes"
Key="Software\!(loc.ProductManufacturer)\!(loc.ProductName)"
Root="HKMU"/>
</Component>
Is there any way to get the actual registry value for use by the component?
This is going to sound backwards, but if you change the Type attribute to string it'll work. The reason is clear when you look at your MSI's Registry table using ORCA.
When you select integer WiX author's "#[PRESERVEMYSETTING]" and when you select string it author's [PRESERVEMYSETTING]. Since PRESERVEMYSETTING is already #1 you want it to be #1 not ##1.
<Component Id="MySettingKey"
Guid="{76C4B14C-14BC-42E1-91F0-75C9F2A20EC8}">
<RegistryValue Id="MySetting"
Action="write"
Name="MySetting"
Value="[PRESERVEMYSETTING]" <!-- Secure Properties are PUBLIC properties -->
Type="string"
KeyPath="yes"
Key="Software\!(loc.ProductManufacturer)\!(loc.ProductName)"
Root="HKMU"/>
</Component>