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; } } }