I'm creating a windows installer with the WiX toolset. I would like to make an URL reservation with the UrlReservation Element for that I would like to get the current user and domainname.
This is what I did:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension"
xmlns:firext="http://schemas.microsoft.com/wix/FirewallExtension"
xmlns:httpext="http://schemas.microsoft.com/wix/HttpExtension">
<Product Id="*" ... >
<Property Id ="PROP_URL_RESERVATION_DOMAIN_NAME" Value="$(env.USERDOMAIN)" Secure="yes" />
<Property Id ="PROP_URL_RESERVATION_USER_NAME" Value="$(env.USERNAME)" Secure="yes" />
<UI>
<UIRef Id="WixUI_FeatureTree_MyApp" />
</UI>
</Product>
The userdomain and username are set correctly but they are compiled in (during candlelight) and are then constant. But I would like to init with the current user and domain when the installer is started.
Can you help me that PROP_URL_RESERVATION_DOMAIN_NAME and PROP_URL_RESERVATION_USER_NAME are initialised with the current when the installer is started?
Thanks
I go the way with RegistrySearch:
<Property Id ="PROP_URL_RESERVATION_DOMAIN_NAME" Value="DOMAIN" Secure="yes">
<RegistrySearch Id="DomainRegistrySearch"
Root="HKCU"
Key="Volatile Environment"
Name="USERDOMAIN"
Type="raw" />
</Property>
<Property Id ="PROP_URL_RESERVATION_USER_NAME" Value="USER" Secure="yes">
<RegistrySearch Id="UserRegistrySearch"
Root="HKCU"
Key="Volatile Environment"
Name="USERNAME"
Type="raw" />
</Property>
Related
We are using Wix Toolset V3.11 to build our setup.
Because of the following declaration, our default installation Path is C:/Program Files(x86)/Acme/AppName.
<Property Id="ApplicationFolderName" Value="$(var.Manufacturer)\$(var.AppFolderName)" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
Via the 'Advanced' button in the setup we change this path to C:/Program Files(x86)/Acme/FooBar:
The following declaration saves the changed path in the registry:
<RegistryKey
Key="Software\$(var.Manufacturer)\$(var.AppName)"
Root="HKLM">
<RegistryValue Id="InstallationRegistry"
Type="string"
Name="InstallDir"
Value="[APPLICATIONFOLDER]" />
</RegistryKey>
Via Regedit.exe I can see the Path C:/Program Files(x86)/Acme/FooBar in the Registry as expected. All okay.
Problem: But now, when I run a new setup which is an update, then all Files have been moved from the custom folder C:/Program Files(x86)/Acme/FooBar to the default folder C:/Program Files(x86)/Acme/AppName.
When I execute an update and click on the 'Advanced' button, then the default path C:/Program Files(x86)/Acme/AppName is preallocated:
I use the following markup to query the Path out of the Registry:
<Property Id="APPLICATIONFOLDER">
<RegistrySearch Id='InstallationRegistrySearch' Type='raw' Root='HKLM' Key='Software\$(var.Manufacturer)\$(var.AppName)' Name='InstallDir' />
</Property>
Here is the relevant markup:
<Fragment>
<ComponentGroup Id="RootComponents" Directory="APPLICATIONFOLDER">
<Component Id="RootComponent" Guid="xxxxxxxxx" Win64='yes'>
<RegistryKey
Key="Software\$(var.Manufacturer)\$(var.AppName)"
Root="HKLM">
<RegistryValue Id="InstallationRegistry"
Type="string"
Name="InstallDir"
Value="[APPLICATIONFOLDER]" />
</RegistryKey>
</Component>
</ComponentGroup>
[...]
<Product ...>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="PROGRAMFILESPATH" Name="$(var.ProgramFilesPath)">
<Directory Id="ManufacturerFolder" Name="$(var.Manufacturer)">
<Directory Id="APPLICATIONFOLDER" Name="$(var.AppFolderName)" >
<!-- here are the application files (e.g. Appname.exe)-->
[...]
</Directory>
</Directory>
</Directory>
</Directory>
[...]
<Property Id="ApplicationFolderName" Value="$(var.Manufacturer)\$(var.AppFolderName)" />
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<Property Id="APPLICATIONFOLDER">
<RegistrySearch Id='InstallationRegistrySearch' Type='raw' Root='HKLM' Key='Software\$(var.Manufacturer)\$(var.AppName)' Name='InstallDir' />
</Property>
<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
<Property Id="ALLUSERS" Value="1"/>
[...]
<UI>
[...]
<UIRef Id="WixUI_Advanced"/>
</UI>
</Product>
What are we doing wrong?
Remember Properties: Property values are not auto-magically persisted by MSI, hence the need for patterns such as the "Remember Property Pattern".
Bitness: It looks like you are reading back from the registry, but could it be that you have a "bitness problem"? In other words you read from the x64-section of the registry and not the x86-section? (or vice versa).
HKEY_LOCAL_MACHINE\SOFTWARE\Manufacturer\Acme\Program
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Manufacturer\Acme\Program
In the released MSI, I had the hard-coded port number, e.g.
<Property Id="HTTP_PORT1" Secure="yes" Value="1000" />
<Component Id="my.exe" Guid="*" Win64="yes" >
<File Id="my.exe" KeyPath="yes" Source="my.exe" />
<RegistryValue Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port1" Value="[HTTP_PORT1]" Type="integer" />
<RegistryValue Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port2" Value="9000" Type="integer" />
</Component>
And for the patch, my Patch.wxs looked like this:
<PatchFamily Id="Rollup" Version="1.0.100" Supersede="yes">
<ComponentRef Id="my.exe"/>
</PatchFamily>
When I manually change those regs to "1111" and "9999" and applied the patch MSP, those Port1 and Port2 were set back to "1000" and "9000" respectively. So I changed "HTTP_PORT1" and added "INT_HTTP_PORT2" like this:
<Property Id="HTTP_PORT1" Secure="yes" Value="#1000" >
<RegistrySearch Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port1" Type="raw" Win64="yes" />
</Property>
<Property Id="INT_HTTP_PORT2" Secure="yes" Value="#9000" >
<RegistrySearch Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port2" Type="raw" Win64="yes" />
</Property>
<Component Id="my.exe" Guid="*" Win64="yes" >
<File Id="my.exe" KeyPath="yes" Source="my.exe" />
<RegistryValue Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port1" Value="[HTTP_PORT1]" Type="string" />
<RegistryValue Root="HKLM" Key="SOFTWARE\MyCompany" Name="Port2" Value="[INT_HTTP_PORT2]" Type="string" />
</Component>
And I changed Patch.wxs like this:
<PatchFamily Id="Rollup" Version="1.0.100" Supersede="yes">
<ComponentRef Id="my.exe"/>
<PropertyRef Id="HTTP_PORT1"/>
<PropertyRef Id="INT_HTTP_PORT2"/>
</PatchFamily>
However, both Port1 and Port2 are changed back to the original values (although Port1 is now REG_SZ.)
Is this an expected behavior? Is it possible to make it work in the patch without using Type1 custom action?
The executable in that component is the keypath item. I'd verify that you increased the version of that exe because it effectively controls whether that component is updated. You could create a verbose log of the patch install to see exactly what's going on.
What you need to look for in the verbose log is what it says about my.exe, whether it's Overwrite or something else. Also, note that if the component rules were broken in the patch it will effectively result in nothing being patched. You will see SELMGR in the log if that's the case.
My program is supposed to be installed to a path that recorded in registry. If the registry key is not found, then install to another(default) path.
For example, I'd like to have something like:
<Property Id="MYINSTALLDIR">
<RegistrySearch Id='MyRegistry' Type='raw' Root='HKCU' Key='Software\MyApp\Foo' Name='InstallDir' />
if not found, then set "MYINSTALLDIR" to "D:\working\defaultApps"
</Property>
How should I write my wxs file to make this happen?
EDIT:
The problem now is:
if not found in registry, then set "MYINSTALLDIR" to LocalAppDataFolder
I tried
<Property Id="MYINSTALLDIR" Value="LocalAppDataFolder">
<RegistrySearch Id='MyRegistry' Type='raw' Root='HKCU' Key='Software\MyApp\Foo' Name='InstallDir' />
</Property>
But error returned:
Error 1606. Could not access network location LocalAppDataFolder.
Ok, I finally figure out how to do it.
With Custom Action, the default value can now be set to another property:
<Property Id="MYINSTALLDIR">
<RegistrySearch Id='MyRegistry' Type='raw' Root='HKCU' Key='Software\MyApp\Foo' Name='InstallDir' />
</Property>
<CustomAction Id="UserInstallDir" Property="InstallDir" Value="[INSTALLDIRCU]" Execute="immediate" />
<CustomAction Id="UserInstallDirDefault" Property="InstallDir" Value="[LocalAppDataFolder]" Execute="immediate" />
<InstallExecuteSequence>
<Custom Action="UserInstallDir" After="AppSearch">MYINSTALLDIR</Custom>
<Custom Action="UserInstallDirDefault" After="AppSearch">NOT MYINSTALLDIR</Custom>
</InstallExecuteSequence>
From memory the example below should work. If no value is found for the search, the property gets the default value. It's only overwritten if the search succeeds.
<Property Id="MYINSTALLDIR" Value="Default Property Value">
<RegistrySearch Id='MyRegistry' Type='raw' Root='HKCU' Key='Software\MyApp\Foo' Name='InstallDir' />
</Property>
Using SharePoint 2010 and Visual Studio I have created a site definition (inheriting from the publishing site) which correctly creates all the required lists and now includes page instances in the "Pages" document library.
The Pages use the correct custom pagelayout and the correct content type, however, because the "pages" library only accepts Article, Blank and Welcome pages by default it doesnt know about my custom content types and therefore the page doesn't work as expected.
I've tried adding an EventListener on the "List Added" event, with no success, the debugging doesnt even break at my breakpoints, I've also tried the List Adding, List Item added and Site Provisioned events. None of which seem to work the way I want.
I've included the XML for the Site Definition below, how do I add my custom content types to the pages library so I dont have to manually add it?
<?xml version="1.0" encoding="utf-8"?>
<Project Title="Custom_Site_Definition" Revision="2" ListDir="" xmlns:ows="Microsoft SharePoint" xmlns="http://schemas.microsoft.com/sharepoint/">
<NavBars>
<NavBar Name="SharePoint Top Navbar" Url="/Site Template" ID="1002" />
<!-- removed -->
</NavBars>
<Configurations>
<Configuration ID="0" Name="Custom_Site_Definition">
<Lists />
<WebFeatures>
<!-- Include the common WSSListTemplateFeatures used by CMS -->
<Feature ID="00BFEA71-DE22-43B2-A848-C05709900100" > </Feature>
<Feature ID="00BFEA71-E717-4E80-AA17-D0C71B360101" > </Feature>
<Feature ID="00BFEA71-52D4-45B3-B544-B1C71B620109" > </Feature>
<Feature ID="00BFEA71-A83E-497E-9BA0-7A5C597D0107" > </Feature>
<Feature ID="00BFEA71-4EA5-48D4-A4AD-305CF7030140" > </Feature>
<Feature ID="00BFEA71-F600-43F6-A895-40C0DE7B0117" > </Feature>
<Feature ID="00BFEA71-4EA5-48D4-A4AD-7EA5C011ABE5">
</Feature>
<Feature ID="22A9EF51-737B-4ff2-9346-694633FE4416">
<Properties xmlns="http://schemas.microsoft.com/sharepoint/">
<Property Key="ChromeMasterUrl" Value=""/>
<Property Key="WelcomePageUrl" Value="$Resources:osrvcore,List_Pages_UrlName;/at-a-glance.aspx"/>
<Property Key="PagesListUrl" Value=""/>
<Property Key="AvailableWebTemplates" Value=""/>
<Property Key="AvailablePageLayouts" Value=""/>
<Property Key="SimplePublishing" Value="true" />
</Properties>
</Feature>
<Feature ID="541F5F57-C847-4e16-B59A-B31E90E6F9EA">
<Properties xmlns="http://schemas.microsoft.com/sharepoint/">
<Property Key="InheritGlobalNavigation" Value="true"/>
<Property Key="ShowSiblings" Value="true"/>
<Property Key="IncludeSubSites" Value="true"/>
</Properties>
</Feature>
<Feature ID="94C94CA6-B32F-4da9-A9E3-1F3D343D7ECB">
<!-- Office SharePoint Server Publishing -->
</Feature>
</WebFeatures>
<Modules>
<Module Name="Home" />
</Modules>
</Configuration>
</Configurations>
<Modules>
<Module Name="Home" Url="$Resources:osrvcore,List_Pages_UrlName;" Path="">
<File Url="at-a-glance.aspx" Type="GhostableInLibrary" Level="Draft" >
<Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/Custom Article Page.aspx, $Resources:cmscore,PageLayout_WelcomeLinks_Title;" />
</File>
<!-- removed -->
</Module>
</Modules>
</Project>
Never mind, I got it...eventually
Solution was to
Add a Feature to the site definition project with the following in its elements.xml file
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ContentTypeBinding ContentTypeId="0x010100899F73B9F6814EA9AED9876985F28B39" ListUrl="Pages" />
</Elements>
Then add a feature dependency in the onet.xml file
<!-- Binds custom content types to Pages library.-->
<Feature ID="8290db1f-0a87-44f3-be22-28c61f9c8965">
</Feature>
and finally to add each page in a module at the end of the file (including the content type)
<File Url="at-a-glance.aspx" Type="GhostableInLibrary" Level="Draft" >
<Property Name="Title" Value="At a glance" />
<Property Name="ContentType" Value="Custom_ContentTypes_Publishing - CustomFive" />
<Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/Custom Article Page.aspx, $Resources:cmscore,PageLayout_WelcomeLinks_Title;" />
</File>
How can I make a major upgrade to an installation set (MSI) built with WiX install into the same folder as the original installation?
The installation is correctly detected as an upgrade, but the directory selection screen is still shown and with the default value (not necessarily the current installation folder).
Do I have to do manual work like saving the installation folder in a registry key upon first installing and then read this key upon upgrade? If so, is there any example?
Or is there some easier way to achieve this in MSI or WiX?
As reference, I my current WiX file is below:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
<Product Id="a2298d1d-ba60-4c4d-92e3-a77413f54a53"
Name="MyCompany Integration Framework 1.0.0"
Language="1033"
Version="1.0.0"
Manufacturer="MyCompany"
UpgradeCode="9071eacc-9b5a-48e3-bb90-8064d2b2c45d">
<!-- Package information -->
<Package Keywords="Installer"
Id="e85e6190-1cd4-49f5-8924-9da5fcb8aee8"
Description="Installs MyCompany Integration Framework 1.0.0"
Comments="Installs MyCompany Integration Framework 1.0.0"
InstallerVersion="100"
Compressed="yes" />
<Upgrade Id='9071eacc-9b5a-48e3-bb90-8064d2b2c45d'>
<UpgradeVersion Property="PATCHFOUND"
OnlyDetect="no"
Minimum="0.0.1"
IncludeMinimum="yes"
Maximum="1.0.0"
IncludeMaximum="yes"/>
</Upgrade>
<!-- Useless but necessary... -->
<Media Id="1" Cabinet="MyCompany.cab" EmbedCab="yes" />
<!-- Precondition: .NET 2 must be installed -->
<Condition Message='This setup requires the .NET Framework 2 or higher.'>
<![CDATA[MsiNetAssemblySupport >= "2.0.50727"]]>
</Condition>
<Directory Id="TARGETDIR"
Name="SourceDir">
<Directory Id="MyCompany"
Name="MyCompany">
<Directory Id="INSTALLDIR"
Name="Integrat"
LongName="MyCompany Integration Framework">
<Component Id="MyCompanyDllComponent"
Guid="4f362043-03a0-472d-a84f-896522ce7d2b"
DiskId="1">
<File Id="MyCompanyIntegrationDll"
Name="IbIntegr.dll"
src="..\Build\MyCompany.Integration.dll"
Vital="yes"
LongName="MyCompany.Integration.dll" />
<File Id="MyCompanyServiceModelDll"
Name="IbSerMod.dll"
src="..\Build\MyCompany.ServiceModel.dll"
Vital="yes"
LongName="MyCompany.ServiceModel.dll" />
</Component>
<!-- More components -->
</Directory>
</Directory>
</Directory>
<Feature Id="MyCompanyProductFeature"
Title='MyCompany Integration Framework'
Description='The complete package'
Display='expand'
Level="1"
InstallDefault='local'
ConfigurableDirectory="INSTALLDIR">
<ComponentRef Id="MyCompanyDllComponent" />
</Feature>
<!-- Task scheduler application. It has to be used as a property -->
<Property Id="finaltaskexe"
Value="MyCompany.Integration.Host.exe" />
<Property Id="WIXUI_INSTALLDIR"
Value="INSTALLDIR" />
<InstallExecuteSequence>
<!-- command must be executed: MyCompany.Integration.Host.exe /INITIALCONFIG parameters.xml -->
<Custom Action='PropertyAssign'
After='InstallFinalize'>NOT Installed AND NOT PATCHFOUND</Custom>
<Custom Action='LaunchFile'
After='InstallFinalize'>NOT Installed AND NOT PATCHFOUND</Custom>
<RemoveExistingProducts Before='CostInitialize' />
</InstallExecuteSequence>
<!-- execute comand -->
<CustomAction Id='PropertyAssign'
Property='PathProperty'
Value='[INSTALLDIR][finaltaskexe]' />
<CustomAction Id='LaunchFile'
Property='PathProperty'
ExeCommand='/INITIALCONFIG "[INSTALLDIR]parameters.xml"'
Return='asyncNoWait' />
<!-- User interface information -->
<UIRef Id="WixUI_InstallDir" />
<UIRef Id="WixUI_ErrorProgressText" />
</Product>
</Wix>
There's an example in the WiX tutorial: https://www.firegiant.com/wix/tutorial/getting-started/where-to-install/
<Property Id="INSTALLDIR">
<RegistrySearch Id='AcmeFoobarRegistry' Type='raw'
Root='HKLM' Key='Software\Acme\Foobar 1.0' Name='InstallDir' />
</Property>
Of course, you've got to set the registry key as part of the install too. Stick this inside a component that's part of the original install:
<RegistryKey
Key="Software\Software\Acme\Foobar 1.0"
Root="HKLM">
<RegistryValue Id="FoobarRegInstallDir"
Type="string"
Name="InstallDir"
Value="[INSTALLDIR]" />
</RegistryKey>
'Registry' is deprecated. Now that part of code should look like this:
<RegistryKey Id="FoobarRegRoot"
Action="createAndRemoveOnUninstall"
Key="Software\Software\Acme\Foobar 1.0"
Root="HKLM">
<RegistryValue Id="FoobarRegInstallDir"
Type="string"
Name="InstallDir"
Value="[INSTALLDIR]" />
</RegistryKey>
You don't really need to separate RegistryKey from RegistryValue in a simple case like this. Also, using HKMU instead of HKLM takes care of it whether you're doing a machine or user install.
<RegistryValue
Root="HKMU"
Key="Software\[Manufacturer]\[ProductName]"
Name="InstallDir"
Type="string"
Value="[INSTALLDIR]"
KeyPath="yes" />