Implemented basic handling of working area.
This commit is contained in:
parent
a35fe0811f
commit
eb6fbf49b8
33 changed files with 678 additions and 152 deletions
|
@ -9,7 +9,7 @@
|
|||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Core.Configuration
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class AboutNotificationIconResource : IIconResource
|
||||
{
|
|
@ -9,7 +9,7 @@
|
|||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
||||
namespace SafeExamBrowser.Core.Configuration
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class AboutNotificationInfo : INotificationInfo
|
||||
{
|
36
SafeExamBrowser.Configuration/Properties/AssemblyInfo.cs
Normal file
36
SafeExamBrowser.Configuration/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.Configuration")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.Configuration")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c388c4dd-a159-457d-af92-89f7ad185109")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C388C4DD-A159-457D-AF92-89F7AD185109}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.Configuration</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.Configuration</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AboutNotificationIconResource.cs" />
|
||||
<Compile Include="AboutNotificationInfo.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="WorkingArea.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Contracts\SafeExamBrowser.Contracts.csproj">
|
||||
<Project>{47DA5933-BEF8-4729-94E6-ABDE2DB12262}</Project>
|
||||
<Name>SafeExamBrowser.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.WindowsApi\SafeExamBrowser.WindowsApi.csproj">
|
||||
<Project>{73724659-4150-4792-a94e-42f5f3c1b696}</Project>
|
||||
<Name>SafeExamBrowser.WindowsApi</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -11,7 +11,7 @@ using System.IO;
|
|||
using System.Reflection;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Core.Configuration
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class Settings : ISettings
|
||||
{
|
61
SafeExamBrowser.Configuration/WorkingArea.cs
Normal file
61
SafeExamBrowser.Configuration/WorkingArea.cs
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.Forms;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.WindowsApi;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
public class WorkingArea : IWorkingArea
|
||||
{
|
||||
private ILogger logger;
|
||||
private RECT? initial;
|
||||
|
||||
public WorkingArea(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void InitializeFor(ITaskbar taskbar)
|
||||
{
|
||||
initial = User32.GetWorkingArea();
|
||||
|
||||
LogWorkingArea("Saved initial working area", initial.Value);
|
||||
|
||||
var area = new RECT
|
||||
{
|
||||
Left = 0,
|
||||
Top = 0,
|
||||
Right = Screen.PrimaryScreen.Bounds.Width,
|
||||
Bottom = Screen.PrimaryScreen.Bounds.Height - taskbar.GetAbsoluteHeight()
|
||||
};
|
||||
|
||||
LogWorkingArea("Setting new working area", area);
|
||||
User32.SetWorkingArea(area);
|
||||
LogWorkingArea("Working area is now set to", User32.GetWorkingArea());
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (initial.HasValue)
|
||||
{
|
||||
User32.SetWorkingArea(initial.Value);
|
||||
LogWorkingArea("Restored initial working area", initial.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogWorkingArea(string message, RECT area)
|
||||
{
|
||||
logger.Info($"{message}: Left = {area.Left}, Top = {area.Top}, Right = {area.Right}, Bottom = {area.Bottom}.");
|
||||
}
|
||||
}
|
||||
}
|
25
SafeExamBrowser.Contracts/Configuration/IWorkingArea.cs
Normal file
25
SafeExamBrowser.Contracts/Configuration/IWorkingArea.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
public interface IWorkingArea
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the Windows working area to accommodate to the taskbar's dimensions.
|
||||
/// </summary>
|
||||
void InitializeFor(ITaskbar taskbar);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the Windows working area to its previous (initial) state.
|
||||
/// </summary>
|
||||
void Reset();
|
||||
}
|
||||
}
|
|
@ -23,8 +23,8 @@ namespace SafeExamBrowser.Contracts.I18n
|
|||
SplashScreen_InitializeBrowser,
|
||||
SplashScreen_InitializeProcessMonitoring,
|
||||
SplashScreen_InitializeTaskbar,
|
||||
SplashScreen_InitializeWorkArea,
|
||||
SplashScreen_RestoreWorkArea,
|
||||
SplashScreen_InitializeWorkingArea,
|
||||
SplashScreen_RestoreWorkingArea,
|
||||
SplashScreen_ShutdownProcedure,
|
||||
SplashScreen_StartupProcedure,
|
||||
SplashScreen_StopProcessMonitoring,
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
<Compile Include="Configuration\ISettings.cs" />
|
||||
<Compile Include="Behaviour\IShutdownController.cs" />
|
||||
<Compile Include="Behaviour\IStartupController.cs" />
|
||||
<Compile Include="Configuration\IWorkingArea.cs" />
|
||||
<Compile Include="I18n\IText.cs" />
|
||||
<Compile Include="I18n\Key.cs" />
|
||||
<Compile Include="Logging\ILogContent.cs" />
|
||||
|
|
|
@ -27,24 +27,15 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
/// </summary>
|
||||
void SetMaxProgress(int max);
|
||||
|
||||
/// <summary>
|
||||
/// Starts an animation indicating the user that something is going on.
|
||||
/// </summary>
|
||||
void StartBusyIndication();
|
||||
|
||||
/// <summary>
|
||||
/// Stops the busy animation, if it was running.
|
||||
/// </summary>
|
||||
void StopBusyIndication();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the progress bar of the splash screen according to the specified amount.
|
||||
/// </summary>
|
||||
void UpdateProgress(int amount = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the status text of the splash screen.
|
||||
/// Updates the status text of the splash screen. If the busy flag is set,
|
||||
/// the splash screen will show an animation to indicate a long-running operation.
|
||||
/// </summary>
|
||||
void UpdateText(Key key);
|
||||
void UpdateText(Key key, bool showBusyIndication = false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,8 @@ namespace SafeExamBrowser.Contracts.UserInterface
|
|||
void AddNotification(ITaskbarNotification button);
|
||||
|
||||
/// <summary>
|
||||
/// Moves the taskbar to the given location on the screen.
|
||||
/// Returns the absolute height of the taskbar (i.e. in physical pixels).
|
||||
/// </summary>
|
||||
void SetPosition(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the size of the taskbar.
|
||||
/// </summary>
|
||||
void SetSize(int width, int height);
|
||||
int GetAbsoluteHeight();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,13 +28,14 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private ISplashScreen splashScreen;
|
||||
private IText text;
|
||||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
private IEnumerable<Action> ShutdownOperations
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return StopProcessMonitoring;
|
||||
yield return RestoreWorkArea;
|
||||
yield return RestoreWorkingArea;
|
||||
yield return FinalizeApplicationLog;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +46,8 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
IProcessMonitor processMonitor,
|
||||
ISettings settings,
|
||||
IText text,
|
||||
IUiElementFactory uiFactory)
|
||||
IUiElementFactory uiFactory,
|
||||
IWorkingArea workingArea)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.messageBox = messageBox;
|
||||
|
@ -53,6 +55,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
this.settings = settings;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public void FinalizeApplication()
|
||||
|
@ -83,11 +86,12 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
splashScreen.SetMaxProgress(ShutdownOperations.Count());
|
||||
splashScreen.UpdateText(Key.SplashScreen_ShutdownProcedure);
|
||||
splashScreen.InvokeShow();
|
||||
logger.Info("--- Initiating shutdown procedure ---");
|
||||
}
|
||||
|
||||
private void StopProcessMonitoring()
|
||||
{
|
||||
logger.Info("Stopping process monitoring.");
|
||||
logger.Info("--- Stopping process monitoring ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_StopProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
|
@ -95,21 +99,22 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
processMonitor.StopMonitoringExplorer();
|
||||
}
|
||||
|
||||
private void RestoreWorkArea()
|
||||
private void RestoreWorkingArea()
|
||||
{
|
||||
logger.Info("Restoring work area.");
|
||||
splashScreen.UpdateText(Key.SplashScreen_RestoreWorkArea);
|
||||
logger.Info("--- Restoring working area ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_RestoreWorkingArea);
|
||||
|
||||
// TODO
|
||||
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup);
|
||||
splashScreen.StartBusyIndication();
|
||||
workingArea.Reset();
|
||||
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerStartup, true);
|
||||
processMonitor.StartExplorerShell();
|
||||
splashScreen.StopBusyIndication();
|
||||
}
|
||||
|
||||
private void FinalizeApplicationLog()
|
||||
{
|
||||
logger.Info("--- Application successfully finalized! ---");
|
||||
logger.Log($"{Environment.NewLine}# Application terminated at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
private ITaskbar taskbar;
|
||||
private IText text;
|
||||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
private IEnumerable<Action> StartupOperations
|
||||
{
|
||||
|
@ -42,7 +43,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
yield return EstablishWcfServiceConnection;
|
||||
yield return DeactivateWindowsFeatures;
|
||||
yield return InitializeProcessMonitoring;
|
||||
yield return InitializeWorkArea;
|
||||
yield return InitializeWorkingArea;
|
||||
yield return InitializeTaskbar;
|
||||
yield return InitializeBrowser;
|
||||
yield return FinishInitialization;
|
||||
|
@ -59,7 +60,8 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
ISettings settings,
|
||||
ITaskbar taskbar,
|
||||
IText text,
|
||||
IUiElementFactory uiFactory)
|
||||
IUiElementFactory uiFactory,
|
||||
IWorkingArea workingArea)
|
||||
{
|
||||
this.browserController = browserController;
|
||||
this.browserInfo = browserInfo;
|
||||
|
@ -71,6 +73,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
this.taskbar = taskbar;
|
||||
this.text = text;
|
||||
this.uiFactory = uiFactory;
|
||||
this.workingArea = workingArea;
|
||||
}
|
||||
|
||||
public bool TryInitializeApplication()
|
||||
|
@ -109,7 +112,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
|
||||
logger.Log($"{titleLine}{copyrightLine}{emptyLine}{githubLine}");
|
||||
logger.Log($"{Environment.NewLine}# Application started at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}{Environment.NewLine}");
|
||||
logger.Info("Initiating startup procedure.");
|
||||
logger.Info("--- Initiating startup procedure ---");
|
||||
}
|
||||
|
||||
private void InitializeSplashScreen()
|
||||
|
@ -142,7 +145,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
|
||||
private void InitializeProcessMonitoring()
|
||||
{
|
||||
logger.Info("Initializing process monitoring.");
|
||||
logger.Info("--- Initializing process monitoring ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeProcessMonitoring);
|
||||
|
||||
// TODO
|
||||
|
@ -150,24 +153,23 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
processMonitor.StartMonitoringExplorer();
|
||||
}
|
||||
|
||||
private void InitializeWorkArea()
|
||||
private void InitializeWorkingArea()
|
||||
{
|
||||
logger.Info("Initializing work area.");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeWorkArea);
|
||||
logger.Info("--- Initializing working area ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination, true);
|
||||
processMonitor.CloseExplorerShell();
|
||||
|
||||
// TODO
|
||||
// - Minimizing all open windows
|
||||
// - Emptying clipboard
|
||||
|
||||
splashScreen.UpdateText(Key.SplashScreen_WaitExplorerTermination);
|
||||
splashScreen.StartBusyIndication();
|
||||
processMonitor.CloseExplorerShell();
|
||||
splashScreen.StopBusyIndication();
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeWorkingArea);
|
||||
workingArea.InitializeFor(taskbar);
|
||||
}
|
||||
|
||||
private void InitializeTaskbar()
|
||||
{
|
||||
logger.Info("Initializing taskbar.");
|
||||
logger.Info("--- Initializing taskbar ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeTaskbar);
|
||||
|
||||
// TODO
|
||||
|
@ -179,7 +181,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
|
||||
private void InitializeBrowser()
|
||||
{
|
||||
logger.Info("Initializing browser.");
|
||||
logger.Info("--- Initializing browser ---");
|
||||
splashScreen.UpdateText(Key.SplashScreen_InitializeBrowser);
|
||||
|
||||
// TODO
|
||||
|
@ -192,7 +194,7 @@ namespace SafeExamBrowser.Core.Behaviour
|
|||
|
||||
private void FinishInitialization()
|
||||
{
|
||||
logger.Info("Application successfully initialized!");
|
||||
logger.Info("--- Application successfully initialized! ---");
|
||||
splashScreen.InvokeClose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<SplashScreen_InitializeBrowser>Initializing browser</SplashScreen_InitializeBrowser>
|
||||
<SplashScreen_InitializeProcessMonitoring>Initializing process monitoring</SplashScreen_InitializeProcessMonitoring>
|
||||
<SplashScreen_InitializeTaskbar>Initializing taskbar</SplashScreen_InitializeTaskbar>
|
||||
<SplashScreen_InitializeWorkArea>Initializing work area</SplashScreen_InitializeWorkArea>
|
||||
<SplashScreen_RestoreWorkArea>Restoring work area</SplashScreen_RestoreWorkArea>
|
||||
<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>
|
||||
|
|
80
SafeExamBrowser.Core/Logging/ModuleLogger.cs
Normal file
80
SafeExamBrowser.Core/Logging/ModuleLogger.cs
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Core.Logging
|
||||
{
|
||||
public class ModuleLogger : ILogger
|
||||
{
|
||||
private ILogger logger;
|
||||
private Type module;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a wrapper around an <c>ILogger</c> that includes information
|
||||
/// about the specified module when logging messages with a severity.
|
||||
/// </summary>
|
||||
public ModuleLogger(ILogger logger, Type module)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void Error(string message)
|
||||
{
|
||||
logger.Error(AppendModuleInfo(message));
|
||||
}
|
||||
|
||||
public void Error(string message, Exception exception)
|
||||
{
|
||||
logger.Error(AppendModuleInfo(message), exception);
|
||||
}
|
||||
|
||||
public IList<ILogContent> GetLog()
|
||||
{
|
||||
return logger.GetLog();
|
||||
}
|
||||
|
||||
public void Info(string message)
|
||||
{
|
||||
logger.Info(AppendModuleInfo(message));
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
logger.Log(message);
|
||||
}
|
||||
|
||||
public void Log(ILogContent content)
|
||||
{
|
||||
logger.Log(content);
|
||||
}
|
||||
|
||||
public void Subscribe(ILogObserver observer)
|
||||
{
|
||||
logger.Subscribe(observer);
|
||||
}
|
||||
|
||||
public void Unsubscribe(ILogObserver observer)
|
||||
{
|
||||
logger.Unsubscribe(observer);
|
||||
}
|
||||
|
||||
public void Warn(string message)
|
||||
{
|
||||
logger.Warn(AppendModuleInfo(message));
|
||||
}
|
||||
|
||||
private string AppendModuleInfo(string message)
|
||||
{
|
||||
return $"[{module.Name}] {message}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,9 +40,6 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration\AboutNotificationIconResource.cs" />
|
||||
<Compile Include="Configuration\AboutNotificationInfo.cs" />
|
||||
<Compile Include="Configuration\Settings.cs" />
|
||||
<Compile Include="Behaviour\ShutdownController.cs" />
|
||||
<Compile Include="Behaviour\StartupController.cs" />
|
||||
<Compile Include="Logging\LogFileWriter.cs" />
|
||||
|
@ -51,6 +48,7 @@
|
|||
<Compile Include="I18n\XmlTextResource.cs" />
|
||||
<Compile Include="Logging\Logger.cs" />
|
||||
<Compile Include="Logging\LogText.cs" />
|
||||
<Compile Include="Logging\ModuleLogger.cs" />
|
||||
<Compile Include="Logging\ThreadInfo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -13,6 +13,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Monitoring.Processes
|
||||
{
|
||||
|
@ -28,9 +29,9 @@ namespace SafeExamBrowser.Monitoring.Processes
|
|||
public void StartExplorerShell()
|
||||
{
|
||||
var process = new Process();
|
||||
var explorerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "explorer.exe");
|
||||
var explorerPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "explorer.exe");
|
||||
|
||||
Log("Restarting explorer shell...");
|
||||
logger.Info("Restarting explorer shell...");
|
||||
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.StartInfo.FileName = explorerPath;
|
||||
|
@ -42,7 +43,7 @@ namespace SafeExamBrowser.Monitoring.Processes
|
|||
}
|
||||
|
||||
process.Refresh();
|
||||
Log($"Explorer shell successfully started with PID = {process.Id}.");
|
||||
logger.Info($"Explorer shell successfully started with PID = {process.Id}.");
|
||||
process.Close();
|
||||
}
|
||||
|
||||
|
@ -64,7 +65,7 @@ namespace SafeExamBrowser.Monitoring.Processes
|
|||
|
||||
if (shellProcess != null)
|
||||
{
|
||||
Log($"Found explorer shell processes with PID = {processId}. Sending close message...");
|
||||
logger.Info($"Found explorer shell processes with PID = {processId}. Sending close message...");
|
||||
User32.PostCloseMessageToShell();
|
||||
|
||||
while (!shellProcess.HasExited)
|
||||
|
@ -73,17 +74,12 @@ namespace SafeExamBrowser.Monitoring.Processes
|
|||
Thread.Sleep(20);
|
||||
}
|
||||
|
||||
Log($"Successfully terminated explorer shell process with PID = {processId}.");
|
||||
logger.Info($"Successfully terminated explorer shell process with PID = {processId}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("The explorer shell seems to already be terminated. Skipping this step...");
|
||||
logger.Info("The explorer shell seems to already be terminated. Skipping this step...");
|
||||
}
|
||||
}
|
||||
|
||||
private void Log(string message)
|
||||
{
|
||||
logger.Info($"[{nameof(ProcessMonitor)}] {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,13 +42,16 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Processes\ProcessMonitor.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="User32.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Contracts\SafeExamBrowser.Contracts.csproj">
|
||||
<Project>{47da5933-bef8-4729-94e6-abde2db12262}</Project>
|
||||
<Name>SafeExamBrowser.Contracts</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.WindowsApi\SafeExamBrowser.WindowsApi.csproj">
|
||||
<Project>{73724659-4150-4792-a94e-42f5f3c1b696}</Project>
|
||||
<Name>SafeExamBrowser.WindowsApi</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Keyboard\" />
|
||||
|
|
|
@ -1,58 +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;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SafeExamBrowser.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the native Windows API exposed by <c>user32.dll</c>.
|
||||
/// </summary>
|
||||
internal static class User32
|
||||
{
|
||||
internal static IntPtr GetShellWindowHandle()
|
||||
{
|
||||
return FindWindow("Shell_TrayWnd", null);
|
||||
}
|
||||
|
||||
internal static uint GetShellProcessId()
|
||||
{
|
||||
var handle = FindWindow("Shell_TrayWnd", null);
|
||||
var threadId = GetWindowThreadProcessId(handle, out uint processId);
|
||||
|
||||
return processId;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The close message <c>0x5B4</c> posted to the shell is undocumented and not officially supported:
|
||||
/// https://stackoverflow.com/questions/5689904/gracefully-exit-explorer-programmatically/5705965#5705965
|
||||
/// </remarks>
|
||||
internal static void PostCloseMessageToShell()
|
||||
{
|
||||
var taskbarHandle = FindWindow("Shell_TrayWnd", null);
|
||||
var success = PostMessage(taskbarHandle, 0x5B4, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
}
|
||||
}
|
|
@ -27,10 +27,10 @@
|
|||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#10FFFFFF" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#2AFFFFFF" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#2AFFFFFF" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#10FFFFFF" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#10FFFFFF" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#2AFFFFFF" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#2AFFFFFF" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#10FFFFFF" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#40FF0000" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#50FF0000" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#60FF0000" />
|
||||
<Setter TargetName="ButtonContent" Property="Background" Value="#40FF0000" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
|
|
@ -45,24 +45,20 @@ namespace SafeExamBrowser.UserInterface
|
|||
model.MaxProgress = max;
|
||||
}
|
||||
|
||||
public void StartBusyIndication()
|
||||
{
|
||||
model.StartBusyIndication();
|
||||
}
|
||||
|
||||
public void StopBusyIndication()
|
||||
{
|
||||
model.StopBusyIndication();
|
||||
}
|
||||
|
||||
public void UpdateProgress(int amount = 1)
|
||||
{
|
||||
model.CurrentProgress += amount;
|
||||
}
|
||||
|
||||
public void UpdateText(Key key)
|
||||
public void UpdateText(Key key, bool showBusyIndication = false)
|
||||
{
|
||||
model.StopBusyIndication();
|
||||
model.Status = text.Get(key);
|
||||
|
||||
if (showBusyIndication)
|
||||
{
|
||||
model.StartBusyIndication();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeSplashScreen()
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface
|
||||
|
@ -17,6 +19,15 @@ namespace SafeExamBrowser.UserInterface
|
|||
public Taskbar()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Loaded += Taskbar_Loaded;
|
||||
}
|
||||
|
||||
private void Taskbar_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Width = SystemParameters.WorkArea.Right;
|
||||
Left = SystemParameters.WorkArea.Right - Width;
|
||||
Top = SystemParameters.WorkArea.Bottom;
|
||||
}
|
||||
|
||||
public void AddButton(ITaskbarButton button)
|
||||
|
@ -35,16 +46,28 @@ namespace SafeExamBrowser.UserInterface
|
|||
}
|
||||
}
|
||||
|
||||
public void SetPosition(int x, int y)
|
||||
public int GetAbsoluteHeight()
|
||||
{
|
||||
Left = x;
|
||||
Top = y;
|
||||
}
|
||||
// WPF works with device-independent pixels. The following code is required
|
||||
// to get the real height of the taskbar (in absolute, device-specific pixels).
|
||||
// Source: https://stackoverflow.com/questions/3286175/how-do-i-convert-a-wpf-size-to-physical-pixels
|
||||
|
||||
public void SetSize(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
Matrix transformToDevice;
|
||||
var source = PresentationSource.FromVisual(this);
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
transformToDevice = source.CompositionTarget.TransformToDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var newSource = new HwndSource(new HwndSourceParameters()))
|
||||
{
|
||||
transformToDevice = newSource.CompositionTarget.TransformToDevice;
|
||||
}
|
||||
}
|
||||
|
||||
return (int) transformToDevice.Transform((Vector) new Size(Width, Height)).Y;
|
||||
}
|
||||
|
||||
private void ApplicationScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
|
||||
|
|
32
SafeExamBrowser.WindowsApi/Constants/SPI.cs
Normal file
32
SafeExamBrowser.WindowsApi/Constants/SPI.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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/SPI.html?diff=y.
|
||||
/// </remarks>
|
||||
internal enum SPI : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the size of the work area. The work area is the portion of the screen not obscured by the system taskbar
|
||||
/// or by application desktop toolbars. The pvParam parameter is a pointer to a RECT structure that specifies the
|
||||
/// new work area rectangle, expressed in virtual screen coordinates. In a system with multiple display monitors,
|
||||
/// the function sets the work area of the monitor that contains the specified rectangle.
|
||||
/// </summary>
|
||||
SETWORKAREA = 0x002F,
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the size of the work area on the primary display monitor. The work area is the portion of the screen
|
||||
/// not obscured by the system taskbar or by application desktop toolbars. The pvParam parameter must point to a
|
||||
/// RECT structure that receives the coordinates of the work area, expressed in virtual screen coordinates. To get
|
||||
/// the work area of a monitor other than the primary display monitor, call the GetMonitorInfo function.
|
||||
/// </summary>
|
||||
GETWORKAREA = 0x0030,
|
||||
}
|
||||
}
|
36
SafeExamBrowser.WindowsApi/Constants/SPIF.cs
Normal file
36
SafeExamBrowser.WindowsApi/Constants/SPIF.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Constants
|
||||
{
|
||||
/// <remarks>
|
||||
/// See http://www.pinvoke.net/default.aspx/Enums/SPIF.html.
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
internal enum SPIF
|
||||
{
|
||||
NONE = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// Writes the new system-wide parameter setting to the user profile.
|
||||
/// </summary>
|
||||
UPDATEINIFILE = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Broadcasts the WM_SETTINGCHANGE message after updating the user profile.
|
||||
/// </summary>
|
||||
SENDCHANGE = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Performs UPDATEINIFILE and SENDCHANGE.
|
||||
/// </summary>
|
||||
UPDATEANDCHANGE = 0x03
|
||||
}
|
||||
}
|
36
SafeExamBrowser.WindowsApi/Properties/AssemblyInfo.cs
Normal file
36
SafeExamBrowser.WindowsApi/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("SafeExamBrowser.WindowsApi")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SafeExamBrowser.WindowsApi")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("73724659-4150-4792-a94e-42f5f3c1b696")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
50
SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
Normal file
50
SafeExamBrowser.WindowsApi/SafeExamBrowser.WindowsApi.csproj
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{73724659-4150-4792-A94E-42F5F3C1B696}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SafeExamBrowser.WindowsApi</RootNamespace>
|
||||
<AssemblyName>SafeExamBrowser.WindowsApi</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Constants\SPI.cs" />
|
||||
<Compile Include="Constants\SPIF.cs" />
|
||||
<Compile Include="Types\RECT.cs" />
|
||||
<Compile Include="User32.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
24
SafeExamBrowser.WindowsApi/Types/RECT.cs
Normal file
24
SafeExamBrowser.WindowsApi/Types/RECT.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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.Runtime.InteropServices;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd162897(v=vs.85).aspx.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int Left;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
}
|
||||
}
|
114
SafeExamBrowser.WindowsApi/User32.cs
Normal file
114
SafeExamBrowser.WindowsApi/User32.cs
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the native Windows API exposed by <c>user32.dll</c>.
|
||||
/// </summary>
|
||||
public static class User32
|
||||
{
|
||||
/// <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).
|
||||
/// </summary>
|
||||
public static IntPtr GetShellWindowHandle()
|
||||
{
|
||||
return FindWindow("Shell_TrayWnd", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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 = FindWindow("Shell_TrayWnd", null);
|
||||
var threadId = GetWindowThreadProcessId(handle, out uint processId);
|
||||
|
||||
return processId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the currently configured working area of the primary screen.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ComponentModel.Win32Exception">
|
||||
/// If the working area could not be retrieved.
|
||||
/// </exception>
|
||||
public static RECT GetWorkingArea()
|
||||
{
|
||||
var workingArea = new RECT();
|
||||
var success = SystemParametersInfo(SPI.GETWORKAREA, 0, ref workingArea, SPIF.NONE);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
return workingArea;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the main Windows explorer process to shut down.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ComponentModel.Win32Exception">
|
||||
/// If the messge could not be successfully posted. Does not apply if the process isn't running!
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// The close message <c>0x5B4</c> posted to the shell is undocumented and not officially supported:
|
||||
/// https://stackoverflow.com/questions/5689904/gracefully-exit-explorer-programmatically/5705965#5705965
|
||||
/// </remarks>
|
||||
public static void PostCloseMessageToShell()
|
||||
{
|
||||
var taskbarHandle = FindWindow("Shell_TrayWnd", null);
|
||||
var success = PostMessage(taskbarHandle, 0x5B4, IntPtr.Zero, IntPtr.Zero);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the working area of the primary screen according to the given dimensions.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ComponentModel.Win32Exception">
|
||||
/// If the working area could not be set.
|
||||
/// </exception>
|
||||
public static void SetWorkingArea(RECT workingArea)
|
||||
{
|
||||
var success = SystemParametersInfo(SPI.SETWORKAREA, 0, ref workingArea, SPIF.UPDATEANDCHANGE);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
|
||||
[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", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Browser", "
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Monitoring", "SafeExamBrowser.Monitoring\SafeExamBrowser.Monitoring.csproj", "{EF563531-4EB5-44B9-A5EC-D6D6F204469B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.Configuration", "SafeExamBrowser.Configuration\SafeExamBrowser.Configuration.csproj", "{C388C4DD-A159-457D-AF92-89F7AD185109}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SafeExamBrowser.WindowsApi", "SafeExamBrowser.WindowsApi\SafeExamBrowser.WindowsApi.csproj", "{73724659-4150-4792-A94E-42F5F3C1B696}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -57,6 +61,14 @@ Global
|
|||
{EF563531-4EB5-44B9-A5EC-D6D6F204469B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF563531-4EB5-44B9-A5EC-D6D6F204469B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF563531-4EB5-44B9-A5EC-D6D6F204469B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C388C4DD-A159-457D-AF92-89F7AD185109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C388C4DD-A159-457D-AF92-89F7AD185109}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C388C4DD-A159-457D-AF92-89F7AD185109}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C388C4DD-A159-457D-AF92-89F7AD185109}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{73724659-4150-4792-A94E-42F5F3C1B696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{73724659-4150-4792-A94E-42F5F3C1B696}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{73724659-4150-4792-A94E-42F5F3C1B696}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{73724659-4150-4792-A94E-42F5F3C1B696}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
using SafeExamBrowser.Browser;
|
||||
using SafeExamBrowser.Configuration;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
|
@ -14,7 +15,6 @@ using SafeExamBrowser.Contracts.Logging;
|
|||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Core.Behaviour;
|
||||
using SafeExamBrowser.Core.Configuration;
|
||||
using SafeExamBrowser.Core.I18n;
|
||||
using SafeExamBrowser.Core.Logging;
|
||||
using SafeExamBrowser.Monitoring.Processes;
|
||||
|
@ -32,8 +32,9 @@ namespace SafeExamBrowser
|
|||
private IProcessMonitor processMonitor;
|
||||
private ISettings settings;
|
||||
private IText text;
|
||||
private IUiElementFactory uiFactory;
|
||||
private ITextResource textResource;
|
||||
private IUiElementFactory uiFactory;
|
||||
private IWorkingArea workingArea;
|
||||
|
||||
public IShutdownController ShutdownController { get; private set; }
|
||||
public IStartupController StartupController { get; private set; }
|
||||
|
@ -54,9 +55,10 @@ namespace SafeExamBrowser
|
|||
|
||||
text = new Text(textResource);
|
||||
aboutInfo = new AboutNotificationInfo(text);
|
||||
processMonitor = new ProcessMonitor(logger);
|
||||
ShutdownController = new ShutdownController(logger, messageBox, processMonitor, settings, text, uiFactory);
|
||||
StartupController = new StartupController(browserController, browserInfo, logger, messageBox, aboutInfo, processMonitor, settings, Taskbar, text, uiFactory);
|
||||
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,10 @@
|
|||
<Project>{04E653F1-98E6-4E34-9DD7-7F2BC1A8B767}</Project>
|
||||
<Name>SafeExamBrowser.Browser</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Configuration\SafeExamBrowser.Configuration.csproj">
|
||||
<Project>{c388c4dd-a159-457d-af92-89f7ad185109}</Project>
|
||||
<Name>SafeExamBrowser.Configuration</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\SafeExamBrowser.Contracts\SafeExamBrowser.Contracts.csproj">
|
||||
<Project>{47DA5933-BEF8-4729-94E6-ABDE2DB12262}</Project>
|
||||
<Name>SafeExamBrowser.Contracts</Name>
|
||||
|
|
Loading…
Reference in a new issue