diff --git a/SafeExamBrowser.Applications.Contracts/InstanceIdentifier.cs b/SafeExamBrowser.Applications.Contracts/InstanceIdentifier.cs
deleted file mode 100644
index 07f3979d..00000000
--- a/SafeExamBrowser.Applications.Contracts/InstanceIdentifier.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-namespace SafeExamBrowser.Applications.Contracts
-{
- ///
- /// Defines an identifier which uniquely identifies an instance in the context of an application.
- ///
- public abstract class InstanceIdentifier
- {
- ///
- /// Determines whether two identifiers are equal (i.e. whether they identify the same application instance).
- ///
- public static bool operator ==(InstanceIdentifier a, InstanceIdentifier b) => Equals(a, b);
-
- ///
- /// Determines whether two identifiers are different (i.e. whether they identify different application instances).
- ///
- public static bool operator !=(InstanceIdentifier a, InstanceIdentifier b) => !Equals(a, b);
-
- ///
- /// Indicates whether the given object is an identifier for the same application instance.
- ///
- public abstract override bool Equals(object other);
-
- ///
- /// Returns a hash code for the identifier.
- ///
- public abstract override int GetHashCode();
-
- ///
- /// Returns a human-readable string representation of the identifier.
- ///
- public abstract override string ToString();
- }
-}
diff --git a/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj b/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj
index add43a26..f2e84263 100644
--- a/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj
+++ b/SafeExamBrowser.Applications.Contracts/SafeExamBrowser.Applications.Contracts.csproj
@@ -62,7 +62,6 @@
-
diff --git a/SafeExamBrowser.Applications/ApplicationFactory.cs b/SafeExamBrowser.Applications/ApplicationFactory.cs
index 99b6db3c..9e5549b8 100644
--- a/SafeExamBrowser.Applications/ApplicationFactory.cs
+++ b/SafeExamBrowser.Applications/ApplicationFactory.cs
@@ -21,11 +21,13 @@ namespace SafeExamBrowser.Applications
public class ApplicationFactory : IApplicationFactory
{
private IModuleLogger logger;
+ private INativeMethods nativeMethods;
private IProcessFactory processFactory;
- public ApplicationFactory(IModuleLogger logger, IProcessFactory processFactory)
+ public ApplicationFactory(IModuleLogger logger, INativeMethods nativeMethods, IProcessFactory processFactory)
{
this.logger = logger;
+ this.nativeMethods = nativeMethods;
this.processFactory = processFactory;
}
@@ -65,7 +67,7 @@ namespace SafeExamBrowser.Applications
{
var icon = new IconResource { Type = IconResourceType.Embedded, Uri = new Uri(executablePath) };
var info = new ApplicationInfo { AutoStart = settings.AutoStart, Icon = icon, Name = settings.DisplayName, Tooltip = settings.Description ?? settings.DisplayName };
- var application = new ExternalApplication(executablePath, info, logger.CloneFor(settings.DisplayName), processFactory);
+ var application = new ExternalApplication(executablePath, info, logger.CloneFor(settings.DisplayName), nativeMethods, processFactory);
return application;
}
diff --git a/SafeExamBrowser.Applications/ApplicationInstanceIdentifier.cs b/SafeExamBrowser.Applications/ApplicationInstanceIdentifier.cs
deleted file mode 100644
index 68e21581..00000000
--- a/SafeExamBrowser.Applications/ApplicationInstanceIdentifier.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-using SafeExamBrowser.Applications.Contracts;
-
-namespace SafeExamBrowser.Applications
-{
- internal class ApplicationInstanceIdentifier : InstanceIdentifier
- {
- internal int ProcessId { get; private set; }
-
- public ApplicationInstanceIdentifier(int processId)
- {
- ProcessId = processId;
- }
-
- public override bool Equals(object other)
- {
- if (other is ApplicationInstanceIdentifier id)
- {
- return ProcessId == id.ProcessId;
- }
-
- return false;
- }
-
- public override int GetHashCode()
- {
- return ProcessId.GetHashCode();
- }
-
- public override string ToString()
- {
- return $"({ProcessId})";
- }
- }
-}
diff --git a/SafeExamBrowser.Applications/Events/InstanceTerminatedEventHandler.cs b/SafeExamBrowser.Applications/Events/InstanceTerminatedEventHandler.cs
new file mode 100644
index 00000000..499a2119
--- /dev/null
+++ b/SafeExamBrowser.Applications/Events/InstanceTerminatedEventHandler.cs
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+namespace SafeExamBrowser.Applications.Events
+{
+ internal delegate void InstanceTerminatedEventHandler(int id);
+}
diff --git a/SafeExamBrowser.Applications/ExternalApplication.cs b/SafeExamBrowser.Applications/ExternalApplication.cs
index df8985a0..0e3e3e4c 100644
--- a/SafeExamBrowser.Applications/ExternalApplication.cs
+++ b/SafeExamBrowser.Applications/ExternalApplication.cs
@@ -18,8 +18,11 @@ namespace SafeExamBrowser.Applications
{
internal class ExternalApplication : IApplication
{
+ private int instanceIdCounter = default(int);
+
private string executablePath;
private IModuleLogger logger;
+ private INativeMethods nativeMethods;
private IList instances;
private IProcessFactory processFactory;
@@ -27,18 +30,24 @@ namespace SafeExamBrowser.Applications
public ApplicationInfo Info { get; }
- internal ExternalApplication(string executablePath, ApplicationInfo info, IModuleLogger logger, IProcessFactory processFactory)
+ internal ExternalApplication(
+ string executablePath,
+ ApplicationInfo info,
+ IModuleLogger logger,
+ INativeMethods nativeMethods,
+ IProcessFactory processFactory)
{
this.executablePath = executablePath;
this.Info = info;
this.logger = logger;
+ this.nativeMethods = nativeMethods;
this.instances = new List();
this.processFactory = processFactory;
}
public IEnumerable GetWindows()
{
- return Enumerable.Empty();
+ return instances.SelectMany(i => i.GetWindows());
}
public void Initialize()
@@ -53,10 +62,13 @@ namespace SafeExamBrowser.Applications
logger.Info("Starting application...");
var process = processFactory.StartNew(executablePath);
- var id = new ApplicationInstanceIdentifier(process.Id);
- var instance = new ExternalApplicationInstance(Info.Icon, id, logger.CloneFor($"{Info.Name} {id}"), process);
+ var id = ++instanceIdCounter;
+ var instanceLogger = logger.CloneFor($"{Info.Name} Instance #{id}");
+ var instance = new ExternalApplicationInstance(Info.Icon, id, instanceLogger, nativeMethods, process);
instance.Initialize();
+ instance.Terminated += Instance_Terminated;
+ instance.WindowsChanged += () => WindowsChanged?.Invoke();
instances.Add(instance);
}
catch (Exception e)
@@ -65,6 +77,12 @@ namespace SafeExamBrowser.Applications
}
}
+ private void Instance_Terminated(int id)
+ {
+ instances.Remove(instances.First(i => i.Id == id));
+ WindowsChanged?.Invoke();
+ }
+
public void Terminate()
{
if (instances.Any())
diff --git a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs
index 90241a86..786c9b3d 100644
--- a/SafeExamBrowser.Applications/ExternalApplicationInstance.cs
+++ b/SafeExamBrowser.Applications/ExternalApplicationInstance.cs
@@ -6,7 +6,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Timers;
using SafeExamBrowser.Applications.Contracts;
+using SafeExamBrowser.Applications.Contracts.Events;
+using SafeExamBrowser.Applications.Events;
using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
@@ -15,22 +21,42 @@ namespace SafeExamBrowser.Applications
{
internal class ExternalApplicationInstance
{
- private IconResource icon;
- private InstanceIdentifier id;
- private ILogger logger;
- private IProcess process;
+ private readonly object @lock = new object();
- internal ExternalApplicationInstance(IconResource icon, InstanceIdentifier id, ILogger logger, IProcess process)
+ private IconResource icon;
+ private ILogger logger;
+ private INativeMethods nativeMethods;
+ private IProcess process;
+ private Timer timer;
+ private IList windows;
+
+ internal int Id { get; }
+
+ internal event InstanceTerminatedEventHandler Terminated;
+ internal event WindowsChangedEventHandler WindowsChanged;
+
+ internal ExternalApplicationInstance(IconResource icon, int id, ILogger logger, INativeMethods nativeMethods, IProcess process)
{
this.icon = icon;
- this.id = id;
+ this.Id = id;
this.logger = logger;
+ this.nativeMethods = nativeMethods;
this.process = process;
+ this.windows = new List();
+ }
+
+ internal IEnumerable GetWindows()
+ {
+ lock (@lock)
+ {
+ return new List(windows);
+ }
}
internal void Initialize()
{
- process.Terminated += Process_Terminated;
+ InitializeEvents();
+ logger.Info("Initialized application instance.");
}
internal void Terminate()
@@ -42,7 +68,7 @@ namespace SafeExamBrowser.Applications
if (!terminated)
{
- process.Terminated -= Process_Terminated;
+ FinalizeEvents();
for (var attempt = 0; attempt < MAX_ATTEMPTS && !terminated; attempt++)
{
@@ -68,7 +94,69 @@ namespace SafeExamBrowser.Applications
private void Process_Terminated(int exitCode)
{
logger.Info($"Application instance has terminated with exit code {exitCode}.");
- // TODO: Terminated?.Invoke(Id); -> Remove from application!
+ FinalizeEvents();
+ Terminated?.Invoke(Id);
+ }
+
+ private void Timer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ var changed = false;
+ var openWindows = nativeMethods.GetOpenWindows();
+
+ lock (@lock)
+ {
+ var closedWindows = windows.Where(w => openWindows.All(ow => ow != w.Handle)).ToList();
+ var openedWindows = openWindows.Where(ow => windows.All(w => w.Handle != ow) && BelongsToInstance(ow));
+
+ foreach (var window in closedWindows)
+ {
+ changed = true;
+ windows.Remove(window);
+ }
+
+ foreach (var window in openedWindows)
+ {
+ changed = true;
+ windows.Add(new ExternalApplicationWindow(icon, nativeMethods, window));
+ }
+
+ foreach (var window in windows)
+ {
+ window.Update();
+ }
+ }
+
+ if (changed)
+ {
+ logger.Error("WINDOWS CHANGED!");
+ WindowsChanged?.Invoke();
+ }
+
+ timer.Start();
+ }
+
+ private bool BelongsToInstance(IntPtr window)
+ {
+ return nativeMethods.GetProcessIdFor(window) == process.Id;
+ }
+
+ private void InitializeEvents()
+ {
+ const int ONE_SECOND = 1000;
+
+ process.Terminated += Process_Terminated;
+
+ timer = new Timer(ONE_SECOND);
+ timer.Elapsed += Timer_Elapsed;
+ timer.Start();
+ }
+
+ private void FinalizeEvents()
+ {
+ timer.Elapsed -= Timer_Elapsed;
+ timer.Stop();
+
+ process.Terminated -= Process_Terminated;
}
}
}
diff --git a/SafeExamBrowser.Applications/ExternalApplicationWindow.cs b/SafeExamBrowser.Applications/ExternalApplicationWindow.cs
new file mode 100644
index 00000000..b5194bb3
--- /dev/null
+++ b/SafeExamBrowser.Applications/ExternalApplicationWindow.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using System;
+using SafeExamBrowser.Applications.Contracts;
+using SafeExamBrowser.Applications.Contracts.Events;
+using SafeExamBrowser.Core.Contracts;
+using SafeExamBrowser.WindowsApi.Contracts;
+
+namespace SafeExamBrowser.Applications
+{
+ internal class ExternalApplicationWindow : IApplicationWindow
+ {
+ private INativeMethods nativeMethods;
+
+ internal IntPtr Handle { get; }
+ public IconResource Icon { get; }
+ public string Title { get; private set; }
+
+ public event IconChangedEventHandler IconChanged { add { } remove { } }
+ public event TitleChangedEventHandler TitleChanged;
+
+ internal ExternalApplicationWindow(IconResource icon, INativeMethods nativeMethods, IntPtr handle)
+ {
+ this.Handle = handle;
+ this.Icon = icon;
+ this.nativeMethods = nativeMethods;
+ }
+
+ public void Activate()
+ {
+ nativeMethods.ActivateWindow(Handle);
+ }
+
+ internal void Update()
+ {
+ var title = nativeMethods.GetWindowTitle(Handle);
+ var hasChanged = Title?.Equals(title, StringComparison.Ordinal) != true;
+
+ if (hasChanged)
+ {
+ Title = title;
+ TitleChanged?.Invoke(title);
+ }
+ }
+ }
+}
diff --git a/SafeExamBrowser.Applications/SafeExamBrowser.Applications.csproj b/SafeExamBrowser.Applications/SafeExamBrowser.Applications.csproj
index ea3676c1..546a58e2 100644
--- a/SafeExamBrowser.Applications/SafeExamBrowser.Applications.csproj
+++ b/SafeExamBrowser.Applications/SafeExamBrowser.Applications.csproj
@@ -55,9 +55,10 @@
-
+
+
diff --git a/SafeExamBrowser.Browser/BrowserApplication.cs b/SafeExamBrowser.Browser/BrowserApplication.cs
index d2c57e2b..1b6578be 100644
--- a/SafeExamBrowser.Browser/BrowserApplication.cs
+++ b/SafeExamBrowser.Browser/BrowserApplication.cs
@@ -112,9 +112,9 @@ namespace SafeExamBrowser.Browser
private void CreateNewInstance(string url = null)
{
- var id = new BrowserInstanceIdentifier(++instanceIdCounter);
+ var id = ++instanceIdCounter;
var isMainInstance = instances.Count == 0;
- var instanceLogger = logger.CloneFor($"BrowserInstance {id}");
+ var instanceLogger = logger.CloneFor($"Browser Instance #{id}");
var startUrl = url ?? settings.StartUrl;
var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, messageBox, instanceLogger, text, uiFactory, startUrl);
@@ -157,10 +157,9 @@ namespace SafeExamBrowser.Browser
CreateNewInstance(args.Url);
}
- private void Instance_Terminated(InstanceIdentifier id)
+ private void Instance_Terminated(int id)
{
- instances.Remove(instances.FirstOrDefault(i => i.Id == id));
- logger.Info($"Browser instance {id} was terminated.");
+ instances.Remove(instances.First(i => i.Id == id));
WindowsChanged?.Invoke();
}
diff --git a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs
index 9a01d5b7..74e2ed63 100644
--- a/SafeExamBrowser.Browser/BrowserApplicationInstance.cs
+++ b/SafeExamBrowser.Browser/BrowserApplicationInstance.cs
@@ -49,7 +49,7 @@ namespace SafeExamBrowser.Browser
get { return isMainInstance ? settings.MainWindow : settings.AdditionalWindow; }
}
- internal BrowserInstanceIdentifier Id { get; private set; }
+ internal int Id { get; }
public IconResource Icon { get; private set; }
public string Title { get; private set; }
@@ -64,7 +64,7 @@ namespace SafeExamBrowser.Browser
public BrowserApplicationInstance(
AppConfig appConfig,
BrowserSettings settings,
- BrowserInstanceIdentifier id,
+ int id,
bool isMainInstance,
IMessageBox messageBox,
IModuleLogger logger,
@@ -166,7 +166,7 @@ namespace SafeExamBrowser.Browser
private void InitializeWindow()
{
window = uiFactory.CreateBrowserWindow(control, settings, isMainInstance);
- window.Closing += () => Terminated?.Invoke(Id);
+ window.Closing += Window_Closing;
window.AddressChanged += Window_AddressChanged;
window.BackwardNavigationRequested += Window_BackwardNavigationRequested;
window.DeveloperConsoleRequested += Window_DeveloperConsoleRequested;
@@ -326,6 +326,12 @@ namespace SafeExamBrowser.Browser
control.NavigateBackwards();
}
+ private void Window_Closing()
+ {
+ logger.Info($"Instance has terminated.");
+ Terminated?.Invoke(Id);
+ }
+
private void Window_DeveloperConsoleRequested()
{
logger.Debug("Showing developer console...");
diff --git a/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs b/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs
deleted file mode 100644
index f9e2cdc1..00000000
--- a/SafeExamBrowser.Browser/BrowserInstanceIdentifier.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-using SafeExamBrowser.Applications.Contracts;
-
-namespace SafeExamBrowser.Browser
-{
- internal class BrowserInstanceIdentifier : InstanceIdentifier
- {
- internal int Value { get; private set; }
-
- public BrowserInstanceIdentifier(int id)
- {
- Value = id;
- }
-
- public override bool Equals(object other)
- {
- if (other is BrowserInstanceIdentifier id)
- {
- return Value == id.Value;
- }
-
- return false;
- }
-
- public override int GetHashCode()
- {
- return Value.GetHashCode();
- }
-
- public override string ToString()
- {
- return $"#{Value}";
- }
- }
-}
diff --git a/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs b/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs
index afbc35e6..7975dfdc 100644
--- a/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs
+++ b/SafeExamBrowser.Browser/Events/InstanceTerminatedEventHandler.cs
@@ -8,5 +8,5 @@
namespace SafeExamBrowser.Browser.Events
{
- internal delegate void InstanceTerminatedEventHandler(BrowserInstanceIdentifier id);
+ internal delegate void InstanceTerminatedEventHandler(int id);
}
diff --git a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj
index 943d6f1d..af07210f 100644
--- a/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj
+++ b/SafeExamBrowser.Browser/SafeExamBrowser.Browser.csproj
@@ -63,7 +63,6 @@
-
diff --git a/SafeExamBrowser.Client/CompositionRoot.cs b/SafeExamBrowser.Client/CompositionRoot.cs
index a11ee56b..386d4957 100644
--- a/SafeExamBrowser.Client/CompositionRoot.cs
+++ b/SafeExamBrowser.Client/CompositionRoot.cs
@@ -98,7 +98,7 @@ namespace SafeExamBrowser.Client
taskView = BuildTaskView();
var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
- var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
+ var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), nativeMethods, processFactory);
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, new ProcessFactory(ModuleLogger(nameof(ProcessFactory))));
var displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);
diff --git a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs
index 1e3ad581..35479681 100644
--- a/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Desktop/TaskView.xaml.cs
@@ -145,7 +145,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left;
Top = (SystemParameters.WorkArea.Height - Height) / 2 + SystemParameters.WorkArea.Top;
- if (!windows.Any())
+ if (!controls.Any())
{
Hide();
}
diff --git a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
index 123447f9..a633f039 100644
--- a/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
+++ b/SafeExamBrowser.UserInterface.Mobile/TaskView.xaml.cs
@@ -145,7 +145,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
Left = (SystemParameters.WorkArea.Width - Width) / 2 + SystemParameters.WorkArea.Left;
Top = (SystemParameters.WorkArea.Height - Height) / 2 + SystemParameters.WorkArea.Top;
- if (!windows.Any())
+ if (!controls.Any())
{
Hide();
}
diff --git a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
index c0769970..6ed3e422 100644
--- a/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi.Contracts/INativeMethods.cs
@@ -17,6 +17,11 @@ namespace SafeExamBrowser.WindowsApi.Contracts
///
public interface INativeMethods
{
+ ///
+ /// Brings the window with the given handle to the foreground and activates it.
+ ///
+ void ActivateWindow(IntPtr handle);
+
///
/// Deregisters a previously registered keyboard hook.
///
@@ -86,7 +91,7 @@ namespace SafeExamBrowser.WindowsApi.Contracts
string GetWallpaperPath();
///
- /// Retrieves the title of the specified window, or an empty string, if the given window does not have a title.
+ /// Retrieves the title of the window with the given handle, or an empty string if the given window does not have a title.
///
string GetWindowTitle(IntPtr window);
diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs
index dbb3cb91..c84ab429 100644
--- a/SafeExamBrowser.WindowsApi/NativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs
@@ -24,34 +24,50 @@ namespace SafeExamBrowser.WindowsApi
{
public class NativeMethods : INativeMethods
{
- private ConcurrentBag KeyboardHooks = new ConcurrentBag();
- private ConcurrentBag MouseHooks = new ConcurrentBag();
- private ConcurrentBag SystemHooks = new ConcurrentBag();
+ private ConcurrentDictionary KeyboardHooks = new ConcurrentDictionary();
+ private ConcurrentDictionary MouseHooks = new ConcurrentDictionary();
+ private ConcurrentDictionary SystemHooks = new ConcurrentDictionary();
///
/// Upon finalization, unregister all active system events and hooks...
///
~NativeMethods()
{
- foreach (var hook in SystemHooks)
+ foreach (var hook in SystemHooks.Values)
{
hook.Detach();
}
- foreach (var hook in KeyboardHooks)
+ foreach (var hook in KeyboardHooks.Values)
{
hook.Detach();
}
- foreach (var hook in MouseHooks)
+ foreach (var hook in MouseHooks.Values)
{
hook.Detach();
}
}
+ public void ActivateWindow(IntPtr handle)
+ {
+ var placement = new WINDOWPLACEMENT();
+
+ User32.BringWindowToTop(handle);
+ User32.SetForegroundWindow(handle);
+
+ placement.length = Marshal.SizeOf(placement);
+ User32.GetWindowPlacement(handle, ref placement);
+
+ if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized)
+ {
+ User32.ShowWindowAsync(handle, (int) ShowWindowCommand.Restore);
+ }
+ }
+
public void DeregisterKeyboardHook(Guid hookId)
{
- var hook = KeyboardHooks.FirstOrDefault(h => h.Id == hookId);
+ var hook = KeyboardHooks.Values.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -62,13 +78,13 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- KeyboardHooks.TryTake(out _);
+ KeyboardHooks.TryRemove(hookId, out _);
}
}
public void DeregisterMouseHook(Guid hookId)
{
- var hook = MouseHooks.FirstOrDefault(h => h.Id == hookId);
+ var hook = MouseHooks.Values.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -79,13 +95,13 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- MouseHooks.TryTake(out _);
+ MouseHooks.TryRemove(hookId, out _);
}
}
public void DeregisterSystemEventHook(Guid hookId)
{
- var hook = SystemHooks.FirstOrDefault(h => h.Id == hookId);
+ var hook = SystemHooks.Values.FirstOrDefault(h => h.Id == hookId);
if (hook != null)
{
@@ -96,7 +112,7 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
- SystemHooks.TryTake(out _);
+ SystemHooks.TryRemove(hookId, out _);
}
}
@@ -254,7 +270,7 @@ namespace SafeExamBrowser.WindowsApi
hook.Attach();
hookId = hook.Id;
- KeyboardHooks.Add(hook);
+ KeyboardHooks[hookId] = hook;
hookReadyEvent.Set();
while (true)
@@ -283,7 +299,7 @@ namespace SafeExamBrowser.WindowsApi
hook.Attach();
hookId = hook.Id;
- MouseHooks.Add(hook);
+ MouseHooks[hookId] = hook;
hookReadyEvent.Set();
while (true)
@@ -321,7 +337,7 @@ namespace SafeExamBrowser.WindowsApi
hook.Attach();
hookId = hook.Id;
- SystemHooks.Add(hook);
+ SystemHooks[hookId] = hook;
hookReadyEvent.Set();
hook.AwaitDetach();
});
diff --git a/SafeExamBrowser.WindowsApi/Process.cs b/SafeExamBrowser.WindowsApi/Process.cs
index 39255541..889cb5d9 100644
--- a/SafeExamBrowser.WindowsApi/Process.cs
+++ b/SafeExamBrowser.WindowsApi/Process.cs
@@ -11,12 +11,9 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management;
-using System.Runtime.InteropServices;
using SafeExamBrowser.Logging.Contracts;
-using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events;
-using SafeExamBrowser.WindowsApi.Types;
namespace SafeExamBrowser.WindowsApi
{
@@ -68,34 +65,6 @@ namespace SafeExamBrowser.WindowsApi
this.namesInitialized = true;
}
- public bool TryActivate()
- {
- try
- {
- var success = true;
- var placement = new WINDOWPLACEMENT();
-
- success &= User32.BringWindowToTop(process.MainWindowHandle);
- success &= User32.SetForegroundWindow(process.MainWindowHandle);
-
- placement.length = Marshal.SizeOf(placement);
- User32.GetWindowPlacement(process.MainWindowHandle, ref placement);
-
- if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized)
- {
- success &= User32.ShowWindowAsync(process.MainWindowHandle, (int) ShowWindowCommand.Restore);
- }
-
- return success;
- }
- catch (Exception e)
- {
- logger.Error("Failed to activate process!", e);
- }
-
- return false;
- }
-
public bool TryClose(int timeout_ms = 0)
{
try
@@ -124,25 +93,6 @@ namespace SafeExamBrowser.WindowsApi
return false;
}
- public bool TryGetWindowTitle(out string title)
- {
- title = default(string);
-
- try
- {
- process.Refresh();
- title = process.MainWindowTitle;
-
- return true;
- }
- catch (Exception e)
- {
- logger.Error("Failed to retrieve title of main window!", e);
- }
-
- return false;
- }
-
public bool TryKill(int timeout_ms = 0)
{
try