From fbe03b86eab867223a3689428fd5323a0c537bbc Mon Sep 17 00:00:00 2001 From: dbuechel Date: Wed, 20 Nov 2019 10:45:08 +0100 Subject: [PATCH] SEBWIN-312: Finished first draft of task view. --- .../ExternalApplicationInstance.cs | 9 +- .../BrowserApplicationInstance.cs | 5 +- .../Operations/BrowserOperationTests.cs | 10 +- SafeExamBrowser.Client/CompositionRoot.cs | 5 +- .../Operations/BrowserOperation.cs | 5 + .../ActionCenter.xaml | 4 +- .../ActionCenterApplicationControl.xaml | 4 +- .../Controls/TaskViewInstanceControl.xaml | 21 +++ .../Controls/TaskViewInstanceControl.xaml.cs | 69 ++++++++++ .../LogWindow.xaml | 2 +- ...feExamBrowser.UserInterface.Desktop.csproj | 7 + .../TaskView.xaml | 11 +- .../TaskView.xaml.cs | 130 +++++++++--------- .../Taskbar.xaml | 6 +- .../Templates/Colors.xaml | 6 +- .../LogWindow.xaml | 2 +- SafeExamBrowser.WindowsApi/NativeMethods.cs | 2 +- SafeExamBrowser.WindowsApi/Process.cs | 7 +- SafeExamBrowser.WindowsApi/ProcessFactory.cs | 1 + SafeExamBrowser.WindowsApi/User32.cs | 6 + 20 files changed, 227 insertions(+), 85 deletions(-) create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml create mode 100644 SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs diff --git a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs index a9512f2c..0ab3724f 100644 --- a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs +++ b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs @@ -21,13 +21,12 @@ namespace SafeExamBrowser.Applications private const int ONE_SECOND = 1000; private ILogger logger; - private string name; private IProcess process; private Timer timer; public IconResource Icon { get; } public InstanceIdentifier Id { get; } - public string Name { get; } + public string Name { get; private set; } public event IconChangedEventHandler IconChanged { add { } remove { } } public event NameChangedEventHandler NameChanged; @@ -114,12 +113,12 @@ namespace SafeExamBrowser.Applications private void Timer_Elapsed(object sender, ElapsedEventArgs e) { var success = process.TryGetWindowTitle(out var title); - var hasChanged = name?.Equals(title, StringComparison.Ordinal) != true; + var hasChanged = Name?.Equals(title, StringComparison.Ordinal) != true; if (success && hasChanged) { - name = title; - NameChanged?.Invoke(name); + Name = title; + NameChanged?.Invoke(Name); } timer.Start(); diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs index 6dfd1e93..b88f544f 100644 --- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs +++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs @@ -194,8 +194,9 @@ namespace SafeExamBrowser.Browser private void Control_TitleChanged(string title) { - window.UpdateTitle(title); - NameChanged?.Invoke(title); + Name = title; + window.UpdateTitle(Name); + NameChanged?.Invoke(Name); } private void DisplayHandler_FaviconChanged(string uri) diff --git a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs index b7b91f58..3eb4668c 100644 --- a/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs +++ b/SafeExamBrowser.Client.UnitTests/Operations/BrowserOperationTests.cs @@ -24,6 +24,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations private ClientContext context; private Mock logger; private Mock taskbar; + private Mock taskView; private Mock uiFactory; private BrowserOperation sut; @@ -36,11 +37,12 @@ namespace SafeExamBrowser.Client.UnitTests.Operations context = new ClientContext(); logger = new Mock(); taskbar = new Mock(); + taskView = new Mock(); uiFactory = new Mock(); context.Browser = browser.Object; - sut = new BrowserOperation(actionCenter.Object, context, logger.Object, taskbar.Object, uiFactory.Object); + sut = new BrowserOperation(actionCenter.Object, context, logger.Object, taskbar.Object, taskView.Object, uiFactory.Object); } [TestMethod] @@ -59,5 +61,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations sut.Revert(); browser.Verify(c => c.Terminate(), Times.Once); } + + [TestMethod] + public void TODO() + { + // TODO: Test initialization of task view! + } } } diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs index 7212d96c..953f1630 100644 --- a/SafeExamBrowser.Client/CompositionRoot.cs +++ b/SafeExamBrowser.Client/CompositionRoot.cs @@ -71,6 +71,7 @@ namespace SafeExamBrowser.Client private IRuntimeProxy runtimeProxy; private ISystemInfo systemInfo; private ITaskbar taskbar; + private ITaskView taskView; private IText text; private ITextResource textResource; private IUserInterfaceFactory uiFactory; @@ -94,6 +95,7 @@ namespace SafeExamBrowser.Client uiFactory = BuildUserInterfaceFactory(); runtimeProxy = new RuntimeProxy(runtimeHostUri, new ProxyObjectFactory(), ModuleLogger(nameof(RuntimeProxy)), Interlocutor.Client); taskbar = BuildTaskbar(); + taskView = BuildTaskView(); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory))); var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory); @@ -197,7 +199,7 @@ namespace SafeExamBrowser.Client { var moduleLogger = ModuleLogger(nameof(BrowserApplication)); var browser = new BrowserApplication(context.AppConfig, context.Settings.Browser, messageBox, moduleLogger, text, uiFactory); - var operation = new BrowserOperation(actionCenter, context, logger, taskbar, uiFactory); + var operation = new BrowserOperation(actionCenter, context, logger, taskbar, taskView, uiFactory); context.Browser = browser; @@ -242,7 +244,6 @@ namespace SafeExamBrowser.Client var logInfo = new LogNotificationInfo(text); var logController = new LogNotificationController(logger, uiFactory); var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply))); - var taskView = BuildTaskView(); var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter))); var operation = new ShellOperation( actionCenter, diff --git a/SafeExamBrowser.Client/Operations/BrowserOperation.cs b/SafeExamBrowser.Client/Operations/BrowserOperation.cs index e44cd11c..eeda4df5 100644 --- a/SafeExamBrowser.Client/Operations/BrowserOperation.cs +++ b/SafeExamBrowser.Client/Operations/BrowserOperation.cs @@ -20,6 +20,7 @@ namespace SafeExamBrowser.Client.Operations private IActionCenter actionCenter; private ILogger logger; private ITaskbar taskbar; + private ITaskView taskView; private IUserInterfaceFactory uiFactory; public override event ActionRequiredEventHandler ActionRequired { add { } remove { } } @@ -30,11 +31,13 @@ namespace SafeExamBrowser.Client.Operations ClientContext context, ILogger logger, ITaskbar taskbar, + ITaskView taskView, IUserInterfaceFactory uiFactory) : base(context) { this.actionCenter = actionCenter; this.logger = logger; this.taskbar = taskbar; + this.taskView = taskView; this.uiFactory = uiFactory; } @@ -55,6 +58,8 @@ namespace SafeExamBrowser.Client.Operations taskbar.AddApplicationControl(uiFactory.CreateApplicationControl(Context.Browser, Location.Taskbar), true); } + taskView.Add(Context.Browser); + return OperationResult.Success; } diff --git a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml index 02a5385f..f628a65e 100644 --- a/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/ActionCenter.xaml @@ -4,10 +4,12 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls" - mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="#EEF0F0F0" AllowsTransparency="True" WindowStyle="None" Topmost="True" ResizeMode="NoResize"> + mc:Ignorable="d" Title="ActionCenter" Height="1000" Width="400" Background="{DynamicResource BackgroundTransparentBrush}" + AllowsTransparency="True" WindowStyle="None" Topmost="True" ResizeMode="NoResize"> + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml index f0e34e0a..c0fefed6 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/ActionCenterApplicationControl.xaml @@ -20,8 +20,8 @@ - + - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml new file mode 100644 index 00000000..1af0d30e --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs new file mode 100644 index 00000000..f1997763 --- /dev/null +++ b/SafeExamBrowser.UserInterface.Desktop/Controls/TaskViewInstanceControl.xaml.cs @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +using System.Windows; +using System.Windows.Controls; +using SafeExamBrowser.Applications.Contracts; +using SafeExamBrowser.Core.Contracts; +using SafeExamBrowser.UserInterface.Shared.Utilities; + +namespace SafeExamBrowser.UserInterface.Desktop.Controls +{ + public partial class TaskViewInstanceControl : UserControl + { + private IApplicationInstance instance; + + internal InstanceIdentifier Id => instance.Id; + + public TaskViewInstanceControl(IApplicationInstance instance) + { + this.instance = instance; + + InitializeComponent(); + InitializeControl(); + } + + internal void Activate() + { + instance.Activate(); + } + + internal void Deselect() + { + Border.Visibility = Visibility.Hidden; + Icon.MaxWidth = 40; + Title.FontWeight = FontWeights.Normal; + } + + internal void Select() + { + Border.Visibility = Visibility.Visible; + Icon.MaxWidth = 50; + Title.FontWeight = FontWeights.SemiBold; + } + + private void InitializeControl() + { + Icon.Content = IconResourceLoader.Load(instance.Icon); + Title.Text = instance.Name; + + instance.IconChanged += Instance_IconChanged; + instance.NameChanged += Instance_NameChanged; + } + + private void Instance_NameChanged(string name) + { + Dispatcher.InvokeAsync(() => Title.Text = name); + } + + private void Instance_IconChanged(IconResource icon) + { + Dispatcher.InvokeAsync(() => Icon.Content = IconResourceLoader.Load(instance.Icon)); + } + } +} diff --git a/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml b/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml index 72350a8b..9f8a9b74 100644 --- a/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/LogWindow.xaml @@ -4,7 +4,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop" - mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="500" Width="1100" MinHeight="350" + mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="750" Width="1000" MinHeight="350" MinWidth="350" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico"> diff --git a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj index 28d5cf22..3675db98 100644 --- a/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj +++ b/SafeExamBrowser.UserInterface.Desktop/SafeExamBrowser.UserInterface.Desktop.csproj @@ -142,6 +142,9 @@ TaskbarWirelessNetworkControl.xaml + + TaskViewInstanceControl.xaml + LockScreen.xaml @@ -314,6 +317,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml index 6985444f..3103e6c8 100644 --- a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml @@ -4,8 +4,15 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop" - mc:Ignorable="d" AllowsTransparency="True" Background="#AA000000" BorderBrush="DodgerBlue" BorderThickness="1" Title="TaskView" - Topmost="True" Height="450" SizeToContent="WidthAndHeight" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None"> + mc:Ignorable="d" AllowsTransparency="True" Background="{DynamicResource BackgroundTransparentBrush}" BorderBrush="DodgerBlue" BorderThickness="1" + Title="TaskView" Topmost="True" Height="450" SizeToContent="WidthAndHeight" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None"> + + + + + + + diff --git a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs index 8f88e170..807cf362 100644 --- a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs +++ b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs @@ -11,23 +11,24 @@ using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Media; using SafeExamBrowser.Applications.Contracts; -using SafeExamBrowser.Core.Contracts; using SafeExamBrowser.UserInterface.Contracts.Shell; -using SafeExamBrowser.UserInterface.Shared.Utilities; +using SafeExamBrowser.UserInterface.Desktop.Controls; namespace SafeExamBrowser.UserInterface.Desktop { public partial class TaskView : Window, ITaskView { - private IList instances; + private LinkedListNode current; + private LinkedList controls; + private List instances; public TaskView() { - InitializeComponent(); + controls = new LinkedList(); instances = new List(); + + InitializeComponent(); } public void Add(IApplication application) @@ -44,61 +45,84 @@ namespace SafeExamBrowser.UserInterface.Desktop private void Application_InstanceStarted(IApplicationInstance instance) { - Dispatcher.InvokeAsync(() => - { - instance.IconChanged += Instance_IconChanged; - instance.NameChanged += Instance_NameChanged; - instance.Terminated += Instance_Terminated; - - instances.Add(instance); - Update(); - }); + Dispatcher.InvokeAsync(() => Add(instance)); } private void Activator_Deactivated() { - Dispatcher.InvokeAsync(Hide); + Dispatcher.InvokeAsync(ActivateAndHide); } private void Activator_Next() { - Dispatcher.InvokeAsync(ShowConditional); + Dispatcher.InvokeAsync(SelectNext); } private void Activator_Previous() { - Dispatcher.InvokeAsync(ShowConditional); - } - - private void Instance_IconChanged(IconResource icon) - { - // TODO Dispatcher.InvokeAsync(...); - } - - private void Instance_NameChanged(string name) - { - // TODO Dispatcher.InvokeAsync(...); + Dispatcher.InvokeAsync(SelectPrevious); } private void Instance_Terminated(InstanceIdentifier id) { - Dispatcher.InvokeAsync(() => - { - var instance = instances.FirstOrDefault(i => i.Id == id); + Dispatcher.InvokeAsync(() => Remove(id)); + } - if (instance != default(IApplicationInstance)) - { - instances.Remove(instance); - Update(); - } - }); + private void ActivateAndHide() + { + Activate(); + current?.Value.Activate(); + Hide(); + } + + private void Add(IApplicationInstance instance) + { + instance.Terminated += Instance_Terminated; + instances.Add(instance); + Update(); + } + + private void Remove(InstanceIdentifier id) + { + var instance = instances.FirstOrDefault(i => i.Id == id); + + if (instance != default(IApplicationInstance)) + { + instances.Remove(instance); + Update(); + } + } + + private void SelectNext() + { + ShowConditional(); + + if (current != null) + { + current.Value.Deselect(); + current = current.Next ?? controls.First; + current.Value.Select(); + } + } + + private void SelectPrevious() + { + ShowConditional(); + + if (current != null) + { + current.Value.Deselect(); + current = current.Previous ?? controls.Last; + current.Value.Select(); + } } private void ShowConditional() { - if (Visibility != Visibility.Visible && instances.Any()) + if (instances.Any() && Visibility != Visibility.Visible) { Show(); + Activate(); } } @@ -107,6 +131,7 @@ namespace SafeExamBrowser.UserInterface.Desktop var max = Math.Ceiling(Math.Sqrt(instances.Count)); var stack = new Stack(instances); + controls.Clear(); Rows.Children.Clear(); for (var rowCount = 0; rowCount < max && stack.Any(); rowCount++) @@ -118,12 +143,16 @@ namespace SafeExamBrowser.UserInterface.Desktop for (var columnIndex = 0; columnIndex < max && stack.Any(); columnIndex++) { var instance = stack.Pop(); - var control = BuildInstanceControl(instance); + var control = new TaskViewInstanceControl(instance); + controls.AddLast(control); row.Children.Add(control); } } + current = controls.First; + current?.Value.Select(); + UpdateLayout(); Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left; @@ -134,28 +163,5 @@ namespace SafeExamBrowser.UserInterface.Desktop Hide(); } } - - private UIElement BuildInstanceControl(IApplicationInstance instance) - { - var border = new Border(); - var stackPanel = new StackPanel(); - var icon = IconResourceLoader.Load(instance.Icon); - - border.BorderBrush = Brushes.White; - border.BorderThickness = new Thickness(1); - border.Height = 150; - border.Margin = new Thickness(5); - border.Padding = new Thickness(2); - border.Width = 250; - border.Child = stackPanel; - - stackPanel.HorizontalAlignment = HorizontalAlignment.Center; - stackPanel.Orientation = Orientation.Vertical; - stackPanel.VerticalAlignment = VerticalAlignment.Center; - stackPanel.Children.Add(new ContentControl { Content = icon, MaxWidth = 50 }); - stackPanel.Children.Add(new TextBlock(new Run($"Instance {instance.Name ?? "NULL"}") { Foreground = Brushes.White, FontWeight = FontWeights.Bold })); - - return border; - } } } diff --git a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml index 7474c85d..50bc14ce 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Taskbar.xaml @@ -5,10 +5,12 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Controls" xmlns:s="clr-namespace:System;assembly=mscorlib" - mc:Ignorable="d" Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico"> + mc:Ignorable="d" Title="Taskbar" Background="{DynamicResource BackgroundBrush}" Height="40" Width="750" WindowStyle="None" Topmost="True" + ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico"> + @@ -26,7 +28,7 @@ - + diff --git a/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml b/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml index 468c0504..6a558e71 100644 --- a/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml +++ b/SafeExamBrowser.UserInterface.Desktop/Templates/Colors.xaml @@ -1,5 +1,9 @@  - #FFF0F0F0 #AA808080 + #FFF0F0F0 + #EEF0F0F0 + #99D3D3D3 + Black + DimGray \ No newline at end of file diff --git a/SafeExamBrowser.UserInterface.Mobile/LogWindow.xaml b/SafeExamBrowser.UserInterface.Mobile/LogWindow.xaml index 37ca97bf..85d7dc3d 100644 --- a/SafeExamBrowser.UserInterface.Mobile/LogWindow.xaml +++ b/SafeExamBrowser.UserInterface.Mobile/LogWindow.xaml @@ -4,7 +4,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile" - mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="500" Width="1100" MinHeight="350" + mc:Ignorable="d" Title="{Binding Path=WindowTitle}" Background="Black" Foreground="White" Height="750" Width="1000" MinHeight="350" MinWidth="350" WindowState="Maximized" WindowStartupLocation="CenterScreen" Icon="./Images/LogNotification.ico"> diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs index d0393f0d..dbb3cb91 100644 --- a/SafeExamBrowser.WindowsApi/NativeMethods.cs +++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs @@ -342,7 +342,7 @@ namespace SafeExamBrowser.WindowsApi public void RestoreWindow(IntPtr window) { - User32.ShowWindow(window, (int)ShowWindowCommand.Restore); + User32.ShowWindow(window, (int) ShowWindowCommand.Restore); } public bool ResumeThread(int threadId) diff --git a/SafeExamBrowser.WindowsApi/Process.cs b/SafeExamBrowser.WindowsApi/Process.cs index 4404a25a..9e9f5318 100644 --- a/SafeExamBrowser.WindowsApi/Process.cs +++ b/SafeExamBrowser.WindowsApi/Process.cs @@ -69,15 +69,18 @@ namespace SafeExamBrowser.WindowsApi { try { - var success = User32.BringWindowToTop(process.MainWindowHandle); + var success = true; var placement = new WINDOWPLACEMENT(); + success &= User32.BringWindowToTop(process.MainWindowHandle); + success &= User32.SetForegroundWindow(process.MainWindowHandle); + placement.length = Marshal.SizeOf(placement); User32.GetWindowPlacement(process.MainWindowHandle, ref placement); if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized) { - success &= User32.ShowWindow(process.MainWindowHandle, (int) ShowWindowCommand.Restore); + success &= User32.ShowWindowAsync(process.MainWindowHandle, (int) ShowWindowCommand.Restore); } return success; diff --git a/SafeExamBrowser.WindowsApi/ProcessFactory.cs b/SafeExamBrowser.WindowsApi/ProcessFactory.cs index bd7be07d..f451eaf0 100644 --- a/SafeExamBrowser.WindowsApi/ProcessFactory.cs +++ b/SafeExamBrowser.WindowsApi/ProcessFactory.cs @@ -59,6 +59,7 @@ namespace SafeExamBrowser.WindowsApi logger.Info($"Attempting to start process '{path}'..."); + // TODO: Fails for certain processes, whereas Process.Start() does not -> use different API?! Use (declare?) CreateProcessW / CreateProcessA? var success = Kernel32.CreateProcess(null, commandLine, IntPtr.Zero, IntPtr.Zero, true, Constant.NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref startupInfo, ref processInfo); if (!success) diff --git a/SafeExamBrowser.WindowsApi/User32.cs b/SafeExamBrowser.WindowsApi/User32.cs index 1424942f..edec6c5c 100644 --- a/SafeExamBrowser.WindowsApi/User32.cs +++ b/SafeExamBrowser.WindowsApi/User32.cs @@ -83,6 +83,9 @@ namespace SafeExamBrowser.WindowsApi [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool SetForegroundWindow(IntPtr hWnd); + [DllImport("user32.dll", SetLastError = true)] internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, EventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); @@ -92,6 +95,9 @@ namespace SafeExamBrowser.WindowsApi [DllImport("user32.dll", SetLastError = true)] internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + [DllImport("user32.dll", SetLastError = true)] + internal static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow); + [DllImport("user32.dll", SetLastError = true)] internal static extern bool SwitchDesktop(IntPtr hDesktop);