Hi all,
I want to share a downloader&installer code that I used with LMI Tasks.
Program is a Non-Interactive File Downloader & Installer tool in .NET C# works on Windows systems.
This program is calling by a LogMeIn One2Many Task like this:
Batch Type: Batch or Exe
Program : CNIPackageInstallerApp.exe
Parameters : -of cnioutput.xml -dl ftp:!!user:pass@ftp.mydownloadserver.com!public!mypackage!MyProgramSetup.Ver1.3.exe,c:#lmidownloads#_MYPROGRAM.EXE -il c:#lmidownloads#_MYPROGRAMSETUP.EXE,!silent
This code is so useful for LMI Tasks. It works as Non-Interactive. All inputs are given from commandline and it writes operation output into given output xml file. If operation success program returns 0 as exitcode, and other if fails.
I use this code to deploy & update/install my products to our customers.
Program doesn't need an user interaction and GUI system.
Works fine on Windows XP and later that installed MS .NET Framework 4.0.
Code can be developed for other languages like Java, C++ ... etc and other systems.
Here is program codes (2 class):
Kernel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Text;
using System.Reflection;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Diagnostics;
using System.Threading;
public static class Kernel {
public const char
Delim_ArgSeperator = ';'
, Delim_SubArgSeperator = ',';
public const string
ResultSection_Download = "Download"
, ResultSection_Install = "Install";
public static string[] startupArgs;
static bool runStatus;
static Exception lastError;
static TimeSpan beginTime, endTime;
static CDict<string, CDict<string, string>> section2OutputDict;
static FileInfo outputFile;
static List<KeyValuePair<string, string>> downloadURLsAndTargets, installFilesAndArguments;
#region Kernel Startup
/// <summary>The main entry point for the application</summary>
[STAThread]
static int Main( string[] args ) {
int exitCode;
try { Application.EnableVisualStyles(); } catch { }
try { Application.SetCompatibleTextRenderingDefault( false ); } catch { }
startupArgs = new string[0];
if (args != null && args.Length > 1) {
startupArgs = new string[args.Length];
for (var i = 0; i < startupArgs.Length; i++)
startupArgs[i] = args[i].Replace( '!', '/' ).Replace( '#', '\\' ).Replace( '?', ' ' );
//startupArgs = new string[args.Length - 1];
//Array.Copy( args, 1, startupArgs, 0, startupArgs.Length );
}
initializeGlobals();
beginTime = DateTime.Now.TimeOfDay;
try { exitCode = run( args ); }
catch (Exception ex) { exitCode = handleFatalError( ex ); }
endTime = DateTime.Now.TimeOfDay;
dumpOutput();
return exitCode;
}
public static int run( string[] args ) {
loadConfig();
initializeStartup();
if (downloadURLsAndTargets.Count > 0)
downloadFiles();
if (installFilesAndArguments.Count > 0)
installFiles();
return ( runStatus ? 0 : 2 );
}
#endregion
#region Islem
static void downloadFiles() {
const int
BufferSize = 1024 * 256
, MaxTryCount = 3
, ErrorWaitTimeMS = 1500;
foreach (var kv in downloadURLsAndTargets) {
int tryCount = -1;
string url;
FileInfo targetFile;
WebRequest req = null;
Stream webSrm = null, fileSrm = null;
WebResponse resp = null;
byte[] buffer = null;
int bytes;
redownload:
tryCount++;
url = kv.Key;
targetFile = new FileInfo( kv.Value );
try { req = WebRequest.Create( url ); }
catch (Exception ex) {
try { req.Abort(); } catch { }
if (tryCount < MaxTryCount) {
Thread.Sleep( ErrorWaitTimeMS );
goto redownload;
}
runStatus = false;
outputDownloadResult( url, "connect_fail " + ex.Message );
continue;
}
try {
if (req is FtpWebRequest) {
( (FtpWebRequest)req ).Method = WebRequestMethods.Ftp.DownloadFile;
( (FtpWebRequest)req ).UsePassive = true;
( (FtpWebRequest)req ).UseBinary = true;
}
else if (req is HttpWebRequest) {
( (HttpWebRequest)req ).Method = WebRequestMethods.Http.Get;
}
else {
try { req.Abort(); } catch { }
if (tryCount < MaxTryCount) {
Thread.Sleep( ErrorWaitTimeMS );
goto redownload;
}
runStatus = false;
outputDownloadResult( url, "invalid_protocol" );
continue;
}
try {
resp = req.GetResponse();
webSrm = resp.GetResponseStream();
}
catch (Exception ex) {
try { req.Abort(); } catch { }
if (tryCount < MaxTryCount) {
Thread.Sleep( ErrorWaitTimeMS );
goto redownload;
}
runStatus = false;
outputDownloadResult( url, "response_read_error " + ex.Message );
continue;
}
if (!targetFile.Directory.Exists) {
targetFile.Directory.Create();
targetFile.Refresh();
}
fileSrm = targetFile.Open( FileMode.Create, FileAccess.ReadWrite, FileShare.Read );
buffer = new byte[BufferSize];
try {
while (( bytes = webSrm.Read( buffer, 0, buffer.Length ) ) > 0)
fileSrm.Write( buffer, 0, bytes );
}
catch (Exception ex) {
try { req.Abort(); } catch { }
if (fileSrm != null)
fileSrm.Close();
targetFile.Refresh();
if (targetFile.Exists) {
targetFile.Delete();
targetFile.Refresh();
}
//if (ex is WebException && ( (WebException)ex ).Status == WebExceptionStatus.UnknownError) {
if (tryCount < MaxTryCount) {
Thread.Sleep( ErrorWaitTimeMS );
goto redownload;
}
runStatus = false;
outputDownloadResult( url, "download_error " + ex.Message );
continue;
}
outputDownloadResult( url, "success" );
}
finally {
if (buffer != null) {
Array.Resize( ref buffer, 1 );
buffer = null;
}
if (fileSrm != null)
fileSrm.Close();
if (webSrm != null)
webSrm.Close();
if (resp != null)
resp.Close();
if (req != null) {
try { req.Abort(); } catch { }
}
}
}
}
static void installFiles() {
foreach (var kv in installFilesAndArguments) {
FileInfo file;
string args;
ProcessStartInfo psi;
Process pr;
file = new FileInfo( kv.Key );
args = kv.Value;
if (!file.Exists) {
runStatus = false;
outputInstallResult( file.FullName, "file_notfound" );
continue;
}
psi = new ProcessStartInfo( file.FullName, args );
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
if (( pr = Process.Start( psi ) ) == null) {
runStatus = false;
outputInstallResult( file.FullName, "processstart_failed" );
continue;
}
pr.WaitForExit();
outputInstallResult( file.FullName, "success_exitcode " + pr.ExitCode.ToString() );
}
}
#endregion
#region Error Handler
public static int handleFatalError( Exception ex ) {
setLastError( ex );
return 99;
}
#endregion
#region Std I/O
static void dumpOutput() {
StringBuilder sb;
string outputData;
FileStream srm;
sb = new StringBuilder();
writeXMLOutputDataTo( new StringWriter( sb ) );
outputData = sb.ToString();
if (runStatus)
Console.Out.Write( outputData );
else
Console.Error.Write( outputData );
if (outputFile != null) {
if (outputFile.Exists) {
outputFile.Delete();
outputFile.Refresh();
}
File.WriteAllText( outputFile.FullName, outputData, Encoding.Default );
}
}
static void writeXMLOutputDataTo( TextWriter sw ) {
Exception currentError;
currentError = lastError;
if (currentError != null && currentError.InnerException != null)
currentError = currentError.InnerException;
sw.WriteLine( string.Format( @"<?xml version=""1.0"" encoding=""{0}"" ?>", Encoding.Default.BodyName ) );
sw.WriteLine( @"<RunResult>" );
sw.WriteLine( string.Format( @" <RunStatus>{0}</RunStatus>", runStatus ? "success" : "fail" ) );
sw.WriteLine( @" <SystemInfo>" );
sw.WriteLine( string.Format( @" <MachineName>{0}</MachineName>", Environment.MachineName ) );
sw.WriteLine( string.Format( @" <DomainName>{0}</DomainName>", Environment.UserDomainName ) );
sw.WriteLine( string.Format( @" <UserName>{0}</UserName>", Environment.UserName ) );
sw.WriteLine( string.Format( @" <IsInteractiveMode>{0}</IsInteractiveMode>", Environment.UserInteractive.ToString() ) );
sw.WriteLine( string.Format( @" <OSBits>{0}</OSBits>", ( Environment.Is64BitOperatingSystem ? "x64" : "x86" ) ) );
sw.WriteLine( string.Format( @" <ProcessorBits>{0}</ProcessorBits>", ( Environment.Is64BitProcess ? "x64" : "x86" ) ) );
sw.WriteLine( string.Format( @" <ProcessorCount>{0}</ProcessorCount>", Environment.ProcessorCount.ToString() ) );
sw.WriteLine( string.Format( @" <ProcessCommandLine>{0}</ProcessCommandLine>", Environment.CommandLine ) );
sw.WriteLine( @" </SystemInfo>" );
sw.WriteLine( @" <Duration>" );
sw.WriteLine( string.Format( @" <BeginTime>{0}</BeginTime>", beginTime.ToString() ) );
sw.WriteLine( string.Format( @" <EndTime>{0}</EndTime>", endTime.ToString() ) );
sw.WriteLine( string.Format( @" <TotalSeconds>{0}</TotalSeconds>", ( endTime - beginTime ).ToString() ) );
sw.WriteLine( @" </Duration>" );
if (lastError == null)
sw.WriteLine( @" <LastError />" );
else {
sw.WriteLine( @" <LastError>" );
sw.WriteLine( string.Format( @" <Class>{0}</Class>", currentError.GetType().Name ) );
sw.WriteLine( string.Format( @" <Message>{0}</Message>", currentError.Message ) );
if (currentError is WebException)
sw.WriteLine( string.Format( @" <Status>{0}</Status>", ( (WebException)currentError ).Status.ToString() ) );
else if (currentError is SocketException)
sw.WriteLine( string.Format( @" <Status>{0}</Status>", ( (SocketException)currentError ).SocketErrorCode.ToString() ) );
else
sw.WriteLine( @" <Status />" );
sw.WriteLine( string.Format( @" <StackTrace>{0}</StackTrace>", currentError.StackTrace ) );
sw.WriteLine( @" </LastError>" );
}
sw.WriteLine( @" <Outputs>" );
primitiveWriteXMLOutputStringResult( sw, ResultSection_Download );
primitiveWriteXMLOutputStringResult( sw, ResultSection_Install );
sw.WriteLine( @" </Outputs>" );
sw.WriteLine( @"</RunResult>" );
sw.Flush();
}
static void outputDownloadResult( string key, string value ) {
primitiveOutputSuccessResult( ResultSection_Download, key, value );
}
static void outputInstallResult( string key, string value ) {
primitiveOutputSuccessResult( ResultSection_Install, key, value );
}
static void setLastError( Exception ex ) {
runStatus = false;
lastError = ex;
}
static void primitiveWriteXMLOutputStringResult( TextWriter sw, string section ) {
if (!section2OutputDict.ContainsKey( section ) || section2OutputDict[section].IsEmpty)
sw.WriteLine( string.Format( @" <{0} />", section ) );
else {
sw.WriteLine( string.Format( @" <{0}>", section ) );
foreach (var kv in section2OutputDict[section])
sw.WriteLine( string.Format( @" <item ref=""{0}"">{1}</item>", kv.Key, kv.Value ) );
sw.WriteLine( string.Format( @" </{0}>", section ) );
}
}
static void primitiveOutputSuccessResult( string section, string key, string value ) {
section2OutputDict[section][key] = value;
}
#endregion
#region Initialize
static void initializeGlobals() {
runStatus = true;
lastError = null;
section2OutputDict = new CDict<string, CDict<string, string>>();
foreach (var attr in new[] { ResultSection_Download, ResultSection_Install })
section2OutputDict[attr] = new CDict<string, string>();
}
static void loadConfig() {
string temp;
outputFile = null;
//downloadMode = "";
downloadURLsAndTargets = new List<KeyValuePair<string, string>>();
installFilesAndArguments = new List<KeyValuePair<string, string>>();
//if (( temp = scanArgValue( "-dm" ) ) != null) {
// if (new[] { "", DownloadMode_FTP, DownloadMode_HTTP }.Contains( temp ))
// downloadMode = temp;
// else
// throw new ArgumentOutOfRangeException( temp ?? "", "invalidstartuparg -dm" );
//}
if (( temp = scanArgValue( "-of" ) ) != null) {
outputFile = new FileInfo( temp );
}
if (( temp = scanArgValue( "-dl" ) ) != null) {
string[] parts, subParts;
downloadURLsAndTargets = new List<KeyValuePair<string, string>>();
parts = temp.Split( new char[] { Delim_ArgSeperator }, StringSplitOptions.RemoveEmptyEntries );
foreach (var part in parts) {
if (string.IsNullOrWhiteSpace( part ))
continue;
subParts = part.Split( new char[] { Delim_SubArgSeperator }, 2 );
downloadURLsAndTargets.Add( new KeyValuePair<string, string>(
subParts[0], ( subParts.Length > 1 ? subParts[1] : "" ) ) );
}
}
if (( temp = scanArgValue( "-il" ) ) != null) {
string[] parts, subParts;
installFilesAndArguments = new List<KeyValuePair<string, string>>();
parts = temp.Split( new char[] { Delim_ArgSeperator }, StringSplitOptions.RemoveEmptyEntries );
foreach (var part in parts) {
if (string.IsNullOrWhiteSpace( part ))
continue;
subParts = part.Split( new char[] { Delim_SubArgSeperator }, 2 );
installFilesAndArguments.Add( new KeyValuePair<string, string>(
subParts[0], ( subParts.Length > 1 ? subParts[1] : "" ) ) );
}
}
}
static void initializeStartup() {
if (outputFile != null && !outputFile.Exists) {
if (!outputFile.Directory.Exists) {
outputFile.Directory.Create();
outputFile.Refresh();
}
}
}
#endregion
#region Yardimci
static string scanArgValue( string arg ) {
int index;
string value;
if (( index = Array.IndexOf( startupArgs, arg ) ) < 0)
return null;
return startupArgs[index + 1];
}
#endregion
}
CDict.cs
#region Using directives
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;
#endregion
/// <summary>Standard CDict yapısı</summary>
[Serializable()]
public class CDict<TKey, TValue> : Dictionary<TKey, TValue> {
#region Get/Set
[TypeConverter( typeof( ExpandableObjectConverter ) )]
public virtual TValue this[TKey key] {
get {
try { return base[key]; }
catch (KeyNotFoundException e) { throw new KeyNotFoundException( string.Format( "KeyNotFound: [{0}]", key ), e ); }
set {
if (base.ContainsKey( key ))
base[key] = value;
else
base.Add( key, value );
}
}
public virtual bool IsEmpty {
get { return this.Count == 0; }
}
#endregion
public CDict() { }
public CDict( params KeyValuePair<TKey, TValue>[] keyValueArray ) {
this.Add( keyValueArray );
}
public CDict( IEnumerable<TKey> keys, IEnumerable<TValue> values ) {
this.AddRange( keys, values );
}
public CDict( IDictionary<TKey, TValue> dict ) {
this.AddRange( dict );
}
public TValue Add( TKey key, TValue value ) {
this[key] = value;
return value;
}
public void Add( params KeyValuePair<TKey, TValue>[] keyValueArray ) {
foreach (var keyValuePair in keyValueArray)
this.Add( keyValuePair.Key, keyValuePair.Value );
}
public CDict<TKey, TValue> AddRange( IEnumerable<TKey> _keys, IEnumerable<TValue> _values ) {
var keys = new List<TKey>( _keys );
var values = new List<TValue>( _values );
if (keys != null && values != null && keys.Count == values.Count) {
for (int i = 0; i < keys.Count; i++)
this.Add(new KeyValuePair<TKey, TValue>(keys[i], values[i] ) );
}
return this;
}
public CDict<TKey, TValue> AddRange( IDictionary<TKey, TValue> dict ) {
foreach (var kv in dict)
Add( kv );
return this;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
CDict<TKey, TValue>.Enumerator dictEnum = base.GetEnumerator();
while (dictEnum.MoveNext())
yield return dictEnum.Current;
}
}