SEBWIN-312: Implemented basic handling of whitelisted applications.

This commit is contained in:
dbuechel 2019-11-13 10:11:11 +01:00
parent 3d55bd6ff4
commit 35dd3dd4c2
19 changed files with 313 additions and 33 deletions

View file

@ -30,19 +30,29 @@ namespace SafeExamBrowser.Applications.Contracts
/// </summary> /// </summary>
event IconChangedEventHandler IconChanged; event IconChangedEventHandler IconChanged;
/// <summary>
/// Event fired when the application instance has been terminated.
/// </summary>
event InstanceTerminatedEventHandler Terminated;
/// <summary> /// <summary>
/// Event fired when the name or (document) title of the application instance has changed. /// Event fired when the name or (document) title of the application instance has changed.
/// </summary> /// </summary>
event NameChangedEventHandler NameChanged; event NameChangedEventHandler NameChanged;
/// <summary>
/// Event fired when the application instance has been terminated.
/// </summary>
event InstanceTerminatedEventHandler Terminated;
/// <summary> /// <summary>
/// Makes this instance the currently active one and brings it to the foreground. /// Makes this instance the currently active one and brings it to the foreground.
/// </summary> /// </summary>
void Activate(); void Activate();
/// <summary>
/// Initializes the application instance.
/// </summary>
void Initialize();
/// <summary>
/// Terminates the application instance.
/// </summary>
void Terminate();
} }
} }

View file

