Files
mirror-processhacker/1.x/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.cs
T
wj32 7bd28e4357 moved branches, tags, trunk to 1.x branch
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2304 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2009-10-25 02:22:46 +00:00

330 lines
11 KiB
C#

/*
* Process Hacker -
* ProcessHacker Updater Download
*
* Copyright (C) 2009 wj32
* Copyright (C) 2009 dmex
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;
using ProcessHacker.Common;
using ProcessHacker.Common.Threading;
using ProcessHacker.Native;
using ProcessHacker.Native.Api;
namespace ProcessHacker
{
public partial class UpdaterDownloadWindow : Form
{
private Updater.UpdateItem _updateItem;
private WebClient _webClient;
private string _fileName;
private ThreadTask _verifyTask;
private bool _redirected = false;
public UpdaterDownloadWindow(Updater.UpdateItem updateItem)
{
InitializeComponent();
this.AddEscapeToClose();
this.SetTopMost();
_updateItem = updateItem;
}
private void UpdaterDownload_Load(object sender, EventArgs e)
{
string version;
version = _updateItem.Version.Major + "." + _updateItem.Version.Minor;
_fileName = Path.GetTempPath() + "processhacker-" + version + "-setup.exe";
labelTitle.Text = "Downloading: Process Hacker " + version;
labelReleased.Text = "Released: " + _updateItem.Date.ToString();
_webClient = new WebClient();
_webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
_webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
_webClient.Headers.Add("User-Agent", "PH/" + version + " (compatible; PH " +
version + "; PH " + version + "; .NET CLR " + Environment.Version.ToString() + ";)");
try
{
_webClient.DownloadFileAsync(new Uri(_updateItem.Url), _fileName);
}
catch (Exception ex)
{
PhUtils.ShowException("Unable to download Process Hacker", ex);
this.Close();
}
}
private void UpdaterDownloadWindow_FormClosing(object sender, FormClosingEventArgs e)
{
if (_verifyTask != null)
_verifyTask.Cancel();
if (OSVersion.HasExtendedTaskbar)
{
TaskbarLib.Windows7Taskbar.SetTaskbarProgressState(
Program.HackerWindowHandle,
TaskbarLib.Windows7Taskbar.ThumbnailProgressState.NoProgress
);
}
}
private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
// Check if the file is actually an executable file.
if (!_redirected)
{
_redirected = true;
try
{
bool isHtml = false;
using (var file = new BinaryReader(File.OpenRead(_fileName)))
{
if (!file.ReadChars(2).Equals("MZ".ToCharArray()))
{
isHtml = true;
}
}
if (isHtml)
{
string text = File.ReadAllText(_fileName);
// Assume this is from Ohloh.
int iframeIndex = text.IndexOf("window.delayed_iframe");
if (iframeIndex == -1)
return;
int httpIndex = text.IndexOf("http://", iframeIndex);
if (httpIndex == -1)
return;
int quoteIndex = text.IndexOf("'", httpIndex);
if (quoteIndex == -1)
return;
_webClient.DownloadFileAsync(new Uri(text.Substring(httpIndex, quoteIndex - httpIndex)), _fileName);
return;
}
}
catch (Exception ex)
{
Logging.Log(ex);
}
}
if (!e.Cancelled)
{
_verifyTask = new ThreadTask();
_verifyTask.RunTask += verifyTask_RunTask;
_verifyTask.Completed += verifyTask_Completed;
_verifyTask.Start();
}
else
{
var webException = e.Error as WebException;
if (webException != null && webException.Status != WebExceptionStatus.RequestCanceled)
{
PhUtils.ShowException("Unable to download the update", webException);
}
}
}
private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
labelProgress.Text =
"Downloaded " +
Utils.FormatSize(e.BytesReceived) + "/" +
Utils.FormatSize(e.TotalBytesToReceive) +
" (" + e.ProgressPercentage.ToString() + "%)";
progressDownload.Value = e.ProgressPercentage;
if (OSVersion.HasExtendedTaskbar)
TaskbarLib.Windows7Taskbar.SetTaskbarProgress(Program.HackerWindow, this.progressDownload);
}
private void verifyTask_RunTask(object param, ref object result)
{
byte[] buffer;
byte[] oldBuffer;
int bytesRead;
int oldBytesRead;
long size;
long totalBytesRead = 0;
using (Stream stream = File.OpenRead(_fileName)) //Change to MD5.Create for MD5 verification
using (System.Security.Cryptography.HashAlgorithm hashAlgorithm = System.Security.Cryptography.SHA1.Create())
{
size = stream.Length;
buffer = new byte[4096];
bytesRead = stream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
do
{
if (_verifyTask.Cancelled)
return;
oldBytesRead = bytesRead;
oldBuffer = buffer;
buffer = new byte[4096];
bytesRead = stream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
if (bytesRead == 0)
{
hashAlgorithm.TransformFinalBlock(oldBuffer, 0, oldBytesRead);
}
else
{
hashAlgorithm.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0);
}
if (this.IsHandleCreated)
{
this.BeginInvoke(new MethodInvoker(() =>
{
this.progressDownload.Value = (int)((double)totalBytesRead * 100 / size);
}));
}
} while (bytesRead != 0);
result = hashAlgorithm.Hash;
}
}
private void verifyTask_Completed(object result)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new ThreadTaskCompletedDelegate(verifyTask_Completed), result);
return;
}
StringBuilder sb = new StringBuilder();
foreach (byte b in (byte[])result)
{
sb.AppendFormat("{0:x2}", b);
}
if (_updateItem.Hash.Equals(sb.ToString(), StringComparison.InvariantCultureIgnoreCase))
{
labelProgress.Text = "Download completed and SHA1 verified successfully.";
buttonInstall.Select();
}
else
{
labelProgress.Text = "SHA1 hash verification failed!";
labelProgress.Font = new System.Drawing.Font(labelProgress.Font, System.Drawing.FontStyle.Bold);
}
// Allow the user to install in both cases, just in case our supplied hash is wrong.
buttonInstall.Enabled = true;
buttonStop.Text = "Close";
// Is elevation needed?
if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited)
buttonInstall.SetShieldIcon(true);
}
private void buttonInstall_Click(object sender, EventArgs e)
{
// We need to close our handle to the PH mutex in order to
// let the installer continue.
if (Program.GlobalMutex != null)
{
Program.GlobalMutex.Dispose();
Program.GlobalMutex = null;
}
bool success = false;
// Force elevation if required to prevent an exception if the user
// clicks no. Otherwise, start it normally.
if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited)
{
Program.StartProgramAdmin(
_fileName,
"",
new MethodInvoker(() => success = true),
ShowWindowType.Normal,
this.Handle
);
}
else
{
try
{
System.Diagnostics.Process.Start(_fileName);
success = true;
}
catch (Exception ex)
{
PhUtils.ShowException("Unable to start the installer", ex);
}
}
if (success)
{
Program.HackerWindow.Exit();
}
else
{
// User canceled. Re-open the mutex.
try
{
Program.GlobalMutex = new ProcessHacker.Native.Threading.Mutant(Program.GlobalMutexName);
}
catch (Exception ex)
{
Logging.Log(ex);
}
}
}
private void buttonStop_Click(object sender, EventArgs e)
{
if (_webClient.IsBusy)
_webClient.CancelAsync();
this.Close();
}
}
}