/* * Copyright (c) 2017 ETH Zürich, Educational Development and Technology (LET) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ using System; using System.ComponentModel; using System.Runtime.InteropServices; using SafeExamBrowser.WindowsApi.Constants; using SafeExamBrowser.WindowsApi.Types; namespace SafeExamBrowser.WindowsApi { /// /// Provides access to the native Windows API exposed by user32.dll. /// public static class User32 { /// /// Retrieves a window handle to the Windows taskbar. Returns IntPtr.Zero /// if the taskbar could not be found (i.e. if it isn't running). /// public static IntPtr GetShellWindowHandle() { return FindWindow("Shell_TrayWnd", null); } /// /// Retrieves the process ID of the main Windows explorer instance controlling /// desktop and taskbar or 0, if the process isn't running. /// /// public static uint GetShellProcessId() { var handle = FindWindow("Shell_TrayWnd", null); var threadId = GetWindowThreadProcessId(handle, out uint processId); return processId; } /// /// Retrieves the currently configured working area of the primary screen. /// /// /// If the working area could not be retrieved. /// public static RECT GetWorkingArea() { var workingArea = new RECT(); var success = SystemParametersInfo(SPI.GETWORKAREA, 0, ref workingArea, SPIF.NONE); if (!success) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return workingArea; } /// /// Instructs the main Windows explorer process to shut down. /// /// /// If the messge could not be successfully posted. Does not apply if the process isn't running! /// /// /// The close message 0x5B4 posted to the shell is undocumented and not officially supported: /// https://stackoverflow.com/questions/5689904/gracefully-exit-explorer-programmatically/5705965#5705965 /// public static void PostCloseMessageToShell() { var taskbarHandle = FindWindow("Shell_TrayWnd", null); var success = PostMessage(taskbarHandle, 0x5B4, IntPtr.Zero, IntPtr.Zero); if (!success) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } /// /// Sets the working area of the primary screen according to the given dimensions. /// /// /// If the working area could not be set. /// public static void SetWorkingArea(RECT workingArea) { var success = SystemParametersInfo(SPI.SETWORKAREA, 0, ref workingArea, SPIF.UPDATEANDCHANGE); if (!success) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", SetLastError = true)] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SystemParametersInfo(SPI uiAction, uint uiParam, ref RECT pvParam, SPIF fWinIni); } }