using System; using System.Threading; using System.Windows.Forms; namespace PaintDotNet.SystemLayer { /// /// Encapsulates information and events about the current user session. /// This relates to Terminal Services in Windows. /// public static class UserSessions { private static OurControl messageControl; private static bool lastRemoteSessionValue; private static EventHandler sessionChanged; private static int sessionChangedCount; private static object lockObject = new object(); private sealed class OurControl : Control { public event EventHandler WmWtSessionChange; private void OnWmWtSessionChange() { if (WmWtSessionChange != null) { WmWtSessionChange(this, EventArgs.Empty); } } protected override void WndProc(ref Message m) { switch (m.Msg) { case NativeConstants.WM_WTSSESSION_CHANGE: OnWmWtSessionChange(); break; default: base.WndProc(ref m); break; } } } private static void OnSessionChanged() { if (sessionChanged != null) { sessionChanged(null, EventArgs.Empty); } } /// /// Occurs when the user changes between sessions. This event will only be /// raised when the value returned by IsRemote() changes. /// /// /// For example, if the user is currently logged in at the console, and then /// switches to a remote session (they use Remote Desktop from another computer), /// then this event will be raised. /// Note to implementors: This may be implemented as a no-op. /// public static event EventHandler SessionChanged { add { lock (lockObject) { sessionChanged += value; ++sessionChangedCount; if (sessionChangedCount == 1) { messageControl = new OurControl(); messageControl.CreateControl(); // force the HWND to be created messageControl.WmWtSessionChange += new EventHandler(SessionStrobeHandler); SafeNativeMethods.WTSRegisterSessionNotification(messageControl.Handle, NativeConstants.NOTIFY_FOR_ALL_SESSIONS); lastRemoteSessionValue = IsRemote; } } } remove { lock (lockObject) { sessionChanged -= value; int decremented = Interlocked.Decrement(ref sessionChangedCount); if (decremented == 0) { try { SafeNativeMethods.WTSUnRegisterSessionNotification(messageControl.Handle); } catch (EntryPointNotFoundException) { } messageControl.Dispose(); messageControl = null; } } } } /// /// Determines whether the user is running within a remoted session (Terminal Server, Remote Desktop). /// /// /// true if we're running in a remote session, false otherwise. /// /// /// You can use this to optimize the presentation of visual elements. Remote sessions /// are often bandwidth limited and less suitable for complex drawing. /// Note to implementors: This may be implemented as a no op; in this case, always return false. /// public static bool IsRemote { get { return 0 != SafeNativeMethods.GetSystemMetrics(NativeConstants.SM_REMOTESESSION); } } private static void SessionStrobeHandler(object sender, EventArgs e) { if (IsRemote != lastRemoteSessionValue) { lastRemoteSessionValue = IsRemote; OnSessionChanged(); } } } }