Implemented basic window handling.
This commit is contained in:
parent
f5d76980d0
commit
94f356b77a
24 changed files with 346 additions and 196 deletions
|
@ -23,11 +23,13 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
SplashScreen_InitializeBrowser,
|
||||
SplashScreen_InitializeProcessMonitoring,
|
||||
SplashScreen_InitializeTaskbar,
|
||||
SplashScreen_InitializeWindowMonitoring,
|
||||
SplashScreen_InitializeWorkingArea,
|
||||
SplashScreen_RestoreWorkingArea,
|
||||
SplashScreen_ShutdownProcedure,
|
||||
SplashScreen_StartupProcedure,
|
||||
SplashScreen_StopProcessMonitoring,
|
||||
SplashScreen_StopWindowMonitoring,
|
||||
SplashScreen_WaitExplorerStartup,
|
||||
SplashScreen_WaitExplorerTermination,
|
||||
Version
|
||||
|
|
|
@ -11,21 +11,21 @@ using SafeExamBrowser.Contracts.I18n;
|
|||
|
||||
namespace SafeExamBrowser.Contracts.UserInterface
|
||||
{
|
||||
public interface IUiElementFactory
|
||||
public interface IUiElementFactory : IMessageBox
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a taskbar button, initialized with the given application information.
|
||||
/// </summary>
|
||||
ITaskbarButton CreateApplicationButton(IApplicationInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new splash screen which runs on its own thread.
|
||||
/// </summary>
|
||||
ISplashScreen CreateSplashScreen(ISettings settings, IText text);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a taskbar notification, initialized with the given notification information.
|
||||
/// </summary>
|
||||
ITaskbarNotification CreateNotification(INotificationInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new splash screen which runs on its own thread.
|
||||
/// </summary>
|
||||
ISplashScreen CreateSplashScreen(ISettings settings, IText text);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ using SafeExamBrowser.Contracts.Behaviour;
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.Behaviour;
|
||||
|
||||
|
@ -22,45 +21,24 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
|
|||
[TestClass]
|
||||
public class ShutdownControllerTests
|
||||
{
|
||||
private Mock<IApplicationController> browserControllerMock;
|
||||
private Mock<IApplicationInfo> browserInfoMock;
|
||||
private Mock<ILogger> loggerMock;
|
||||
private Mock<IMessageBox> messageBoxMock;
|
||||
private Mock<INotificationInfo> aboutInfoMock;
|
||||
private Mock<IProcessMonitor> processMonitorMock;
|
||||
private Mock<ISettings> settingsMock;
|
||||
private Mock<ITaskbar> taskbarMock;
|
||||
private Mock<IText> textMock;
|
||||
private Mock<IUiElementFactory> uiFactoryMock;
|
||||
private Mock<IWorkingArea> workingAreaMock;
|
||||
|
||||
private IShutdownController sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
browserControllerMock = new Mock<IApplicationController>();
|
||||
browserInfoMock = new Mock<IApplicationInfo>();
|
||||
loggerMock = new Mock<ILogger>();
|
||||
messageBoxMock = new Mock<IMessageBox>();
|
||||
aboutInfoMock = new Mock<INotificationInfo>();
|
||||
processMonitorMock = new Mock<IProcessMonitor>();
|
||||
settingsMock = new Mock<ISettings>();
|
||||
taskbarMock = new Mock<ITaskbar>();
|
||||
textMock = new Mock<IText>();
|
||||
uiFactoryMock = new Mock<IUiElementFactory>();
|
||||
workingAreaMock = new Mock<IWorkingArea>();
|
||||
|
||||
uiFactoryMock.Setup(f => f.CreateSplashScreen(settingsMock.Object, textMock.Object)).Returns(new Mock<ISplashScreen>().Object);
|
||||
|
||||
sut = new ShutdownController(
|
||||
loggerMock.Object,
|
||||
messageBoxMock.Object,
|
||||
processMonitorMock.Object,
|
||||
settingsMock.Object,
|
||||
textMock.Object,
|
||||
uiFactoryMock.Object,
|
||||
workingAreaMock.Object);
|
||||
sut = new ShutdownController(loggerMock.Object, settingsMock.Object, textMock.Object, uiFactoryMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -14,7 +14,6 @@ using SafeExamBrowser.Contracts.Behaviour;
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.Behaviour;
|
||||
|
||||
|
@ -23,49 +22,24 @@ namespace SafeExamBrowser.Core.UnitTests.Behaviour
|
|||
[TestClass]
|
||||
public class StartupControllerTests
|
||||
{
|
||||
private Mock<IApplicationController> browserControllerMock;
|
||||
private Mock<IApplicationInfo> browserInfoMock;
|
||||
private Mock<ILogger> loggerMock;
|
||||
private Mock<IMessageBox> messageBoxMock;
|
||||
private Mock<INotificationInfo> aboutInfoMock;
|
||||
private Mock<IProcessMonitor> processMonitorMock;
|
||||
private Mock<ISettings> settingsMock;
|
||||
private Mock<ITaskbar> taskbarMock;
|
||||
private Mock<IText> textMock;
|
||||
private Mock<IUiElementFactory> uiFactoryMock;
|
||||
private Mock<IWorkingArea> workingAreaMock;
|
||||
|
||||
private IStartupController sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
browserControllerMock = new Mock<IApplicationController>();
|
||||
browserInfoMock = new Mock<IApplicationInfo>();
|
||||
loggerMock = new Mock<ILogger>();
|
||||
messageBoxMock = new Mock<IMessageBox>();
|
||||
aboutInfoMock = new Mock<INotificationInfo>();
|
||||
processMonitorMock = new Mock<IProcessMonitor>();
|
||||
settingsMock = new Mock<ISettings>();
|
||||
taskbarMock = new Mock<ITaskbar>();
|
||||
textMock = new Mock<IText>();
|
||||
uiFactoryMock = new Mock<IUiElementFactory>();
|
||||
workingAreaMock = new Mock<IWorkingArea>();
|
||||
|
||||
uiFactoryMock.Setup(f => f.CreateSplashScreen(settingsMock.Object, textMock.Object)).Returns(new Mock<ISplashScreen>().Object);
|
||||
|
||||
sut = new StartupController(
|
||||
browserControllerMock.Object,
|
||||
browserInfoMock.Object,
|
||||
loggerMock.Object,
|
||||
messageBoxMock.Object,
|
||||
aboutInfoMock.Object,
|
||||
processMonitorMock.Object,
|
||||
settingsMock.Object,
|
||||
taskbarMock.Object,
|
||||
textMock.Object,
|
||||
uiFactoryMock.Object,
|
||||
workingAreaMock.Object);
|
||||
sut = new StartupController(loggerMock.Object, settingsMock.Object, textMock.Object, uiFactoryMock.Object);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing browser ---");
|
||||
logger.Info("Initializing browser...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeBrowser);
|
||||
|
||||
var browserButton = uiFactory.CreateApplicationButton(browserInfo);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing process monitoring ---");
|
||||
logger.Info("Initializing process monitoring...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true);
|
||||
|
||||
processMonitor.CloseExplorerShell();
|
||||
|
@ -42,7 +42,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("--- Stopping process monitoring ---");
|
||||
logger.Info("Stopping process monitoring...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing taskbar ---");
|
||||
logger.Info("Initializing taskbar...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar);
|
||||
|
||||
var aboutNotification = uiFactory.CreateNotification(aboutInfo);
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2017 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 SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour.Operations
|
||||
{
|
||||
public class WindowMonitoringOperation : IOperation
|
||||
{
|
||||
private ILogger logger;
|
||||
private IWindowMonitor windowMonitor;
|
||||
|
||||
public ISplashScreen SplashScreen { private get; set; }
|
||||
|
||||
public WindowMonitoringOperation(ILogger logger, IWindowMonitor windowMonitor)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.windowMonitor = windowMonitor;
|
||||
}
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("Initializing window monitoring...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeWindowMonitoring);
|
||||
|
||||
windowMonitor.HideAllWindows();
|
||||
windowMonitor.StartMonitoringWindows();
|
||||
}
|
||||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("Stopping window monitoring...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_StopWindowMonitoring);
|
||||
|
||||
windowMonitor.StopMonitoringWindows();
|
||||
windowMonitor.RestoreHiddenWindows();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Perform()
|
||||
{
|
||||
logger.Info("--- Initializing working area ---");
|
||||
logger.Info("Initializing working area...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea);
|
||||
|
||||
// TODO
|
||||
|
@ -42,7 +42,7 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
|
|||
|
||||
public void Revert()
|
||||
{
|
||||
logger.Info("--- Restoring working area ---");
|
||||
logger.Info("Restoring working area...");
|
||||
SplashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea);
|
||||
|
||||
// TODO
|
||||
|
|
|
@ -13,7 +13,6 @@ using SafeExamBrowser.Contracts.Behaviour;
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour
|
||||
|
@ -21,30 +20,17 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
public class ShutdownController : IShutdownController
|
||||
{
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private IProcessMonitor processMonitor;
|
||||
private ISettings settings;
|
||||
private ISplashScreen splashScreen;
|
||||
private IText text;
|
||||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
public ShutdownController(
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
IProcessMonitor processMonitor,
|
||||
ISettings settings,
|
||||
IText text,
|
||||
IUiElementFactory uiFactory,
|
||||
IWorkingArea workingArea)
|
||||
public ShutdownController(ILogger logger, ISettings settings, IText text, IUiElementFactory uiFactory)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.processMonitor = processMonitor;
|
||||
this.settings = settings;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public void FinalizeApplication(Queue<IOperation> operations)
|
||||
|
@ -86,7 +72,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private void LogAndShowException(Exception e)
|
||||
{
|
||||
logger.Error($"Failed to finalize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
|
||||
uiFactory.Show(text.Get(Key.MessageBox_ShutdownError), text.Get(Key.MessageBox_ShutdownErrorTitle), icon: MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
private void FinalizeApplicationLog(bool success = true)
|
||||
|
@ -95,10 +81,8 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
{
|
||||
logger.Info("--- Application successfully finalized! ---");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,52 +14,26 @@ using SafeExamBrowser.Contracts.Behaviour;
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Core.Behaviour
|
||||
{
|
||||
public class StartupController : IStartupController
|
||||
{
|
||||
private IApplicationController browserController;
|
||||
private IApplicationInfo browserInfo;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private INotificationInfo aboutInfo;
|
||||
private IProcessMonitor processMonitor;
|
||||
private ISettings settings;
|
||||
private ISplashScreen splashScreen;
|
||||
private ITaskbar taskbar;
|
||||
private IText text;
|
||||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
private Stack<IOperation> stack = new Stack<IOperation>();
|
||||
|
||||
public StartupController(
|
||||
IApplicationController browserController,
|
||||
IApplicationInfo browserInfo,
|
||||
ILogger logger,
|
||||
IMessageBox messageBox,
|
||||
INotificationInfo aboutInfo,
|
||||
IProcessMonitor processMonitor,
|
||||
ISettings settings,
|
||||
ITaskbar taskbar,
|
||||
IText text,
|
||||
IUiElementFactory uiFactory,
|
||||
IWorkingArea workingArea)
|
||||
public StartupController(ILogger logger, ISettings settings, IText text, IUiElementFactory uiFactory)
|
||||
{
|
||||
this.browserController = browserController;
|
||||
this.browserInfo = browserInfo;
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
this.aboutInfo = aboutInfo;
|
||||
this.processMonitor = processMonitor;
|
||||
this.settings = settings;
|
||||
this.taskbar = taskbar;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public bool TryInitializeApplication(Queue<IOperation> operations)
|
||||
|
@ -138,7 +112,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private void LogAndShowException(Exception e)
|
||||
{
|
||||
logger.Error($"Failed to initialize application!", e);
|
||||
messageBox.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
|
||||
uiFactory.Show(text.Get(Key.MessageBox_StartupError), text.Get(Key.MessageBox_StartupErrorTitle), icon: MessageBoxIcon.Error);
|
||||
logger.Info("Reverting operations...");
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
|
||||
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
|
||||
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
|
||||
<SplashScreen_InitializeWindowMonitoring>Initializing window monitoring</SplashScreen_InitializeWindowMonitoring>
|
||||
<SplashScreen_InitializeWorkingArea>Initializing working area</SplashScreen_InitializeWorkingArea>
|
||||
<SplashScreen_RestoreWorkingArea>Restoring working area</SplashScreen_RestoreWorkingArea>
|
||||
<SplashScreen_ShutdownProcedure>Initiating shutdown procedure</SplashScreen_ShutdownProcedure>
|
||||
<SplashScreen_StartupProcedure>Initiating startup procedure</SplashScreen_StartupProcedure>
|
||||
<SplashScreen_StopProcessMonitoring>Stopping process monitoring</SplashScreen_StopProcessMonitoring>
|
||||
<SplashScreen_StopWindowMonitoring>Stopping window monitoring</SplashScreen_StopWindowMonitoring>
|
||||
<SplashScreen_WaitExplorerStartup>Waiting for Windows explorer to start up</SplashScreen_WaitExplorerStartup>
|
||||
<SplashScreen_WaitExplorerTermination>Waiting for Windows explorer to shut down</SplashScreen_WaitExplorerTermination>
|
||||
<Version>Version</Version>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<Compile Include="Behaviour\Operations\BrowserInitializationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\ProcessMonitoringOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\TaskbarInitializationOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\WindowMonitoringOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\WorkingAreaOperation.cs" />
|
||||
<Compile Include="Behaviour\ShutdownController.cs" />
|
||||
<Compile Include="Behaviour\StartupController.cs" />
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.WindowsApi;
|
||||
|
@ -16,17 +17,29 @@ namespace SafeExamBrowser.Monitoring.Windows
|
|||
public class WindowMonitor : IWindowMonitor
|
||||
{
|
||||
private ILogger logger;
|
||||
private IList<Window> minimizedWindows = new List<Window>();
|
||||
|
||||
public WindowMonitor(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
|
||||
// TODO: Make operation for window monitor OR operation for all desktop initialization?!
|
||||
// ...
|
||||
}
|
||||
|
||||
public void HideAllWindows()
|
||||
{
|
||||
logger.Info("Saving windows to be minimized...");
|
||||
|
||||
foreach (var handle in User32.GetOpenWindows())
|
||||
{
|
||||
var window = new Window
|
||||
{
|
||||
Handle = handle,
|
||||
Title = User32.GetWindowTitle(handle)
|
||||
};
|
||||
|
||||
minimizedWindows.Add(window);
|
||||
logger.Info($"Saved window '{window.Title}' with handle = {window.Handle}.");
|
||||
}
|
||||
|
||||
logger.Info("Minimizing all open windows...");
|
||||
User32.MinimizeAllOpenWindows();
|
||||
logger.Info("Open windows successfully minimized.");
|
||||
|
@ -34,17 +47,31 @@ namespace SafeExamBrowser.Monitoring.Windows
|
|||
|
||||
public void RestoreHiddenWindows()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
logger.Info("Restoring all minimized windows...");
|
||||
|
||||
foreach (var window in minimizedWindows)
|
||||
{
|
||||
User32.RestoreWindow(window.Handle);
|
||||
logger.Info($"Restored window '{window.Title}' with handle = {window.Handle}.");
|
||||
}
|
||||
|
||||
logger.Info("Minimized windows successfully restored.");
|
||||
}
|
||||
|
||||
public void StartMonitoringWindows()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// TODO
|
||||
}
|
||||
|
||||
public void StopMonitoringWindows()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// TODO
|
||||
}
|
||||
|
||||
private struct Window
|
||||
{
|
||||
internal IntPtr Handle { get; set; }
|
||||
internal string Title { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
<Compile Include="Utilities\IconResourceLoader.cs" />
|
||||
<Compile Include="ViewModels\DateTimeViewModel.cs" />
|
||||
<Compile Include="ViewModels\SplashScreenViewModel.cs" />
|
||||
<Compile Include="WpfMessageBox.cs" />
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen" Cursor="Wait" Icon="./Images/SafeExamBrowser.ico">
|
||||
Title="SplashScreen" Height="200" Width="350" WindowStyle="None" AllowsTransparency="True" WindowStartupLocation="CenterScreen"
|
||||
Cursor="Wait" Icon="./Images/SafeExamBrowser.ico" ResizeMode="NoResize" Topmost="True">
|
||||
<Window.Background>
|
||||
<SolidColorBrush Color="Black" Opacity="0.8" />
|
||||
</Window.Background>
|
||||
<Border BorderBrush="CadetBlue" BorderThickness="1">
|
||||
<Border BorderBrush="DodgerBlue" BorderThickness="1">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
|
|
|
@ -10,26 +10,28 @@
|
|||
<Window.Background>
|
||||
<SolidColorBrush Color="Black" Opacity="0.8" />
|
||||
</Window.Background>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="40" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" PreviewMouseWheel="ApplicationScrollViewer_PreviewMouseWheel">
|
||||
<ScrollViewer.Resources>
|
||||
<s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
|
||||
</ScrollViewer.Resources>
|
||||
<StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Auto">
|
||||
<ScrollViewer.Resources>
|
||||
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
||||
</ScrollViewer.Resources>
|
||||
<WrapPanel x:Name="NotificationWrapPanel" Margin="10,2,5,2" MaxWidth="100" VerticalAlignment="Center" />
|
||||
</ScrollViewer>
|
||||
<local:DateTimeControl Grid.Column="2" />
|
||||
<local:QuitButton Grid.Column="3" />
|
||||
</Grid>
|
||||
<Border BorderBrush="White" BorderThickness="0,0.5,0,0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="40" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" PreviewMouseWheel="ApplicationScrollViewer_PreviewMouseWheel">
|
||||
<ScrollViewer.Resources>
|
||||
<s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
|
||||
</ScrollViewer.Resources>
|
||||
<StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Grid.Column="1" VerticalScrollBarVisibility="Auto">
|
||||
<ScrollViewer.Resources>
|
||||
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
||||
</ScrollViewer.Resources>
|
||||
<WrapPanel x:Name="NotificationWrapPanel" Margin="10,2,5,2" MaxWidth="100" VerticalAlignment="Center" />
|
||||
</ScrollViewer>
|
||||
<local:DateTimeControl Grid.Column="2" />
|
||||
<local:QuitButton Grid.Column="3" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
@ -21,6 +22,16 @@ namespace SafeExamBrowser.UserInterface
|
|||
return new ApplicationButton(info);
|
||||
}
|
||||
|
||||
public void Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
|
||||
{
|
||||
MessageBox.Show(message, title, ToButton(action), ToImage(icon));
|
||||
}
|
||||
|
||||
public ITaskbarNotification CreateNotification(INotificationInfo info)
|
||||
{
|
||||
return new NotificationIcon(info);
|
||||
}
|
||||
|
||||
public ISplashScreen CreateSplashScreen(ISettings settings, IText text)
|
||||
{
|
||||
SplashScreen splashScreen = null;
|
||||
|
@ -46,9 +57,26 @@ namespace SafeExamBrowser.UserInterface
|
|||
return splashScreen;
|
||||
}
|
||||
|
||||
public ITaskbarNotification CreateNotification(INotificationInfo info)
|
||||
private MessageBoxButton ToButton(MessageBoxAction action)
|
||||
{
|
||||
return new NotificationIcon(info);
|
||||
switch (action)
|
||||
{
|
||||
default:
|
||||
return MessageBoxButton.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private MessageBoxImage ToImage(MessageBoxIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxIcon.Warning:
|
||||
return MessageBoxImage.Warning;
|
||||
case MessageBoxIcon.Error:
|
||||
return MessageBoxImage.Error;
|
||||
default:
|
||||
return MessageBoxImage.Information;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2017 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 SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface
|
||||
{
|
||||
public class WpfMessageBox : IMessageBox
|
||||
{
|
||||
public void Show(string message, string title, MessageBoxAction action = MessageBoxAction.Confirm, MessageBoxIcon icon = MessageBoxIcon.Information)
|
||||
{
|
||||
MessageBox.Show(message, title, ToButton(action), ToImage(icon));
|
||||
}
|
||||
|
||||
private MessageBoxButton ToButton(MessageBoxAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
default:
|
||||
return MessageBoxButton.OK;
|
||||
}
|
||||
}
|
||||
|
||||
private MessageBoxImage ToImage(MessageBoxIcon icon)
|
||||
{
|
||||
switch (icon)
|
||||
{
|
||||
case MessageBoxIcon.Warning:
|
||||
return MessageBoxImage.Warning;
|
||||
case MessageBoxIcon.Error:
|
||||
return MessageBoxImage.Error;
|
||||
default:
|
||||
return MessageBoxImage.Information;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,10 @@ namespace SafeExamBrowser.WindowsApi.Constants
|
|||
static class Constant
|
||||
{
|
||||
internal const int WM_COMMAND = 0x111;
|
||||
|
||||
/// <summary>
|
||||
/// Minimize all open windows.
|
||||
/// </summary>
|
||||
internal const int MIN_ALL = 419;
|
||||
}
|
||||
}
|
||||
|
|
97
SafeExamBrowser.WindowsApi/Constants/ShowWindowCommand.cs
Normal file
97
SafeExamBrowser.WindowsApi/Constants/ShowWindowCommand.cs
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2017 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/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Constants
|
||||
{
|
||||
/// <remarks>
|
||||
/// See http://www.pinvoke.net/default.aspx/Enums/ShowWindowCommand.html.
|
||||
/// </remarks>
|
||||
internal enum ShowWindowCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Hides the window and activates another window.
|
||||
/// </summary>
|
||||
Hide = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Activates and displays a window. If the window is minimized or
|
||||
/// maximized, the system restores it to its original size and position.
|
||||
/// An application should specify this flag when displaying the window
|
||||
/// for the first time.
|
||||
/// </summary>
|
||||
Normal = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it as a minimized window.
|
||||
/// </summary>
|
||||
ShowMinimized = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Maximizes the specified window.
|
||||
/// </summary>
|
||||
Maximize = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it as a maximized window.
|
||||
/// </summary>
|
||||
ShowMaximized = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Displays a window in its most recent size and position. This value
|
||||
/// is similar to <see cref="Win32.ShowWindowCommand.Normal"/>, except
|
||||
/// the window is not activated.
|
||||
/// </summary>
|
||||
ShowNoActivate = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Activates the window and displays it in its current size and position.
|
||||
/// </summary>
|
||||
Show = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Minimizes the specified window and activates the next top-level
|
||||
/// window in the Z order.
|
||||
/// </summary>
|
||||
Minimize = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window as a minimized window. This value is similar to
|
||||
/// <see cref="Win32.ShowWindowCommand.ShowMinimized"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowMinNoActive = 7,
|
||||
|
||||
/// <summary>
|
||||
/// Displays the window in its current size and position. This value is
|
||||
/// similar to <see cref="Win32.ShowWindowCommand.Show"/>, except the
|
||||
/// window is not activated.
|
||||
/// </summary>
|
||||
ShowNA = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Activates and displays the window. If the window is minimized or
|
||||
/// maximized, the system restores it to its original size and position.
|
||||
/// An application should specify this flag when restoring a minimized window.
|
||||
/// </summary>
|
||||
Restore = 9,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the show state based on the SW_* value specified in the
|
||||
/// STARTUPINFO structure passed to the CreateProcess function by the
|
||||
/// program that started the application.
|
||||
/// </summary>
|
||||
ShowDefault = 10,
|
||||
|
||||
/// <summary>
|
||||
/// <b>Windows 2000/XP:</b> Minimizes a window, even if the thread
|
||||
/// that owns the window is not responding. This flag should only be
|
||||
/// used when minimizing windows from a different thread.
|
||||
/// </summary>
|
||||
ForceMinimize = 11
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Constants\Constant.cs" />
|
||||
<Compile Include="Constants\ShowWindowCommand.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Constants\SPI.cs" />
|
||||
<Compile Include="Constants\SPIF.cs" />
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
|
@ -19,6 +21,30 @@ namespace SafeExamBrowser.WindowsApi
|
|||
/// </summary>
|
||||
public static class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
|
||||
/// </summary>
|
||||
public static IEnumerable<IntPtr> GetOpenWindows()
|
||||
{
|
||||
var windows = new List<IntPtr>();
|
||||
var success = EnumWindows(delegate (IntPtr hWnd, IntPtr lParam)
|
||||
{
|
||||
if (hWnd != GetShellWindowHandle() && IsWindowVisible(hWnd) && GetWindowTextLength(hWnd) > 0)
|
||||
{
|
||||
windows.Add(hWnd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}, IntPtr.Zero);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
return windows;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a window handle to the Windows taskbar. Returns <c>IntPtr.Zero</c>
|
||||
/// if the taskbar could not be found (i.e. if it isn't running).
|
||||
|
@ -32,7 +58,6 @@ namespace SafeExamBrowser.WindowsApi
|
|||
/// Retrieves the process ID of the main Windows explorer instance controlling
|
||||
/// desktop and taskbar or <c>0</c>, if the process isn't running.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static uint GetShellProcessId()
|
||||
{
|
||||
var handle = GetShellWindowHandle();
|
||||
|
@ -41,6 +66,26 @@ namespace SafeExamBrowser.WindowsApi
|
|||
return processId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the title of the specified window, or an empty string, if the
|
||||
/// given window does not have a title.
|
||||
/// </summary>
|
||||
public static string GetWindowTitle(IntPtr window)
|
||||
{
|
||||
var length = GetWindowTextLength(window);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
var builder = new StringBuilder(length);
|
||||
|
||||
GetWindowText(window, builder, length + 1);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the currently configured working area of the primary screen.
|
||||
/// </summary>
|
||||
|
@ -91,6 +136,14 @@ namespace SafeExamBrowser.WindowsApi
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the specified window to its original size and position.
|
||||
/// </summary>
|
||||
public static void RestoreWindow(IntPtr window)
|
||||
{
|
||||
ShowWindow(window, (int) ShowWindowCommand.Restore);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the working area of the primary screen according to the given dimensions.
|
||||
/// </summary>
|
||||
|
@ -107,21 +160,40 @@ namespace SafeExamBrowser.WindowsApi
|
|||
}
|
||||
}
|
||||
|
||||
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", EntryPoint = "SendMessage")]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
private static extern bool IsWindowVisible(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SendMessage")]
|
||||
private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ namespace SafeExamBrowser
|
|||
private IApplicationController browserController;
|
||||
private IApplicationInfo browserInfo;
|
||||
private ILogger logger;
|
||||
private IMessageBox messageBox;
|
||||
private INotificationInfo aboutInfo;
|
||||
private IProcessMonitor processMonitor;
|
||||
private ISettings settings;
|
||||
|
@ -50,7 +49,6 @@ namespace SafeExamBrowser
|
|||
browserController = new BrowserApplicationController();
|
||||
browserInfo = new BrowserApplicationInfo();
|
||||
logger = new Logger();
|
||||
messageBox = new WpfMessageBox();
|
||||
settings = new Settings();
|
||||
Taskbar = new Taskbar();
|
||||
textResource = new XmlTextResource();
|
||||
|
@ -63,10 +61,11 @@ namespace SafeExamBrowser
|
|||
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)));
|
||||
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)));
|
||||
workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea)));
|
||||
ShutdownController = new ShutdownController(logger, messageBox, processMonitor, settings, text, uiFactory, workingArea);
|
||||
StartupController = new StartupController(browserController, browserInfo, logger, messageBox, aboutInfo, processMonitor, settings, Taskbar, text, uiFactory, workingArea);
|
||||
ShutdownController = new ShutdownController(logger, settings, text, uiFactory);
|
||||
StartupController = new StartupController(logger, settings, text, uiFactory);
|
||||
|
||||
StartupOperations = new Queue<IOperation>();
|
||||
StartupOperations.Enqueue(new WindowMonitoringOperation(logger, windowMonitor));
|
||||
StartupOperations.Enqueue(new ProcessMonitoringOperation(logger, processMonitor));
|
||||
StartupOperations.Enqueue(new WorkingAreaOperation(logger, Taskbar, workingArea));
|
||||
StartupOperations.Enqueue(new TaskbarInitializationOperation(logger, aboutInfo, Taskbar, uiFactory));
|
||||
|
|
Loading…
Reference in a new issue