@ -14,16 +14,19 @@ using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Core.Contracts; using SafeExamBrowser.Core.Contracts;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.Settings.Applications; using SafeExamBrowser.Settings.Applications;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Applications namespace SafeExamBrowser.Applications
{ {
public class ApplicationFactory : IApplicationFactory public class ApplicationFactory : IApplicationFactory
{ {
private ILogger logger; private IModuleLogger logger;
private IProcessFactory processFactory;
public ApplicationFactory(ILogger logger) public ApplicationFactory(IModuleLogger logger, IProcessFactory processFactory)
{ {
this.logger = logger; this.logger = logger;
this.processFactory = processFactory;
} }
public FactoryResult TryCreate(WhitelistApplication settings, out IApplication application) public FactoryResult TryCreate(WhitelistApplication settings, out IApplication application)
@ -62,7 +65,7 @@ namespace SafeExamBrowser.Applications
{ {
var icon = new IconResource { Type = IconResourceType.Embedded, Uri = new Uri(executablePath) }; var icon = new IconResource { Type = IconResourceType.Embedded, Uri = new Uri(executablePath) };
var info = new ApplicationInfo { IconResource = icon, Name = settings.DisplayName, Tooltip = settings.Description ?? settings.DisplayName }; var info = new ApplicationInfo { IconResource = icon, Name = settings.DisplayName, Tooltip = settings.Description ?? settings.DisplayName };
var application = new ExternalApplication(executablePath, info); var application = new ExternalApplication(executablePath, info, logger.CloneFor(settings.DisplayName), processFactory);
return application; return application;
} }

View file

@ -0,0 +1,42 @@
/*
* 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})";
}
}
}

View file

@ -6,38 +6,64 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
using System.Collections.Generic;
using System.Linq;
using SafeExamBrowser.Applications.Contracts; using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Applications.Contracts.Events; using SafeExamBrowser.Applications.Contracts.Events;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Applications namespace SafeExamBrowser.Applications
{ {
internal class ExternalApplication : IApplication internal class ExternalApplication : IApplication
{ {
private string executablePath; private string executablePath;
private IModuleLogger logger;
private IList<IApplicationInstance> instances;
private IProcessFactory processFactory;
public ApplicationInfo Info { get; } public ApplicationInfo Info { get; }
public event InstanceStartedEventHandler InstanceStarted; public event InstanceStartedEventHandler InstanceStarted;
internal ExternalApplication(string executablePath, ApplicationInfo info) internal ExternalApplication(string executablePath, ApplicationInfo info, IModuleLogger logger, IProcessFactory processFactory)
{ {
this.executablePath = executablePath; this.executablePath = executablePath;
this.Info = info; this.Info = info;
this.logger = logger;
this.instances = new List<IApplicationInstance>();
this.processFactory = processFactory;
} }
public void Initialize() public void Initialize()
{ {
// Nothing to do here for now.
} }
public void Start() public void Start()
{ {
logger.Info("Starting application...");
var process = processFactory.StartNew(executablePath);
var id = new ApplicationInstanceIdentifier(process.Id);
var instance = new ExternalApplicationInstance(id, logger.CloneFor($"{Info.Name} {id}"), process);
instance.Initialize();
instances.Add(instance);
InstanceStarted?.Invoke(instance);
} }
public void Terminate() public void Terminate()
{ {
if (instances.Any())
{
logger.Info("Terminating application...");
}
foreach (var instance in instances)
{
instance.Terminate();
}
} }
} }
} }

View file

@ -0,0 +1,115 @@
/*
* 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 System.Timers;
using SafeExamBrowser.Applications.Contracts;
using SafeExamBrowser.Applications.Contracts.Events;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Contracts;
namespace SafeExamBrowser.Applications
{
internal class ExternalApplicationInstance : IApplicationInstance
{
private const int ONE_SECOND = 1000;
private ILogger logger;
private string name;
private IProcess process;
private Timer timer;
public InstanceIdentifier Id { get; }
public string Name { get; }
public event IconChangedEventHandler IconChanged { add { } remove { } }
public event NameChangedEventHandler NameChanged;
public event InstanceTerminatedEventHandler Terminated;
public ExternalApplicationInstance(InstanceIdentifier id, ILogger logger, IProcess process)
{
this.Id = id;
this.logger = logger;
this.process = process;
}
public void Activate()
{
var success = process.TryActivate();
if (!success)
{
logger.Warn("Failed to activate instance!");
}
}
public void Initialize()
{
process.Terminated += Process_Terminated;
timer = new Timer(ONE_SECOND);
timer.Elapsed += Timer_Elapsed;
timer.Start();
logger.Info("Initialized application instance.");
}
public void Terminate()
{
const int MAX_ATTEMPTS = 5;
const int TIMEOUT_MS = 500;
timer.Elapsed -= Timer_Elapsed;
timer?.Stop();
var terminated = process.HasTerminated;
for (var attempt = 0; attempt < MAX_ATTEMPTS && !terminated; attempt++)
{
terminated = process.TryClose(TIMEOUT_MS);
}
for (var attempt = 0; attempt < MAX_ATTEMPTS && !terminated; attempt++)
{
terminated = process.TryKill(TIMEOUT_MS);
}
if (terminated)
{
logger.Info("Successfully terminated application instance.");
}
else
{
logger.Warn("Failed to terminate application instance!");
}
}
private void Process_Terminated(int exitCode)
{
logger.Info($"Application instance has terminated with exit code {exitCode}.");
Terminated?.Invoke(Id);
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
var success = process.TryGetWindowTitle(out var title);
var hasChanged = name?.Equals(title, StringComparison.Ordinal) != true;
// TODO: Use this and ensure log window doesn't hang on shutdown (if it is open)!
// logger.Warn($"Success: {success} HasChanged: {hasChanged}");
if (success && hasChanged)
{
name = title;
NameChanged?.Invoke(name);
}
timer.Start();
}
}
}

View file

@ -55,7 +55,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ApplicationFactory.cs" /> <Compile Include="ApplicationFactory.cs" />
<Compile Include="ApplicationInstanceIdentifier.cs" />
<Compile Include="ExternalApplication.cs" /> <Compile Include="ExternalApplication.cs" />
<Compile Include="ExternalApplicationInstance.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -75,6 +77,10 @@
<Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project> <Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project>
<Name>SafeExamBrowser.Settings</Name> <Name>SafeExamBrowser.Settings</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\SafeExamBrowser.WindowsApi.Contracts\SafeExamBrowser.WindowsApi.Contracts.csproj">
<Project>{7016f080-9aa5-41b2-a225-385ad877c171}</Project>
<Name>SafeExamBrowser.WindowsApi.Contracts</Name>
</ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project> </Project>

View file

@ -53,9 +53,9 @@ namespace SafeExamBrowser.Browser
public event DownloadRequestedEventHandler ConfigurationDownloadRequested; public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
public event IconChangedEventHandler IconChanged; public event IconChangedEventHandler IconChanged;
public event InstanceTerminatedEventHandler Terminated;
public event NameChangedEventHandler NameChanged; public event NameChangedEventHandler NameChanged;
public event PopupRequestedEventHandler PopupRequested; public event PopupRequestedEventHandler PopupRequested;
public event InstanceTerminatedEventHandler Terminated;
public BrowserApplicationInstance( public BrowserApplicationInstance(
AppConfig appConfig, AppConfig appConfig,
@ -85,13 +85,13 @@ namespace SafeExamBrowser.Browser
window?.BringToForeground(); window?.BringToForeground();
} }
internal void Initialize() public void Initialize()
{ {
InitializeControl(); InitializeControl();
InitializeWindow(); InitializeWindow();
} }
internal void Terminate() public void Terminate()
{ {
window?.Close(); window?.Close();
} }

View file

@ -12,7 +12,7 @@ namespace SafeExamBrowser.Browser
{ {
internal class BrowserInstanceIdentifier : InstanceIdentifier internal class BrowserInstanceIdentifier : InstanceIdentifier
{ {
public int Value { get; private set; } internal int Value { get; private set; }
public BrowserInstanceIdentifier(int id) public BrowserInstanceIdentifier(int id)
{ {

View file

@ -96,7 +96,8 @@ namespace SafeExamBrowser.Client
taskbar = BuildTaskbar(); taskbar = BuildTaskbar();
terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator))); terminationActivator = new TerminationActivator(ModuleLogger(nameof(TerminationActivator)));
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory))); var processFactory = new ProcessFactory(ModuleLogger(nameof(ProcessFactory)));
var applicationFactory = new ApplicationFactory(ModuleLogger(nameof(ApplicationFactory)), processFactory);
var applicationMonitor = new ApplicationMonitor(TWO_SECONDS, ModuleLogger(nameof(ApplicationMonitor)), nativeMethods, new ProcessFactory(ModuleLogger(nameof(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 displayMonitor = new DisplayMonitor(ModuleLogger(nameof(DisplayMonitor)), nativeMethods, systemInfo);
var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods); var explorerShell = new ExplorerShell(ModuleLogger(nameof(ExplorerShell)), nativeMethods);

View file

@ -21,7 +21,7 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" /> <TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" />
<ContentControl Grid.Row="1" x:Name="ApplicationButton" /> <ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" /> <StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" />
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -23,6 +23,6 @@
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" /> <Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" />
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -21,7 +21,7 @@
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" /> <TextBlock Grid.Row="0" x:Name="ApplicationName" Background="#99D3D3D3" FontWeight="Bold" Padding="5" TextAlignment="Center" />
<ContentControl Grid.Row="1" x:Name="ApplicationButton" /> <ContentControl Grid.Row="1" x:Name="ApplicationButton" FontWeight="Bold" />
<StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" /> <StackPanel Grid.Row="2" x:Name="InstancePanel" Background="#99D3D3D3" Orientation="Vertical" />
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -23,6 +23,6 @@
</ScrollViewer> </ScrollViewer>
</Border> </Border>
</Popup> </Popup>
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Padding="4" Template="{StaticResource TaskbarButton}" Width="60" /> <Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Padding="4" Template="{StaticResource TaskbarButton}" Width="60" />
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -40,6 +40,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
/// </summary> /// </summary>
event ProcessTerminatedEventHandler Terminated; event ProcessTerminatedEventHandler Terminated;
/// <summary>
/// Attempts to activate the process (i.e. bring its main window to the foreground). This may only work for interactive processes which have
/// a main window. Returns <c>true</c> if the process was successfully activated, otherwise <c>false</c>.
/// </summary>
bool TryActivate();
/// <summary> /// <summary>
/// Attempts to gracefully terminate the process by closing its main window. This will only work for interactive processes which have a main /// Attempts to gracefully terminate the process by closing its main window. This will only work for interactive processes which have a main
/// window. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c> if the process has terminated, /// window. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c> if the process has terminated,
@ -47,6 +53,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
/// </summary> /// </summary>
bool TryClose(int timeout_ms = 0); bool TryClose(int timeout_ms = 0);
/// <summary>
/// Attempts to retrieve the title of the main window of the process. This will only work if for interactive processes which have a main
/// window. Returns <c>true</c> if the title was successfully retrieved, otherwise <c>false</c>.
/// </summary>
bool TryGetWindowTitle(out string title);
/// <summary> /// <summary>
/// Attempts to immediately kill the process. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c> /// Attempts to immediately kill the process. Optionally waits the specified amount of time for the process to terminate. Returns <c>true</c>
/// if the process has terminated, otherwise <c>false</c>. /// if the process has terminated, otherwise <c>false</c>.

View file

@ -19,7 +19,6 @@ namespace SafeExamBrowser.WindowsApi
internal class Kernel32 internal class Kernel32
{ {
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hObject); internal static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)] [DllImport("kernel32.dll", SetLastError = true)]

View file

@ -11,9 +11,12 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Management; using System.Management;
using System.Runtime.InteropServices;
using SafeExamBrowser.Logging.Contracts; using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Contracts; using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events; using SafeExamBrowser.WindowsApi.Contracts.Events;
using SafeExamBrowser.WindowsApi.Types;
namespace SafeExamBrowser.WindowsApi namespace SafeExamBrowser.WindowsApi
{ {
@ -62,6 +65,31 @@ namespace SafeExamBrowser.WindowsApi
this.originalNameInitialized = true; this.originalNameInitialized = true;
} }
public bool TryActivate()
{
try
{
var success = User32.BringWindowToTop(process.MainWindowHandle);
var placement = new WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
User32.GetWindowPlacement(process.MainWindowHandle, ref placement);
if (placement.showCmd == (int) ShowWindowCommand.ShowMinimized)
{
success &= User32.ShowWindow(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) public bool TryClose(int timeout_ms = 0)
{ {
try try
@ -90,6 +118,25 @@ namespace SafeExamBrowser.WindowsApi
return false; 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) public bool TryKill(int timeout_ms = 0)
{ {
try try

View file

@ -51,6 +51,7 @@
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" /> <Reference Include="System.Management" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -91,6 +92,7 @@
<Compile Include="Types\RECT.cs" /> <Compile Include="Types\RECT.cs" />
<Compile Include="Types\STARTUPINFO.cs" /> <Compile Include="Types\STARTUPINFO.cs" />
<Compile Include="Types\Window.cs" /> <Compile Include="Types\Window.cs" />
<Compile Include="Types\WINDOWPLACEMENT.cs" />
<Compile Include="User32.cs" /> <Compile Include="User32.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -0,0 +1,22 @@
/*
* 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.Drawing;
namespace SafeExamBrowser.WindowsApi.Types
{
internal struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public Point ptMinPosition;
public Point ptMaxPosition;
public Rectangle rcNormalPosition;
}
}

View file

@ -24,7 +24,6 @@ namespace SafeExamBrowser.WindowsApi
internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); internal static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseClipboard(); internal static extern bool CloseClipboard();
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
@ -34,15 +33,15 @@ namespace SafeExamBrowser.WindowsApi
internal static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, uint dwDesiredAccess, IntPtr lpsa); internal static extern IntPtr CreateDesktop(string lpszDesktop, IntPtr lpszDevice, IntPtr pDevmode, int dwFlags, uint dwDesiredAccess, IntPtr lpsa);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)] internal static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool EmptyClipboard(); internal static extern bool EmptyClipboard();
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopDelegate lpEnumFunc, IntPtr lParam); internal static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopDelegate lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumWindows(EnumWindowsDelegate enumProc, IntPtr lParam); internal static extern bool EnumWindows(EnumWindowsDelegate enumProc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
@ -60,6 +59,9 @@ namespace SafeExamBrowser.WindowsApi
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, IntPtr pvInfo, int nLength, ref int lpnLengthNeeded); internal static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, IntPtr pvInfo, int nLength, ref int lpnLengthNeeded);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount); internal static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
@ -70,15 +72,12 @@ namespace SafeExamBrowser.WindowsApi
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsWindowVisible(IntPtr hWnd); internal static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool OpenClipboard(IntPtr hWndNewOwner); internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); internal static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
@ -91,25 +90,21 @@ namespace SafeExamBrowser.WindowsApi
internal static extern IntPtr SetWindowsHookEx(HookType hookType, HookDelegate lpfn, IntPtr hMod, uint dwThreadId); internal static extern IntPtr SetWindowsHookEx(HookType hookType, HookDelegate lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
internal static extern bool SwitchDesktop(IntPtr hDesktop); internal static extern bool SwitchDesktop(IntPtr hDesktop);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni); internal static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni); internal static extern bool SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook); internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UnhookWindowsHookEx(IntPtr hhk); internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
} }
} }