diff --git a/SafeExamBrowser.Contracts/I18n/TextKey.cs b/SafeExamBrowser.Contracts/I18n/TextKey.cs
index 50547810..00e9bcd0 100644
--- a/SafeExamBrowser.Contracts/I18n/TextKey.cs
+++ b/SafeExamBrowser.Contracts/I18n/TextKey.cs
@@ -23,6 +23,7 @@ namespace SafeExamBrowser.Contracts.I18n
MessageBox_StartupErrorTitle,
Notification_AboutTooltip,
Notification_LogTooltip,
+ SplashScreen_EmptyClipboard,
SplashScreen_InitializeBrowser,
SplashScreen_InitializeProcessMonitoring,
SplashScreen_InitializeTaskbar,
diff --git a/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs b/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
index 2cf66181..a3c88c6a 100644
--- a/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
+++ b/SafeExamBrowser.Contracts/WindowsApi/INativeMethods.cs
@@ -38,6 +38,14 @@ namespace SafeExamBrowser.Contracts.WindowsApi
///
void DeregisterSystemEvent(IntPtr handle);
+ ///
+ /// Empties the clipboard.
+ ///
+ ///
+ /// If the emptying of the clipboard failed.
+ ///
+ void EmptyClipboard();
+
///
/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
///
diff --git a/SafeExamBrowser.Core/Behaviour/Operations/ClipboardOperation.cs b/SafeExamBrowser.Core/Behaviour/Operations/ClipboardOperation.cs
new file mode 100644
index 00000000..5403223f
--- /dev/null
+++ b/SafeExamBrowser.Core/Behaviour/Operations/ClipboardOperation.cs
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET)
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+using SafeExamBrowser.Contracts.Behaviour;
+using SafeExamBrowser.Contracts.I18n;
+using SafeExamBrowser.Contracts.Logging;
+using SafeExamBrowser.Contracts.UserInterface;
+using SafeExamBrowser.Contracts.WindowsApi;
+
+namespace SafeExamBrowser.Core.Behaviour.Operations
+{
+ public class ClipboardOperation : IOperation
+ {
+ private ILogger logger;
+ private INativeMethods nativeMethods;
+
+ public ISplashScreen SplashScreen { private get; set; }
+
+ public ClipboardOperation(ILogger logger, INativeMethods nativeMethods)
+ {
+ this.logger = logger;
+ this.nativeMethods = nativeMethods;
+ }
+
+ public void Perform()
+ {
+ EmptyClipboard();
+ }
+
+ public void Revert()
+ {
+ EmptyClipboard();
+ }
+
+ private void EmptyClipboard()
+ {
+ logger.Info("Emptying clipboard...");
+ SplashScreen.UpdateText(TextKey.SplashScreen_EmptyClipboard);
+
+ nativeMethods.EmptyClipboard();
+ }
+ }
+}
diff --git a/SafeExamBrowser.Core/I18n/Text.xml b/SafeExamBrowser.Core/I18n/Text.xml
index cad11af8..73fd5e5a 100644
--- a/SafeExamBrowser.Core/I18n/Text.xml
+++ b/SafeExamBrowser.Core/I18n/Text.xml
@@ -8,6 +8,7 @@
Startup Error
About Safe Exam Browser
Application Log
+ Emptying clipboard
Initializing browser
Initializing process monitoring
Initializing taskbar
diff --git a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
index 7cd14296..1bb728e2 100644
--- a/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
+++ b/SafeExamBrowser.Core/SafeExamBrowser.Core.csproj
@@ -58,6 +58,7 @@
+
diff --git a/SafeExamBrowser.UserInterface/Utilities/IconResourceLoader.cs b/SafeExamBrowser.UserInterface/Utilities/IconResourceLoader.cs
index cba02954..d38c5dee 100644
--- a/SafeExamBrowser.UserInterface/Utilities/IconResourceLoader.cs
+++ b/SafeExamBrowser.UserInterface/Utilities/IconResourceLoader.cs
@@ -9,7 +9,9 @@
using System;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Documents;
using System.Windows.Markup;
+using System.Windows.Media;
using System.Windows.Media.Imaging;
using SafeExamBrowser.Contracts.Configuration;
@@ -19,22 +21,39 @@ namespace SafeExamBrowser.UserInterface.Utilities
{
internal static UIElement Load(IIconResource resource)
{
- if (resource.IsBitmapResource)
+ try
{
- return new Image
+ if (resource.IsBitmapResource)
{
- Source = new BitmapImage(resource.Uri)
- };
- }
- else if (resource.IsXamlResource)
- {
- using (var stream = Application.GetResourceStream(resource.Uri)?.Stream)
- {
- return XamlReader.Load(stream) as UIElement;
+ return LoadBitmapResource(resource);
}
+ else if (resource.IsXamlResource)
+ {
+ return LoadXamlResource(resource);
+ }
+ }
+ catch (Exception)
+ {
+ return new TextBlock(new Run("X") { Foreground = Brushes.Red, FontWeight = FontWeights.Bold });
}
throw new NotSupportedException($"Application icon resource of type '{resource.GetType()}' is not supported!");
}
+
+ private static UIElement LoadBitmapResource(IIconResource resource)
+ {
+ return new Image
+ {
+ Source = new BitmapImage(resource.Uri)
+ };
+ }
+
+ private static UIElement LoadXamlResource(IIconResource resource)
+ {
+ using (var stream = Application.GetResourceStream(resource.Uri)?.Stream)
+ {
+ return XamlReader.Load(stream) as UIElement;
+ }
+ }
}
}
diff --git a/SafeExamBrowser.WindowsApi/NativeMethods.cs b/SafeExamBrowser.WindowsApi/NativeMethods.cs
index aac9aff1..fbaf5d19 100644
--- a/SafeExamBrowser.WindowsApi/NativeMethods.cs
+++ b/SafeExamBrowser.WindowsApi/NativeMethods.cs
@@ -94,6 +94,20 @@ namespace SafeExamBrowser.WindowsApi
EventDelegates.TryRemove(handle, out EventProc d);
}
+ public void EmptyClipboard()
+ {
+ var success = true;
+
+ success &= User32.OpenClipboard(IntPtr.Zero);
+ success &= User32.EmptyClipboard();
+ success &= User32.CloseClipboard();
+
+ if (!success)
+ {
+ throw new Win32Exception(Marshal.GetLastWin32Error());
+ }
+ }
+
public IEnumerable GetOpenWindows()
{
var windows = new List();
diff --git a/SafeExamBrowser.WindowsApi/User32.cs b/SafeExamBrowser.WindowsApi/User32.cs
index 0d6f5ed2..f888d4f3 100644
--- a/SafeExamBrowser.WindowsApi/User32.cs
+++ b/SafeExamBrowser.WindowsApi/User32.cs
@@ -26,6 +26,14 @@ namespace SafeExamBrowser.WindowsApi
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CloseClipboard();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool EmptyClipboard();
+
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumWindows(EnumWindowsDelegate enumProc, IntPtr lParam);
@@ -46,6 +54,10 @@ namespace SafeExamBrowser.WindowsApi
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsWindowVisible(IntPtr hWnd);
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
+
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
diff --git a/SafeExamBrowser/CompositionRoot.cs b/SafeExamBrowser/CompositionRoot.cs
index 33eeba07..5403d6b9 100644
--- a/SafeExamBrowser/CompositionRoot.cs
+++ b/SafeExamBrowser/CompositionRoot.cs
@@ -86,6 +86,7 @@ namespace SafeExamBrowser
StartupOperations.Enqueue(new TaskbarOperation(logger, logFormatter, settings, Taskbar, text, uiFactory));
StartupOperations.Enqueue(new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory));
StartupOperations.Enqueue(new RuntimeControllerOperation(runtimeController, logger));
+ StartupOperations.Enqueue(new ClipboardOperation(logger, nativeMethods));
StartupOperations.Enqueue(new MouseInterceptorOperation(logger, mouseInterceptor, nativeMethods));
}
}