diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs deleted file mode 100644 index 9a34500b52..0000000000 --- a/src/modules/MouseWithoutBorders/App/Class/Common.cs +++ /dev/null @@ -1,1661 +0,0 @@ -// Copyright (c) Microsoft Corporation -// The Microsoft Corporation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Drawing; -using System.Drawing.Imaging; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; -using System.Runtime.InteropServices; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Windows.Forms; - -using Microsoft.PowerToys.Settings.UI.Library; - -// -// Most of the helper methods. -// -// -// 2008 created by Truong Do (ductdo). -// 2009-... modified by Truong Do (TruongDo). -// 2023- Included in PowerToys. -// -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; -using MouseWithoutBorders.Exceptions; - -using Clipboard = MouseWithoutBorders.Core.Clipboard; -using Thread = MouseWithoutBorders.Core.Thread; - -// Log is enough -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckClipboard()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetAsStartupItem(System.Boolean)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HelperThread()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetMyStorageDir()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#MouseEvent(MouseWithoutBorders.MOUSEDATA)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#KeybdEvent(MouseWithoutBorders.KEYBDDATA)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HookClipboard()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardData(MouseWithoutBorders.DATA,System.Boolean)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiverCallback(System.Object)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckNewVersion()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartServiceAndSendLogoffSignal()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetScreenConfig()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CaptureScreen()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#InitEncryption()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ToggleIcon()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNameAndIPAddresses()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#Cleanup()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "type", Target = "MouseWithoutBorders.Common", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ProcessPackage(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#get_Machine_Pool()", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean,System.String)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNewImageAndSaveTo(System.String,System.String)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#LogAll()", MessageId = "System.String.Format(System.IFormatProvider,System.String,System.Object[])", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#DragDropStep04()", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", MessageId = "MouseWithoutBorders.NativeMethods.WaitForSingleObject(System.IntPtr,System.Int32)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#GetText(System.IntPtr)", MessageId = "MouseWithoutBorders.NativeMethods.GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", MessageId = "MouseWithoutBorders.NativeMethods.WTSQueryUserToken(System.UInt32,System.IntPtr@)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32,System.Boolean,System.Int64)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateProcessInInputDesktopSession(System.String,System.String,System.String,System.Boolean,System.Int16)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SkSend(MouseWithoutBorders.DATA,System.Boolean,System.Int32)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardDataUsingTCP(MouseWithoutBorders.DATA,System.Boolean,System.Net.Sockets.Socket)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#UpdateMachineMatrix(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")] -[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReopenSockets(System.Boolean)", Justification = "Dotnet port with style preservation")] - -namespace MouseWithoutBorders -{ - internal partial class Common - { - internal Common() - { - } - - private static InputHook hook; - private static FrmMatrix matrixForm; - private static FrmInputCallback inputCallbackForm; - private static FrmAbout aboutForm; -#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter - internal static Thread helper; - internal static int screenWidth; - internal static int screenHeight; -#pragma warning restore SA1307 - private static int lastX; - private static int lastY; - - private static bool mainFormVisible = true; - private static bool runOnLogonDesktop; - private static bool runOnScrSaverDesktop; - -#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter - internal static int[] toggleIcons; - internal static int toggleIconsIndex; -#pragma warning restore SA1307 - internal const int TOGGLE_ICONS_SIZE = 4; - internal const int ICON_ONE = 0; - internal const int ICON_ALL = 1; - internal const int ICON_SMALL_CLIPBOARD = 2; - internal const int ICON_BIG_CLIPBOARD = 3; - internal const int ICON_ERROR = 4; - internal const int JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999; - - internal const int NETWORK_STREAM_BUF_SIZE = 1024 * 1024; - internal static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset); - private static Point lastPos; -#pragma warning disable SA1307 // Accessible fields should begin with upper-case names - internal static int switchCount; -#pragma warning restore SA1307 - private static long lastReconnectByHotKeyTime; -#pragma warning disable SA1307 // Accessible fields should begin with upper-case names - internal static int tcpPort; -#pragma warning restore SA1307 - private static bool secondOpenSocketTry; - private static string binaryName; - - internal static Process CurrentProcess { get; set; } - - internal static bool HotkeyMatched(int vkCode, bool winDown, bool ctrlDown, bool altDown, bool shiftDown, HotkeySettings hotkey) - { - return !hotkey.IsEmpty() && (vkCode == hotkey.Code) && (!hotkey.Win || winDown) && (!hotkey.Alt || altDown) && (!hotkey.Shift || shiftDown) && (!hotkey.Ctrl || ctrlDown); - } - - public static string BinaryName - { - get => Common.binaryName; - set => Common.binaryName = value; - } - - public static bool SecondOpenSocketTry - { - get => Common.secondOpenSocketTry; - set => Common.secondOpenSocketTry = value; - } - - public static long LastReconnectByHotKeyTime - { - get => Common.lastReconnectByHotKeyTime; - set => Common.lastReconnectByHotKeyTime = value; - } - - public static int SwitchCount - { - get => Common.switchCount; - set => Common.switchCount = value; - } - - public static Point LastPos - { - get => Common.lastPos; - set => Common.lastPos = value; - } - - internal static FrmAbout AboutForm - { - get => Common.aboutForm; - set => Common.aboutForm = value; - } - - internal static FrmInputCallback InputCallbackForm - { - get => Common.inputCallbackForm; - set => Common.inputCallbackForm = value; - } - - public static int PaintCount { get; set; } - - internal static bool RunOnScrSaverDesktop - { - get => Common.runOnScrSaverDesktop; - set => Common.runOnScrSaverDesktop = value; - } - - internal static bool RunOnLogonDesktop - { - get => Common.runOnLogonDesktop; - set => Common.runOnLogonDesktop = value; - } - - internal static bool RunWithNoAdminRight { get; set; } - - internal static int LastX - { - get => Common.lastX; - set => Common.lastX = value; - } - - internal static int LastY - { - get => Common.lastY; - set => Common.lastY = value; - } - - internal static int[] ToggleIcons => Common.toggleIcons; - - internal static int ScreenHeight => Common.screenHeight; - - internal static int ScreenWidth => Common.screenWidth; - - internal static bool Is64bitOS - { - get; set; - - // set { Common.is64bitOS = value; } - } - - internal static int ToggleIconsIndex - { - // get { return Common.toggleIconsIndex; } - set => Common.toggleIconsIndex = value; - } - - internal static InputHook Hook - { - get => Common.hook; - set => Common.hook = value; - } - - internal static SocketStuff Sk { get; set; } - - internal static FrmScreen MainForm { get; set; } - - internal static FrmMouseCursor MouseCursorForm { get; set; } - - internal static FrmMatrix MatrixForm - { - get => Common.matrixForm; - set => Common.matrixForm = value; - } - - internal static ID DesMachineID - { - get => MachineStuff.desMachineID; - - set - { - MachineStuff.desMachineID = value; - MachineStuff.DesMachineName = MachineStuff.NameFromID(MachineStuff.desMachineID); - } - } - - internal static ID MachineID => (ID)Setting.Values.MachineId; - - internal static string MachineName { get; set; } - - internal static bool MainFormVisible - { - get => Common.mainFormVisible; - set => Common.mainFormVisible = value; - } - - internal static Mutex SocketMutex { get; set; } // Synchronization between MouseWithoutBorders running in different desktops - - // TODO: For telemetry only, to be removed. - private static int socketMutexBalance; - - internal static void ReleaseSocketMutex() - { - if (SocketMutex != null) - { - Logger.LogDebug("SOCKET MUTEX BEGIN RELEASE."); - - try - { - _ = Interlocked.Decrement(ref socketMutexBalance); - SocketMutex.ReleaseMutex(); - } - catch (ApplicationException e) - { - // The current thread does not own the mutex, the thread acquired it will own it. - Logger.TelemetryLogTrace($"{nameof(ReleaseSocketMutex)}: {e.Message}. {Thread.CurrentThread.ManagedThreadId}/{UIThreadID}.", SeverityLevel.Warning); - } - - Logger.LogDebug("SOCKET MUTEX RELEASED."); - } - else - { - Logger.LogDebug("SOCKET MUTEX NULL."); - } - } - - internal static void AcquireSocketMutex() - { - if (SocketMutex != null) - { - Logger.LogDebug("SOCKET MUTEX BEGIN WAIT."); - int waitTimeout = 60000; // TcpListener.Stop may take very long to complete for some reason. - - int socketMutexBalance = int.MinValue; - - bool acquireMutex = ExecuteAndTrace( - "Waiting for sockets to close", - () => - { - socketMutexBalance = Interlocked.Increment(ref Common.socketMutexBalance); - _ = SocketMutex.WaitOne(waitTimeout); // The app now requires .Net 4.0. Note: .Net20RTM does not have the one-parameter version of the API. - }, - TimeSpan.FromSeconds(5)); - - // Took longer than expected. - if (!acquireMutex) - { - Process[] ps = Process.GetProcessesByName(Common.BinaryName); - Logger.TelemetryLogTrace($"Balance: {socketMutexBalance}, Active: {WinAPI.IsMyDesktopActive()}, Sid/Console: {Process.GetCurrentProcess().SessionId}/{NativeMethods.WTSGetActiveConsoleSessionId()}, Desktop/Input: {WinAPI.GetMyDesktop()}/{WinAPI.GetInputDesktop()}, count: {ps?.Length}.", SeverityLevel.Warning); - } - - Logger.LogDebug("SOCKET MUTEX ENDED."); - } - else - { - Logger.LogDebug("SOCKET MUTEX NULL."); - } - } - - internal static bool BlockingUI { get; private set; } - - internal static bool ExecuteAndTrace(string actionName, Action action, TimeSpan timeout, bool restart = false) - { - bool rv = true; - Logger.LogDebug(actionName); - bool done = false; - - BlockingUI = true; - - if (restart) - { - Common.MainForm.Text = Setting.Values.MyIdEx; - - /* closesocket() rarely gets stuck for some reason inside ntdll!ZwClose ...=>... afd!AfdCleanupCore. - * There is no good workaround for it so far, still working with [Winsock 2.0 Discussions] to address the issue. - * */ - new Thread( - () => - { - for (int i = 0; i < timeout.TotalSeconds; i++) - { - Thread.Sleep(1000); - - if (done) - { - return; - } - } - - Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}, restarting the process.", SeverityLevel.Warning, true); - - string desktop = WinAPI.GetMyDesktop(); - MachineStuff.oneInstanceCheck?.Close(); - _ = Process.Start(Application.ExecutablePath, desktop); - Logger.LogDebug($"Started on desktop {desktop}"); - - Process.GetCurrentProcess().KillProcess(true); - }, - $"{actionName} watchdog").Start(); - } - - Stopwatch timer = Stopwatch.StartNew(); - - try - { - action(); - } - finally - { - done = true; - BlockingUI = false; - - if (restart) - { - Common.MainForm.Text = Setting.Values.MyID; - } - - timer.Stop(); - - if (timer.Elapsed > timeout) - { - rv = false; - - if (!restart) - { - Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}: {(long)timer.Elapsed.TotalSeconds}.", SeverityLevel.Warning); - } - } - } - - return rv; - } - - internal static byte[] GetBytes(string st) - { - return ASCIIEncoding.ASCII.GetBytes(st); - } - - internal static string GetString(byte[] bytes) - { - return ASCIIEncoding.ASCII.GetString(bytes); - } - - internal static byte[] GetBytesU(string st) - { - return ASCIIEncoding.Unicode.GetBytes(st); - } - - internal static string GetStringU(byte[] bytes) - { - return ASCIIEncoding.Unicode.GetString(bytes); - } - - internal static int UIThreadID { get; set; } - - internal static void DoSomethingInUIThread(Action action, bool blocking = false) - { - InvokeInFormThread(MainForm, UIThreadID, action, blocking); - } - - internal static int InputCallbackThreadID { get; set; } - - internal static void DoSomethingInTheInputCallbackThread(Action action, bool blocking = true) - { - InvokeInFormThread(InputCallbackForm, InputCallbackThreadID, action, blocking); - } - - private static void InvokeInFormThread(System.Windows.Forms.Form form, int threadId, Action action, bool blocking) - { - if (form != null) - { - int currentThreadId = Thread.CurrentThread.ManagedThreadId; - - if (currentThreadId == threadId) - { - action(); - } - else - { - bool done = false; - - try - { - Action callback = () => - { - try - { - action(); - } - catch (Exception e) - { - Logger.Log(e); - } - finally - { - done = true; - } - }; - _ = form.BeginInvoke(callback); - } - catch (Exception e) - { - done = true; - Logger.Log(e); - } - - while (blocking && !done) - { - Thread.Sleep(16); - - if (currentThreadId == UIThreadID || currentThreadId == InputCallbackThreadID) - { - Application.DoEvents(); - } - } - } - } - } - - private static readonly Lock InputSimulationLock = new(); - - internal static void DoSomethingInTheInputSimulationThread(ThreadStart target) - { - /* - * For some reason, SendInput may hit deadlock if it is called in the InputHookProc thread. - * For now leave it as is in the caller thread which is the socket receiver thread. - * */ - - // SendInput is thread-safe but few users seem to hit a deadlock occasionally, probably a Windows bug. - lock (InputSimulationLock) - { - target(); - } - } - - internal static void SendPackage(ID des, PackageType packageType) - { - DATA package = new(); - package.Type = packageType; - package.Des = des; - package.MachineName = MachineName; - - SkSend(package, null, false); - } - - internal static void SendHeartBeat(bool initial = false) - { - SendPackage(ID.ALL, initial && Encryption.GeneratedKey ? PackageType.Heartbeat_ex : PackageType.Heartbeat); - } - - private static long lastSendNextMachine; - - internal static void SendNextMachine(ID hostMachine, ID nextMachine, Point requestedXY) - { - Logger.LogDebug($"SendNextMachine: Host machine: {hostMachine}, Next machine: {nextMachine}, Requested XY: {requestedXY}"); - - if (GetTick() - lastSendNextMachine < 100) - { - Logger.LogDebug("Machine switching in progress."); // "Move Mouse relatively" mode, slow machine/network, quick/busy hand. - return; - } - - lastSendNextMachine = GetTick(); - - DATA package = new(); - package.Type = PackageType.NextMachine; - - package.Des = hostMachine; - - package.Md.X = requestedXY.X; - package.Md.Y = requestedXY.Y; - package.Md.WheelDelta = (int)nextMachine; - - SkSend(package, null, false); - - Logger.LogDebug("SendNextMachine done."); - } - - private static ulong lastInputEventCount; - private static ulong lastRealInputEventCount; - - internal static void SendAwakeBeat() - { - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive() && - Setting.Values.BlockScreenSaver && lastRealInputEventCount != Event.RealInputEventCount) - { - SendPackage(ID.ALL, PackageType.Awake); - } - else - { - SendHeartBeat(); - } - - lastInputEventCount = Event.InputEventCount; - lastRealInputEventCount = Event.RealInputEventCount; - } - - internal static void HumanBeingDetected() - { - if (lastInputEventCount == Event.InputEventCount) - { - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive()) - { - PokeMyself(); - } - } - - lastInputEventCount = Event.InputEventCount; - } - - internal static void PokeMyself() - { - int x, y = 0; - - for (int i = 0; i < 10; i++) - { - x = Encryption.Ran.Next(-9, 10); - InputSimulation.MoveMouseRelative(x, y); - Thread.Sleep(50); - InputSimulation.MoveMouseRelative(-x, -y); - Thread.Sleep(50); - - if (lastInputEventCount != Event.InputEventCount) - { - break; - } - } - } - - internal static void InitLastInputEventCount() - { - lastInputEventCount = Event.InputEventCount; - lastRealInputEventCount = Event.RealInputEventCount; - } - - internal static void SendHello() - { - SendPackage(ID.ALL, PackageType.Hello); - } - - /* - internal static void SendHi() - { - SendPackage(IP.ALL, PackageType.hi); - } - * */ - - internal static void SendByeBye() - { - Logger.LogDebug($"{nameof(SendByeBye)}"); - SendPackage(ID.ALL, PackageType.ByeBye); - } - - internal static void SendClipboardBeat() - { - SendPackage(ID.ALL, PackageType.Clipboard); - } - - internal static void ProcessByeByeMessage(DATA package) - { - if (package.Src == MachineStuff.desMachineID) - { - MachineStuff.SwitchToMachine(MachineName.Trim()); - } - - _ = MachineStuff.RemoveDeadMachines(package.Src); - } - - internal static long GetTick() // ms - { - return DateTime.Now.Ticks / 10000; - } - - internal static void SetToggleIcon(int[] toggleIcons) - { - Logger.LogDebug($"{nameof(SetToggleIcon)}: {toggleIcons?.FirstOrDefault()}"); - Common.toggleIcons = toggleIcons; - toggleIconsIndex = 0; - } - - internal static string CaptureScreen() - { - try - { - string fileName = GetMyStorageDir() + @"ScreenCaptureByMouseWithoutBorders.png"; - int w = MachineStuff.desktopBounds.Right - MachineStuff.desktopBounds.Left; - int h = MachineStuff.desktopBounds.Bottom - MachineStuff.desktopBounds.Top; - Bitmap bm = new(w, h); - Graphics g = Graphics.FromImage(bm); - Size s = new(w, h); - g.CopyFromScreen(MachineStuff.desktopBounds.Left, MachineStuff.desktopBounds.Top, 0, 0, s); - bm.Save(fileName, ImageFormat.Png); - bm.Dispose(); - return fileName; - } - catch (Exception e) - { - Logger.Log(e); - return null; - } - } - - internal static void PrepareScreenCapture() - { - Common.DoSomethingInUIThread(() => - { - if (!DragDrop.MouseDown && Helper.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0) - { - Common.MMSleep(0.2); - InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT }); - InputSimulation.SendKey(new KEYBDDATA() { dwFlags = (int)WM.LLKHF.UP, wVk = (int)VK.SNAPSHOT }); - - Logger.LogDebug("PrepareScreenCapture: SNAPSHOT simulated."); - - _ = NativeMethods.MoveWindow( - (IntPtr)NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT), - MachineStuff.DesktopBounds.Left, - MachineStuff.DesktopBounds.Top, - MachineStuff.DesktopBounds.Right - MachineStuff.DesktopBounds.Left, - MachineStuff.DesktopBounds.Bottom - MachineStuff.DesktopBounds.Top, - false); - - _ = Helper.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false); - } - else - { - Logger.Log("PrepareScreenCapture: Validation failed."); - } - }); - } - - internal static void OpenImage(string file) - { - // We want to run mspaint under the user account who ran explorer.exe (who logged in this current input desktop) - - // ImpersonateLoggedOnUserAndDoSomething(delegate() - // { - // Process.Start("explorer", "\"" + file + "\""); - // }); - _ = Launch.CreateProcessInInputDesktopSession( - "\"" + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") + - "\"", - "\"" + file + "\"", - WinAPI.GetInputDesktop(), - 1); - - // CreateNormalIntegrityProcess(Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") + - // " \"" + file + "\""); - - // We don't want to run mspaint as local system account - /* - ProcessStartInfo s = new ProcessStartInfo( - Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe"), - "\"" + file + "\""); - s.WindowStyle = ProcessWindowStyle.Maximized; - Process.Start(s); - * */ - } - - internal static void SendImage(string machine, string file) - { - Clipboard.LastDragDropFile = file; - - // Send ClipboardCapture - if (machine.Equals("All", StringComparison.OrdinalIgnoreCase)) - { - SendPackage(ID.ALL, PackageType.ClipboardCapture); - } - else - { - ID id = MachineStuff.MachinePool.ResolveID(machine); - if (id != ID.NONE) - { - SendPackage(id, PackageType.ClipboardCapture); - } - } - } - - internal static void SendImage(ID src, string file) - { - Clipboard.LastDragDropFile = file; - - // Send ClipboardCapture - SendPackage(src, PackageType.ClipboardCapture); - } - - internal static void ShowToolTip(string tip, int timeOutInMilliseconds = 5000, ToolTipIcon icon = ToolTipIcon.Info, bool showBalloonTip = true, bool forceEvenIfHidingOldUI = false) - { - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) - { - DoSomethingInUIThread(() => - { - if (Setting.Values.FirstRun) - { - MachineStuff.Settings?.ShowTip(icon, tip, timeOutInMilliseconds); - } - - Common.MatrixForm?.ShowTip(icon, tip, timeOutInMilliseconds); - - if (showBalloonTip) - { - if (MainForm != null) - { - MainForm.ShowToolTip(tip, timeOutInMilliseconds, forceEvenIfHidingOldUI: forceEvenIfHidingOldUI); - } - else - { - Logger.Log(tip); - } - } - }); - } - } - - private static FrmMessage topMostMessageForm; - - internal static void ToggleShowTopMostMessage(string text, string bigText, int timeOut) - { - DoSomethingInUIThread(() => - { - if (topMostMessageForm == null) - { - topMostMessageForm = new FrmMessage(text, bigText, timeOut); - topMostMessageForm.Show(); - } - else - { - FrmMessage currentMessageForm = topMostMessageForm; - topMostMessageForm = null; - currentMessageForm.Close(); - } - }); - } - - internal static void HideTopMostMessage() - { - DoSomethingInUIThread(() => - { - topMostMessageForm?.Close(); - }); - } - - internal static void NullTopMostMessage() - { - DoSomethingInUIThread(() => - { - if (topMostMessageForm != null) - { - topMostMessageForm = null; - } - }); - } - - internal static bool IsTopMostMessageNotNull() - { - return topMostMessageForm != null; - } - - private static bool TestSend(TcpSk t) - { - ID remoteMachineID; - - if (t.Status == SocketStatus.Connected) - { - try - { - DATA package = new(); - package.Type = PackageType.Hi; - package.Des = remoteMachineID = (ID)t.MachineId; - package.MachineName = MachineName; - - _ = Sk.TcpSend(t, package); - t.EncryptedStream?.Flush(); - - return true; - } - catch (ExpectedSocketException) - { - t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() - } - } - - t.Status = SocketStatus.SendError; - return false; - } - - internal static bool IsConnectedTo(ID remoteMachineID) - { - bool updateClientSockets = false; - - if (remoteMachineID == MachineID) - { - return true; - } - - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - if (sk.TcpSockets != null) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t.Status == SocketStatus.Connected && (uint)remoteMachineID == t.MachineId) - { - if (TestSend(t)) - { - return true; - } - else - { - updateClientSockets = true; - } - } - } - } - } - } - - if (updateClientSockets) - { - MachineStuff.UpdateClientSockets(nameof(IsConnectedTo)); - } - - return false; - } - -#if DEBUG - private static long minSendTime = long.MaxValue; - private static long avgSendTime; - private static long maxSendTime; - private static long totalSendCount; - private static long totalSendTime; -#endif - - internal static void SkSend(DATA data, uint? exceptDes, bool includeHandShakingSockets) - { - bool connected = false; - - SocketStuff sk = Sk; - - if (sk != null) - { -#if DEBUG - long startStop = DateTime.Now.Ticks; - totalSendCount++; -#endif - - try - { - data.Id = Interlocked.Increment(ref Package.PackageID); - - bool updateClientSockets = false; - - lock (sk.TcpSocketsLock) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t != null && t.BackingSocket != null && (t.Status == SocketStatus.Connected || (t.Status == SocketStatus.Handshaking && includeHandShakingSockets))) - { - if (t.MachineId == (uint)data.Des || (data.Des == ID.ALL && t.MachineId != exceptDes && MachineStuff.InMachineMatrix(t.MachineName))) - { - try - { - sk.TcpSend(t, data); - - if (data.Des != ID.ALL) - { - connected = true; - } - } - catch (ExpectedSocketException) - { - t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() - updateClientSockets = true; - } - catch (Exception e) - { - Logger.Log(e); - t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() - updateClientSockets = true; - } - } - } - } - } - - if (!connected && data.Des != ID.ALL) - { - Logger.LogDebug("********** No active connection found for the remote machine! **********" + data.Des.ToString()); - - if (data.Des == ID.NONE || MachineStuff.RemoveDeadMachines(data.Des)) - { - // SwitchToMachine(MachineName.Trim()); - MachineStuff.NewDesMachineID = DesMachineID = MachineID; - MachineStuff.SwitchLocation.X = Event.XY_BY_PIXEL + Event.myLastX; - MachineStuff.SwitchLocation.Y = Event.XY_BY_PIXEL + Event.myLastY; - MachineStuff.SwitchLocation.ResetCount(); - EvSwitch.Set(); - } - } - - if (updateClientSockets) - { - MachineStuff.UpdateClientSockets("SkSend"); - } - } - catch (Exception e) - { - Logger.Log(e); - } - -#if DEBUG - startStop = DateTime.Now.Ticks - startStop; - totalSendTime += startStop; - if (startStop < minSendTime) - { - minSendTime = startStop; - } - - if (startStop > maxSendTime) - { - maxSendTime = startStop; - } - - avgSendTime = totalSendTime / totalSendCount; -#endif - } - else - { - Package.PackageSent.Nil++; - } - } - - internal static void CloseAnUnusedSocket() - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - if (sk.TcpSockets != null) - { - TcpSk tobeRemoved = null; - - foreach (TcpSk t in sk.TcpSockets) - { - if ((t.Status != SocketStatus.Connected && t.BirthTime < GetTick() - SocketStuff.CONNECT_TIMEOUT) || t.BackingSocket == null) - { - Logger.LogDebug("CloseAnUnusedSocket: " + t.MachineName + ":" + t.MachineId + "|" + t.Status.ToString()); - tobeRemoved = t; - - if (t.BackingSocket != null) - { - try - { - t.BackingSocket.Close(); - } - catch (Exception e) - { - Logger.Log(e); - } - } - - break; // Each time we try to remove one socket only. - } - } - - if (tobeRemoved != null) - { - _ = sk.TcpSockets.Remove(tobeRemoved); - } - } - } - } - } - - internal static bool AtLeastOneSocketConnected() - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - if (sk.TcpSockets != null) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t.Status == SocketStatus.Connected) - { - Logger.LogDebug("AtLeastOneSocketConnected returning true: " + t.MachineName); - return true; - } - } - } - } - } - - Logger.LogDebug("AtLeastOneSocketConnected returning false."); - return false; - } - - internal static Socket AtLeastOneServerSocketConnected() - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - if (sk.TcpSockets != null) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (!t.IsClient && t.Status == SocketStatus.Connected) - { - Logger.LogDebug("AtLeastOneServerSocketConnected returning true: " + t.MachineName); - return t.BackingSocket; - } - } - } - } - } - - Logger.LogDebug("AtLeastOneServerSocketConnected returning false."); - return null; - } - - internal static TcpSk GetConnectedClientSocket() - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - return sk.TcpSockets?.FirstOrDefault(item => item.IsClient && item.Status == SocketStatus.Connected); - } - } - else - { - return null; - } - } - - internal static bool AtLeastOneSocketEstablished() - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - if (sk.TcpSockets != null) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t.BackingSocket != null && t.BackingSocket.Connected) - { - if (TestSend(t)) - { - Logger.LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning true: {t.MachineName}"); - return true; - } - } - } - } - } - } - - Logger.LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning false."); - return false; - } - - internal static bool IsConnectedByAClientSocketTo(string machineName) - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t != null && t.IsClient && t.Status == SocketStatus.Connected - && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - } - - return false; - } - - internal static IPAddress GetConnectedClientSocketIPAddressFor(string machineName) - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - return sk.TcpSockets.FirstOrDefault(t => t != null && t.IsClient && t.Status == SocketStatus.Connected - && t.Address != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase)) - ?.Address; - } - } - - return null; - } - - internal static bool IsConnectingByAClientSocketTo(string machineName, IPAddress ip) - { - SocketStuff sk = Common.Sk; - - if (sk != null) - { - lock (sk.TcpSocketsLock) - { - foreach (TcpSk t in sk.TcpSockets) - { - if (t != null && t.IsClient && t.Status == SocketStatus.Connecting - && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase) - && t.Address.ToString().Equals(ip.ToString(), StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - } - - return false; - } - - internal static void UpdateSetupMachineMatrix(string desMachine) - { - int machineCt = 0; - - foreach (string m in MachineStuff.MachineMatrix) - { - if (!string.IsNullOrEmpty(m.Trim())) - { - machineCt++; - } - } - - if (machineCt < 2 && MachineStuff.Settings != null && (MachineStuff.Settings.GetCurrentPage() is SetupPage1 || MachineStuff.Settings.GetCurrentPage() is SetupPage2b)) - { - MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { Common.MachineName.Trim(), desMachine, string.Empty, string.Empty }; - Logger.LogDebug("UpdateSetupMachineMatrix: " + string.Join(",", MachineStuff.MachineMatrix)); - - Common.DoSomethingInUIThread( - () => - { - MachineStuff.Settings.SetControlPage(new SetupPage4()); - }, - true); - } - } - - internal static void ReopenSockets(bool byUser) - { - DoSomethingInUIThread( - () => - { - try - { - SocketStuff tmpSk = Sk; - - if (tmpSk != null) - { - Sk = null; // TODO: This looks redundant. - tmpSk.Close(byUser); - } - - Sk = new SocketStuff(tcpPort, byUser); - } - catch (Exception e) - { - Sk = null; - Logger.Log(e); - } - - if (Sk != null) - { - if (byUser) - { - SocketStuff.ClearBadIPs(); - } - - MachineStuff.UpdateClientSockets("ReopenSockets"); - } - }, - true); - - if (Sk == null) - { - return; - } - - Common.DoSomethingInTheInputCallbackThread(() => - { - if (Common.Hook != null) - { - Common.Hook.Stop(); - Common.Hook = null; - } - - if (byUser) - { - Common.InputCallbackForm.Close(); - Common.InputCallbackForm = null; - Program.StartInputCallbackThread(); - } - else - { - Common.InputCallbackForm.InstallKeyboardAndMouseHook(); - } - }); - } - - internal static string GetMyStorageDir() - { - string st = string.Empty; - - try - { - if (RunOnLogonDesktop || RunOnScrSaverDesktop) - { - st = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); - if (!Directory.Exists(st)) - { - _ = Directory.CreateDirectory(st); - } - - st += @"\" + Common.BinaryName; - if (!Directory.Exists(st)) - { - _ = Directory.CreateDirectory(st); - } - - st += @"\ScreenCaptures\"; - if (!Directory.Exists(st)) - { - _ = Directory.CreateDirectory(st); - } - } - else - { - _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => - { - st = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\" + Common.BinaryName; - if (!Directory.Exists(st)) - { - _ = Directory.CreateDirectory(st); - } - - st += @"\ScreenCaptures\"; - if (!Directory.Exists(st)) - { - _ = Directory.CreateDirectory(st); - } - }); - } - - Logger.LogDebug("GetMyStorageDir: " + st); - - // Delete old files. - foreach (FileInfo fi in new DirectoryInfo(st).GetFiles()) - { - if (fi.CreationTime.AddDays(1) < DateTime.Now) - { - fi.Delete(); - } - } - - return st; - } - catch (Exception e) - { - Logger.Log(e); - - if (string.IsNullOrEmpty(st) || !st.Contains(Common.BinaryName)) - { - st = Path.GetTempPath(); - } - - return st; - } - } - - internal static void GetMachineName() - { - string machine_Name = string.Empty; - - try - { - machine_Name = Dns.GetHostName(); - Logger.LogDebug("GetHostName = " + machine_Name); - } - catch (Exception e) - { - Logger.Log(e); - - if (string.IsNullOrEmpty(machine_Name)) - { - machine_Name = "RANDOM" + Encryption.Ran.Next().ToString(CultureInfo.CurrentCulture); - } - } - - if (machine_Name.Length > 32) - { - machine_Name = machine_Name[..32]; - } - - Common.MachineName = machine_Name.Trim(); - - Logger.LogDebug($"========== {nameof(GetMachineName)} ended!"); - } - - private static string GetNetworkName(NetworkInterface networkInterface) - { - return $"{networkInterface.Name} | {networkInterface.Description.Replace(":", "-")}"; - } - - internal static string GetRemoteStringIP(Socket s, bool throwException = false) - { - if (s == null) - { - return string.Empty; - } - - string ip; - - try - { - ip = (s?.RemoteEndPoint as IPEndPoint)?.Address?.ToString(); - - if (string.IsNullOrEmpty(ip)) - { - return string.Empty; - } - } - catch (ObjectDisposedException e) - { - Logger.Log($"{nameof(GetRemoteStringIP)}: The socket could have been disposed by other threads, error: {e.Message}"); - - if (throwException) - { - throw; - } - - return string.Empty; - } - catch (SocketException e) - { - Logger.Log($"{nameof(GetRemoteStringIP)}: {e.Message}"); - - if (throwException) - { - throw; - } - - return string.Empty; - } - - return ip; - } - - internal static void CloseAllFormsAndHooks() - { - if (Hook != null) - { - Hook.Stop(); - Hook = null; - if (InputCallbackForm != null) - { - DoSomethingInTheInputCallbackThread(() => - { - InputCallbackForm.Close(); - InputCallbackForm = null; - }); - } - } - - if (MainForm != null) - { - MainForm.Destroy(); - MainForm = null; - } - - if (MatrixForm != null) - { - MatrixForm.Close(); - MatrixForm = null; - } - - if (AboutForm != null) - { - AboutForm.Close(); - AboutForm = null; - } - } - - internal static void MoveMouseToCenter() - { - Logger.LogDebug("+++++ MoveMouseToCenter"); - InputSimulation.MoveMouse( - MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2), - MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2)); - } - - internal static void HideMouseCursor(bool byHideMouseMessage) - { - Common.LastPos = new Point( - MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2), - Setting.Values.HideMouse ? 4 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2)); - - if ((MachineStuff.desMachineID != MachineID && MachineStuff.desMachineID != ID.ALL) || byHideMouseMessage) - { - _ = NativeMethods.SetCursorPos(Common.LastPos.X, Common.LastPos.Y); - _ = NativeMethods.GetCursorPos(ref Common.lastPos); - Logger.LogDebug($"+++++ HideMouseCursor, byHideMouseMessage = {byHideMouseMessage}"); - } - - CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); - } - - internal static string GetText(IntPtr hWnd) - { - int length = NativeMethods.GetWindowTextLength(hWnd); - StringBuilder sb = new(length + 1); - int rv = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity); - Logger.LogDebug("GetWindowText returned " + rv.ToString(CultureInfo.CurrentCulture)); - return sb.ToString(); - } - - public static string GetWindowClassName(IntPtr hWnd) - { - StringBuilder buffer = new(128); - _ = NativeMethods.GetClassName(hWnd, buffer, buffer.Capacity); - return buffer.ToString(); - } - - internal static void MMSleep(double secs) - { - for (int i = 0; i < secs * 10; i++) - { - Application.DoEvents(); - Thread.Sleep(100); - } - } - - internal static void UpdateMultipleModeIconAndMenu() - { - MainForm?.UpdateMultipleModeIconAndMenu(); - } - - internal static void SendOrReceiveARandomDataBlockPerInitialIV(Stream st, bool send = true) - { - byte[] ranData = new byte[Encryption.SymAlBlockSize]; - - try - { - if (send) - { - ranData = RandomNumberGenerator.GetBytes(Encryption.SymAlBlockSize); - st.Write(ranData, 0, ranData.Length); - } - else - { - int toRead = ranData.Length; - int read = st.ReadEx(ranData, 0, toRead); - - if (read != toRead) - { - Logger.LogDebug("Stream has no more data after reading {0} bytes.", read); - } - } - } - catch (IOException e) - { - string log = $"{nameof(SendOrReceiveARandomDataBlockPerInitialIV)}: Exception {(send ? "writing" : "reading")} to the socket stream: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; - Logger.Log(log); - - if (e.InnerException is not (SocketException or ObjectDisposedException)) - { - throw; - } - } - } - - private static bool DisableEasyMouseWhenForegroundWindowIsFullscreenSetting() - { - return Setting.Values.DisableEasyMouseWhenForegroundWindowIsFullscreen; - } - - private static bool IsAppIgnoredByEasyMouseFullscreenCheck(IntPtr foregroundWindowHandle) - { - if (NativeMethods.GetWindowThreadProcessId(foregroundWindowHandle, out var processId) == 0) - { - Logger.LogDebug($"GetWindowThreadProcessId failed with error : {Marshal.GetLastWin32Error()}"); - return false; - } - - var processHandle = NativeMethods.OpenProcess(0x1000, false, processId); - if (processHandle == IntPtr.Zero) - { - return false; - } - - uint maxPath = 260; - var nameBuffer = new char[maxPath]; - if (!NativeMethods.QueryFullProcessImageName( - processHandle, NativeMethods.QUERY_FULL_PROCESS_NAME_FLAGS.DEFAULT, nameBuffer, ref maxPath)) - { - Logger.LogDebug($"QueryFullProcessImageName failed with error : {Marshal.GetLastWin32Error()}"); - NativeMethods.CloseHandle(processHandle); - return false; - } - - NativeMethods.CloseHandle(processHandle); - - var name = new string(nameBuffer, 0, (int)maxPath); - - var excludedApps = Setting.Values.EasyMouseFullscreenSwitchBlockExcludedApps; - - return excludedApps.Contains(Path.GetFileNameWithoutExtension(name), StringComparer.OrdinalIgnoreCase) - || excludedApps.Contains(Path.GetFileName(name), StringComparer.OrdinalIgnoreCase); - } - - internal static bool IsEasyMouseBlockedByFullscreenWindow() - { - var shellHandle = NativeMethods.GetShellWindow(); - var desktopHandle = NativeMethods.GetDesktopWindow(); - var foregroundHandle = NativeMethods.GetForegroundWindow(); - - // If the foreground window is either the desktop or the Windows shell, we are not in fullscreen mode. - if (foregroundHandle.Equals(shellHandle) || foregroundHandle.Equals(desktopHandle)) - { - return false; - } - - if (NativeMethods.SHQueryUserNotificationState(out var userNotificationState) != 0) - { - Logger.LogDebug($"SHQueryUserNotificationState failed with error : {Marshal.GetLastWin32Error()}"); - return false; - } - - switch (userNotificationState) - { - // An application running in full screen mode, check if the foreground window is - // listed as ignored in the settings. - case NativeMethods.USER_NOTIFICATION_STATE.BUSY: - case NativeMethods.USER_NOTIFICATION_STATE.RUNNING_D3D_FULL_SCREEN: - case NativeMethods.USER_NOTIFICATION_STATE.PRESENTATION_MODE: - return !IsAppIgnoredByEasyMouseFullscreenCheck(foregroundHandle); - - // No full screen app running. - case NativeMethods.USER_NOTIFICATION_STATE.NOT_PRESENT: - case NativeMethods.USER_NOTIFICATION_STATE.ACCEPTS_NOTIFICATIONS: - case NativeMethods.USER_NOTIFICATION_STATE.QUIET_TIME: - // Cannot determine - case NativeMethods.USER_NOTIFICATION_STATE.APP: - default: - return false; - } - } - - /// - /// Check if a machine switch triggered by EasyMouse would be allowed to proceed due to other settings. - /// - /// A boolean that tells us if the switch isn't blocked by any other settings - internal static bool IsEasyMouseSwitchAllowed() - { - // Never prevent a switch if we are not moving out of the host machine. - if (!DisableEasyMouseWhenForegroundWindowIsFullscreenSetting() || DesMachineID != MachineID) - { - return true; - } - - // Check if the switch is blocked by a full-screen window running in the foreground - return !IsEasyMouseBlockedByFullscreenWindow(); - } - } -} diff --git a/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs index 62360b4795..15ac6fb8b8 100644 --- a/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs +++ b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs @@ -18,12 +18,12 @@ using System.Threading.Tasks; using System.Windows.Forms; using Microsoft.VisualStudio.Threading; +using MouseWithoutBorders.Core; using Newtonsoft.Json; using StreamJsonRpc; #if !MM_HELPER using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; #endif using SystemClipboard = System.Windows.Forms.Clipboard; @@ -246,11 +246,11 @@ WellKnownSidType.AuthenticatedUserSid, null); CancellationToken cancellationToken = _serverTaskCancellationSource.Token; IpcChannel.StartIpcServer(ChannelName + "/" + RemoteObjectName, cancellationToken); - Common.IpcChannelCreated = true; + IpcChannelHelper.IpcChannelCreated = true; } catch (Exception e) { - Common.IpcChannelCreated = false; + IpcChannelHelper.IpcChannelCreated = false; Common.ShowToolTip("Error setting up clipboard sharing, clipboard sharing will not work!", 5000, ToolTipIcon.Error); Logger.Log(e); } @@ -405,7 +405,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.ContainsFileDropList), () => { return SystemClipboard.ContainsFileDropList(); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsFileDropList), () => { return SystemClipboard.ContainsFileDropList(); }, (log) => Log(log)); } catch (ExternalException e) { @@ -427,7 +427,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.ContainsImage), () => { return SystemClipboard.ContainsImage(); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsImage), () => { return SystemClipboard.ContainsImage(); }, (log) => Log(log)); } catch (ExternalException e) { @@ -449,7 +449,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.ContainsText), () => { return SystemClipboard.ContainsText(); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsText), () => { return SystemClipboard.ContainsText(); }, (log) => Log(log)); } catch (ExternalException e) { @@ -471,7 +471,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.GetFileDropList), () => { return SystemClipboard.GetFileDropList(); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetFileDropList), () => { return SystemClipboard.GetFileDropList(); }, (log) => Log(log)); } catch (ExternalException e) { @@ -493,7 +493,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.GetImage), () => { return SystemClipboard.GetImage(); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetImage), () => { return SystemClipboard.GetImage(); }, (log) => Log(log)); } catch (ExternalException e) { @@ -515,7 +515,7 @@ WellKnownSidType.AuthenticatedUserSid, null); try { - rv = Common.Retry(nameof(SystemClipboard.GetText), () => { return SystemClipboard.GetText(format); }, (log) => Log(log)); + rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetText), () => { return SystemClipboard.GetText(format); }, (log) => Log(log)); } catch (ExternalException e) { @@ -539,7 +539,7 @@ WellKnownSidType.AuthenticatedUserSid, null); { try { - _ = Common.Retry( + _ = IpcChannelHelper.Retry( nameof(SystemClipboard.SetImage), () => { @@ -568,7 +568,7 @@ WellKnownSidType.AuthenticatedUserSid, null); { try { - _ = Common.Retry( + _ = IpcChannelHelper.Retry( nameof(SystemClipboard.SetText), () => { @@ -600,44 +600,4 @@ WellKnownSidType.AuthenticatedUserSid, null); { internal const int QUIT_CMD = 0x409; } - - internal sealed partial class Common - { - internal static bool IpcChannelCreated { get; set; } - - internal static T Retry(string name, Func func, Action log, Action preRetry = null) - { - int count = 0; - - do - { - try - { - T rv = func(); - - if (count > 0) - { - log($"Trace: {name} has been successful after {count} retry."); - } - - return rv; - } - catch (Exception) - { - count++; - - preRetry?.Invoke(); - - if (count > 10) - { - throw; - } - - Application.DoEvents(); - Thread.Sleep(200); - } - } - while (true); - } - } } diff --git a/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs b/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs index e557ff4a37..db16ac8b4d 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Clipboard.cs @@ -1036,7 +1036,7 @@ internal static class Clipboard { try { - _ = Common.Retry( + _ = IpcChannelHelper.Retry( nameof(SystemClipboard.SetFileDropList), () => { @@ -1073,7 +1073,7 @@ internal static class Clipboard { try { - _ = Common.Retry( + _ = IpcChannelHelper.Retry( nameof(SystemClipboard.SetImage), () => { @@ -1104,7 +1104,7 @@ internal static class Clipboard { try { - _ = Common.Retry( + _ = IpcChannelHelper.Retry( nameof(SystemClipboard.SetText), () => { diff --git a/src/modules/MouseWithoutBorders/App/Core/Common.cs b/src/modules/MouseWithoutBorders/App/Core/Common.cs new file mode 100644 index 0000000000..3c2206f2ab --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/Common.cs @@ -0,0 +1,1654 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +using Microsoft.PowerToys.Settings.UI.Library; +using MouseWithoutBorders.Class; +using MouseWithoutBorders.Exceptions; + +using Clipboard = MouseWithoutBorders.Core.Clipboard; +using Thread = MouseWithoutBorders.Core.Thread; + +// Log is enough +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckClipboard()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetAsStartupItem(System.Boolean)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HelperThread()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetMyStorageDir()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#MouseEvent(MouseWithoutBorders.MOUSEDATA)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#KeybdEvent(MouseWithoutBorders.KEYBDDATA)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HookClipboard()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardData(MouseWithoutBorders.DATA,System.Boolean)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiverCallback(System.Object)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckNewVersion()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartServiceAndSendLogoffSignal()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetScreenConfig()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CaptureScreen()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#InitEncryption()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ToggleIcon()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNameAndIPAddresses()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#Cleanup()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "type", Target = "MouseWithoutBorders.Common", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ProcessPackage(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#get_Machine_Pool()", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean,System.String)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNewImageAndSaveTo(System.String,System.String)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#LogAll()", MessageId = "System.String.Format(System.IFormatProvider,System.String,System.Object[])", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#DragDropStep04()", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", MessageId = "MouseWithoutBorders.NativeMethods.WaitForSingleObject(System.IntPtr,System.Int32)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#GetText(System.IntPtr)", MessageId = "MouseWithoutBorders.NativeMethods.GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", MessageId = "MouseWithoutBorders.NativeMethods.WTSQueryUserToken(System.UInt32,System.IntPtr@)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32,System.Boolean,System.Int64)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateProcessInInputDesktopSession(System.String,System.String,System.String,System.Boolean,System.Int16)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SkSend(MouseWithoutBorders.DATA,System.Boolean,System.Int32)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardDataUsingTCP(MouseWithoutBorders.DATA,System.Boolean,System.Net.Sockets.Socket)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#UpdateMachineMatrix(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")] +[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReopenSockets(System.Boolean)", Justification = "Dotnet port with style preservation")] + +// +// Most of the helper methods. +// +// +// 2008 created by Truong Do (ductdo). +// 2009-... modified by Truong Do (TruongDo). +// 2023- Included in PowerToys. +// +namespace MouseWithoutBorders.Core; + +internal static class Common +{ + private static InputHook hook; + private static FrmMatrix matrixForm; + private static FrmInputCallback inputCallbackForm; + private static FrmAbout aboutForm; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter + internal static Thread helper; + internal static int screenWidth; + internal static int screenHeight; +#pragma warning restore SA1307 + private static int lastX; + private static int lastY; + + private static bool mainFormVisible = true; + private static bool runOnLogonDesktop; + private static bool runOnScrSaverDesktop; + +#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter + internal static int[] toggleIcons; + internal static int toggleIconsIndex; +#pragma warning restore SA1307 + internal const int TOGGLE_ICONS_SIZE = 4; + internal const int ICON_ONE = 0; + internal const int ICON_ALL = 1; + internal const int ICON_SMALL_CLIPBOARD = 2; + internal const int ICON_BIG_CLIPBOARD = 3; + internal const int ICON_ERROR = 4; + internal const int JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999; + + internal const int NETWORK_STREAM_BUF_SIZE = 1024 * 1024; + internal static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset); + private static Point lastPos; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case names + internal static int switchCount; +#pragma warning restore SA1307 + private static long lastReconnectByHotKeyTime; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case names + internal static int tcpPort; +#pragma warning restore SA1307 + private static bool secondOpenSocketTry; + private static string binaryName; + + internal static Process CurrentProcess { get; set; } + + internal static bool HotkeyMatched(int vkCode, bool winDown, bool ctrlDown, bool altDown, bool shiftDown, HotkeySettings hotkey) + { + return !hotkey.IsEmpty() && (vkCode == hotkey.Code) && (!hotkey.Win || winDown) && (!hotkey.Alt || altDown) && (!hotkey.Shift || shiftDown) && (!hotkey.Ctrl || ctrlDown); + } + + internal static string BinaryName + { + get => Common.binaryName; + set => Common.binaryName = value; + } + + internal static bool SecondOpenSocketTry + { + get => Common.secondOpenSocketTry; + set => Common.secondOpenSocketTry = value; + } + + internal static long LastReconnectByHotKeyTime + { + get => Common.lastReconnectByHotKeyTime; + set => Common.lastReconnectByHotKeyTime = value; + } + + internal static int SwitchCount + { + get => Common.switchCount; + set => Common.switchCount = value; + } + + internal static Point LastPos + { + get => Common.lastPos; + set => Common.lastPos = value; + } + + internal static FrmAbout AboutForm + { + get => Common.aboutForm; + set => Common.aboutForm = value; + } + + internal static FrmInputCallback InputCallbackForm + { + get => Common.inputCallbackForm; + set => Common.inputCallbackForm = value; + } + + internal static int PaintCount { get; set; } + + internal static bool RunOnScrSaverDesktop + { + get => Common.runOnScrSaverDesktop; + set => Common.runOnScrSaverDesktop = value; + } + + internal static bool RunOnLogonDesktop + { + get => Common.runOnLogonDesktop; + set => Common.runOnLogonDesktop = value; + } + + internal static bool RunWithNoAdminRight { get; set; } + + internal static int LastX + { + get => Common.lastX; + set => Common.lastX = value; + } + + internal static int LastY + { + get => Common.lastY; + set => Common.lastY = value; + } + + internal static int[] ToggleIcons => Common.toggleIcons; + + internal static int ScreenHeight => Common.screenHeight; + + internal static int ScreenWidth => Common.screenWidth; + + internal static bool Is64bitOS + { + get; set; + + // set { Common.is64bitOS = value; } + } + + internal static int ToggleIconsIndex + { + // get { return Common.toggleIconsIndex; } + set => Common.toggleIconsIndex = value; + } + + internal static InputHook Hook + { + get => Common.hook; + set => Common.hook = value; + } + + internal static SocketStuff Sk { get; set; } + + internal static FrmScreen MainForm { get; set; } + + internal static FrmMouseCursor MouseCursorForm { get; set; } + + internal static FrmMatrix MatrixForm + { + get => Common.matrixForm; + set => Common.matrixForm = value; + } + + internal static ID DesMachineID + { + get => MachineStuff.desMachineID; + + set + { + MachineStuff.desMachineID = value; + MachineStuff.DesMachineName = MachineStuff.NameFromID(MachineStuff.desMachineID); + } + } + + internal static ID MachineID => (ID)Setting.Values.MachineId; + + internal static string MachineName { get; set; } + + internal static bool MainFormVisible + { + get => Common.mainFormVisible; + set => Common.mainFormVisible = value; + } + + internal static Mutex SocketMutex { get; set; } // Synchronization between MouseWithoutBorders running in different desktops + + // TODO: For telemetry only, to be removed. + private static int socketMutexBalance; + + internal static void ReleaseSocketMutex() + { + if (SocketMutex != null) + { + Logger.LogDebug("SOCKET MUTEX BEGIN RELEASE."); + + try + { + _ = Interlocked.Decrement(ref socketMutexBalance); + SocketMutex.ReleaseMutex(); + } + catch (ApplicationException e) + { + // The current thread does not own the mutex, the thread acquired it will own it. + Logger.TelemetryLogTrace($"{nameof(ReleaseSocketMutex)}: {e.Message}. {Thread.CurrentThread.ManagedThreadId}/{UIThreadID}.", SeverityLevel.Warning); + } + + Logger.LogDebug("SOCKET MUTEX RELEASED."); + } + else + { + Logger.LogDebug("SOCKET MUTEX NULL."); + } + } + + internal static void AcquireSocketMutex() + { + if (SocketMutex != null) + { + Logger.LogDebug("SOCKET MUTEX BEGIN WAIT."); + int waitTimeout = 60000; // TcpListener.Stop may take very long to complete for some reason. + + int socketMutexBalance = int.MinValue; + + bool acquireMutex = ExecuteAndTrace( + "Waiting for sockets to close", + () => + { + socketMutexBalance = Interlocked.Increment(ref Common.socketMutexBalance); + _ = SocketMutex.WaitOne(waitTimeout); // The app now requires .Net 4.0. Note: .Net20RTM does not have the one-parameter version of the API. + }, + TimeSpan.FromSeconds(5)); + + // Took longer than expected. + if (!acquireMutex) + { + Process[] ps = Process.GetProcessesByName(Common.BinaryName); + Logger.TelemetryLogTrace($"Balance: {socketMutexBalance}, Active: {WinAPI.IsMyDesktopActive()}, Sid/Console: {Process.GetCurrentProcess().SessionId}/{NativeMethods.WTSGetActiveConsoleSessionId()}, Desktop/Input: {WinAPI.GetMyDesktop()}/{WinAPI.GetInputDesktop()}, count: {ps?.Length}.", SeverityLevel.Warning); + } + + Logger.LogDebug("SOCKET MUTEX ENDED."); + } + else + { + Logger.LogDebug("SOCKET MUTEX NULL."); + } + } + + internal static bool BlockingUI { get; private set; } + + internal static bool ExecuteAndTrace(string actionName, Action action, TimeSpan timeout, bool restart = false) + { + bool rv = true; + Logger.LogDebug(actionName); + bool done = false; + + BlockingUI = true; + + if (restart) + { + Common.MainForm.Text = Setting.Values.MyIdEx; + + /* closesocket() rarely gets stuck for some reason inside ntdll!ZwClose ...=>... afd!AfdCleanupCore. + * There is no good workaround for it so far, still working with [Winsock 2.0 Discussions] to address the issue. + * */ + new Thread( + () => + { + for (int i = 0; i < timeout.TotalSeconds; i++) + { + Thread.Sleep(1000); + + if (done) + { + return; + } + } + + Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}, restarting the process.", SeverityLevel.Warning, true); + + string desktop = WinAPI.GetMyDesktop(); + MachineStuff.oneInstanceCheck?.Close(); + _ = Process.Start(Application.ExecutablePath, desktop); + Logger.LogDebug($"Started on desktop {desktop}"); + + Process.GetCurrentProcess().KillProcess(true); + }, + $"{actionName} watchdog").Start(); + } + + Stopwatch timer = Stopwatch.StartNew(); + + try + { + action(); + } + finally + { + done = true; + BlockingUI = false; + + if (restart) + { + Common.MainForm.Text = Setting.Values.MyID; + } + + timer.Stop(); + + if (timer.Elapsed > timeout) + { + rv = false; + + if (!restart) + { + Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}: {(long)timer.Elapsed.TotalSeconds}.", SeverityLevel.Warning); + } + } + } + + return rv; + } + + internal static byte[] GetBytes(string st) + { + return ASCIIEncoding.ASCII.GetBytes(st); + } + + internal static string GetString(byte[] bytes) + { + return ASCIIEncoding.ASCII.GetString(bytes); + } + + internal static byte[] GetBytesU(string st) + { + return ASCIIEncoding.Unicode.GetBytes(st); + } + + internal static string GetStringU(byte[] bytes) + { + return ASCIIEncoding.Unicode.GetString(bytes); + } + + internal static int UIThreadID { get; set; } + + internal static void DoSomethingInUIThread(Action action, bool blocking = false) + { + InvokeInFormThread(MainForm, UIThreadID, action, blocking); + } + + internal static int InputCallbackThreadID { get; set; } + + internal static void DoSomethingInTheInputCallbackThread(Action action, bool blocking = true) + { + InvokeInFormThread(InputCallbackForm, InputCallbackThreadID, action, blocking); + } + + private static void InvokeInFormThread(System.Windows.Forms.Form form, int threadId, Action action, bool blocking) + { + if (form != null) + { + int currentThreadId = Thread.CurrentThread.ManagedThreadId; + + if (currentThreadId == threadId) + { + action(); + } + else + { + bool done = false; + + try + { + Action callback = () => + { + try + { + action(); + } + catch (Exception e) + { + Logger.Log(e); + } + finally + { + done = true; + } + }; + _ = form.BeginInvoke(callback); + } + catch (Exception e) + { + done = true; + Logger.Log(e); + } + + while (blocking && !done) + { + Thread.Sleep(16); + + if (currentThreadId == UIThreadID || currentThreadId == InputCallbackThreadID) + { + Application.DoEvents(); + } + } + } + } + } + + private static readonly Lock InputSimulationLock = new(); + + internal static void DoSomethingInTheInputSimulationThread(ThreadStart target) + { + /* + * For some reason, SendInput may hit deadlock if it is called in the InputHookProc thread. + * For now leave it as is in the caller thread which is the socket receiver thread. + * */ + + // SendInput is thread-safe but few users seem to hit a deadlock occasionally, probably a Windows bug. + lock (InputSimulationLock) + { + target(); + } + } + + internal static void SendPackage(ID des, PackageType packageType) + { + DATA package = new(); + package.Type = packageType; + package.Des = des; + package.MachineName = MachineName; + + SkSend(package, null, false); + } + + internal static void SendHeartBeat(bool initial = false) + { + SendPackage(ID.ALL, initial && Encryption.GeneratedKey ? PackageType.Heartbeat_ex : PackageType.Heartbeat); + } + + private static long lastSendNextMachine; + + internal static void SendNextMachine(ID hostMachine, ID nextMachine, Point requestedXY) + { + Logger.LogDebug($"SendNextMachine: Host machine: {hostMachine}, Next machine: {nextMachine}, Requested XY: {requestedXY}"); + + if (GetTick() - lastSendNextMachine < 100) + { + Logger.LogDebug("Machine switching in progress."); // "Move Mouse relatively" mode, slow machine/network, quick/busy hand. + return; + } + + lastSendNextMachine = GetTick(); + + DATA package = new(); + package.Type = PackageType.NextMachine; + + package.Des = hostMachine; + + package.Md.X = requestedXY.X; + package.Md.Y = requestedXY.Y; + package.Md.WheelDelta = (int)nextMachine; + + SkSend(package, null, false); + + Logger.LogDebug("SendNextMachine done."); + } + + private static ulong lastInputEventCount; + private static ulong lastRealInputEventCount; + + internal static void SendAwakeBeat() + { + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive() && + Setting.Values.BlockScreenSaver && lastRealInputEventCount != Event.RealInputEventCount) + { + SendPackage(ID.ALL, PackageType.Awake); + } + else + { + SendHeartBeat(); + } + + lastInputEventCount = Event.InputEventCount; + lastRealInputEventCount = Event.RealInputEventCount; + } + + internal static void HumanBeingDetected() + { + if (lastInputEventCount == Event.InputEventCount) + { + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive()) + { + PokeMyself(); + } + } + + lastInputEventCount = Event.InputEventCount; + } + + private static void PokeMyself() + { + int x, y = 0; + + for (int i = 0; i < 10; i++) + { + x = Encryption.Ran.Next(-9, 10); + InputSimulation.MoveMouseRelative(x, y); + Thread.Sleep(50); + InputSimulation.MoveMouseRelative(-x, -y); + Thread.Sleep(50); + + if (lastInputEventCount != Event.InputEventCount) + { + break; + } + } + } + + internal static void InitLastInputEventCount() + { + lastInputEventCount = Event.InputEventCount; + lastRealInputEventCount = Event.RealInputEventCount; + } + + internal static void SendHello() + { + SendPackage(ID.ALL, PackageType.Hello); + } + + /* + internal static void SendHi() + { + SendPackage(IP.ALL, PackageType.hi); + } + * */ + + internal static void SendByeBye() + { + Logger.LogDebug($"{nameof(SendByeBye)}"); + SendPackage(ID.ALL, PackageType.ByeBye); + } + + internal static void SendClipboardBeat() + { + SendPackage(ID.ALL, PackageType.Clipboard); + } + + internal static void ProcessByeByeMessage(DATA package) + { + if (package.Src == MachineStuff.desMachineID) + { + MachineStuff.SwitchToMachine(MachineName.Trim()); + } + + _ = MachineStuff.RemoveDeadMachines(package.Src); + } + + internal static long GetTick() // ms + { + return DateTime.Now.Ticks / 10000; + } + + internal static void SetToggleIcon(int[] toggleIcons) + { + Logger.LogDebug($"{nameof(SetToggleIcon)}: {toggleIcons?.FirstOrDefault()}"); + Common.toggleIcons = toggleIcons; + toggleIconsIndex = 0; + } + + internal static string CaptureScreen() + { + try + { + string fileName = GetMyStorageDir() + @"ScreenCaptureByMouseWithoutBorders.png"; + int w = MachineStuff.desktopBounds.Right - MachineStuff.desktopBounds.Left; + int h = MachineStuff.desktopBounds.Bottom - MachineStuff.desktopBounds.Top; + Bitmap bm = new(w, h); + Graphics g = Graphics.FromImage(bm); + Size s = new(w, h); + g.CopyFromScreen(MachineStuff.desktopBounds.Left, MachineStuff.desktopBounds.Top, 0, 0, s); + bm.Save(fileName, ImageFormat.Png); + bm.Dispose(); + return fileName; + } + catch (Exception e) + { + Logger.Log(e); + return null; + } + } + + private static void PrepareScreenCapture() + { + Common.DoSomethingInUIThread(() => + { + if (!DragDrop.MouseDown && Helper.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0) + { + Common.MMSleep(0.2); + InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT }); + InputSimulation.SendKey(new KEYBDDATA() { dwFlags = (int)WM.LLKHF.UP, wVk = (int)VK.SNAPSHOT }); + + Logger.LogDebug("PrepareScreenCapture: SNAPSHOT simulated."); + + _ = NativeMethods.MoveWindow( + (IntPtr)NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT), + MachineStuff.DesktopBounds.Left, + MachineStuff.DesktopBounds.Top, + MachineStuff.DesktopBounds.Right - MachineStuff.DesktopBounds.Left, + MachineStuff.DesktopBounds.Bottom - MachineStuff.DesktopBounds.Top, + false); + + _ = Helper.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false); + } + else + { + Logger.Log("PrepareScreenCapture: Validation failed."); + } + }); + } + + internal static void OpenImage(string file) + { + // We want to run mspaint under the user account who ran explorer.exe (who logged in this current input desktop) + + // ImpersonateLoggedOnUserAndDoSomething(delegate() + // { + // Process.Start("explorer", "\"" + file + "\""); + // }); + _ = Launch.CreateProcessInInputDesktopSession( + "\"" + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") + + "\"", + "\"" + file + "\"", + WinAPI.GetInputDesktop(), + 1); + + // CreateNormalIntegrityProcess(Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") + + // " \"" + file + "\""); + + // We don't want to run mspaint as local system account + /* + ProcessStartInfo s = new ProcessStartInfo( + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe"), + "\"" + file + "\""); + s.WindowStyle = ProcessWindowStyle.Maximized; + Process.Start(s); + * */ + } + + internal static void SendImage(string machine, string file) + { + Clipboard.LastDragDropFile = file; + + // Send ClipboardCapture + if (machine.Equals("All", StringComparison.OrdinalIgnoreCase)) + { + SendPackage(ID.ALL, PackageType.ClipboardCapture); + } + else + { + ID id = MachineStuff.MachinePool.ResolveID(machine); + if (id != ID.NONE) + { + SendPackage(id, PackageType.ClipboardCapture); + } + } + } + + internal static void SendImage(ID src, string file) + { + Clipboard.LastDragDropFile = file; + + // Send ClipboardCapture + SendPackage(src, PackageType.ClipboardCapture); + } + + internal static void ShowToolTip(string tip, int timeOutInMilliseconds = 5000, ToolTipIcon icon = ToolTipIcon.Info, bool showBalloonTip = true, bool forceEvenIfHidingOldUI = false) + { + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) + { + DoSomethingInUIThread(() => + { + if (Setting.Values.FirstRun) + { + MachineStuff.Settings?.ShowTip(icon, tip, timeOutInMilliseconds); + } + + Common.MatrixForm?.ShowTip(icon, tip, timeOutInMilliseconds); + + if (showBalloonTip) + { + if (MainForm != null) + { + MainForm.ShowToolTip(tip, timeOutInMilliseconds, forceEvenIfHidingOldUI: forceEvenIfHidingOldUI); + } + else + { + Logger.Log(tip); + } + } + }); + } + } + + private static FrmMessage topMostMessageForm; + + internal static void ToggleShowTopMostMessage(string text, string bigText, int timeOut) + { + DoSomethingInUIThread(() => + { + if (topMostMessageForm == null) + { + topMostMessageForm = new FrmMessage(text, bigText, timeOut); + topMostMessageForm.Show(); + } + else + { + FrmMessage currentMessageForm = topMostMessageForm; + topMostMessageForm = null; + currentMessageForm.Close(); + } + }); + } + + internal static void HideTopMostMessage() + { + DoSomethingInUIThread(() => + { + topMostMessageForm?.Close(); + }); + } + + internal static void NullTopMostMessage() + { + DoSomethingInUIThread(() => + { + if (topMostMessageForm != null) + { + topMostMessageForm = null; + } + }); + } + + internal static bool IsTopMostMessageNotNull() + { + return topMostMessageForm != null; + } + + private static bool TestSend(TcpSk t) + { + ID remoteMachineID; + + if (t.Status == SocketStatus.Connected) + { + try + { + DATA package = new(); + package.Type = PackageType.Hi; + package.Des = remoteMachineID = (ID)t.MachineId; + package.MachineName = MachineName; + + _ = Sk.TcpSend(t, package); + t.EncryptedStream?.Flush(); + + return true; + } + catch (ExpectedSocketException) + { + t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() + } + } + + t.Status = SocketStatus.SendError; + return false; + } + + internal static bool IsConnectedTo(ID remoteMachineID) + { + bool updateClientSockets = false; + + if (remoteMachineID == MachineID) + { + return true; + } + + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + if (sk.TcpSockets != null) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t.Status == SocketStatus.Connected && (uint)remoteMachineID == t.MachineId) + { + if (TestSend(t)) + { + return true; + } + else + { + updateClientSockets = true; + } + } + } + } + } + } + + if (updateClientSockets) + { + MachineStuff.UpdateClientSockets(nameof(IsConnectedTo)); + } + + return false; + } + +#if DEBUG + private static long minSendTime = long.MaxValue; + private static long avgSendTime; + private static long maxSendTime; + private static long totalSendCount; + private static long totalSendTime; +#endif + + internal static void SkSend(DATA data, uint? exceptDes, bool includeHandShakingSockets) + { + bool connected = false; + + SocketStuff sk = Sk; + + if (sk != null) + { +#if DEBUG + long startStop = DateTime.Now.Ticks; + totalSendCount++; +#endif + + try + { + data.Id = Interlocked.Increment(ref Package.PackageID); + + bool updateClientSockets = false; + + lock (sk.TcpSocketsLock) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t != null && t.BackingSocket != null && (t.Status == SocketStatus.Connected || (t.Status == SocketStatus.Handshaking && includeHandShakingSockets))) + { + if (t.MachineId == (uint)data.Des || (data.Des == ID.ALL && t.MachineId != exceptDes && MachineStuff.InMachineMatrix(t.MachineName))) + { + try + { + sk.TcpSend(t, data); + + if (data.Des != ID.ALL) + { + connected = true; + } + } + catch (ExpectedSocketException) + { + t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() + updateClientSockets = true; + } + catch (Exception e) + { + Logger.Log(e); + t.BackingSocket = null; // To be removed at CloseAnUnusedSocket() + updateClientSockets = true; + } + } + } + } + } + + if (!connected && data.Des != ID.ALL) + { + Logger.LogDebug("********** No active connection found for the remote machine! **********" + data.Des.ToString()); + + if (data.Des == ID.NONE || MachineStuff.RemoveDeadMachines(data.Des)) + { + // SwitchToMachine(MachineName.Trim()); + MachineStuff.NewDesMachineID = DesMachineID = MachineID; + MachineStuff.SwitchLocation.X = Event.XY_BY_PIXEL + Event.myLastX; + MachineStuff.SwitchLocation.Y = Event.XY_BY_PIXEL + Event.myLastY; + MachineStuff.SwitchLocation.ResetCount(); + EvSwitch.Set(); + } + } + + if (updateClientSockets) + { + MachineStuff.UpdateClientSockets("SkSend"); + } + } + catch (Exception e) + { + Logger.Log(e); + } + +#if DEBUG + startStop = DateTime.Now.Ticks - startStop; + totalSendTime += startStop; + if (startStop < minSendTime) + { + minSendTime = startStop; + } + + if (startStop > maxSendTime) + { + maxSendTime = startStop; + } + + avgSendTime = totalSendTime / totalSendCount; +#endif + } + else + { + Package.PackageSent.Nil++; + } + } + + internal static void CloseAnUnusedSocket() + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + if (sk.TcpSockets != null) + { + TcpSk tobeRemoved = null; + + foreach (TcpSk t in sk.TcpSockets) + { + if ((t.Status != SocketStatus.Connected && t.BirthTime < GetTick() - SocketStuff.CONNECT_TIMEOUT) || t.BackingSocket == null) + { + Logger.LogDebug("CloseAnUnusedSocket: " + t.MachineName + ":" + t.MachineId + "|" + t.Status.ToString()); + tobeRemoved = t; + + if (t.BackingSocket != null) + { + try + { + t.BackingSocket.Close(); + } + catch (Exception e) + { + Logger.Log(e); + } + } + + break; // Each time we try to remove one socket only. + } + } + + if (tobeRemoved != null) + { + _ = sk.TcpSockets.Remove(tobeRemoved); + } + } + } + } + } + + internal static bool AtLeastOneSocketConnected() + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + if (sk.TcpSockets != null) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t.Status == SocketStatus.Connected) + { + Logger.LogDebug("AtLeastOneSocketConnected returning true: " + t.MachineName); + return true; + } + } + } + } + } + + Logger.LogDebug("AtLeastOneSocketConnected returning false."); + return false; + } + + private static Socket AtLeastOneServerSocketConnected() + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + if (sk.TcpSockets != null) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (!t.IsClient && t.Status == SocketStatus.Connected) + { + Logger.LogDebug("AtLeastOneServerSocketConnected returning true: " + t.MachineName); + return t.BackingSocket; + } + } + } + } + } + + Logger.LogDebug("AtLeastOneServerSocketConnected returning false."); + return null; + } + + internal static TcpSk GetConnectedClientSocket() + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + return sk.TcpSockets?.FirstOrDefault(item => item.IsClient && item.Status == SocketStatus.Connected); + } + } + else + { + return null; + } + } + + internal static bool AtLeastOneSocketEstablished() + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + if (sk.TcpSockets != null) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t.BackingSocket != null && t.BackingSocket.Connected) + { + if (TestSend(t)) + { + Logger.LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning true: {t.MachineName}"); + return true; + } + } + } + } + } + } + + Logger.LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning false."); + return false; + } + + internal static bool IsConnectedByAClientSocketTo(string machineName) + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t != null && t.IsClient && t.Status == SocketStatus.Connected + && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + } + } + + return false; + } + + internal static IPAddress GetConnectedClientSocketIPAddressFor(string machineName) + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + return sk.TcpSockets.FirstOrDefault(t => t != null && t.IsClient && t.Status == SocketStatus.Connected + && t.Address != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase)) + ?.Address; + } + } + + return null; + } + + internal static bool IsConnectingByAClientSocketTo(string machineName, IPAddress ip) + { + SocketStuff sk = Common.Sk; + + if (sk != null) + { + lock (sk.TcpSocketsLock) + { + foreach (TcpSk t in sk.TcpSockets) + { + if (t != null && t.IsClient && t.Status == SocketStatus.Connecting + && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase) + && t.Address.ToString().Equals(ip.ToString(), StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + } + } + + return false; + } + + internal static void UpdateSetupMachineMatrix(string desMachine) + { + int machineCt = 0; + + foreach (string m in MachineStuff.MachineMatrix) + { + if (!string.IsNullOrEmpty(m.Trim())) + { + machineCt++; + } + } + + if (machineCt < 2 && MachineStuff.Settings != null && (MachineStuff.Settings.GetCurrentPage() is SetupPage1 || MachineStuff.Settings.GetCurrentPage() is SetupPage2b)) + { + MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { Common.MachineName.Trim(), desMachine, string.Empty, string.Empty }; + Logger.LogDebug("UpdateSetupMachineMatrix: " + string.Join(",", MachineStuff.MachineMatrix)); + + Common.DoSomethingInUIThread( + () => + { + MachineStuff.Settings.SetControlPage(new SetupPage4()); + }, + true); + } + } + + internal static void ReopenSockets(bool byUser) + { + DoSomethingInUIThread( + () => + { + try + { + SocketStuff tmpSk = Sk; + + if (tmpSk != null) + { + Sk = null; // TODO: This looks redundant. + tmpSk.Close(byUser); + } + + Sk = new SocketStuff(tcpPort, byUser); + } + catch (Exception e) + { + Sk = null; + Logger.Log(e); + } + + if (Sk != null) + { + if (byUser) + { + SocketStuff.ClearBadIPs(); + } + + MachineStuff.UpdateClientSockets("ReopenSockets"); + } + }, + true); + + if (Sk == null) + { + return; + } + + Common.DoSomethingInTheInputCallbackThread(() => + { + if (Common.Hook != null) + { + Common.Hook.Stop(); + Common.Hook = null; + } + + if (byUser) + { + Common.InputCallbackForm.Close(); + Common.InputCallbackForm = null; + Program.StartInputCallbackThread(); + } + else + { + Common.InputCallbackForm.InstallKeyboardAndMouseHook(); + } + }); + } + + internal static string GetMyStorageDir() + { + string st = string.Empty; + + try + { + if (RunOnLogonDesktop || RunOnScrSaverDesktop) + { + st = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + if (!Directory.Exists(st)) + { + _ = Directory.CreateDirectory(st); + } + + st += @"\" + Common.BinaryName; + if (!Directory.Exists(st)) + { + _ = Directory.CreateDirectory(st); + } + + st += @"\ScreenCaptures\"; + if (!Directory.Exists(st)) + { + _ = Directory.CreateDirectory(st); + } + } + else + { + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => + { + st = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\" + Common.BinaryName; + if (!Directory.Exists(st)) + { + _ = Directory.CreateDirectory(st); + } + + st += @"\ScreenCaptures\"; + if (!Directory.Exists(st)) + { + _ = Directory.CreateDirectory(st); + } + }); + } + + Logger.LogDebug("GetMyStorageDir: " + st); + + // Delete old files. + foreach (FileInfo fi in new DirectoryInfo(st).GetFiles()) + { + if (fi.CreationTime.AddDays(1) < DateTime.Now) + { + fi.Delete(); + } + } + + return st; + } + catch (Exception e) + { + Logger.Log(e); + + if (string.IsNullOrEmpty(st) || !st.Contains(Common.BinaryName)) + { + st = Path.GetTempPath(); + } + + return st; + } + } + + internal static void GetMachineName() + { + string machine_Name = string.Empty; + + try + { + machine_Name = Dns.GetHostName(); + Logger.LogDebug("GetHostName = " + machine_Name); + } + catch (Exception e) + { + Logger.Log(e); + + if (string.IsNullOrEmpty(machine_Name)) + { + machine_Name = "RANDOM" + Encryption.Ran.Next().ToString(CultureInfo.CurrentCulture); + } + } + + if (machine_Name.Length > 32) + { + machine_Name = machine_Name[..32]; + } + + Common.MachineName = machine_Name.Trim(); + + Logger.LogDebug($"========== {nameof(GetMachineName)} ended!"); + } + + private static string GetNetworkName(NetworkInterface networkInterface) + { + return $"{networkInterface.Name} | {networkInterface.Description.Replace(":", "-")}"; + } + + internal static string GetRemoteStringIP(Socket s, bool throwException = false) + { + if (s == null) + { + return string.Empty; + } + + string ip; + + try + { + ip = (s?.RemoteEndPoint as IPEndPoint)?.Address?.ToString(); + + if (string.IsNullOrEmpty(ip)) + { + return string.Empty; + } + } + catch (ObjectDisposedException e) + { + Logger.Log($"{nameof(GetRemoteStringIP)}: The socket could have been disposed by other threads, error: {e.Message}"); + + if (throwException) + { + throw; + } + + return string.Empty; + } + catch (SocketException e) + { + Logger.Log($"{nameof(GetRemoteStringIP)}: {e.Message}"); + + if (throwException) + { + throw; + } + + return string.Empty; + } + + return ip; + } + + internal static void CloseAllFormsAndHooks() + { + if (Hook != null) + { + Hook.Stop(); + Hook = null; + if (InputCallbackForm != null) + { + DoSomethingInTheInputCallbackThread(() => + { + InputCallbackForm.Close(); + InputCallbackForm = null; + }); + } + } + + if (MainForm != null) + { + MainForm.Destroy(); + MainForm = null; + } + + if (MatrixForm != null) + { + MatrixForm.Close(); + MatrixForm = null; + } + + if (AboutForm != null) + { + AboutForm.Close(); + AboutForm = null; + } + } + + internal static void MoveMouseToCenter() + { + Logger.LogDebug("+++++ MoveMouseToCenter"); + InputSimulation.MoveMouse( + MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2), + MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2)); + } + + internal static void HideMouseCursor(bool byHideMouseMessage) + { + Common.LastPos = new Point( + MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2), + Setting.Values.HideMouse ? 4 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2)); + + if ((MachineStuff.desMachineID != MachineID && MachineStuff.desMachineID != ID.ALL) || byHideMouseMessage) + { + _ = NativeMethods.SetCursorPos(Common.LastPos.X, Common.LastPos.Y); + _ = NativeMethods.GetCursorPos(ref Common.lastPos); + Logger.LogDebug($"+++++ HideMouseCursor, byHideMouseMessage = {byHideMouseMessage}"); + } + + CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); + } + + internal static string GetText(IntPtr hWnd) + { + int length = NativeMethods.GetWindowTextLength(hWnd); + StringBuilder sb = new(length + 1); + int rv = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity); + Logger.LogDebug("GetWindowText returned " + rv.ToString(CultureInfo.CurrentCulture)); + return sb.ToString(); + } + + private static string GetWindowClassName(IntPtr hWnd) + { + StringBuilder buffer = new(128); + _ = NativeMethods.GetClassName(hWnd, buffer, buffer.Capacity); + return buffer.ToString(); + } + + internal static void MMSleep(double secs) + { + for (int i = 0; i < secs * 10; i++) + { + Application.DoEvents(); + Thread.Sleep(100); + } + } + + internal static void UpdateMultipleModeIconAndMenu() + { + MainForm?.UpdateMultipleModeIconAndMenu(); + } + + internal static void SendOrReceiveARandomDataBlockPerInitialIV(Stream st, bool send = true) + { + byte[] ranData = new byte[Encryption.SymAlBlockSize]; + + try + { + if (send) + { + ranData = RandomNumberGenerator.GetBytes(Encryption.SymAlBlockSize); + st.Write(ranData, 0, ranData.Length); + } + else + { + int toRead = ranData.Length; + int read = st.ReadEx(ranData, 0, toRead); + + if (read != toRead) + { + Logger.LogDebug("Stream has no more data after reading {0} bytes.", read); + } + } + } + catch (IOException e) + { + string log = $"{nameof(SendOrReceiveARandomDataBlockPerInitialIV)}: Exception {(send ? "writing" : "reading")} to the socket stream: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)"; + Logger.Log(log); + + if (e.InnerException is not (SocketException or ObjectDisposedException)) + { + throw; + } + } + } + + private static bool DisableEasyMouseWhenForegroundWindowIsFullscreenSetting() + { + return Setting.Values.DisableEasyMouseWhenForegroundWindowIsFullscreen; + } + + private static bool IsAppIgnoredByEasyMouseFullscreenCheck(IntPtr foregroundWindowHandle) + { + if (NativeMethods.GetWindowThreadProcessId(foregroundWindowHandle, out var processId) == 0) + { + Logger.LogDebug($"GetWindowThreadProcessId failed with error : {Marshal.GetLastWin32Error()}"); + return false; + } + + var processHandle = NativeMethods.OpenProcess(0x1000, false, processId); + if (processHandle == IntPtr.Zero) + { + return false; + } + + uint maxPath = 260; + var nameBuffer = new char[maxPath]; + if (!NativeMethods.QueryFullProcessImageName( + processHandle, NativeMethods.QUERY_FULL_PROCESS_NAME_FLAGS.DEFAULT, nameBuffer, ref maxPath)) + { + Logger.LogDebug($"QueryFullProcessImageName failed with error : {Marshal.GetLastWin32Error()}"); + NativeMethods.CloseHandle(processHandle); + return false; + } + + NativeMethods.CloseHandle(processHandle); + + var name = new string(nameBuffer, 0, (int)maxPath); + + var excludedApps = Setting.Values.EasyMouseFullscreenSwitchBlockExcludedApps; + + return excludedApps.Contains(Path.GetFileNameWithoutExtension(name), StringComparer.OrdinalIgnoreCase) + || excludedApps.Contains(Path.GetFileName(name), StringComparer.OrdinalIgnoreCase); + } + + private static bool IsEasyMouseBlockedByFullscreenWindow() + { + var shellHandle = NativeMethods.GetShellWindow(); + var desktopHandle = NativeMethods.GetDesktopWindow(); + var foregroundHandle = NativeMethods.GetForegroundWindow(); + + // If the foreground window is either the desktop or the Windows shell, we are not in fullscreen mode. + if (foregroundHandle.Equals(shellHandle) || foregroundHandle.Equals(desktopHandle)) + { + return false; + } + + if (NativeMethods.SHQueryUserNotificationState(out var userNotificationState) != 0) + { + Logger.LogDebug($"SHQueryUserNotificationState failed with error : {Marshal.GetLastWin32Error()}"); + return false; + } + + switch (userNotificationState) + { + // An application running in full screen mode, check if the foreground window is + // listed as ignored in the settings. + case NativeMethods.USER_NOTIFICATION_STATE.BUSY: + case NativeMethods.USER_NOTIFICATION_STATE.RUNNING_D3D_FULL_SCREEN: + case NativeMethods.USER_NOTIFICATION_STATE.PRESENTATION_MODE: + return !IsAppIgnoredByEasyMouseFullscreenCheck(foregroundHandle); + + // No full screen app running. + case NativeMethods.USER_NOTIFICATION_STATE.NOT_PRESENT: + case NativeMethods.USER_NOTIFICATION_STATE.ACCEPTS_NOTIFICATIONS: + case NativeMethods.USER_NOTIFICATION_STATE.QUIET_TIME: + // Cannot determine + case NativeMethods.USER_NOTIFICATION_STATE.APP: + default: + return false; + } + } + + /// + /// Check if a machine switch triggered by EasyMouse would be allowed to proceed due to other settings. + /// + /// A boolean that tells us if the switch isn't blocked by any other settings + internal static bool IsEasyMouseSwitchAllowed() + { + // Never prevent a switch if we are not moving out of the host machine. + if (!DisableEasyMouseWhenForegroundWindowIsFullscreenSetting() || DesMachineID != MachineID) + { + return true; + } + + // Check if the switch is blocked by a full-screen window running in the foreground + return !IsEasyMouseBlockedByFullscreenWindow(); + } +} diff --git a/src/modules/MouseWithoutBorders/App/Core/Helper.cs b/src/modules/MouseWithoutBorders/App/Core/Helper.cs index 8c291fb417..2d97d91123 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Helper.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Helper.cs @@ -295,9 +295,9 @@ internal static class Helper return; } - if (!Common.IpcChannelCreated) + if (!IpcChannelHelper.IpcChannelCreated) { - Logger.TelemetryLogTrace($"{nameof(Common.IpcChannelCreated)} = {Common.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); + Logger.TelemetryLogTrace($"{nameof(IpcChannelHelper.IpcChannelCreated)} = {IpcChannelHelper.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); return; } diff --git a/src/modules/MouseWithoutBorders/App/Core/IpcChannelHelper.cs b/src/modules/MouseWithoutBorders/App/Core/IpcChannelHelper.cs new file mode 100644 index 0000000000..7e6bfd0217 --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/IpcChannelHelper.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Threading; +using System.Windows.Forms; + +#if !MM_HELPER +using Thread = MouseWithoutBorders.Core.Thread; +#endif + +namespace MouseWithoutBorders.Core; + +internal static class IpcChannelHelper +{ + internal static bool IpcChannelCreated { get; set; } + + internal static T Retry(string name, Func func, Action log, Action preRetry = null) + { + int count = 0; + + do + { + try + { + T rv = func(); + + if (count > 0) + { + log($"Trace: {name} has been successful after {count} retry."); + } + + return rv; + } + catch (Exception) + { + count++; + + preRetry?.Invoke(); + + if (count > 10) + { + throw; + } + + Application.DoEvents(); + Thread.Sleep(200); + } + } + while (true); + } +} diff --git a/src/modules/MouseWithoutBorders/App/Core/Logger.cs b/src/modules/MouseWithoutBorders/App/Core/Logger.cs index 4d39983c35..334d269400 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Logger.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Logger.cs @@ -198,7 +198,6 @@ internal static class Logger } Logger.DumpProgramLogs(sb, level); - Logger.DumpOtherLogs(sb, level); Logger.DumpStaticTypes(sb, level); log = string.Format( @@ -240,19 +239,16 @@ internal static class Logger _ = Logger.PrivateDump(sb, AllLogs, "[Program logs]\r\n===============\r\n", 0, level, false); } - internal static void DumpOtherLogs(StringBuilder sb, int level) - { - _ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, level, false); - } - internal static void DumpStaticTypes(StringBuilder sb, int level) { var staticTypes = new List { typeof(Clipboard), + typeof(Common), typeof(DragDrop), typeof(Encryption), typeof(Event), + typeof(IpcChannelHelper), typeof(InitAndCleanup), typeof(Helper), typeof(Launch), diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs index 5649ae8d7f..bb802aa159 100644 --- a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs +++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs @@ -2,6 +2,8 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using MouseWithoutBorders.Core; + namespace MouseWithoutBorders { public partial class SetupPage2b : SettingsFormPage diff --git a/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs b/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs index 3a7ae9901c..069c428589 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs @@ -15,6 +15,8 @@ using System.Globalization; using System.Reflection; using System.Windows.Forms; +using MouseWithoutBorders.Core; + namespace MouseWithoutBorders { internal partial class FrmAbout : System.Windows.Forms.Form, IDisposable diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs b/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs index 2abb18f932..e258df9709 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs @@ -6,6 +6,8 @@ using System; using System.Globalization; using System.Windows.Forms; +using MouseWithoutBorders.Core; + namespace MouseWithoutBorders { public partial class FrmMessage : System.Windows.Forms.Form diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs index b4c2f13efd..e5b8095d18 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs @@ -6,6 +6,7 @@ using System; using System.Windows.Forms; using MouseWithoutBorders.Class; +using MouseWithoutBorders.Core; namespace MouseWithoutBorders { diff --git a/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj index f97c0c44f3..981266c0cb 100644 --- a/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj +++ b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj @@ -49,6 +49,9 @@ IClipboardHelper.cs + + IpcChannelHelper.cs + diff --git a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt index 34a83830cd..3a36e9b3d2 100644 --- a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt +++ b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt @@ -1,9 +1,38 @@ [Program logs] =============== = System.String[] -[Other Logs] +[Clipboard] +=============== +Comma = System.Char[] +--System.Char[] = System.Char[]: N/A +Star = System.Char[] +--System.Char[] = System.Char[]: N/A +NullSeparator = System.Char[] +--System.Char[] = System.Char[]: N/A +lastClipboardEventTime = 0 +clipboardCopiedTime = 0 +k__BackingField = NONE +k__BackingField = 0 +k__BackingField = False +lastClipboardObject = +k__BackingField = False +ClipboardThreadOldLock = Lock +--_owningThreadId = 0 +--_state = 0 +--_recursionCount = 0 +--_spinCount = 22 +--_waiterStartTimeMs = 0 +--s_contentionCount = 0 +--s_maxSpinCount = 22 +--s_minSpinCountForAdaptiveSpin = -100 +BIG_CLIPBOARD_DATA_TIMEOUT = 30000 +MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576 +MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600 +TEXT_HEADER_SIZE = 12 +DATA_SIZE = 48 +TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F} +[Common] =============== - = MouseWithoutBorders.Common screenWidth = 0 screenHeight = 0 lastX = 0 @@ -46,7 +75,6 @@ avgSendTime = 0 maxSendTime = 0 totalSendCount = 0 totalSendTime = 0 -k__BackingField = False TOGGLE_ICONS_SIZE = 4 ICON_ONE = 0 ICON_ALL = 1 @@ -55,36 +83,6 @@ ICON_BIG_CLIPBOARD = 3 ICON_ERROR = 4 JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999 NETWORK_STREAM_BUF_SIZE = 1048576 -[Clipboard] -=============== -Comma = System.Char[] ---System.Char[] = System.Char[]: N/A -Star = System.Char[] ---System.Char[] = System.Char[]: N/A -NullSeparator = System.Char[] ---System.Char[] = System.Char[]: N/A -lastClipboardEventTime = 0 -clipboardCopiedTime = 0 -k__BackingField = NONE -k__BackingField = 0 -k__BackingField = False -lastClipboardObject = -k__BackingField = False -ClipboardThreadOldLock = Lock ---_owningThreadId = 0 ---_state = 0 ---_recursionCount = 0 ---_spinCount = 22 ---_waiterStartTimeMs = 0 ---s_contentionCount = 0 ---s_maxSpinCount = 22 ---s_minSpinCountForAdaptiveSpin = -100 -BIG_CLIPBOARD_DATA_TIMEOUT = 30000 -MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576 -MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600 -TEXT_HEADER_SIZE = 12 -DATA_SIZE = 48 -TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F} [DragDrop] =============== isDragging = False @@ -174,6 +172,9 @@ actualLastPos = {X=0,Y=0} --Empty = {X=0,Y=0} myLastX = 0 myLastY = 0 +[IpcChannelHelper] +=============== +k__BackingField = False [InitAndCleanup] =============== initDone = False @@ -440,6 +441,7 @@ WM_LBUTTONDBLCLK = 515 WM_RBUTTONDBLCLK = 518 WM_MBUTTONDBLCLK = 521 WM_MOUSEWHEEL = 522 +WM_MOUSEHWHEEL = 526 WM_KEYDOWN = 256 WM_KEYUP = 257 WM_SYSKEYDOWN = 260 diff --git a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs index 6ca983724c..f7cd3b461a 100644 --- a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs +++ b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs @@ -117,7 +117,6 @@ public static class LoggerTests // copied from DumpObjects in Logger.cs var sb = new StringBuilder(1000000); Logger.DumpProgramLogs(sb, settingsDumpObjectsLevel); - Logger.DumpOtherLogs(sb, settingsDumpObjectsLevel); Logger.DumpStaticTypes(sb, settingsDumpObjectsLevel); var actual = sb.ToString();