/* * Copyright (c) 2024 ETH Zürich, IT Services * * 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.Threading; using SafeExamBrowser.WindowsApi.Constants; using SafeExamBrowser.WindowsApi.Contracts.Events; using SafeExamBrowser.WindowsApi.Delegates; namespace SafeExamBrowser.WindowsApi.Hooks { internal class SystemHook { private SystemEventCallback callback; private AutoResetEvent detachEvent, detachResultAvailableEvent; private bool detachSuccess; private EventDelegate eventDelegate; private uint eventId; private IntPtr handle; internal Guid Id { get; private set; } public SystemHook(SystemEventCallback callback, uint eventId) { this.callback = callback; this.detachEvent = new AutoResetEvent(false); this.detachResultAvailableEvent = new AutoResetEvent(false); this.eventId = eventId; this.Id = Guid.NewGuid(); } internal void Attach() { // IMPORTANT: // Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code. // Not doing so will result in a CallbackOnCollectedDelegate error and subsequent application crash! eventDelegate = new EventDelegate(LowLevelSystemProc); handle = User32.SetWinEventHook(eventId, eventId, IntPtr.Zero, eventDelegate, 0, 0, Constant.WINEVENT_OUTOFCONTEXT); } internal void AwaitDetach() { detachEvent.WaitOne(); detachSuccess = User32.UnhookWinEvent(handle); detachResultAvailableEvent.Set(); } internal bool Detach() { detachEvent.Set(); detachResultAvailableEvent.WaitOne(); return detachSuccess; } private void LowLevelSystemProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) { callback(hwnd); } } }