using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Threading;
namespace Tango.PPC.Updater
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int nIndex);
private String _sourceFolder = AppDomain.CurrentDomain.BaseDirectory;
private String _msProcessName = "Tango.PPC.UI";
private String _appPath;
private bool EMULATE_EXCEPTION = false;
private bool _isEureka;
public MainWindow()
{
#if Eureka
_isEureka = true;
#endif
//Launch debugger..
#if DEBUG
if (!Debugger.IsAttached)
{
Debugger.Launch();
}
#endif
InitializeComponent();
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
WindowStartupLocation = WindowStartupLocation.Manual;
Topmost = !_isEureka; // sure?
var screens = System.Windows.Forms.Screen.AllScreens;
//Search for the vertical touch monitor.
var touch_screen = screens.Where(x => x.Bounds.Height > x.Bounds.Width).LastOrDefault();
if (touch_screen != null)
{
Left = touch_screen.Bounds.Left;
Top = touch_screen.Bounds.Top;
Width = touch_screen.Bounds.Width;
Height = touch_screen.Bounds.Height;
}
else
{
Top = 0;
Left = 0;
}
if (_isEureka)
{
bool hasTouch = IsTouchEnabled();
if (!hasTouch)
{
WindowStyle = WindowStyle.SingleBorderWindow;
ResizeMode = ResizeMode.CanResize;
Width = 1280;
Height = 720;
WindowStartupLocation = WindowStartupLocation.CenterScreen;
WindowState = WindowState.Normal;
Topmost = false; // sure?
}
else
{
WindowState = WindowState.Normal;
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
Left = screens.Length == 2 ? screens[0].Bounds.Width : 0;
Top = 0;
Width = 1920;
Height = 1080;
WindowStartupLocation = WindowStartupLocation.Manual;
Topmost = false; // sure?
}
}
ContentRendered += MainWindow_ContentRendered;
btnRetry.Click += BtnRetry_Click;
btnAbort.Click += BtnAbort_Click;
}
private void MainWindow_ContentRendered(object sender, EventArgs e)
{
Update();
}
private void Update()
{
try
{
ShowProgress();
if (!IdentityUtils.IsElevated())
{
ShowError("The updater utility is not running under elevated permissions and cannot perform.\nThe process will restart.");
var exeName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
ProcessStartInfo startInfo = new ProcessStartInfo(exeName);
startInfo.Arguments = String.Join(" ", App.StartupArgs);
startInfo.Verb = "runas";
Process.Start(startInfo);
Environment.Exit(0);
return;
}
}
catch { }
try
{
Init();
if (EMULATE_EXCEPTION)
{
EMULATE_EXCEPTION = false;
throw new InvalidOperationException("This is an emulated error.");
}
EnsureTangoIsDown();
RemoveOldDLLFiles();
ReplaceFiles();
txtStatus.Text = "Update completed. Starting application...";
DoEvents();
Thread.Sleep(1000);
StartTango(true);
Exit();
}
catch (Exception ex)
{
ShowFailed(ex);
}
}
private void Exit()
{
try
{
foreach (var file in Directory.GetFiles(_sourceFolder, "*.*", SearchOption.AllDirectories))
{
try
{
File.Delete(file);
}
catch { }
}
}
catch { }
Environment.Exit(0);
}
private void Init()
{
try
{
_appPath = String.Join(" ", App.StartupArgs);
if (!_appPath.EndsWith("\\"))
{
_appPath += "\\";
}
}
catch
{
throw new ArgumentException("Error parsing startup arguments.");
}
if (!Directory.Exists(_appPath))
{
throw new InvalidOperationException("This update utility can only be executed by the main Tango application.");
}
}
private void StartTango(bool success)
{
Process p = new Process();
p.StartInfo.FileName = _appPath + "\\" + _msProcessName + ".exe";
p.StartInfo.LoadUserProfile = true;
p.StartInfo.UseShellExecute = true;
if (success)
{
p.StartInfo.Arguments = "-update_ok";
}
else
{
p.StartInfo.Arguments = "-update_failed";
}
p.Start();
}
private void ReplaceFiles()
{
txtStatus.Text = "Updating files...";
int maxProgress = Directory.GetFiles(_sourceFolder, "*.*", SearchOption.AllDirectories).Length;
int progress = 0;
foreach (string dirPath in Directory.GetDirectories(_sourceFolder, "*", SearchOption.AllDirectories))
{
try
{
Directory.CreateDirectory(dirPath.Replace(_sourceFolder, _appPath));
}
catch (Exception ex)
{
ShowError("Could not create directory " + Path.GetFileName(dirPath) + Environment.NewLine + ex.Message);
}
}
foreach (string newPath in Directory.GetFiles(_sourceFolder, "*.*", SearchOption.AllDirectories))
{
try
{
DoEvents();
File.Copy(newPath, newPath.Replace(_sourceFolder, _appPath), true);
prog.Maximum = maxProgress;
prog.Value = progress++;
DoEvents();
}
catch (Exception ex)
{
if (!newPath.ToLower().Contains("updater.exe"))
{
ShowError("Could not create file " + Path.GetFileName(newPath) + Environment.NewLine + ex.Message);
}
}
}
}
private void RemoveOldDLLFiles()
{
foreach (string dll in Directory.GetFiles(_appPath, "*.dll"))
{
try
{
File.Delete(dll);
}
catch
{
ShowError($"The file '{Path.GetFileName(dll)}' could not be removed. Please close all instances of Tango and press OK.");
RemoveOldDLLFiles();
return;
}
}
}
private void EnsureTangoIsDown()
{
Process appProcess = null;
for (int i = 0; i < 20; i++)
{
try
{
appProcess = Process.GetProcessesByName(_msProcessName).FirstOrDefault();
}
catch
{
Thread.Sleep(1000);
continue;
}
if (appProcess != null)
{
try
{
appProcess.Kill();
}
catch { }
try
{
Process p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.FileName = "wmic";
p.StartInfo.Arguments = String.Format("process where name='{0}' delete", _msProcessName);
p.Start();
}
catch { }
}
else
{
break;
}
Thread.Sleep(1000);
}
if (appProcess != null)
{
throw new IOException("The main Tango process seems to in a frozen state. Please restart your computer and try again.");
}
}
///
/// Forces UI rendering.
///
private void DoEvents()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
}
private void ShowError(String error)
{
MessageBox.Show(error, "Tango Update", MessageBoxButton.OK, MessageBoxImage.Error);
}
private bool ShowErrorRetry(String error)
{
var result = MessageBox.Show(error + "\n" + "Press yes to retry.", "Tango Update", MessageBoxButton.YesNo, MessageBoxImage.Error);
return result == MessageBoxResult.Yes;
}
private void ShowProgress()
{
stackProgress.Visibility = Visibility.Visible;
stackFailed.Visibility = Visibility.Collapsed;
}
private void ShowFailed(Exception ex)
{
try
{
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "PPC Updater";
eventLog.WriteEntry($"PPC Updater Failed\n{ex.ToString()}", EventLogEntryType.Error, 101, 1);
}
}
catch { }
stackProgress.Visibility = Visibility.Collapsed;
stackFailed.Visibility = Visibility.Visible;
txtError.Text = ex.Message;
}
private void BtnAbort_Click(object sender, RoutedEventArgs e)
{
ShowProgress();
txtStatus.Text = "Update failed. Restoring previous application state...";
DoEvents();
Thread.Sleep(1000);
StartTango(false);
Exit();
}
private void BtnRetry_Click(object sender, RoutedEventArgs e)
{
Update();
}
///
/// Determines whether the current machine is touch enabled.
///
public static bool IsTouchEnabled()
{
const int MAXTOUCHES_INDEX = 95;
int maxTouches = GetSystemMetrics(MAXTOUCHES_INDEX);
if (maxTouches > 0)
{
return true;
}
foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
{
if (tabletDevice.Type == TabletDeviceType.Touch && !String.IsNullOrWhiteSpace(tabletDevice.Name))
return true;
}
return false;
}
}
}