Skip to content

Instantly share code, notes, and snippets.

@tkouba
Forked from josheinstein/InstallClickOnceApp.cs
Created October 18, 2019 06:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkouba/20fe9963445b503436f44595d2266ca9 to your computer and use it in GitHub Desktop.
Save tkouba/20fe9963445b503436f44595d2266ca9 to your computer and use it in GitHub Desktop.
Install ClickOnce application programmatically (C#)
using System;
using System.Collections.Generic;
using System.Deployment.Application;
using System.Linq;
using System.Text;
using System.Threading;
namespace InstallClickOnceApp
{
/// <summary>
/// InstallClickOnceApp.exe uri | unc
/// Programmatically installs a ClickOnce application under the current user's profile without
/// launching the application. Perfect for group policy deployment or logon scripts.
/// </summary>
public static class Program
{
private static AutoResetEvent waitHandle;
private const int E_OK = 0;
private const int E_NOARGS = 1;
private const int E_INVALIDURI = 2;
private const int E_MANIFESTERROR = 3;
private const int E_REQUIREMENTS = 4;
private const int E_DOWNLOADERROR = 5;
/// <summary>
/// Main program entry point, which receives the command line arguments passed to the application, if any.
/// </summary>
/// <param name="args">The command line arguments passed to the application.</param>
public static void Main( string[] args )
{
Console.WriteLine( "Install ClickOnce Application Utility" );
Console.WriteLine( );
if ( args == null || args.Length == 0 ) {
PrintUsage( null );
Environment.Exit( E_NOARGS );
}
Uri deploymentUri;
if ( !Uri.TryCreate( args[0], UriKind.Absolute, out deploymentUri ) ) {
PrintUsage( "Invalid deployment URI: {0}", args[0] );
Environment.Exit( E_INVALIDURI );
}
waitHandle = new AutoResetEvent( false );
using ( var host = new InPlaceHostingManager( deploymentUri, false ) ) {
GetApplicationManifest( host );
AssertApplicationRequirements( host );
DownloadApplication( host );
}
Console.WriteLine( "Done" );
}
/// <summary>
/// Begins downloading the application manifest and blocks until complete.
/// </summary>
/// <remarks>
/// If an error occurs, the process will exit and the method will not return. Cheap, I know. I'm in a hurry.
/// </remarks>
/// <param name="host">The ClickOnce hosting manager.</param>
private static void GetApplicationManifest( InPlaceHostingManager host )
{
Console.WriteLine( "Retrieving application manifest." );
host.GetManifestCompleted += ( sender, e ) => {
if ( e.Error != null ) { ExitWithError( e.Error, E_MANIFESTERROR ); }
Console.WriteLine( );
Console.WriteLine( "Product: {0}", e.ProductName );
Console.WriteLine( "Log: {0}", e.LogFilePath );
Console.WriteLine( );
waitHandle.Set( );
};
host.GetManifestAsync( );
waitHandle.WaitOne( );
}
/// <summary>
/// Verifies that the computer meets the requirements of the application based on its manifest.
/// (ie. assemblies that are required to be in the GAC are already present, framework version, etc.)
/// </summary>
/// <remarks>
/// If an error occurs, the process will exit and the method will not return. Cheap, I know. I'm in a hurry.
/// </remarks>
/// <param name="host">The ClickOnce hosting manager.</param>
private static void AssertApplicationRequirements( InPlaceHostingManager host )
{
Console.WriteLine( "Verifying system requirements." );
try {
host.AssertApplicationRequirements( );
}
catch ( Exception error ) {
ExitWithError( error, E_REQUIREMENTS );
}
}
/// <summary>
/// Begins downloading the application binaries and blocks until complete.
/// </summary>
/// <remarks>
/// If an error occurs, the process will exit and the method will not return. Cheap, I know. I'm in a hurry.
/// </remarks>
/// <param name="host">The ClickOnce hosting manager.</param>
private static void DownloadApplication( InPlaceHostingManager host )
{
Console.WriteLine( "Downloading application." );
host.DownloadApplicationCompleted += ( sender, e ) => {
if ( e.Error != null ) { ExitWithError( e.Error, E_DOWNLOADERROR ); }
Console.WriteLine( "Download completed." );
waitHandle.Set( );
};
host.DownloadApplicationAsync( );
waitHandle.WaitOne( );
}
/// <summary>
/// Displays basic instructions for how to run the application as well as an optional
/// additional error message.
/// </summary>
/// <param name="message">If not null, this error message is displayed under the usage.</param>
/// <param name="args">String format placeholder values.</param>
private static void PrintUsage( string message, params object[] args )
{
Console.WriteLine( );
Console.WriteLine( "Usage: InstallClickOnceApp <url | unc>" );
Console.WriteLine( );
if ( message != null ) {
Console.WriteLine( message, args );
Console.WriteLine( );
}
}
/// <summary>
/// This method terminates the process with the specified exit code after writing the
/// exception message to the console.
/// </summary>
/// <param name="error">The error message to write.</param>
/// <param name="exitCode">The exit code to return to the OS.</param>
private static void ExitWithError( Exception error, int exitCode = 99 )
{
Console.WriteLine( "Error: {0}", error.Message );
Console.WriteLine( );
Environment.Exit( exitCode );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment