SEBWIN-219: Finished scaffolding for application startup sequence.
This commit is contained in:
parent
10202a807f
commit
dda1b78ec5
69 changed files with 999 additions and 252 deletions
|
@ -25,7 +25,7 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
private Mock<ITaskbar> taskbarMock;
|
||||
private Mock<IWindowMonitor> windowMonitorMock;
|
||||
|
||||
private IClientController sut;
|
||||
//private IClientController sut;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using System;
|
||||
using SafeExamBrowser.Contracts.Behaviour;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.Monitoring;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||
|
@ -21,6 +22,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
private ILogger logger;
|
||||
private IOperationSequence operations;
|
||||
private IProcessMonitor processMonitor;
|
||||
private IRuntimeProxy runtime;
|
||||
private ITaskbar taskbar;
|
||||
private IWindowMonitor windowMonitor;
|
||||
|
||||
|
@ -29,6 +31,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
ILogger logger,
|
||||
IOperationSequence operations,
|
||||
IProcessMonitor processMonitor,
|
||||
IRuntimeProxy runtime,
|
||||
ITaskbar taskbar,
|
||||
IWindowMonitor windowMonitor)
|
||||
{
|
||||
|
@ -36,6 +39,7 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
this.logger = logger;
|
||||
this.operations = operations;
|
||||
this.processMonitor = processMonitor;
|
||||
this.runtime = runtime;
|
||||
this.taskbar = taskbar;
|
||||
this.windowMonitor = windowMonitor;
|
||||
}
|
||||
|
@ -45,15 +49,29 @@ namespace SafeExamBrowser.Client.Behaviour
|
|||
displayMonitor.DisplayChanged -= DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted -= ProcessMonitor_ExplorerStarted;
|
||||
windowMonitor.WindowChanged -= WindowMonitor_WindowChanged;
|
||||
|
||||
// TODO
|
||||
|
||||
operations.TryRevert();
|
||||
}
|
||||
|
||||
public bool TryStart()
|
||||
{
|
||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||
windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
|
||||
|
||||
return true;
|
||||
// TODO
|
||||
|
||||
var success = operations.TryPerform();
|
||||
|
||||
if (success)
|
||||
{
|
||||
displayMonitor.DisplayChanged += DisplayMonitor_DisplaySettingsChanged;
|
||||
processMonitor.ExplorerStarted += ProcessMonitor_ExplorerStarted;
|
||||
windowMonitor.WindowChanged += WindowMonitor_WindowChanged;
|
||||
|
||||
runtime.InformClientReady();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private void DisplayMonitor_DisplaySettingsChanged()
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
|||
var config = runtime.GetConfiguration();
|
||||
|
||||
configuration.RuntimeInfo = config.RuntimeInfo;
|
||||
configuration.SessionData = config.SessionData;
|
||||
configuration.SessionId = config.SessionId;
|
||||
configuration.Settings = config.Settings;
|
||||
|
||||
logger.Info("Successfully retrieved the application configuration from the runtime.");
|
||||
|
|
|
@ -40,18 +40,20 @@ namespace SafeExamBrowser.Client.Behaviour.Operations
|
|||
try
|
||||
{
|
||||
connected = runtime.Connect(token);
|
||||
|
||||
logger.Info("Successfully connected to the runtime host.");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("An unexpected error occurred while trying to connect to the runtime host!", e);
|
||||
logger.Error("An unexpected error occurred while trying to connect to the runtime!", e);
|
||||
}
|
||||
|
||||
if (!connected)
|
||||
if (connected)
|
||||
{
|
||||
logger.Info("Successfully connected to the runtime.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Abort = true;
|
||||
logger.Info("Failed to connect to the runtime. Aborting startup...");
|
||||
logger.Error("Failed to connect to the runtime. Aborting startup...");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,26 +17,32 @@ namespace SafeExamBrowser.Client.Communication
|
|||
{
|
||||
internal class ClientHost : BaseHost, IClientHost
|
||||
{
|
||||
public Guid StartupToken { private get; set; }
|
||||
|
||||
public ClientHost(string address, ILogger logger) : base(address, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IConnectResponse OnConnect(Guid? token)
|
||||
protected override bool OnConnect(Guid? token)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
return StartupToken == token;
|
||||
}
|
||||
|
||||
protected override void OnDisconnect(IMessage message)
|
||||
protected override void OnDisconnect()
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override IResponse OnReceive(IMessage message)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IResponse OnReceive(Message message)
|
||||
{
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
var sequence = new OperationSequence(logger, operations);
|
||||
|
||||
ClientController = new ClientController(displayMonitor, logger, sequence, processMonitor, Taskbar, windowMonitor);
|
||||
ClientController = new ClientController(displayMonitor, logger, sequence, processMonitor, runtimeProxy, Taskbar, windowMonitor);
|
||||
}
|
||||
|
||||
private void Validate(string[] args)
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace SafeExamBrowser.Configuration
|
|||
[Serializable]
|
||||
public class ClientConfiguration : IClientConfiguration
|
||||
{
|
||||
public ISessionData SessionData { get; set; }
|
||||
public Guid SessionId { get; set; }
|
||||
public ISettings Settings { get; set; }
|
||||
public IRuntimeInfo RuntimeInfo { get; set; }
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace SafeExamBrowser.Configuration
|
|||
{
|
||||
private RuntimeInfo runtimeInfo;
|
||||
|
||||
public ISessionData CurrentSessionData { get; private set; }
|
||||
public ISession CurrentSession { get; private set; }
|
||||
public ISettings CurrentSettings { get; private set; }
|
||||
|
||||
public IRuntimeInfo RuntimeInfo
|
||||
|
@ -34,15 +34,17 @@ namespace SafeExamBrowser.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public ISessionData InitializeSessionData()
|
||||
public ISession InitializeSession()
|
||||
{
|
||||
var sessionData = new SessionData();
|
||||
var session = new Session
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
StartupToken = Guid.NewGuid()
|
||||
};
|
||||
|
||||
sessionData.Id = Guid.NewGuid();
|
||||
CurrentSession = session;
|
||||
|
||||
CurrentSessionData = sessionData;
|
||||
|
||||
return sessionData;
|
||||
return session;
|
||||
}
|
||||
|
||||
public IClientConfiguration BuildClientConfiguration()
|
||||
|
@ -50,7 +52,7 @@ namespace SafeExamBrowser.Configuration
|
|||
return new ClientConfiguration
|
||||
{
|
||||
RuntimeInfo = RuntimeInfo,
|
||||
SessionData = CurrentSessionData,
|
||||
SessionId = CurrentSession.Id,
|
||||
Settings = CurrentSettings
|
||||
};
|
||||
}
|
||||
|
@ -64,10 +66,11 @@ namespace SafeExamBrowser.Configuration
|
|||
|
||||
public ISettings LoadDefaultSettings()
|
||||
{
|
||||
var settings = new Settings.Settings();
|
||||
|
||||
// TODO
|
||||
settings.ServicePolicy = ServicePolicy.Optional;
|
||||
var settings = new Settings.Settings
|
||||
{
|
||||
// TODO
|
||||
ServicePolicy = ServicePolicy.Optional
|
||||
};
|
||||
|
||||
CurrentSettings = settings;
|
||||
|
||||
|
@ -93,6 +96,7 @@ namespace SafeExamBrowser.Configuration
|
|||
BrowserLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Browser.txt"),
|
||||
ClientId = Guid.NewGuid(),
|
||||
ClientAddress = $"{baseAddress}/client/{clientId}",
|
||||
ClientExecutablePath = Path.Combine(Path.GetDirectoryName(executable.Location), $"{nameof(SafeExamBrowser)}.Client.exe"),
|
||||
ClientLogFile = Path.Combine(logFolder, $"{logFilePrefix}_Client.txt"),
|
||||
DefaultSettingsFileName = "SebClientSettings.seb",
|
||||
ProgramCopyright = executable.GetCustomAttribute<AssemblyCopyrightAttribute>().Copyright,
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace SafeExamBrowser.Configuration
|
|||
public string BrowserCachePath { get; set; }
|
||||
public string BrowserLogFile { get; set; }
|
||||
public string ClientAddress { get; set; }
|
||||
public string ClientExecutablePath { get; set; }
|
||||
public Guid ClientId { get; set; }
|
||||
public string ClientLogFile { get; set; }
|
||||
public string DefaultSettingsFileName { get; set; }
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="ClientConfiguration.cs" />
|
||||
<Compile Include="RuntimeInfo.cs" />
|
||||
<Compile Include="SessionData.cs" />
|
||||
<Compile Include="Session.cs" />
|
||||
<Compile Include="Settings\BrowserSettings.cs" />
|
||||
<Compile Include="Settings\KeyboardSettings.cs" />
|
||||
<Compile Include="Settings\MouseSettings.cs" />
|
||||
|
|
|
@ -8,12 +8,14 @@
|
|||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Configuration
|
||||
{
|
||||
[Serializable]
|
||||
public class SessionData : ISessionData
|
||||
public class Session : ISession
|
||||
{
|
||||
public IProcess ClientProcess { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
public Guid StartupToken { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Behaviour
|
||||
{
|
||||
// TODO: Interface really needed?!
|
||||
|
|
|
@ -6,10 +6,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public interface IClientHost : ICommunicationHost
|
||||
{
|
||||
// TODO: Necessary?
|
||||
/// <summary>
|
||||
/// The startup token used for initial authentication.
|
||||
/// </summary>
|
||||
Guid StartupToken { set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,15 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public interface IClientProxy
|
||||
public interface IClientProxy : ICommunicationProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to connect to the client host.
|
||||
/// Instructs the client to submit its authentication data.
|
||||
/// </summary>
|
||||
bool Connect(Guid token);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the client host.
|
||||
/// </summary>
|
||||
void Disconnect();
|
||||
IAuthenticationResponse RequestAuthentication();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,21 +17,20 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
public interface ICommunication
|
||||
{
|
||||
/// <summary>
|
||||
/// Initiates a connection to the host and must thus be called before any other opertion. To authenticate itself to the host, the
|
||||
/// client can specify a security token. If the connection request was successful, a new session will be created by the host and
|
||||
/// the client will subsequently be allowed to start communicating with the host.
|
||||
/// Initiates a connection and must thus be called before any other opertion. Where applicable, an authentication token should be
|
||||
/// specified. Returns a response indicating whether the connection request was successful or not.
|
||||
/// </summary>
|
||||
[OperationContract(IsInitiating = true)]
|
||||
IConnectResponse Connect(Guid? token = null);
|
||||
IConnectionResponse Connect(Guid? token = null);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the connection to the host and instructs it to terminate the communication session.
|
||||
/// Closes a connection. Returns a response indicating whether the disconnection request was successful or not.
|
||||
/// </summary>
|
||||
[OperationContract(IsInitiating = false, IsTerminating = true)]
|
||||
void Disconnect(IMessage message);
|
||||
IDisconnectionResponse Disconnect(IDisconnectionMessage message);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message to the host, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
||||
/// Sends a message, optionally returning a response. If no response is expected, <c>null</c> will be returned.
|
||||
/// </summary>
|
||||
[OperationContract(IsInitiating = false)]
|
||||
IResponse Send(IMessage message);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public delegate void CommunicationEventHandler();
|
||||
|
||||
public interface ICommunicationHost
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication
|
||||
{
|
||||
public interface ICommunicationProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to establish a connection. Returns <c>true</c> if successful, otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
bool Connect(Guid? token = null);
|
||||
|
||||
/// <summary>
|
||||
/// Terminates an open connection. Returns <c>true</c> if successful, otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
bool Disconnect();
|
||||
}
|
||||
}
|
|
@ -6,10 +6,20 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public interface IRuntimeHost : ICommunicationHost
|
||||
{
|
||||
// TODO: Necessary?
|
||||
/// <summary>
|
||||
/// The startup token used for initial authentication.
|
||||
/// </summary>
|
||||
Guid StartupToken { set; }
|
||||
|
||||
/// <summary>
|
||||
/// Event fired once the client has signaled that it is ready to operate.
|
||||
/// </summary>
|
||||
event CommunicationEventHandler ClientReady;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,26 +6,20 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public interface IRuntimeProxy
|
||||
public interface IRuntimeProxy : ICommunicationProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to establish a connection with the runtime host, utilizing the specified authentication token.
|
||||
/// </summary>
|
||||
bool Connect(Guid token);
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the runtime host.
|
||||
/// </summary>
|
||||
void Disconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the application configuration from the runtime host.
|
||||
/// Retrieves the application configuration from the runtime.
|
||||
/// </summary>
|
||||
IClientConfiguration GetConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Informs the runtime that the client is ready.
|
||||
/// </summary>
|
||||
void InformClientReady();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ using SafeExamBrowser.Contracts.Configuration.Settings;
|
|||
|
||||
namespace SafeExamBrowser.Contracts.Communication
|
||||
{
|
||||
public interface IServiceProxy
|
||||
public interface IServiceProxy : ICommunicationProxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Instructs the proxy to ignore all operations or simulate a connection, where applicable. To be set e.g. when the service
|
||||
|
@ -19,16 +19,6 @@ namespace SafeExamBrowser.Contracts.Communication
|
|||
/// </summary>
|
||||
bool Ignore { set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tries to connect to the service host.
|
||||
/// </summary>
|
||||
bool Connect();
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects from the service host.
|
||||
/// </summary>
|
||||
void Disconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the service to start a new session according to the given parameters.
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication.Messages
|
||||
{
|
||||
public interface IDisconnectionMessage : IMessage
|
||||
{
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ namespace SafeExamBrowser.Contracts.Communication.Messages
|
|||
public interface IMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// The communication token needed for authentication with the host.
|
||||
/// The communication token needed for authentication.
|
||||
/// </summary>
|
||||
Guid CommunicationToken { get; }
|
||||
Guid CommunicationToken { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication.Messages
|
||||
{
|
||||
public interface ISimpleMessage : IMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// The purport of the message.
|
||||
/// </summary>
|
||||
Message Purport { get; }
|
||||
}
|
||||
}
|
28
SafeExamBrowser.Contracts/Communication/Messages/Message.cs
Normal file
28
SafeExamBrowser.Contracts/Communication/Messages/Message.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication.Messages
|
||||
{
|
||||
public enum Message
|
||||
{
|
||||
/// <summary>
|
||||
/// Requests an interlocutor to submit data for authentication.
|
||||
/// </summary>
|
||||
Authenticate = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Sent from the client to the runtime to indicate that the client is ready to operate.
|
||||
/// </summary>
|
||||
ClientIsReady,
|
||||
|
||||
/// <summary>
|
||||
/// Sent from the client to the runtime to ask for the client configuration.
|
||||
/// </summary>
|
||||
ConfigurationNeeded,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication.Responses
|
||||
{
|
||||
public interface IAuthenticationResponse : IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The process identifier used for authentication.
|
||||
/// </summary>
|
||||
int ProcessId { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||
{
|
||||
public interface IConfigurationResponse : IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The configuration to be used by the client.
|
||||
/// </summary>
|
||||
IClientConfiguration Configuration { get; }
|
||||
}
|
||||
}
|
|
@ -10,15 +10,15 @@ using System;
|
|||
|
||||
namespace SafeExamBrowser.Contracts.Communication.Responses
|
||||
{
|
||||
public interface IConnectResponse : IResponse
|
||||
public interface IConnectionResponse : IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// The communication token needed for authentication with the host. Is <c>null</c> if a connection was refused.
|
||||
/// The communication token needed for authentication. Is <c>null</c> if a connection was refused.
|
||||
/// </summary>
|
||||
Guid? CommunicationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the host has accepted the connection request.
|
||||
/// Indicates whether the connection request has been accepted.
|
||||
/// </summary>
|
||||
bool ConnectionEstablished { get; }
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Communication.Responses
|
||||
{
|
||||
public interface IDisconnectionResponse : IResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the connection has been terminated.
|
||||
/// </summary>
|
||||
bool ConnectionTerminated { get; }
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
|
@ -13,9 +14,9 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
public interface IClientConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// The session data to be used by the client.
|
||||
/// The unique identifier for the current session.
|
||||
/// </summary>
|
||||
ISessionData SessionData { get; set; }
|
||||
Guid SessionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The application settings to be used by the client.
|
||||
|
|
|
@ -14,10 +14,10 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
public interface IConfigurationRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the current session data, i.e. the last ones which were initialized. If no session has been initialized yet, this
|
||||
/// Retrieves the current session, i.e. the last one which was initialized. If no session has been initialized yet, this
|
||||
/// property will be <c>null</c>!
|
||||
/// </summary>
|
||||
ISessionData CurrentSessionData { get; }
|
||||
ISession CurrentSession { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the current settings, i.e. the last ones which were loaded. If no settings have been loaded yet, this property will
|
||||
|
@ -31,14 +31,14 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
IRuntimeInfo RuntimeInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Builds a configuration for the client component, given the currently loaded settings, session data and runtime information.
|
||||
/// Builds a configuration for the client component, given the currently loaded settings, session and runtime information.
|
||||
/// </summary>
|
||||
IClientConfiguration BuildClientConfiguration();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes all relevant data for a new session.
|
||||
/// </summary>
|
||||
ISessionData InitializeSessionData();
|
||||
ISession InitializeSession();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load settings from the specified path.
|
||||
|
|
|
@ -40,10 +40,15 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
/// </summary>
|
||||
string ClientAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The executable path of the client compontent.
|
||||
/// </summary>
|
||||
string ClientExecutablePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier for the currently running client instance.
|
||||
///
|
||||
/// TODO: Will need to be updated for each new client instance!
|
||||
/// TODO: Will need to be updated for each new client instance! -> Remove if unused!
|
||||
///
|
||||
/// </summary>
|
||||
Guid ClientId { get; }
|
||||
|
@ -85,6 +90,9 @@ namespace SafeExamBrowser.Contracts.Configuration
|
|||
|
||||
/// <summary>
|
||||
/// The unique identifier for the currently running runtime instance.
|
||||
///
|
||||
/// TODO: Remove if unused!
|
||||
///
|
||||
/// </summary>
|
||||
Guid RuntimeId { get; }
|
||||
|
||||
|
|
31
SafeExamBrowser.Contracts/Configuration/ISession.cs
Normal file
31
SafeExamBrowser.Contracts/Configuration/ISession.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
{
|
||||
public interface ISession
|
||||
{
|
||||
/// <summary>
|
||||
/// The process information of the client instance associated to this session.
|
||||
/// </summary>
|
||||
IProcess ClientProcess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique session identifier.
|
||||
/// </summary>
|
||||
Guid Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The startup token used by the client and runtime components for initial authentication.
|
||||
/// </summary>
|
||||
Guid StartupToken { get; }
|
||||
}
|
||||
}
|
|
@ -60,15 +60,22 @@
|
|||
<Compile Include="Communication\ICommunication.cs" />
|
||||
<Compile Include="Communication\IClientProxy.cs" />
|
||||
<Compile Include="Communication\ICommunicationHost.cs" />
|
||||
<Compile Include="Communication\ICommunicationProxy.cs" />
|
||||
<Compile Include="Communication\IRuntimeHost.cs" />
|
||||
<Compile Include="Communication\IRuntimeProxy.cs" />
|
||||
<Compile Include="Communication\IServiceProxy.cs" />
|
||||
<Compile Include="Communication\Messages\IDisconnectionMessage.cs" />
|
||||
<Compile Include="Communication\Messages\IMessage.cs" />
|
||||
<Compile Include="Communication\Messages\ISimpleMessage.cs" />
|
||||
<Compile Include="Communication\Messages\Message.cs" />
|
||||
<Compile Include="Communication\Responses\IAuthenticationResponse.cs" />
|
||||
<Compile Include="Communication\Responses\IConfigurationResponse.cs" />
|
||||
<Compile Include="Communication\Responses\IDisconnectionResponse.cs" />
|
||||
<Compile Include="Communication\Responses\IResponse.cs" />
|
||||
<Compile Include="Communication\Responses\IConnectResponse.cs" />
|
||||
<Compile Include="Communication\Responses\IConnectionResponse.cs" />
|
||||
<Compile Include="Configuration\IClientConfiguration.cs" />
|
||||
<Compile Include="Configuration\IRuntimeInfo.cs" />
|
||||
<Compile Include="Configuration\ISessionData.cs" />
|
||||
<Compile Include="Configuration\ISession.cs" />
|
||||
<Compile Include="Configuration\Settings\ConfigurationMode.cs" />
|
||||
<Compile Include="Behaviour\INotificationController.cs" />
|
||||
<Compile Include="Behaviour\Operations\IOperation.cs" />
|
||||
|
@ -131,10 +138,11 @@
|
|||
<Compile Include="UserInterface\MessageBoxAction.cs" />
|
||||
<Compile Include="UserInterface\MessageBoxIcon.cs" />
|
||||
<Compile Include="WindowsApi\IBounds.cs" />
|
||||
<Compile Include="WindowsApi\IDesktop.cs" />
|
||||
<Compile Include="WindowsApi\INativeMethods.cs" />
|
||||
<Compile Include="WindowsApi\IProcess.cs" />
|
||||
<Compile Include="WindowsApi\IProcessFactory.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Client\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
18
SafeExamBrowser.Contracts/WindowsApi/IDesktop.cs
Normal file
18
SafeExamBrowser.Contracts/WindowsApi/IDesktop.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.WindowsApi
|
||||
{
|
||||
public interface IDesktop
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the name of the currently active desktop.
|
||||
/// </summary>
|
||||
string CurrentName { get; }
|
||||
}
|
||||
}
|
|
@ -6,15 +6,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Contracts.Configuration
|
||||
namespace SafeExamBrowser.Contracts.WindowsApi
|
||||
{
|
||||
public interface ISessionData
|
||||
public interface IProcess
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique session identifier.
|
||||
/// The process identifier.
|
||||
/// </summary>
|
||||
Guid Id { get; }
|
||||
int Id { get; }
|
||||
}
|
||||
}
|
19
SafeExamBrowser.Contracts/WindowsApi/IProcessFactory.cs
Normal file
19
SafeExamBrowser.Contracts/WindowsApi/IProcessFactory.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.WindowsApi
|
||||
{
|
||||
public interface IProcessFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts a new process on the currently active desktop.
|
||||
/// </summary>
|
||||
/// <exception cref="System.ComponentModel.Win32Exception">If the process could not be started.</exception>
|
||||
IProcess StartNew(string path, params string[] args);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ using SafeExamBrowser.Contracts.Communication;
|
|||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Responses;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
|
@ -22,6 +23,9 @@ namespace SafeExamBrowser.Core.Communication
|
|||
private ILogger logger;
|
||||
private ServiceHost host;
|
||||
|
||||
protected Guid? CommunicationToken { get; private set; }
|
||||
protected ILogger Logger { get; private set; }
|
||||
|
||||
public bool IsRunning
|
||||
{
|
||||
get { return host?.State == CommunicationState.Opened; }
|
||||
|
@ -33,33 +37,64 @@ namespace SafeExamBrowser.Core.Communication
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
protected abstract IConnectResponse OnConnect(Guid? token);
|
||||
protected abstract void OnDisconnect(IMessage message);
|
||||
protected abstract bool OnConnect(Guid? token);
|
||||
protected abstract void OnDisconnect();
|
||||
protected abstract IResponse OnReceive(IMessage message);
|
||||
protected abstract IResponse OnReceive(Message message);
|
||||
|
||||
public IConnectResponse Connect(Guid? token = null)
|
||||
public IConnectionResponse Connect(Guid? token = null)
|
||||
{
|
||||
logger.Debug($"Received connection request with token '{token}'.");
|
||||
logger.Debug($"Received connection request with authentication token '{token}'.");
|
||||
|
||||
var response = OnConnect(token);
|
||||
var response = new ConnectionResponse();
|
||||
var connected = OnConnect(token);
|
||||
|
||||
logger.Debug($"{(response.ConnectionEstablished ? "Accepted" : "Denied")} connection request.");
|
||||
if (connected)
|
||||
{
|
||||
response.CommunicationToken = CommunicationToken = Guid.NewGuid();
|
||||
response.ConnectionEstablished = true;
|
||||
}
|
||||
|
||||
logger.Debug($"{(connected ? "Accepted" : "Denied")} connection request.");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void Disconnect(IMessage message)
|
||||
public IDisconnectionResponse Disconnect(IDisconnectionMessage message)
|
||||
{
|
||||
var response = new DisconnectionResponse();
|
||||
|
||||
// TODO: Compare with ToString in BaseProxy - needed?
|
||||
logger.Debug($"Received disconnection request with message '{message}'.");
|
||||
|
||||
OnDisconnect(message);
|
||||
if (IsAuthorized(message?.CommunicationToken))
|
||||
{
|
||||
OnDisconnect();
|
||||
|
||||
CommunicationToken = null;
|
||||
response.ConnectionTerminated = true;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public IResponse Send(IMessage message)
|
||||
{
|
||||
IResponse response = null;
|
||||
|
||||
logger.Debug($"Received message '{message}'.");
|
||||
|
||||
var response = OnReceive(message);
|
||||
if (IsAuthorized(message?.CommunicationToken))
|
||||
{
|
||||
if (message is ISimpleMessage)
|
||||
{
|
||||
response = OnReceive((message as ISimpleMessage).Purport);
|
||||
}
|
||||
else
|
||||
{
|
||||
response = OnReceive(message);
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug($"Sending response '{response}'.");
|
||||
|
||||
|
@ -87,6 +122,11 @@ namespace SafeExamBrowser.Core.Communication
|
|||
logger.Debug($"Terminated communication host for endpoint '{address}'.");
|
||||
}
|
||||
|
||||
private bool IsAuthorized(Guid? token)
|
||||
{
|
||||
return CommunicationToken == token;
|
||||
}
|
||||
|
||||
private void Host_Closed(object sender, EventArgs e)
|
||||
{
|
||||
logger.Debug("Communication host has been closed.");
|
||||
|
|
|
@ -12,15 +12,16 @@ using SafeExamBrowser.Contracts.Communication;
|
|||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Messages;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
public abstract class BaseProxy : ICommunication
|
||||
public abstract class BaseProxy : ICommunicationProxy
|
||||
{
|
||||
private string address;
|
||||
private ICommunication channel;
|
||||
private Guid? communicationToken;
|
||||
|
||||
protected Guid? CommunicationToken { get; private set; }
|
||||
protected ILogger Logger { get; private set; }
|
||||
|
||||
public BaseProxy(string address, ILogger logger)
|
||||
|
@ -29,7 +30,7 @@ namespace SafeExamBrowser.Core.Communication
|
|||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public IConnectResponse Connect(Guid? token = null)
|
||||
public virtual bool Connect(Guid? token = null)
|
||||
{
|
||||
var endpoint = new EndpointAddress(address);
|
||||
|
||||
|
@ -42,48 +43,47 @@ namespace SafeExamBrowser.Core.Communication
|
|||
|
||||
var response = channel.Connect(token);
|
||||
|
||||
CommunicationToken = response.CommunicationToken;
|
||||
communicationToken = response.CommunicationToken;
|
||||
Logger.Debug($"Tried to connect to {address}, connection was {(response.ConnectionEstablished ? "established" : "refused")}.");
|
||||
|
||||
return response.ConnectionEstablished;
|
||||
}
|
||||
|
||||
public virtual bool Disconnect()
|
||||
{
|
||||
FailIfNotConnected(nameof(Disconnect));
|
||||
|
||||
var message = new DisconnectionMessage { CommunicationToken = communicationToken.Value };
|
||||
var response = channel.Disconnect(message);
|
||||
|
||||
Logger.Debug($"{(response.ConnectionTerminated ? "Disconnected" : "Failed to disconnect")} from {address}.");
|
||||
|
||||
return response.ConnectionTerminated;
|
||||
}
|
||||
|
||||
protected IResponse Send(IMessage message)
|
||||
{
|
||||
FailIfNotConnected(nameof(Send));
|
||||
|
||||
message.CommunicationToken = communicationToken.Value;
|
||||
|
||||
var response = channel.Send(message);
|
||||
|
||||
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void Disconnect(IMessage message)
|
||||
protected IResponse Send(Message purport)
|
||||
{
|
||||
if (ChannelIsReady())
|
||||
{
|
||||
channel.Disconnect(message);
|
||||
Logger.Debug($"Disconnected from {address}, transmitting {ToString(message)}.");
|
||||
}
|
||||
FailIfNotConnected(nameof(Send));
|
||||
|
||||
throw new CommunicationException($"Tried to disconnect from host, but channel was {GetChannelState()}!");
|
||||
}
|
||||
var message = new SimpleMessage { Purport = purport };
|
||||
var response = channel.Send(message);
|
||||
|
||||
public IResponse Send(IMessage message)
|
||||
{
|
||||
if (ChannelIsReady())
|
||||
{
|
||||
var response = channel.Send(message);
|
||||
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||
|
||||
Logger.Debug($"Sent {ToString(message)}, got {ToString(response)}.");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new CommunicationException($"Tried to send {ToString(message)}, but channel was {GetChannelState()}!");
|
||||
}
|
||||
|
||||
protected void FailIfNotConnected(string operationName)
|
||||
{
|
||||
if (!CommunicationToken.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
||||
}
|
||||
}
|
||||
|
||||
private bool ChannelIsReady()
|
||||
{
|
||||
return channel != null && (channel as ICommunicationObject).State == CommunicationState.Opened;
|
||||
return response;
|
||||
}
|
||||
|
||||
private void BaseProxy_Closed(object sender, EventArgs e)
|
||||
|
@ -111,6 +111,19 @@ namespace SafeExamBrowser.Core.Communication
|
|||
Logger.Debug("Communication channel is opening...");
|
||||
}
|
||||
|
||||
private void FailIfNotConnected(string operationName)
|
||||
{
|
||||
if (!communicationToken.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot perform '{operationName}' before being connected to endpoint!");
|
||||
}
|
||||
|
||||
if (channel == null || (channel as ICommunicationObject).State != CommunicationState.Opened)
|
||||
{
|
||||
throw new CommunicationException($"Tried to perform {operationName}, but channel was {GetChannelState()}!");
|
||||
}
|
||||
}
|
||||
|
||||
private string GetChannelState()
|
||||
{
|
||||
return channel == null ? "null" : $"in state '{(channel as ICommunicationObject).State}'";
|
||||
|
|
27
SafeExamBrowser.Core/Communication/ClientProxy.cs
Normal file
27
SafeExamBrowser.Core/Communication/ClientProxy.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
public class ClientProxy : BaseProxy, IClientProxy
|
||||
{
|
||||
public ClientProxy(string address, ILogger logger) : base(address, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public IAuthenticationResponse RequestAuthentication()
|
||||
{
|
||||
return (IAuthenticationResponse) Send(Message.ClientIsReady);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ using SafeExamBrowser.Contracts.Communication.Messages;
|
|||
namespace SafeExamBrowser.Core.Communication.Messages
|
||||
{
|
||||
[Serializable]
|
||||
internal class Message : IMessage
|
||||
internal class BaseMessage : IMessage
|
||||
{
|
||||
public Guid CommunicationToken { get; set; }
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Communication.Messages;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication.Messages
|
||||
{
|
||||
[Serializable]
|
||||
internal class DisconnectionMessage : BaseMessage, IDisconnectionMessage
|
||||
{
|
||||
}
|
||||
}
|
19
SafeExamBrowser.Core/Communication/Messages/SimpleMessage.cs
Normal file
19
SafeExamBrowser.Core/Communication/Messages/SimpleMessage.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Communication.Messages;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication.Messages
|
||||
{
|
||||
[Serializable]
|
||||
internal class SimpleMessage : BaseMessage, ISimpleMessage
|
||||
{
|
||||
public Message Purport { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Communication.Responses;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication.Responses
|
||||
{
|
||||
[Serializable]
|
||||
internal class ConnectionResponse : IConnectionResponse
|
||||
{
|
||||
public Guid? CommunicationToken { get; set; }
|
||||
public bool ConnectionEstablished { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Communication.Responses;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication.Responses
|
||||
{
|
||||
[Serializable]
|
||||
internal class DisconnectionResponse : IDisconnectionResponse
|
||||
{
|
||||
public bool ConnectionTerminated { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,11 +6,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Messages;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
|
@ -20,22 +20,14 @@ namespace SafeExamBrowser.Core.Communication
|
|||
{
|
||||
}
|
||||
|
||||
public bool Connect(Guid token)
|
||||
{
|
||||
return base.Connect(token).ConnectionEstablished;
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
FailIfNotConnected(nameof(Disconnect));
|
||||
|
||||
base.Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
|
||||
}
|
||||
|
||||
public IClientConfiguration GetConfiguration()
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
return ((IConfigurationResponse) Send(Message.ConfigurationNeeded)).Configuration;
|
||||
}
|
||||
|
||||
public void InformClientReady()
|
||||
{
|
||||
Send(Message.ClientIsReady);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ using System;
|
|||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration.Settings;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication.Messages;
|
||||
|
||||
namespace SafeExamBrowser.Core.Communication
|
||||
{
|
||||
|
@ -22,26 +21,24 @@ namespace SafeExamBrowser.Core.Communication
|
|||
{
|
||||
}
|
||||
|
||||
public bool Connect()
|
||||
public override bool Connect(Guid? token)
|
||||
{
|
||||
if (IgnoreOperation(nameof(Connect)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.Connect().ConnectionEstablished;
|
||||
return base.Connect();
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
public override bool Disconnect()
|
||||
{
|
||||
if (IgnoreOperation(nameof(Disconnect)))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
FailIfNotConnected(nameof(Disconnect));
|
||||
|
||||
Disconnect(new Message { CommunicationToken = CommunicationToken.Value });
|
||||
return base.Disconnect();
|
||||
}
|
||||
|
||||
public void StartSession(Guid sessionId, ISettings settings)
|
||||
|
@ -51,8 +48,6 @@ namespace SafeExamBrowser.Core.Communication
|
|||
return;
|
||||
}
|
||||
|
||||
FailIfNotConnected(nameof(StartSession));
|
||||
|
||||
// TODO: Send(new StartSessionMessage { Id = sessionId, Settings = settings });
|
||||
}
|
||||
|
||||
|
@ -63,8 +58,6 @@ namespace SafeExamBrowser.Core.Communication
|
|||
return;
|
||||
}
|
||||
|
||||
FailIfNotConnected(nameof(StopSession));
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,12 @@
|
|||
<Compile Include="Behaviour\Operations\OperationSequence.cs" />
|
||||
<Compile Include="Communication\BaseProxy.cs" />
|
||||
<Compile Include="Communication\BaseHost.cs" />
|
||||
<Compile Include="Communication\Messages\Message.cs" />
|
||||
<Compile Include="Communication\ClientProxy.cs" />
|
||||
<Compile Include="Communication\Messages\DisconnectionMessage.cs" />
|
||||
<Compile Include="Communication\Messages\BaseMessage.cs" />
|
||||
<Compile Include="Communication\Messages\SimpleMessage.cs" />
|
||||
<Compile Include="Communication\Responses\ConnectionResponse.cs" />
|
||||
<Compile Include="Communication\Responses\DisconnectionResponse.cs" />
|
||||
<Compile Include="Communication\RuntimeProxy.cs" />
|
||||
<Compile Include="Communication\ServiceProxy.cs" />
|
||||
<Compile Include="Logging\DefaultLogFormatter.cs" />
|
||||
|
@ -87,8 +92,6 @@
|
|||
<Name>SafeExamBrowser.Contracts</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Communication\Responses\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -44,38 +44,38 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustConnectToService()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Connect(null)).Returns(true);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Connect(null)).Returns(true);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Verify(s => s.Connect(), Times.Exactly(2));
|
||||
service.Verify(s => s.Connect(null), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MustNotFailIfServiceNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
@ -84,7 +84,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustAbortIfServiceMandatoryAndNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
|
@ -95,7 +95,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustNotAbortIfServiceOptionalAndNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
@ -107,13 +107,13 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustDisconnectWhenReverting()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Connect(null)).Returns(true);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Connect(null)).Returns(true);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
@ -125,7 +125,7 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustNotFailWhenDisconnecting()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(true);
|
||||
service.Setup(s => s.Connect(null)).Returns(true);
|
||||
service.Setup(s => s.Disconnect()).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
|
@ -138,25 +138,25 @@ namespace SafeExamBrowser.Runtime.UnitTests.Behaviour.Operations
|
|||
[TestMethod]
|
||||
public void MustNotDisconnnectIfNotAvailable()
|
||||
{
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Returns(false);
|
||||
service.Setup(s => s.Connect(null)).Returns(false);
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Mandatory);
|
||||
|
||||
sut.Perform();
|
||||
sut.Revert();
|
||||
|
||||
service.Setup(s => s.Connect()).Throws<Exception>();
|
||||
service.Setup(s => s.Connect(null)).Throws<Exception>();
|
||||
configuration.SetupGet(s => s.CurrentSettings.ServicePolicy).Returns(ServicePolicy.Optional);
|
||||
|
||||
sut.Perform();
|
||||
|
|
|
@ -37,13 +37,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
logger.Info($"Initializing kiosk mode '{kioskMode}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_InitializeKioskMode);
|
||||
|
||||
if (kioskMode == KioskMode.CreateNewDesktop)
|
||||
switch (kioskMode)
|
||||
{
|
||||
CreateNewDesktop();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisableExplorerShell();
|
||||
case KioskMode.CreateNewDesktop:
|
||||
CreateNewDesktop();
|
||||
break;
|
||||
case KioskMode.DisableExplorerShell:
|
||||
DisableExplorerShell();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,13 +58,14 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
logger.Info($"Reverting kiosk mode '{kioskMode}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_RevertKioskMode);
|
||||
|
||||
if (kioskMode == KioskMode.CreateNewDesktop)
|
||||
switch (kioskMode)
|
||||
{
|
||||
CloseNewDesktop();
|
||||
}
|
||||
else
|
||||
{
|
||||
RestartExplorerShell();
|
||||
case KioskMode.CreateNewDesktop:
|
||||
CloseNewDesktop();
|
||||
break;
|
||||
case KioskMode.DisableExplorerShell:
|
||||
RestartExplorerShell();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
if (mandatory && !connected)
|
||||
{
|
||||
Abort = true;
|
||||
logger.Info("Aborting startup because the service is mandatory but not available!");
|
||||
logger.Error("Aborting startup because the service is mandatory but not available!");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error("Failed to disconnect from service host!", e);
|
||||
logger.Error("Failed to disconnect from the service!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,19 @@
|
|||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal class SessionSequenceEndOperation : SessionSequenceOperation
|
||||
{
|
||||
public SessionSequenceEndOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
|
||||
public SessionSequenceEndOperation(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -6,31 +6,46 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using SafeExamBrowser.Contracts.Behaviour.Operations;
|
||||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.I18n;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.UserInterface;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal abstract class SessionSequenceOperation : IOperation
|
||||
{
|
||||
private bool sessionRunning;
|
||||
private IClientProxy client;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IServiceProxy serviceProxy;
|
||||
private ISessionData sessionData;
|
||||
private IProcessFactory processFactory;
|
||||
private IRuntimeHost runtimeHost;
|
||||
private IServiceProxy service;
|
||||
private ISession session;
|
||||
|
||||
public bool Abort { get; private set; }
|
||||
public IProgressIndicator ProgressIndicator { private get; set; }
|
||||
|
||||
public SessionSequenceOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy)
|
||||
public SessionSequenceOperation(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service)
|
||||
{
|
||||
this.client = client;
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.serviceProxy = serviceProxy;
|
||||
this.processFactory = processFactory;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
public abstract void Perform();
|
||||
|
@ -42,34 +57,80 @@ namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
|||
logger.Info("Starting new session...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StartSession, true);
|
||||
|
||||
sessionData = configuration.InitializeSessionData();
|
||||
serviceProxy.StartSession(sessionData.Id, configuration.CurrentSettings);
|
||||
session = configuration.InitializeSession();
|
||||
runtimeHost.StartupToken = session.StartupToken;
|
||||
|
||||
// TODO:
|
||||
// - Create and connect to client
|
||||
// - Verify session integrity and start event handling -> in runtime controller?
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
service.StartSession(session.Id, configuration.CurrentSettings);
|
||||
|
||||
sessionRunning = true;
|
||||
logger.Info($"Successfully started new session with identifier '{sessionData.Id}'.");
|
||||
try
|
||||
{
|
||||
StartClient();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
service.StopSession(session.Id);
|
||||
logger.Error("Failed to start client!", e);
|
||||
}
|
||||
|
||||
if (sessionRunning)
|
||||
{
|
||||
logger.Info($"Successfully started new session with identifier '{session.Id}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Abort = true;
|
||||
logger.Info($"Failed to start new session! Aborting...");
|
||||
}
|
||||
}
|
||||
|
||||
protected void StopSession()
|
||||
{
|
||||
if (sessionRunning)
|
||||
{
|
||||
logger.Info($"Stopping session with identifier '{sessionData.Id}'...");
|
||||
logger.Info($"Stopping session with identifier '{session.Id}'...");
|
||||
ProgressIndicator?.UpdateText(TextKey.ProgressIndicator_StopSession, true);
|
||||
|
||||
serviceProxy.StopSession(sessionData.Id);
|
||||
service.StopSession(session.Id);
|
||||
|
||||
// TODO:
|
||||
// - Terminate client (or does it terminate itself?)
|
||||
// - Stop event handling and verify session termination -> in runtime controller?
|
||||
System.Threading.Thread.Sleep(5000);
|
||||
|
||||
sessionRunning = false;
|
||||
logger.Info($"Successfully stopped session with identifier '{sessionData.Id}'.");
|
||||
logger.Info($"Successfully stopped session with identifier '{session.Id}'.");
|
||||
}
|
||||
}
|
||||
|
||||
private void StartClient()
|
||||
{
|
||||
var clientReady = new AutoResetEvent(false);
|
||||
var clientReadyHandler = new CommunicationEventHandler(() => clientReady.Set());
|
||||
var clientExecutable = configuration.RuntimeInfo.ClientExecutablePath;
|
||||
var hostUri = configuration.RuntimeInfo.RuntimeAddress;
|
||||
var token = session.StartupToken.ToString("D");
|
||||
|
||||
runtimeHost.ClientReady += clientReadyHandler;
|
||||
session.ClientProcess = processFactory.StartNew(clientExecutable, hostUri, token);
|
||||
|
||||
clientReady.WaitOne();
|
||||
runtimeHost.ClientReady -= clientReadyHandler;
|
||||
|
||||
if (client.Connect(session.StartupToken))
|
||||
{
|
||||
var response = client.RequestAuthentication();
|
||||
|
||||
// TODO: Further integrity checks necessary?
|
||||
if (session.ClientProcess.Id == response.ProcessId)
|
||||
{
|
||||
sessionRunning = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to verify client integrity!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to connect to client!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,19 @@
|
|||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Behaviour.Operations
|
||||
{
|
||||
internal class SessionSequenceStartOperation : SessionSequenceOperation
|
||||
{
|
||||
public SessionSequenceStartOperation(IConfigurationRepository configuration, ILogger logger, IServiceProxy serviceProxy) : base(configuration, logger, serviceProxy)
|
||||
public SessionSequenceStartOperation(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IProcessFactory processFactory,
|
||||
IRuntimeHost runtimeHost,
|
||||
IServiceProxy service) : base(client, configuration, logger, processFactory, runtimeHost, service)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
{
|
||||
private bool sessionRunning;
|
||||
|
||||
private IClientProxy client;
|
||||
private IConfigurationRepository configuration;
|
||||
private ILogger logger;
|
||||
private IOperationSequence bootstrapSequence;
|
||||
|
@ -29,29 +30,31 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
private IRuntimeHost runtimeHost;
|
||||
private IRuntimeInfo runtimeInfo;
|
||||
private IRuntimeWindow runtimeWindow;
|
||||
private IServiceProxy serviceProxy;
|
||||
private IServiceProxy service;
|
||||
private ISplashScreen splashScreen;
|
||||
private Action shutdown;
|
||||
private IUserInterfaceFactory uiFactory;
|
||||
|
||||
public RuntimeController(
|
||||
IClientProxy client,
|
||||
IConfigurationRepository configuration,
|
||||
ILogger logger,
|
||||
IOperationSequence bootstrapSequence,
|
||||
IOperationSequence sessionSequence,
|
||||
IRuntimeHost runtimeHost,
|
||||
IRuntimeInfo runtimeInfo,
|
||||
IServiceProxy serviceProxy,
|
||||
IServiceProxy service,
|
||||
Action shutdown,
|
||||
IUserInterfaceFactory uiFactory)
|
||||
{
|
||||
this.client = client;
|
||||
this.configuration = configuration;
|
||||
this.logger = logger;
|
||||
this.bootstrapSequence = bootstrapSequence;
|
||||
this.sessionSequence = sessionSequence;
|
||||
this.runtimeHost = runtimeHost;
|
||||
this.runtimeInfo = runtimeInfo;
|
||||
this.serviceProxy = serviceProxy;
|
||||
this.service = service;
|
||||
this.shutdown = shutdown;
|
||||
this.uiFactory = uiFactory;
|
||||
}
|
||||
|
@ -103,10 +106,6 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
logger.Log(string.Empty);
|
||||
logger.Info("--- Initiating shutdown procedure ---");
|
||||
|
||||
// TODO:
|
||||
// - Disconnect from service
|
||||
// - Terminate runtime communication host
|
||||
// - Revert kiosk mode (or do that when stopping session?)
|
||||
var success = bootstrapSequence.TryRevert();
|
||||
|
||||
if (success)
|
||||
|
@ -142,7 +141,6 @@ namespace SafeExamBrowser.Runtime.Behaviour
|
|||
else
|
||||
{
|
||||
uiFactory.Show(TextKey.MessageBox_SessionStartError, TextKey.MessageBox_SessionStartErrorTitle, icon: MessageBoxIcon.Error);
|
||||
logger.Info($"Failed to start new session. Terminating application...");
|
||||
|
||||
if (!initial)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Communication.Responses
|
||||
{
|
||||
[Serializable]
|
||||
internal class ConfigurationResponse : IConfigurationResponse
|
||||
{
|
||||
public IClientConfiguration Configuration { get; set; }
|
||||
}
|
||||
}
|
|
@ -10,33 +10,54 @@ using System;
|
|||
using SafeExamBrowser.Contracts.Communication;
|
||||
using SafeExamBrowser.Contracts.Communication.Messages;
|
||||
using SafeExamBrowser.Contracts.Communication.Responses;
|
||||
using SafeExamBrowser.Contracts.Configuration;
|
||||
using SafeExamBrowser.Contracts.Logging;
|
||||
using SafeExamBrowser.Core.Communication;
|
||||
using SafeExamBrowser.Runtime.Communication.Responses;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.Communication
|
||||
{
|
||||
internal class RuntimeHost : BaseHost, IRuntimeHost
|
||||
{
|
||||
public RuntimeHost(string address, ILogger logger) : base(address, logger)
|
||||
private IConfigurationRepository configuration;
|
||||
|
||||
public Guid StartupToken { private get; set; }
|
||||
|
||||
public event CommunicationEventHandler ClientReady;
|
||||
|
||||
public RuntimeHost(string address, IConfigurationRepository configuration, ILogger logger) : base(address, logger)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
protected override IConnectResponse OnConnect(Guid? token = null)
|
||||
protected override bool OnConnect(Guid? token = null)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
return StartupToken == token;
|
||||
}
|
||||
|
||||
protected override void OnDisconnect(IMessage message)
|
||||
protected override void OnDisconnect()
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override IResponse OnReceive(IMessage message)
|
||||
{
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override IResponse OnReceive(Message message)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case Message.ClientIsReady:
|
||||
ClientReady?.Invoke();
|
||||
break;
|
||||
case Message.ConfigurationNeeded:
|
||||
return new ConfigurationResponse { Configuration = configuration.BuildClientConfiguration() };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace SafeExamBrowser.Runtime
|
|||
var args = Environment.GetCommandLineArgs();
|
||||
var configuration = new ConfigurationRepository();
|
||||
var nativeMethods = new NativeMethods();
|
||||
Action shutdown = Application.Current.Shutdown;
|
||||
|
||||
logger = new Logger();
|
||||
runtimeInfo = configuration.RuntimeInfo;
|
||||
|
@ -48,7 +49,10 @@ namespace SafeExamBrowser.Runtime
|
|||
|
||||
var text = new Text(logger);
|
||||
var uiFactory = new UserInterfaceFactory(text);
|
||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||
var desktop = new Desktop(new ModuleLogger(logger, typeof(Desktop)));
|
||||
var processFactory = new ProcessFactory(desktop, new ModuleLogger(logger, typeof(ProcessFactory)));
|
||||
var clientProxy = new ClientProxy(runtimeInfo.ClientAddress, new ModuleLogger(logger, typeof(ClientProxy)));
|
||||
var runtimeHost = new RuntimeHost(runtimeInfo.RuntimeAddress, configuration, new ModuleLogger(logger, typeof(RuntimeHost)));
|
||||
var serviceProxy = new ServiceProxy(runtimeInfo.ServiceAddress, new ModuleLogger(logger, typeof(ServiceProxy)));
|
||||
|
||||
var bootstrapOperations = new Queue<IOperation>();
|
||||
|
@ -57,16 +61,16 @@ namespace SafeExamBrowser.Runtime
|
|||
bootstrapOperations.Enqueue(new I18nOperation(logger, text));
|
||||
bootstrapOperations.Enqueue(new CommunicationOperation(runtimeHost, logger));
|
||||
|
||||
sessionOperations.Enqueue(new SessionSequenceStartOperation(configuration, logger, serviceProxy));
|
||||
sessionOperations.Enqueue(new SessionSequenceStartOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||
sessionOperations.Enqueue(new ConfigurationOperation(configuration, logger, runtimeInfo, text, uiFactory, args));
|
||||
sessionOperations.Enqueue(new ServiceConnectionOperation(configuration, logger, serviceProxy, text));
|
||||
sessionOperations.Enqueue(new KioskModeOperation(logger, configuration));
|
||||
sessionOperations.Enqueue(new SessionSequenceEndOperation(configuration, logger, serviceProxy));
|
||||
sessionOperations.Enqueue(new SessionSequenceEndOperation(clientProxy, configuration, logger, processFactory, runtimeHost, serviceProxy));
|
||||
|
||||
var boostrapSequence = new OperationSequence(logger, bootstrapOperations);
|
||||
var sessionSequence = new OperationSequence(logger, sessionOperations);
|
||||
|
||||
RuntimeController = new RuntimeController(configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, Application.Current.Shutdown, uiFactory);
|
||||
RuntimeController = new RuntimeController(clientProxy, configuration, logger, boostrapSequence, sessionSequence, runtimeHost, runtimeInfo, serviceProxy, shutdown, uiFactory);
|
||||
}
|
||||
|
||||
internal void LogStartupInformation()
|
||||
|
|
|
@ -93,6 +93,7 @@
|
|||
<Compile Include="Behaviour\Operations\SessionSequenceEndOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\SessionSequenceOperation.cs" />
|
||||
<Compile Include="Behaviour\Operations\SessionSequenceStartOperation.cs" />
|
||||
<Compile Include="Communication\Responses\ConfigurationResponse.cs" />
|
||||
<Compile Include="Communication\RuntimeHost.cs" />
|
||||
<Compile Include="CompositionRoot.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
|
@ -162,4 +163,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>xcopy /E /Y "$(SolutionDir)SafeExamBrowser.Client\bin\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)bin\$(PlatformName)\$(ConfigurationName)"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -32,6 +32,13 @@ namespace SafeExamBrowser.WindowsApi.Constants
|
|||
/// </summary>
|
||||
internal const int MIN_ALL = 419;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the default priority class for processes, i.e. a process with no special scheduling needs.
|
||||
///
|
||||
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686219(v=vs.85).aspx.
|
||||
/// </summary>
|
||||
internal const int NORMAL_PRIORITY_CLASS = 0x20;
|
||||
|
||||
/// <summary>
|
||||
/// The callback function is not mapped into the address space of the process that generates the event. Because the hook function
|
||||
/// is called across process boundaries, the system must queue events. Although this method is asynchronous, events are guaranteed
|
||||
|
|
26
SafeExamBrowser.WindowsApi/Desktop.cs
Normal file
26
SafeExamBrowser.WindowsApi/Desktop.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi
|
||||
{
|
||||
public class Desktop : IDesktop
|
||||
{
|
||||
private ILogger logger;
|
||||
|
||||
// TODO!
|
||||
public string CurrentName => "Default";
|
||||
|
||||
public Desktop(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,6 +17,19 @@ namespace SafeExamBrowser.WindowsApi
|
|||
/// </summary>
|
||||
internal class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
ref SECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
ref SECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
bool bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string lpCurrentDirectory,
|
||||
[In] ref STARTUPINFO lpStartupInfo,
|
||||
out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
{
|
||||
var handle = GetShellWindowHandle();
|
||||
|
||||
User32.SendMessage(handle, Constant.WM_COMMAND, (IntPtr)Constant.MIN_ALL, IntPtr.Zero);
|
||||
User32.SendMessage(handle, Constant.WM_COMMAND, (IntPtr) Constant.MIN_ALL, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public void PostCloseMessageToShell()
|
||||
|
@ -245,10 +245,10 @@ namespace SafeExamBrowser.WindowsApi
|
|||
|
||||
public IntPtr RegisterSystemForegroundEvent(Action<IntPtr> callback)
|
||||
{
|
||||
EventProc eventProc = (IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) =>
|
||||
void eventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
callback(hwnd);
|
||||
};
|
||||
}
|
||||
|
||||
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_FOREGROUND, Constant.EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
||||
|
||||
|
@ -262,10 +262,10 @@ namespace SafeExamBrowser.WindowsApi
|
|||
|
||||
public IntPtr RegisterSystemCaptureStartEvent(Action<IntPtr> callback)
|
||||
{
|
||||
EventProc eventProc = (IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) =>
|
||||
void eventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
|
||||
{
|
||||
callback(hwnd);
|
||||
};
|
||||
}
|
||||
|
||||
var handle = User32.SetWinEventHook(Constant.EVENT_SYSTEM_CAPTURESTART, Constant.EVENT_SYSTEM_CAPTURESTART, IntPtr.Zero, eventProc, 0, 0, Constant.WINEVENT_OUTOFCONTEXT);
|
||||
|
||||
|
|
27
SafeExamBrowser.WindowsApi/Process.cs
Normal file
27
SafeExamBrowser.WindowsApi/Process.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.WindowsApi;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi
|
||||
{
|
||||
internal class Process : IProcess
|
||||
{
|
||||
private System.Diagnostics.Process process;
|
||||
|
||||
public int Id
|
||||
{
|
||||
get { return process.Id; }
|
||||
}
|
||||
|
||||
public Process(int id)
|
||||
{
|
||||
process = System.Diagnostics.Process.GetProcessById(id);
|
||||
}
|
||||
}
|
||||
}
|
60
SafeExamBrowser.WindowsApi/ProcessFactory.cs
Normal file
60
SafeExamBrowser.WindowsApi/ProcessFactory.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Contracts.Logging;
|
||||
using SafeExamBrowser.Contracts.WindowsApi;
|
||||
using SafeExamBrowser.WindowsApi.Constants;
|
||||
using SafeExamBrowser.WindowsApi.Types;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi
|
||||
{
|
||||
public class ProcessFactory : IProcessFactory
|
||||
{
|
||||
private IDesktop desktop;
|
||||
private ILogger logger;
|
||||
|
||||
public ProcessFactory(IDesktop desktop, ILogger logger)
|
||||
{
|
||||
this.desktop = desktop;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public IProcess StartNew(string path, params string[] args)
|
||||
{
|
||||
var processInfo = new PROCESS_INFORMATION();
|
||||
var processAttributes = new SECURITY_ATTRIBUTES();
|
||||
var threadAttributes = new SECURITY_ATTRIBUTES();
|
||||
var startupInfo = new STARTUPINFO();
|
||||
|
||||
startupInfo.cb = Marshal.SizeOf(startupInfo);
|
||||
startupInfo.lpDesktop = desktop.CurrentName;
|
||||
|
||||
var success = Kernel32.CreateProcess(
|
||||
null,
|
||||
path,
|
||||
ref processAttributes,
|
||||
ref threadAttributes,
|
||||
true,
|
||||
Constant.NORMAL_PRIORITY_CLASS,
|
||||
IntPtr.Zero,
|
||||
null,
|
||||
ref startupInfo,
|
||||
out processInfo);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
return new Process(processInfo.dwProcessId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,7 +54,10 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Constants\Constant.cs" />
|
||||
<Compile Include="Constants\HookType.cs" />
|
||||
<Compile Include="Desktop.cs" />
|
||||
<Compile Include="Monitoring\MouseHook.cs" />
|
||||
<Compile Include="Process.cs" />
|
||||
<Compile Include="ProcessFactory.cs" />
|
||||
<Compile Include="Types\Bounds.cs" />
|
||||
<Compile Include="Types\EXECUTION_STATE.cs" />
|
||||
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
|
||||
|
@ -69,7 +72,10 @@
|
|||
<Compile Include="Constants\SPIF.cs" />
|
||||
<Compile Include="Types\MSLLHOOKSTRUCT.cs" />
|
||||
<Compile Include="Types\POINT.cs" />
|
||||
<Compile Include="Types\PROCESS_INFORMATION.cs" />
|
||||
<Compile Include="Types\RECT.cs" />
|
||||
<Compile Include="Types\SECURITY_ATTRIBUTES.cs" />
|
||||
<Compile Include="Types\STARTUPINFO.cs" />
|
||||
<Compile Include="User32.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
26
SafeExamBrowser.WindowsApi/Types/PROCESS_INFORMATION.cs
Normal file
26
SafeExamBrowser.WindowsApi/Types/PROCESS_INFORMATION.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Runtime.InteropServices;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Types
|
||||
{
|
||||
/// <remarks>
|
||||
/// See http://pinvoke.net/default.aspx/Structures/PROCESS_INFORMATION.html.
|
||||
/// See https://msdn.microsoft.com/en-us/library/ms684873(VS.85).aspx.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct PROCESS_INFORMATION
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public int dwProcessId;
|
||||
public int dwThreadId;
|
||||
}
|
||||
}
|
25
SafeExamBrowser.WindowsApi/Types/SECURITY_ATTRIBUTES.cs
Normal file
25
SafeExamBrowser.WindowsApi/Types/SECURITY_ATTRIBUTES.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Runtime.InteropServices;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Types
|
||||
{
|
||||
/// <remarks>
|
||||
/// See http://pinvoke.net/default.aspx/Structures/SECURITY_ATTRIBUTES.html.
|
||||
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560(v=vs.85).aspx.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SECURITY_ATTRIBUTES
|
||||
{
|
||||
public int nLength;
|
||||
public IntPtr lpSecurityDescriptor;
|
||||
public int bInheritHandle;
|
||||
}
|
||||
}
|
39
SafeExamBrowser.WindowsApi/Types/STARTUPINFO.cs
Normal file
39
SafeExamBrowser.WindowsApi/Types/STARTUPINFO.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.Runtime.InteropServices;
|
||||
|
||||
namespace SafeExamBrowser.WindowsApi.Types
|
||||
{
|
||||
/// <remarks>
|
||||
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx.
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct STARTUPINFO
|
||||
{
|
||||
public int cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public int dwX;
|
||||
public int dwY;
|
||||
public int dwXSize;
|
||||
public int dwYSize;
|
||||
public int dwXCountChars;
|
||||
public int dwYCountChars;
|
||||
public int dwFillAttribute;
|
||||
public int dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue