With Windows Installer 4.5, there was a new table added for MsiEmbeddedChainer Table. This table was supposed to allow multiple-package installation. WiX added support for the table by creating the EmbeddedChainer element. I've read the wiki, but are there any examples on how to use the element?
I'm attempting to install a JRE before my program.
Embedded chainers only work after the installer that contained them is installed, and can only install raw .msi files (.msi files with their own bootstrap .exe files cannot be used), so I don't think you'll be able to install the JRE the way you want.
Do the following steps:
Changes in WXS file:
...
<Component DiskId="1" Guid="5CE59096-E197-4694-8DC2-E8EB4601C7C5" Id="CHAINERRUN.EXE">
<File Id="CHAINERRUN.EXE" Name="ChainerRun.exe" Source="..\ClinAppChainers\bin\ChainerRun.exe" />
<File Id="MICROSOFT.DEPLOYMENT.WINDOWSINSTALLER.DLL" Name="Microsoft.Deployment.WindowsInstaller.dll" Source="C:\Program Files\Windows Installer XML v3.6\SDK\Microsoft.Deployment.WindowsInstaller.dll" />
<File Id="MICROSOFT.CSHARP.DLL" Name="Microsoft.CSharp.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.CSharp.dll" />
<File Id="SYSTEM.DLL" Name="System.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll" />
<File Id="SYSTEM.CORE.DLL" Name="System.Core.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll" />
<File Id="SYSTEM.XML.DLL" Name="System.Xml.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Xml.dll" />
<File Id="SYSTEM.XML.LINQ.DLL" Name="System.Xml.Linq.dll" Source="C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Xml.Linq.dll" />
</Component>
...
<EmbeddedChainer Id="ChainerRun" FileSource="CHAINERRUN.EXE" />
The FileSource is the reference to the File element ID defined in the component
Create a C# project, reference to the file Microsoft.Deployment.WindowsInstaller.dll, or create a new WIX "C# Custom action project" then change the output to Console application EXE instead of DLL. The body of the CS file should contain the Main function
ChainerRun.CS
namespace ChainerRun
{
public class CustomActions
{
static void Main(string[] args)
{
System.Diagnostics.Debugger.Launch();
try
{
IntPtr ptr = new IntPtr(Convert.ToInt32(args[0], 16));
//ptr = System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(args[0]);
Transaction transaction = Transaction.FromHandle(ptr, true);
transaction.Join(TransactionAttributes.JoinExistingEmbeddedUI);
// Installer.InstallProduct(#"c:\MyOtherApp.msi", argline);
transaction.Commit();
transaction.Close();
}
catch (Exception e)
{
throw e;
}
}
[CustomAction]
public static ActionResult CustomAction1(Session session)
{
System.Diagnostics.Debugger.Launch();
session.Log("My CustomAction1() begins ...");
}
}
There is a bug in the c# code below: In the line "IntPtr ptr = new IntPtr(Convert.ToInt32(args[0], 16));" the "16" must be a "10"!
Otherwise you will get "bad handle" errors when there are more than 10 transactions (e.g. when there are five or more sub msi's called from the embedded chainer).
The approach to embed the JRE as a package in a multi package transaction is an overkill which unnecessarily complicates maintenance.
There are two reasonable solutions with low maintenance.
Use burn and install the JRE as a separate package in the bundle. Advantage of being able to use a prepared installation such as the ones from Oracle.
The JRE by design is self versioned and requires no registrations or special handling, given that it may be best to include the jre in the main application MSI. This is a practice that I've seen in many professional java-based applications and has the added advantage of easily creating application shortcuts by referencing java.exe directly.
Related
I'm developing a Visual Studio extension. The extension's associated VS project template includes a call to a custom task in the extension's DLL:
<UsingTask TaskName="MyTask" AssemblyFile="path to MyDLL.dll" />
The extension will be installed in the usual place, through use of the VSIX installer.
My question is: Is there a good MSBuild property or macro that I can use to construct the path to the extension's DLL (i.e., MyDLL.dll)? I'm aware of $(DevEnvDir) and could extend that path when using the project and extension in Visual Studio 2015 (append \VendorName\ProductName\Version), but that doesn't seem to work in VS 2017, where the appended path uses a mangled name that can't be predicted ahead of time (or can it?). There's also the issue that the project/extension should work in the VS experimental instance, which does not appear to reflect $(DevEnvDir).
Is there any good way to do this with MSBuild properties, or will I need to look at alternatives like environment variables or the registry?
Is there any good way to do this with MSBuild properties, or will I need to look at alternatives like environment variables or the registry?
You can use environment variables or the registry to achieve it.
environment variables
you could use environment variables like this:
<UsingTask TaskName="MyTask" AssemblyFile="$(yourenvironmentvariablesname)MyDLL.dll" />
For more information, please refer to:
https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-environment-variables-in-a-build
registry
You could use registry like this:
<UsingTask TaskName="MyTask" AssemblyFile="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework#DbgManagedDebugger)MyDLL.dll" />
Note: please change related registry path as you want.
https://blogs.msdn.microsoft.com/msbuild/2007/05/04/new-registry-syntax-in-msbuild-v3-5/
The solution that made sense for me was to create a wizard and to set the path to the extension install location in the replacements dictionary and use the replacement in the template with the UsingTask.
public class ProjectLocationWizard : IWizard
{
public void BeforeOpeningFile(ProjectItem projectItem)
{
}
public void ProjectFinishedGenerating(Project project)
{
}
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
}
public void RunFinished()
{
}
public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
var wizardDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
replacementsDictionary.Add("$installlocation$", wizardDirectory);
}
public bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
<UsingTask AssemblyFile="$installlocation$\MyTask.dll" TaskName="MyTask" />
Although the wizard docs say to sign the wizard assembly, I did not, and it works fine without.
I need to create a symbolic-link for a particular folder; that folder is created by a WIX installer. Is there any way to create a symbolic-link from WIX installer? I have read about mklink, but I do not know how to use that in WIX (v3)?
You can use Custom actions to run the mklink. Run the custom actions after InstallFinalize.
Or you can use Short cut instead of symbolic links.
In Custom Action file:
[CustomAction]
public static ActionResult symboliclink(Session session)
{
string filePath = session["FilePath"];
string symboliclink = session["symboliclink"];
Process p = new Process();
p.StartInfo.FileName = "mklink.exe";
p.StartInfo.Arguments = "/d" + symboliclink + " " + filePath;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Environment.CurrentDirectory = Path.GetDirectoryName(p.StartInfo.FileName);
p.Start();
p.WaitForExit();
return ActionResult.Success;
}
Wix File:
<Binary Id="Symboliclink" SourceFile="Symboliclink.CA.dll" /> <CustomAction Id="SymbolicLink" BinaryKey="Symboliclink" DllEntry="symboliclink" Return="ignore" Execute="immediate" />
Include the Custom Action in InstallExecuteSequence
<Custom Action="SymbolicLink" Sequence="6703"/>
I had crated a link by using Shortcut keyword. And I found it is the easiest way to resolve this. Please find this code.
<Component Id="XXXX" Guid="E4920A35-13E1-4949-BD3A-7DCC8A70C647">
<File Id="xxXX" Name="xxXX.yyy" Source="..\Installer\Miscellaneous\xxXX.yyy" DiskId="1" Vital="yes" />
<Shortcut Id="xxXX_link" Directory="Dir1" Name="xxXX.yyy" Target="[INSTALLLOCATION]xxXX.yyy" WorkingDirectory="INSTALLLOCATION" />
</Component>
But this is not equivalent to symbolic link.
I'm creating a site definition with a web-scoped feature that creates a subsite on the current site. I want to activate this feature on the site when an user creates a site based on that definition.
The feature works normally when I activate it, the problem is that I get the following error when I try to create a site based on the definition:
Feature with Id 'Id' is not installed in this farm and cannot be added to this scope.
I tried to change the scope to Farm, but it gets me the error "Error occurred in deployment step 'Add Solution': Unable to cast object of type 'Microsoft.SharePoint.Administration.SPWebService' to type 'Microsoft.SharePoint.SPWeb'", also, I guess it doesn't make sense to have this feature farm-scoped.
My site definition 'web features' node contains:
<WebFeatures>
<Feature ID="6e512cb1-1a3f-43d6-a756-55c1a9eadd2c" />
</WebFeatures>
My Feature Receiver method is:
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
if (!web.Webs["subsite1"].Exists)
{
web.Webs.Add("subsite1");
web.Update();
}
}
Please let me know if anyone needs more information.
Open the Feature designer and select Scope: WebApplication
<SiteFeatures>
<Feature ID="C85E5759-F323-4EFB-B548-443D2216EFB5" />
<Feature ID="A392DA98-270B-4e85-9769-04C0FDE267AA" />
<Feature ID="7C637B23-06C4-472d-9A9A-7C175762C5C4" />
</SiteFeatures>
<WebFeatures>
<Feature ID="00BFEA71-DE22-43B2-A848-C05709900100" />
<Feature ID="00BFEA71-E717-4E80-AA17-D0C71B360101" />
</WebFeatures>
<Modules>
<Module Name="Home" />
</Modules>
We have a few MSI packages (generated by WIX) that install WCF services. Most of these services need net.tcp for their endpoint bindings.
I'd like to make our deployment life easier and automate the process of adding net.tcp.
I already know the WixIisExtension.dll and make use of its useful functions (create web site, virt. directory, etc.).
Can I use the WixIisExtension to enable the net.tcp protocol?
If not, how can I achieve that?
Add a new Project to your Setup Solution (Windows Installer XML -> C# Custom Action Project)
In this Project add a reference to the Assembly Microsoft.Web.Administration, which can be found here: C:\Windows\System32\inetsrv and is required to add the protocols.
My Custom Action looks like this:
using System;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Web.Administration;
namespace Setup.CustomAction.EnableProtocols
{
public class CustomActions
{
[CustomAction]
public static ActionResult EnableProtocols(Session session)
{
session.Log("Begin EnableProtocols");
var siteName = session["SITE"];
if (string.IsNullOrEmpty(siteName))
{
session.Log("Property [SITE] missing");
return ActionResult.NotExecuted;
}
var alias = session["VIRTUALDIRECTORYALIAS"];
if (string.IsNullOrEmpty(alias))
{
session.Log("Property [VIRTUALDIRECTORYALIAS] missing");
return ActionResult.NotExecuted;
}
var protocols = session["PROTOCOLS"];
if (string.IsNullOrEmpty(protocols))
{
session.Log("Property [PROTOCOLS] missing");
return ActionResult.NotExecuted;
}
try
{
var manager = new ServerManager();
var site = manager.Sites.FirstOrDefault(x => x.Name.ToUpper() == siteName.ToUpper());
if (site == null)
{
session.Log("Site with name {0} not found", siteName);
return ActionResult.NotExecuted;
}
var application = site.Applications.FirstOrDefault(x => x.Path.ToUpper().Contains(alias.ToUpper()));
if (application == null)
{
session.Log("Application with path containing {0} not found", alias);
return ActionResult.NotExecuted;
}
application.EnabledProtocols = protocols;
manager.CommitChanges();
return ActionResult.Success;
}
catch (Exception exception)
{
session.Log("Error setting enabled protocols: {0}", exception.ToString());
return ActionResult.Failure;
}
}
}
}
Please note that I am assuming three properties here: SITE, VIRTUALDIRECTORYALIAS & PROTOCOLS
Build the solution now. In the background, WiX creates two assemblies %Project%.dll and %Project%.CA.dll. The CA.dll includes the depending Microsoft.Web.Administration automatically.
Then in your WiX Setup Project include a reference to the new Custom Action Project. The reference is required for referencing the %Projet%.CA.dll.
Edit the product.wxs
First add the properties somewhere inside the product element:
<!-- Properties -->
<Property Id="SITE" Value="MySite" />
<Property Id="VIRTUALDIRECTORYALIAS" Value="MyVirtDirectoryAlias" />
<Property Id="PROTOCOLS" Value="http,net.tcp" />
Below add the binary element:
<!-- Binaries -->
<Binary Id="CustomAction.EnableProtocols" SourceFile="$(var.Setup.CustomAction.EnableProtocols.TargetDir)Setup.CustomAction.EnableProtocols.CA.dll" />
Note that you have to add the CA.dll.
Below add the Custom Action:
<!-- Custom Actions -->
<CustomAction Id="EnableProtocols" BinaryKey="CustomAction.EnableProtocols" DllEntry="EnableProtocols" Execute="immediate" Return="check" />
And finally the Installation Sequence where you want the execution to take place.
<!-- Installation Sequence -->
<InstallExecuteSequence>
<Custom Action="EnableProtocols" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
that's all. Should work.
Thanks to Darin Dimitrov for providing the links above.
Here is the right way to do this in WIX (assuming you are installing on a 64-bit operating system - if not at a guess I'd say change CAQuietExec64 to CAQuietExec although this is untested):
Get a reference to appcmd.exe:
<Property Id="APPCMD">
<DirectorySearch Id="FindAppCmd" Depth="1" Path="[WindowsFolder]\system32\inetsrv\">
<FileSearch Name="appcmd.exe"/>
</DirectorySearch>
</Property>
Define the following custom actions (the properties [WEB_SITE_NAME] and [WEB_APP_NAME] can be populated elsewhere in your installer; or to test you can hard-code them):
<CustomAction
Id="SetEnableNetTCPCommmand"
Property="EnableNetTCP"
Value=""[APPCMD]" set app "[WEB_SITE_NAME]/[WEB_APP_NAME]" /enabledProtocols:http,net.tcp"/>
<CustomAction
Id="EnableNetTCP"
BinaryKey="WixCA"
DllEntry="CAQuietExec64"
Execute="deferred"
Return="ignore"
Impersonate="no" />
Now in the InstallExecuteSequence add
<InstallExecuteSequence>
...
<Custom Action="SetEnableNetTCPCommmand" After="InstallExecute">APPCMD AND NOT Installed</Custom>
<Custom Action="EnableNetTCP" After="SetEnableNetTCPCommmand">APPCMD AND NOT Installed</Custom>
...
</InstallExecuteSequence>
And if all is well in the world that will now update the protocols.
You may take a look at this article on MSDN. There's a section at the end which illustrates how to use the managed API to achieve configure a WAS enabled service. I am not familiar with Wix but you could probably use and plug this code into some custom deployment step.
This can't be done using the standard WiXIIsExtension, as far as I know. Thus, the only option you have is a custom action.
You can also find this thread interesting - it gives a hint how to achieve the similar thing in MSBuild script, but you should be able to translate it to custom action easily.
Good luck!
Is there a way to automatically increment the "minimum required version" fields in a ClickOnce deployment to always equal the current build number? Basically, I always want my deployment to be automatically updated at launch.
I suspect I'm going to need a some pre-/post-build events, but I hope there's an easier way.
I may be a little late with answering this one but I found it difficult to find the solution on google but eventually figured it out so thought I would share.
With MSBuild version 4 (VS2010 and VS2012) this can be achieved by inserting the following target:
<Target Name="AutoSetMinimumRequiredVersion" BeforeTargets="GenerateDeploymentManifest">
<FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
<Output PropertyName="MinimumRequiredVersion" TaskParameter="OutputVersion" />
</FormatVersion>
<FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
<Output PropertyName="_DeploymentBuiltMinimumRequiredVersion" TaskParameter="OutputVersion" />
</FormatVersion>
</Target>
The $(ApplicationVersion) is the same setting that you can set manually in the project's Publish window in the VS IDE, with the revision part set to an asterisk. The $(ApplicationRevision) is the actual revision being used for the published version. The FormatVersion task is a built-in MSBuild task that formats the two into a single full version number.
This will set the 'Minimum Required Version' to be the same as the 'Publish Version' therefore ensuring that the new deployment will always be installed by users, ie no option to Skip the update.
Of course, if you don't want to set the minimum required version to the publish version and want to use a different source property then it is straight-forward to amend the target, but the principle is the same.
I ended up actually rolling an AddIn to VS that synchronizes all the version numbers, and then builds and publishes with a single click. It was pretty easy.
Public Sub Publish()
Try
Dim startProjName As String = Nothing
Dim targetProj As Project = Nothing
Dim soln As Solution2 = TryCast(Me._applicationObject.DTE.Solution, Solution2)
If soln IsNot Nothing Then
For Each prop As [Property] In soln.Properties
If prop.Name = "StartupProject" Then
startProjName = prop.Value.ToString()
Exit For
End If
Next
If startProjName IsNot Nothing Then
For Each proj As Project In soln.Projects
If proj.Name = startProjName Then
targetProj = proj
Exit For
End If
Next
If targetProj IsNot Nothing Then
Dim currAssemVersionString As String = targetProj.Properties.Item("AssemblyVersion").Value.ToString
Dim currAssemVer As New Version(currAssemVersionString)
Dim newAssemVer As New Version(currAssemVer.Major, currAssemVer.Minor, currAssemVer.Build, currAssemVer.Revision + 1)
targetProj.Properties.Item("AssemblyVersion").Value = newAssemVer.ToString()
targetProj.Properties.Item("AssemblyFileVersion").Value = newAssemVer.ToString()
Dim publishProps As Properties = TryCast(targetProj.Properties.Item("Publish").Value, Properties)
Dim shouldPublish As Boolean = False
If publishProps IsNot Nothing Then
shouldPublish = CBool(publishProps.Item("Install").Value)
If shouldPublish Then
targetProj.Properties.Item("GenerateManifests").Value = "true"
publishProps.Item("ApplicationVersion").Value = newAssemVer.ToString()
publishProps.Item("MinimumRequiredVersion").Value = newAssemVer.ToString()
publishProps.Item("ApplicationRevision").Value = newAssemVer.Revision.ToString()
End If
End If
targetProj.Save()
Dim build As SolutionBuild2 = TryCast(soln.SolutionBuild, SolutionBuild2)
If build IsNot Nothing Then
build.Clean(True)
build.Build(True)
If shouldPublish Then
If build.LastBuildInfo = 0 Then
build.Publish(True)
End If
End If
End If
End If
End If
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Out of the box, I don't belive there is a way. It's not too much effort to spin your own however.
The approach I use is as follows:
1) create a Version.Properties file
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Util-VersionMajor>1</Util-VersionMajor>
<Util-VersionMinor>11</Util-VersionMinor>
<Util-VersionBuild>25</Util-VersionBuild>
<Util-VersionRevision>0</Util-VersionRevision>
<Util-VersionDots>$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)</Util-VersionDots>
<Util-VersionUnders>$(Util-VersionMajor)_$(Util-VersionMinor)_$(Util-VersionBuild)_$(Util-VersionRevision)</Util-VersionUnders>
<MinimumRequiredVersion>$(Util-VersionDots)</MinimumRequiredVersion>
<ApplicationVersion>$(Util-VersionDots)</ApplicationVersion>
<ApplicationRevision>$(Util-VersionRevision)</ApplicationRevision>
</PropertyGroup>
</Project>
2) Import the Version.Properties file into your project files
3) Create a task to increment the version on Build. Here's mine
<Target Name="IncrementVersion" DependsOnTargets="Build" Condition="'$(BuildingInsideVisualStudio)'==''">
<ItemGroup>
<Util-VersionProjectFileItem Include="$(Util-VersionProjectFile)" />
</ItemGroup>
<PropertyGroup>
<Util-VersionProjectFileFullPath>#(Util-VersionProjectFileItem->'%(FullPath)')</Util-VersionProjectFileFullPath>
</PropertyGroup>
<Exec Command=""$(TfCommand)" get /overwrite /force /noprompt "$(Util-VersionProjectFileFullPath)"" Outputs="" />
<Exec Command=""$(TfCommand)" checkout /lock:checkout "$(Util-VersionProjectFileFullPath)"" Outputs="" />
<Version Major="$(Util-VersionMajor)" Minor="$(Util-VersionMinor)" Build="$(Util-VersionBuild)" Revision="$(Util-VersionRevision)" RevisionType="None" BuildType="Increment">
<Output TaskParameter="Major" PropertyName="Util-VersionMajor" />
<Output TaskParameter="Minor" PropertyName="Util-VersionMinor" />
<Output TaskParameter="Build" PropertyName="Util-VersionBuild" />
<Output TaskParameter="Revision" PropertyName="Util-VersionRevision" />
</Version>
<XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionMajor" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionMajor)" />
<XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionMinor" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionMinor)" />
<XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionBuild" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionBuild)" />
<XmlUpdate Prefix="msb" Namespace="http://schemas.microsoft.com/developer/msbuild/2003" XPath="/msb:Project/msb:PropertyGroup/msb:Util-VersionRevision" XmlFileName="$(Util-VersionProjectFile)" Value="$(Util-VersionRevision)" />
<Exec Command=""$(TfCommand)" checkin /override:AutoBuildIncrement /comment:***NO_CI*** "$(Util-VersionProjectFileFullPath)"" />
<Exec Command=""$(TfCommand)" get /overwrite /force /noprompt "$(Util-AssemblyInfoFile)"" Outputs="" />
<Exec Command=""$(TfCommand)" checkout /lock:checkout "$(Util-AssemblyInfoFile)"" Outputs="" />
<AssemblyInfo CodeLanguage="CS" OutputFile="$(Util-AssemblyInfoFile)" AssemblyConfiguration="$(Configuration)" AssemblyVersion="$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)" AssemblyFileVersion="$(Util-VersionMajor).$(Util-VersionMinor).$(Util-VersionBuild).$(Util-VersionRevision)" />
<Exec Command=""$(TfCommand)" checkin /override:AutoBuildIncrement /comment:***NO_CI*** "$(Util-AssemblyInfoFile)"" />
</Target>
Some additional clickonce tricks here http://weblogs.asp.net/sweinstein/archive/2008/08/24/top-5-secrets-of-net-desktop-deployment-wizards.aspx
Here's how I handled this one. First I created a custom task that wraps string replacement:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
namespace SynchBuild
{
public class RemoveAsterisk : Task
{
private string myVersion;
[Required]
public string Version
{
set{myVersion = value;}
}
[Output]
public string ReturnValue
{
get { return myVersion.Replace("*", ""); }
}
public override bool Execute()
{
return true;
}
}
}
So that gets built into SynchBuild.dll which you see referenced in the UsingTask below. Now I tried just overwritting the MinimumRequiredVersion property, but it didn't seem to get picked up, so I just overwrote the GenerateApplicationManifest target by adding the following lines to the end of my csproj file:
<UsingTask AssemblyFile="$(MSBuildExtensionsPath)\WegmansBuildTasks\SynchBuild.dll" TaskName="SynchBuild.RemoveAsterisk" />
<Target Name="GenerateDeploymentManifest" DependsOnTargets="GenerateApplicationManifest" Inputs="
$(MSBuildAllProjects);
#(ApplicationManifest)
" Outputs="#(DeployManifest)">
<RemoveAsterisk Version="$(ApplicationVersion)$(ApplicationRevision)">
<Output TaskParameter="ReturnValue" PropertyName="MinimumRequiredVersion" />
</RemoveAsterisk>
<GenerateDeploymentManifest MinimumRequiredVersion="$(MinimumRequiredVersion)" AssemblyName="$(_DeploymentDeployManifestIdentity)" AssemblyVersion="$(_DeploymentManifestVersion)" CreateDesktopShortcut="$(CreateDesktopShortcut)" DeploymentUrl="$(_DeploymentFormattedDeploymentUrl)" Description="$(Description)" DisallowUrlActivation="$(DisallowUrlActivation)" EntryPoint="#(_DeploymentResolvedDeploymentManifestEntryPoint)" ErrorReportUrl="$(_DeploymentFormattedErrorReportUrl)" Install="$(Install)" MapFileExtensions="$(MapFileExtensions)" MaxTargetPath="$(MaxTargetPath)" OutputManifest="#(DeployManifest)" Platform="$(PlatformTarget)" Product="$(ProductName)" Publisher="$(PublisherName)" SuiteName="$(SuiteName)" SupportUrl="$(_DeploymentFormattedSupportUrl)" TargetCulture="$(TargetCulture)" TargetFrameworkVersion="$(TargetFrameworkVersion)" TrustUrlParameters="$(TrustUrlParameters)" UpdateEnabled="$(UpdateEnabled)" UpdateInterval="$(_DeploymentBuiltUpdateInterval)" UpdateMode="$(UpdateMode)" UpdateUnit="$(_DeploymentBuiltUpdateIntervalUnits)" Condition="'$(GenerateClickOnceManifests)'=='true'">
<Output TaskParameter="OutputManifest" ItemName="FileWrites" />
</GenerateDeploymentManifest>
</Target>
The end result is we take the app version and revision, combine them, remove the asterisk, then set the minimum required version. I have the auto increment app version in my publish properties set so that's how incrementing takes place, then I'm just setting the minimumrequiredversion to always match.I don't use team build, this is just designed so that a developer using visual studio can make all clickonce deployments required. Hope this helps.
If you are publishing your ClickOnce application from Visual Studio then just install the AutoUpdateProjectsMinimumRequiredClickOnceVersion NuGet Package in your project and you're good to go.
If you are publishing from a build server or other script, then you can use the Set-ProjectFilesClickOnceVersion PowerShell script. My blog describes in more detail how to setup your build server to accommodate publishing ClickOnce applications.
Are you looking for Application Updates?
Right clicking on the project in the Solution Explorer and then clicking Publish... is the wrong way to get Application Updates. You have to right-click your project and the click Properties, then click the Publish tab. Click the Updates... button and then check the "The application should check for updates" check box. There you can also specify a minimum required version for the application. (I haven't used that functionality but the Updates functionality is the core reason I use ClickOnce and it works great.)