From c31e671e6ea37c91e0e1642b5db9bd957f4c7bd0 Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Fri, 21 Feb 2025 18:50:21 +0000 Subject: [PATCH 1/6] [MouseWithoutBorders] - moving Common.Event.cs -> Core\Event.cs - #35155 --- .../App/Class/Common.Event.cs | 277 ------------------ .../App/Class/Common.Helper.cs | 4 +- .../MouseWithoutBorders/App/Class/Common.cs | 24 +- .../App/Class/InputHook.cs | 18 +- .../MouseWithoutBorders/App/Core/Event.cs | 275 +++++++++++++++++ .../MouseWithoutBorders/App/Core/Logger.cs | 4 +- .../App/Core/MachineStuff.cs | 4 +- .../MouseWithoutBorders/App/Core/Receiver.cs | 14 +- .../App/Form/frmInputCallback.cs | 4 +- .../MouseWithoutBorders/App/Form/frmScreen.cs | 2 +- 10 files changed, 313 insertions(+), 313 deletions(-) delete mode 100644 src/modules/MouseWithoutBorders/App/Class/Common.Event.cs create mode 100644 src/modules/MouseWithoutBorders/App/Core/Event.cs diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs deleted file mode 100644 index 92122bcc8fd6..000000000000 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs +++ /dev/null @@ -1,277 +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.CodeAnalysis; -using System.Drawing; -using System.Globalization; -using System.Threading; -using System.Threading.Tasks; - -// -// Keyboard/Mouse hook callback implementation. -// -// -// 2008 created by Truong Do (ductdo). -// 2009-... modified by Truong Do (TruongDo). -// 2023- Included in PowerToys. -// -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; -using MouseWithoutBorders.Form; - -using Thread = MouseWithoutBorders.Core.Thread; - -namespace MouseWithoutBorders -{ - internal partial class Common - { - private static readonly DATA KeybdPackage = new(); - private static readonly DATA MousePackage = new(); -#pragma warning disable SA1307 // Accessible fields should begin with upper-case names - internal static ulong inputEventCount; - internal static ulong invalidPackageCount; -#pragma warning restore SA1307 - internal static int MOVE_MOUSE_RELATIVE = 100000; - internal static int XY_BY_PIXEL = 300000; - - static Common() - { - } - - internal static ulong InvalidPackageCount - { - get => Common.invalidPackageCount; - set => Common.invalidPackageCount = value; - } - - internal static ulong InputEventCount - { - get => Common.inputEventCount; - set => Common.inputEventCount = value; - } - - internal static ulong RealInputEventCount - { - get; - set; - } - - private static Point actualLastPos; - private static int myLastX; - private static int myLastY; - - [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Dotnet port with style preservation")] - internal static void MouseEvent(MOUSEDATA e, int dx, int dy) - { - try - { - PaintCount = 0; - bool switchByMouseEnabled = IsSwitchingByMouseEnabled(); - - if (switchByMouseEnabled && Sk != null && (DesMachineID == MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == WM_MOUSEMOVE) - { - Point p = MachineStuff.MoveToMyNeighbourIfNeeded(e.X, e.Y, MachineStuff.desMachineID); - - if (!p.IsEmpty) - { - HasSwitchedMachineSinceLastCopy = true; - - Logger.LogDebug(string.Format( - CultureInfo.CurrentCulture, - "***** Host Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})", - MachineStuff.newDesMachineIdEx, - e.X, - e.Y)); - - myLastX = e.X; - myLastY = e.Y; - - PrepareToSwitchToMachine(MachineStuff.newDesMachineIdEx, p); - } - } - - if (MachineStuff.desMachineID != MachineID && MachineStuff.SwitchLocation.Count <= 0) - { - MousePackage.Des = MachineStuff.desMachineID; - MousePackage.Type = PackageType.Mouse; - MousePackage.Md.dwFlags = e.dwFlags; - MousePackage.Md.WheelDelta = e.WheelDelta; - - // Relative move - if (Setting.Values.MoveMouseRelatively && Math.Abs(dx) >= MOVE_MOUSE_RELATIVE && Math.Abs(dy) >= MOVE_MOUSE_RELATIVE) - { - MousePackage.Md.X = dx; - MousePackage.Md.Y = dy; - } - else - { - MousePackage.Md.X = (e.X - MachineStuff.primaryScreenBounds.Left) * 65535 / screenWidth; - MousePackage.Md.Y = (e.Y - MachineStuff.primaryScreenBounds.Top) * 65535 / screenHeight; - } - - SkSend(MousePackage, null, false); - - if (MousePackage.Md.dwFlags is WM_LBUTTONUP or WM_RBUTTONUP) - { - Thread.Sleep(10); - } - - NativeMethods.GetCursorPos(ref actualLastPos); - - if (actualLastPos != Common.LastPos) - { - Logger.LogDebug($"Mouse cursor has moved unexpectedly: Expected: {Common.LastPos}, actual: {actualLastPos}."); - Common.LastPos = actualLastPos; - } - } - -#if SHOW_ON_WINLOGON_EX - if (RunOnLogonDesktop && e.dwFlags == WM_RBUTTONUP && - desMachineID == machineID && - e.x > 2 && e.x < 100 && e.y > 2 && e.y < 20) - { - DoSomethingInUIThread(delegate() - { - MainForm.HideMenuWhenRunOnLogonDesktop(); - MainForm.MainMenu.Hide(); - MainForm.MainMenu.Show(e.x - 5, e.y - 3); - }); - } -#endif - } - catch (Exception ex) - { - Logger.Log(ex); - } - } - - internal static bool IsSwitchingByMouseEnabled() - { - return (EasyMouseOption)Setting.Values.EasyMouse == EasyMouseOption.Enable || InputHook.EasyMouseKeyDown; - } - - internal static void PrepareToSwitchToMachine(ID newDesMachineID, Point desMachineXY) - { - Logger.LogDebug($"PrepareToSwitchToMachine: newDesMachineID = {newDesMachineID}, desMachineXY = {desMachineXY}"); - - if (((GetTick() - MachineStuff.lastJump < 100) && (GetTick() - MachineStuff.lastJump > 0)) || MachineStuff.desMachineID == ID.ALL) - { - Logger.LogDebug("PrepareToSwitchToMachine: lastJump"); - return; - } - - MachineStuff.lastJump = GetTick(); - - string newDesMachineName = MachineStuff.NameFromID(newDesMachineID); - - if (!IsConnectedTo(newDesMachineID)) - {// Connection lost, cancel switching - Logger.LogDebug("No active connection found for " + newDesMachineName); - - // ShowToolTip("No active connection found for [" + newDesMachineName + "]!", 500); - } - else - { - MachineStuff.newDesMachineID = newDesMachineID; - MachineStuff.SwitchLocation.X = desMachineXY.X; - MachineStuff.SwitchLocation.Y = desMachineXY.Y; - MachineStuff.SwitchLocation.ResetCount(); - _ = EvSwitch.Set(); - - // PostMessage(mainForm.Handle, WM_SWITCH, IntPtr.Zero, IntPtr.Zero); - if (newDesMachineID != DragDrop.DragMachine) - { - if (!DragDrop.IsDragging && !DragDrop.IsDropping) - { - if (DragDrop.MouseDown && !RunOnLogonDesktop && !RunOnScrSaverDesktop) - { - DragDrop.DragDropStep02(); - } - } - else if (DragDrop.DragMachine != (ID)1) - { - DragDrop.ChangeDropMachine(); - } - } - else - { - DragDrop.DragDropStep11(); - } - - // Change des machine - if (MachineStuff.desMachineID != newDesMachineID) - { - Logger.LogDebug("MouseEvent: Switching to new machine:" + newDesMachineName); - - // Ask current machine to hide the Mouse cursor - if (newDesMachineID != ID.ALL && MachineStuff.desMachineID != MachineID) - { - SendPackage(MachineStuff.desMachineID, PackageType.HideMouse); - } - - DesMachineID = newDesMachineID; - - if (MachineStuff.desMachineID == MachineID) - { - if (GetTick() - clipboardCopiedTime < BIG_CLIPBOARD_DATA_TIMEOUT) - { - clipboardCopiedTime = 0; - Common.GetRemoteClipboard("PrepareToSwitchToMachine"); - } - } - else - { - // Ask the new active machine to get clipboard data (if the data is too big) - SendPackage(MachineStuff.desMachineID, PackageType.MachineSwitched); - } - - _ = Interlocked.Increment(ref switchCount); - } - } - } - - internal static void SaveSwitchCount() - { - if (SwitchCount > 0) - { - _ = Task.Run(() => - { - Setting.Values.SwitchCount += SwitchCount; - _ = Interlocked.Exchange(ref switchCount, 0); - }); - } - } - - internal static void KeybdEvent(KEYBDDATA e) - { - try - { - PaintCount = 0; - if (MachineStuff.desMachineID != MachineStuff.newDesMachineID) - { - Logger.LogDebug("KeybdEvent: Switching to new machine..."); - DesMachineID = MachineStuff.newDesMachineID; - } - - if (MachineStuff.desMachineID != MachineID) - { - KeybdPackage.Des = MachineStuff.desMachineID; - KeybdPackage.Type = PackageType.Keyboard; - KeybdPackage.Kd = e; - KeybdPackage.DateTime = GetTick(); - SkSend(KeybdPackage, null, false); - if (KeybdPackage.Kd.dwFlags is WM_KEYUP or WM_SYSKEYUP) - { - Thread.Sleep(10); - } - } - } - catch (Exception ex) - { - Logger.Log(ex); - } - } - } -} diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs index b741f9525626..5bfafcc782c4 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs @@ -103,9 +103,9 @@ private static void HelperThread() Logger.LogDebug($"+++++ Moving mouse to {MachineStuff.SwitchLocation.X}, {MachineStuff.SwitchLocation.Y}"); // MaxXY = 65535 so 100k is safe. - if (MachineStuff.SwitchLocation.X > XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > XY_BY_PIXEL - 100000) + if (MachineStuff.SwitchLocation.X > Event.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Event.XY_BY_PIXEL - 100000) { - InputSimulation.MoveMouse(MachineStuff.SwitchLocation.X - XY_BY_PIXEL, MachineStuff.SwitchLocation.Y - XY_BY_PIXEL); + InputSimulation.MoveMouse(MachineStuff.SwitchLocation.X - Event.XY_BY_PIXEL, MachineStuff.SwitchLocation.Y - Event.XY_BY_PIXEL); } else { diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs index 40699b355b65..549390bc467f 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.cs @@ -114,7 +114,9 @@ internal Common() internal const int NETWORK_STREAM_BUF_SIZE = 1024 * 1024; internal static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset); private static Point lastPos; - private static int switchCount; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case names + internal static int switchCount; +#pragma warning restore SA1307 private static long lastReconnectByHotKeyTime; private static int tcpPort; private static bool secondOpenSocketTry; @@ -543,7 +545,7 @@ internal static void SendNextMachine(ID hostMachine, ID nextMachine, Point reque internal static void SendAwakeBeat() { if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() && - Setting.Values.BlockScreenSaver && lastRealInputEventCount != Common.RealInputEventCount) + Setting.Values.BlockScreenSaver && lastRealInputEventCount != Event.RealInputEventCount) { SendPackage(ID.ALL, PackageType.Awake); } @@ -552,13 +554,13 @@ internal static void SendAwakeBeat() SendHeartBeat(); } - lastInputEventCount = Common.InputEventCount; - lastRealInputEventCount = Common.RealInputEventCount; + lastInputEventCount = Event.InputEventCount; + lastRealInputEventCount = Event.RealInputEventCount; } internal static void HumanBeingDetected() { - if (lastInputEventCount == Common.InputEventCount) + if (lastInputEventCount == Event.InputEventCount) { if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive()) { @@ -566,7 +568,7 @@ internal static void HumanBeingDetected() } } - lastInputEventCount = Common.InputEventCount; + lastInputEventCount = Event.InputEventCount; } private static void PokeMyself() @@ -581,7 +583,7 @@ private static void PokeMyself() InputSimulation.MoveMouseRelative(-x, -y); Thread.Sleep(50); - if (lastInputEventCount != Common.InputEventCount) + if (lastInputEventCount != Event.InputEventCount) { break; } @@ -590,8 +592,8 @@ private static void PokeMyself() internal static void InitLastInputEventCount() { - lastInputEventCount = Common.InputEventCount; - lastRealInputEventCount = Common.RealInputEventCount; + lastInputEventCount = Event.InputEventCount; + lastRealInputEventCount = Event.RealInputEventCount; } internal static void SendHello() @@ -956,8 +958,8 @@ internal static void SkSend(DATA data, uint? exceptDes, bool includeHandShakingS { // SwitchToMachine(MachineName.Trim()); MachineStuff.NewDesMachineID = DesMachineID = MachineID; - MachineStuff.SwitchLocation.X = XY_BY_PIXEL + myLastX; - MachineStuff.SwitchLocation.Y = XY_BY_PIXEL + myLastY; + MachineStuff.SwitchLocation.X = Event.XY_BY_PIXEL + Event.myLastX; + MachineStuff.SwitchLocation.Y = Event.XY_BY_PIXEL + Event.myLastY; MachineStuff.SwitchLocation.ResetCount(); EvSwitch.Set(); } diff --git a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs index 9bd7b5c4bfe9..35a70572e3da 100644 --- a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs +++ b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs @@ -206,7 +206,7 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) { int rv = 1, dx = 0, dy = 0; bool local = false; - Common.InputEventCount++; + Event.InputEventCount++; try { @@ -220,7 +220,7 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) } else { - Common.RealInputEventCount++; + Event.RealInputEventCount++; if (MachineStuff.NewDesMachineID == Common.MachineID || MachineStuff.NewDesMachineID == ID.ALL) { @@ -269,10 +269,10 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) { MachineStuff.SwitchLocation.Count--; - if (MachineStuff.SwitchLocation.X > Common.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Common.XY_BY_PIXEL - 100000) + if (MachineStuff.SwitchLocation.X > Event.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Event.XY_BY_PIXEL - 100000) { - hookCallbackMouseData.X = MachineStuff.SwitchLocation.X - Common.XY_BY_PIXEL; - hookCallbackMouseData.Y = MachineStuff.SwitchLocation.Y - Common.XY_BY_PIXEL; + hookCallbackMouseData.X = MachineStuff.SwitchLocation.X - Event.XY_BY_PIXEL; + hookCallbackMouseData.Y = MachineStuff.SwitchLocation.Y - Event.XY_BY_PIXEL; } else { @@ -308,8 +308,8 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) hookCallbackMouseData.Y = MachineStuff.PrimaryScreenBounds.Bottom + 1; } - dx += dx < 0 ? -Common.MOVE_MOUSE_RELATIVE : Common.MOVE_MOUSE_RELATIVE; - dy += dy < 0 ? -Common.MOVE_MOUSE_RELATIVE : Common.MOVE_MOUSE_RELATIVE; + dx += dx < 0 ? -Event.MOVE_MOUSE_RELATIVE : Event.MOVE_MOUSE_RELATIVE; + dy += dy < 0 ? -Event.MOVE_MOUSE_RELATIVE : Event.MOVE_MOUSE_RELATIVE; } } @@ -336,13 +336,13 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam) { - Common.InputEventCount++; + Event.InputEventCount++; if (!RealData) { return NativeMethods.CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); } - Common.RealInputEventCount++; + Event.RealInputEventCount++; keyboardHookStruct = LParamToKeyboardHookStruct(lParam); hookCallbackKeybdData.dwFlags = keyboardHookStruct.Flags; diff --git a/src/modules/MouseWithoutBorders/App/Core/Event.cs b/src/modules/MouseWithoutBorders/App/Core/Event.cs new file mode 100644 index 000000000000..2766f031215e --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/Event.cs @@ -0,0 +1,275 @@ +// 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.CodeAnalysis; +using System.Drawing; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; + +// +// Keyboard/Mouse hook callback implementation. +// +// +// 2008 created by Truong Do (ductdo). +// 2009-... modified by Truong Do (TruongDo). +// 2023- Included in PowerToys. +// +using MouseWithoutBorders.Class; +using MouseWithoutBorders.Form; + +namespace MouseWithoutBorders.Core; + +internal static class Event +{ + private static readonly DATA KeybdPackage = new(); + private static readonly DATA MousePackage = new(); +#pragma warning disable SA1307 // Accessible fields should begin with upper-case names + internal static ulong inputEventCount; + internal static ulong invalidPackageCount; +#pragma warning restore SA1307 + internal static int MOVE_MOUSE_RELATIVE = 100000; + internal static int XY_BY_PIXEL = 300000; + + static Event() + { + } + + internal static ulong InvalidPackageCount + { + get => Event.invalidPackageCount; + set => Event.invalidPackageCount = value; + } + + internal static ulong InputEventCount + { + get => Event.inputEventCount; + set => Event.inputEventCount = value; + } + + internal static ulong RealInputEventCount + { + get; + set; + } + + private static Point actualLastPos; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case names + internal static int myLastX; + internal static int myLastY; +#pragma warning restore SA1307 + + [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Dotnet port with style preservation")] + internal static void MouseEvent(MOUSEDATA e, int dx, int dy) + { + try + { + Common.PaintCount = 0; + bool switchByMouseEnabled = IsSwitchingByMouseEnabled(); + + if (switchByMouseEnabled && Common.Sk != null && (Common.DesMachineID == Common.MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == Common.WM_MOUSEMOVE) + { + Point p = MachineStuff.MoveToMyNeighbourIfNeeded(e.X, e.Y, MachineStuff.desMachineID); + + if (!p.IsEmpty) + { + Common.HasSwitchedMachineSinceLastCopy = true; + + Logger.LogDebug(string.Format( + CultureInfo.CurrentCulture, + "***** Host Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})", + MachineStuff.newDesMachineIdEx, + e.X, + e.Y)); + + myLastX = e.X; + myLastY = e.Y; + + PrepareToSwitchToMachine(MachineStuff.newDesMachineIdEx, p); + } + } + + if (MachineStuff.desMachineID != Common.MachineID && MachineStuff.SwitchLocation.Count <= 0) + { + MousePackage.Des = MachineStuff.desMachineID; + MousePackage.Type = PackageType.Mouse; + MousePackage.Md.dwFlags = e.dwFlags; + MousePackage.Md.WheelDelta = e.WheelDelta; + + // Relative move + if (Setting.Values.MoveMouseRelatively && Math.Abs(dx) >= MOVE_MOUSE_RELATIVE && Math.Abs(dy) >= MOVE_MOUSE_RELATIVE) + { + MousePackage.Md.X = dx; + MousePackage.Md.Y = dy; + } + else + { + MousePackage.Md.X = (e.X - MachineStuff.primaryScreenBounds.Left) * 65535 / Common.screenWidth; + MousePackage.Md.Y = (e.Y - MachineStuff.primaryScreenBounds.Top) * 65535 / Common.screenHeight; + } + + Common.SkSend(MousePackage, null, false); + + if (MousePackage.Md.dwFlags is Common.WM_LBUTTONUP or Common.WM_RBUTTONUP) + { + Thread.Sleep(10); + } + + NativeMethods.GetCursorPos(ref actualLastPos); + + if (actualLastPos != Common.LastPos) + { + Logger.LogDebug($"Mouse cursor has moved unexpectedly: Expected: {Common.LastPos}, actual: {actualLastPos}."); + Common.LastPos = actualLastPos; + } + } + +#if SHOW_ON_WINLOGON_EX + if (RunOnLogonDesktop && e.dwFlags == WM_RBUTTONUP && + desMachineID == machineID && + e.x > 2 && e.x < 100 && e.y > 2 && e.y < 20) + { + DoSomethingInUIThread(delegate() + { + MainForm.HideMenuWhenRunOnLogonDesktop(); + MainForm.MainMenu.Hide(); + MainForm.MainMenu.Show(e.x - 5, e.y - 3); + }); + } +#endif + } + catch (Exception ex) + { + Logger.Log(ex); + } + } + + internal static bool IsSwitchingByMouseEnabled() + { + return (EasyMouseOption)Setting.Values.EasyMouse == EasyMouseOption.Enable || InputHook.EasyMouseKeyDown; + } + + internal static void PrepareToSwitchToMachine(ID newDesMachineID, Point desMachineXY) + { + Logger.LogDebug($"PrepareToSwitchToMachine: newDesMachineID = {newDesMachineID}, desMachineXY = {desMachineXY}"); + + if (((Common.GetTick() - MachineStuff.lastJump < 100) && (Common.GetTick() - MachineStuff.lastJump > 0)) || MachineStuff.desMachineID == ID.ALL) + { + Logger.LogDebug("PrepareToSwitchToMachine: lastJump"); + return; + } + + MachineStuff.lastJump = Common.GetTick(); + + string newDesMachineName = MachineStuff.NameFromID(newDesMachineID); + + if (!Common.IsConnectedTo(newDesMachineID)) + {// Connection lost, cancel switching + Logger.LogDebug("No active connection found for " + newDesMachineName); + + // ShowToolTip("No active connection found for [" + newDesMachineName + "]!", 500); + } + else + { + MachineStuff.newDesMachineID = newDesMachineID; + MachineStuff.SwitchLocation.X = desMachineXY.X; + MachineStuff.SwitchLocation.Y = desMachineXY.Y; + MachineStuff.SwitchLocation.ResetCount(); + _ = Common.EvSwitch.Set(); + + // PostMessage(mainForm.Handle, WM_SWITCH, IntPtr.Zero, IntPtr.Zero); + if (newDesMachineID != DragDrop.DragMachine) + { + if (!DragDrop.IsDragging && !DragDrop.IsDropping) + { + if (DragDrop.MouseDown && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) + { + DragDrop.DragDropStep02(); + } + } + else if (DragDrop.DragMachine != (ID)1) + { + DragDrop.ChangeDropMachine(); + } + } + else + { + DragDrop.DragDropStep11(); + } + + // Change des machine + if (MachineStuff.desMachineID != newDesMachineID) + { + Logger.LogDebug("MouseEvent: Switching to new machine:" + newDesMachineName); + + // Ask current machine to hide the Mouse cursor + if (newDesMachineID != ID.ALL && MachineStuff.desMachineID != Common.MachineID) + { + Common.SendPackage(MachineStuff.desMachineID, PackageType.HideMouse); + } + + Common.DesMachineID = newDesMachineID; + + if (MachineStuff.desMachineID == Common.MachineID) + { + if (Common.GetTick() - Common.clipboardCopiedTime < Common.BIG_CLIPBOARD_DATA_TIMEOUT) + { + Common.clipboardCopiedTime = 0; + Common.GetRemoteClipboard("PrepareToSwitchToMachine"); + } + } + else + { + // Ask the new active machine to get clipboard data (if the data is too big) + Common.SendPackage(MachineStuff.desMachineID, PackageType.MachineSwitched); + } + + _ = Interlocked.Increment(ref Common.switchCount); + } + } + } + + internal static void SaveSwitchCount() + { + if (Common.SwitchCount > 0) + { + _ = Task.Run(() => + { + Setting.Values.SwitchCount += Common.SwitchCount; + _ = Interlocked.Exchange(ref Common.switchCount, 0); + }); + } + } + + internal static void KeybdEvent(KEYBDDATA e) + { + try + { + Common.PaintCount = 0; + if (MachineStuff.desMachineID != MachineStuff.newDesMachineID) + { + Logger.LogDebug("KeybdEvent: Switching to new machine..."); + Common.DesMachineID = MachineStuff.newDesMachineID; + } + + if (MachineStuff.desMachineID != Common.MachineID) + { + KeybdPackage.Des = MachineStuff.desMachineID; + KeybdPackage.Type = PackageType.Keyboard; + KeybdPackage.Kd = e; + KeybdPackage.DateTime = Common.GetTick(); + Common.SkSend(KeybdPackage, null, false); + if (KeybdPackage.Kd.dwFlags is Common.WM_KEYUP or Common.WM_SYSKEYUP) + { + Thread.Sleep(10); + } + } + } + catch (Exception ex) + { + Logger.Log(ex); + } + } +} diff --git a/src/modules/MouseWithoutBorders/App/Core/Logger.cs b/src/modules/MouseWithoutBorders/App/Core/Logger.cs index 520f1671e3e5..892d9d233be3 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Logger.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Logger.cs @@ -138,7 +138,7 @@ internal static void LogAll() Common.PackageSent.ClipboardDragDrop, Common.PackageSent.ClipboardDragDropEnd, Common.PackageSent.ExplorerDragDrop, - Common.inputEventCount, + Event.inputEventCount, Common.PackageSent.Nil); Log(log); lastPackageSent = Common.PackageSent; // Copy data @@ -161,7 +161,7 @@ internal static void LogAll() Common.PackageReceived.ClipboardDragDrop, Common.PackageReceived.ClipboardDragDropEnd, Common.PackageReceived.ExplorerDragDrop, - Common.invalidPackageCount, + Event.invalidPackageCount, Common.PackageReceived.Nil, Receiver.processedPackageCount, Receiver.skippedPackageCount); diff --git a/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs b/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs index b835ce3420d6..144102629f6a 100644 --- a/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs +++ b/src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs @@ -1018,8 +1018,8 @@ internal static void SwitchToMachine(string name) } NewDesMachineID = Common.DesMachineID = id; - SwitchLocation.X = Common.XY_BY_PIXEL + primaryScreenBounds.Left + ((primaryScreenBounds.Right - primaryScreenBounds.Left) / 2); - SwitchLocation.Y = Common.XY_BY_PIXEL + primaryScreenBounds.Top + ((primaryScreenBounds.Bottom - primaryScreenBounds.Top) / 2); + SwitchLocation.X = Event.XY_BY_PIXEL + primaryScreenBounds.Left + ((primaryScreenBounds.Right - primaryScreenBounds.Left) / 2); + SwitchLocation.Y = Event.XY_BY_PIXEL + primaryScreenBounds.Top + ((primaryScreenBounds.Bottom - primaryScreenBounds.Top) / 2); SwitchLocation.ResetCount(); Common.UpdateMultipleModeIconAndMenu(); Common.HideMouseCursor(false); diff --git a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs index 787c9a5a9ed6..d7dd3e115adc 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs @@ -41,12 +41,12 @@ private static bool PreProcess(DATA package) { if (package.Type == PackageType.Invalid) { - if ((Common.InvalidPackageCount % 100) == 0) + if ((Event.InvalidPackageCount % 100) == 0) { Common.ShowToolTip("Invalid packages received!", 1000, ToolTipIcon.Warning, false); } - Common.InvalidPackageCount++; + Event.InvalidPackageCount++; Logger.Log("Invalid packages received!"); return false; } @@ -144,13 +144,13 @@ internal static void ProcessPackage(DATA package, TcpSk tcp) return; } - if (Math.Abs(package.Md.X) >= Common.MOVE_MOUSE_RELATIVE && Math.Abs(package.Md.Y) >= Common.MOVE_MOUSE_RELATIVE) + if (Math.Abs(package.Md.X) >= Event.MOVE_MOUSE_RELATIVE && Math.Abs(package.Md.Y) >= Event.MOVE_MOUSE_RELATIVE) { if (package.Md.dwFlags == Common.WM_MOUSEMOVE) { InputSimulation.MoveMouseRelative( - package.Md.X < 0 ? package.Md.X + Common.MOVE_MOUSE_RELATIVE : package.Md.X - Common.MOVE_MOUSE_RELATIVE, - package.Md.Y < 0 ? package.Md.Y + Common.MOVE_MOUSE_RELATIVE : package.Md.Y - Common.MOVE_MOUSE_RELATIVE); + package.Md.X < 0 ? package.Md.X + Event.MOVE_MOUSE_RELATIVE : package.Md.X - Event.MOVE_MOUSE_RELATIVE, + package.Md.Y < 0 ? package.Md.Y + Event.MOVE_MOUSE_RELATIVE : package.Md.Y - Event.MOVE_MOUSE_RELATIVE); _ = NativeMethods.GetCursorPos(ref lastXY); Point p = MachineStuff.MoveToMyNeighbourIfNeeded(lastXY.X, lastXY.Y, Common.MachineID); @@ -195,9 +195,9 @@ internal static void ProcessPackage(DATA package, TcpSk tcp) case PackageType.NextMachine: Logger.LogDebug("PackageType.NextMachine received!"); - if (Common.IsSwitchingByMouseEnabled()) + if (Event.IsSwitchingByMouseEnabled()) { - Common.PrepareToSwitchToMachine((ID)package.Md.WheelDelta, new Point(package.Md.X, package.Md.Y)); + Event.PrepareToSwitchToMachine((ID)package.Md.WheelDelta, new Point(package.Md.X, package.Md.Y)); } break; diff --git a/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs index edd35035adbc..ad04cafdc0d8 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs @@ -63,8 +63,8 @@ internal void InstallKeyboardAndMouseHook() try { Common.Hook = new InputHook(); - Common.Hook.MouseEvent += new InputHook.MouseEvHandler(Common.MouseEvent); - Common.Hook.KeyboardEvent += new InputHook.KeybdEvHandler(Common.KeybdEvent); + Common.Hook.MouseEvent += new InputHook.MouseEvHandler(Event.MouseEvent); + Common.Hook.KeyboardEvent += new InputHook.KeybdEvHandler(Event.KeybdEvent); Logger.Log("(((((Keyboard/Mouse hooks installed/reinstalled!)))))"); /* The hook is called in the context of the thread that installed it. diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs index 7963a7572121..9f7a59f2fc74 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs @@ -578,7 +578,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) } else if ((count % 36005) == 0) {// One hour - Common.SaveSwitchCount(); + Event.SaveSwitchCount(); int rv = 0; From 4885c30103f1ac80968f8c968b190125607446da Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Fri, 21 Feb 2025 18:50:59 +0000 Subject: [PATCH 2/6] [MouseWithoutBorders] - moving Common.Service.cs -> Core\Service.cs - #35155 --- .../App/Class/Common.Service.cs | 161 ------------------ .../App/Class/Common.WinAPI.cs | 2 +- .../MouseWithoutBorders/App/Class/Program.cs | 2 +- .../MouseWithoutBorders/App/Core/Service.cs | 159 +++++++++++++++++ .../MouseWithoutBorders/App/Form/frmScreen.cs | 4 +- 5 files changed, 163 insertions(+), 165 deletions(-) delete mode 100644 src/modules/MouseWithoutBorders/App/Class/Common.Service.cs create mode 100644 src/modules/MouseWithoutBorders/App/Core/Service.cs diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs deleted file mode 100644 index a5a71baf5cc8..000000000000 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs +++ /dev/null @@ -1,161 +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.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.ServiceProcess; -using System.Threading.Tasks; -using System.Windows.Forms; - -// -// Service control code. -// -// -// 2008 created by Truong Do (ductdo). -// 2009-... modified by Truong Do (TruongDo). -// 2023- Included in PowerToys. -// -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; - -[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] - -namespace MouseWithoutBorders -{ - internal partial class Common - { - private static bool shownErrMessage; - private static DateTime lastStartServiceTime = DateTime.UtcNow; - - internal static void StartMouseWithoutBordersService(string desktopToRunMouseWithoutBordersOn = null, string startTag1 = "byapp", string startTag2 = null) - { - // NOTE(@yuyoyuppe): the new flow assumes we run both mwb processes directly from the svc. - if (Common.RunWithNoAdminRight || true) - { - return; - } - - Logger.Log($"{nameof(StartMouseWithoutBordersService)}: {Logger.GetStackTrace(new StackTrace())}."); - - Task task = Task.Run(() => - { - Process[] ps = Process.GetProcessesByName("MouseWithoutBordersSvc"); - - if (ps.Length != 0) - { - if (DateTime.UtcNow - lastStartServiceTime < TimeSpan.FromSeconds(5)) - { - Logger.Log($"{nameof(StartMouseWithoutBordersService)}: Aborted."); - return; - } - - foreach (Process pp in ps) - { - Logger.Log(string.Format(CultureInfo.InvariantCulture, "Killing process MouseWithoutBordersSvc {0}.", pp.Id)); - pp.KillProcess(); - } - } - - lastStartServiceTime = DateTime.UtcNow; - ServiceController service = new("MouseWithoutBordersSvc"); - - try - { - Logger.Log("Starting " + service.ServiceName); - } - catch (Exception) - { - if (!shownErrMessage) - { - shownErrMessage = true; - _ = MessageBox.Show( - Application.ProductName + " is not installed yet, please run Setup.exe first!", - Application.ProductName, - MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - - return; - } - - try - { - int c = 0; - - while (service.Status != ServiceControllerStatus.Stopped && c++ < 5) - { - Thread.Sleep(1000); - service = new ServiceController("MouseWithoutBordersSvc"); - } - - if (string.IsNullOrWhiteSpace(desktopToRunMouseWithoutBordersOn)) - { - startTag2 ??= Process.GetCurrentProcess().SessionId.ToString(CultureInfo.InvariantCulture); - service.Start(new string[] { startTag1, startTag2 }); - } - else - { - service.Start(new string[] { desktopToRunMouseWithoutBordersOn }); - } - } - catch (Exception e) - { - Logger.Log(e); - - // ERROR_SERVICE_ALREADY_RUNNING - if (!(shownErrMessage || ((e?.InnerException as Win32Exception)?.NativeErrorCode == 1056))) - { - shownErrMessage = true; - _ = MessageBox.Show( - "Cannot start service " + service.ServiceName + ": " + e.Message, - Common.BinaryName, - MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - - return; - } - }); - - // Wait for the task while not blocking the UI thread. - do - { - MMSleep(1); - - if (task.IsCanceled || task.IsCompleted || task.IsFaulted) - { - break; - } - } - while (true); - } - - internal static void StartServiceAndSendLogoffSignal() - { - try - { - Process[] p = Process.GetProcessesByName("winlogon"); - Process me = Process.GetCurrentProcess(); - string myWinlogon = p?.FirstOrDefault(item => item.SessionId == me.SessionId)?.Id.ToString(CultureInfo.InvariantCulture) ?? null; - - if (string.IsNullOrWhiteSpace(myWinlogon)) - { - StartMouseWithoutBordersService(null, "logoff"); - } - else - { - StartMouseWithoutBordersService(null, "logoff", myWinlogon); - } - } - catch (Exception e) - { - Logger.Log($"{nameof(StartServiceAndSendLogoffSignal)}: {e.Message}"); - } - } - } -} diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs index f1190a7cc7b5..0e6e84760997 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs @@ -269,7 +269,7 @@ internal static void StartMMService(string desktopToRunMouseWithoutBordersOn) if (!Common.RunWithNoAdminRight) { Logger.LogDebug("*** Starting on active Desktop: " + desktopToRunMouseWithoutBordersOn); - StartMouseWithoutBordersService(desktopToRunMouseWithoutBordersOn); + Service.StartMouseWithoutBordersService(desktopToRunMouseWithoutBordersOn); } } diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs index 203f5f277dd1..1e5543ca02e6 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Program.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs @@ -430,7 +430,7 @@ internal static void StartService() Logger.Log(e); } - Common.StartMouseWithoutBordersService(); + Service.StartMouseWithoutBordersService(); } internal static string User { get; set; } diff --git a/src/modules/MouseWithoutBorders/App/Core/Service.cs b/src/modules/MouseWithoutBorders/App/Core/Service.cs new file mode 100644 index 000000000000..129d941512fe --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/Service.cs @@ -0,0 +1,159 @@ +// 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.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.ServiceProcess; +using System.Threading.Tasks; +using System.Windows.Forms; + +// +// Service control code. +// +// +// 2008 created by Truong Do (ductdo). +// 2009-... modified by Truong Do (TruongDo). +// 2023- Included in PowerToys. +// +using MouseWithoutBorders.Class; + +[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] + +namespace MouseWithoutBorders.Core; + +internal static class Service +{ + private static bool shownErrMessage; + private static DateTime lastStartServiceTime = DateTime.UtcNow; + + internal static void StartMouseWithoutBordersService(string desktopToRunMouseWithoutBordersOn = null, string startTag1 = "byapp", string startTag2 = null) + { + // NOTE(@yuyoyuppe): the new flow assumes we run both mwb processes directly from the svc. + if (Common.RunWithNoAdminRight || true) + { + return; + } + + Logger.Log($"{nameof(StartMouseWithoutBordersService)}: {Logger.GetStackTrace(new StackTrace())}."); + + Task task = Task.Run(() => + { + Process[] ps = Process.GetProcessesByName("MouseWithoutBordersSvc"); + + if (ps.Length != 0) + { + if (DateTime.UtcNow - lastStartServiceTime < TimeSpan.FromSeconds(5)) + { + Logger.Log($"{nameof(StartMouseWithoutBordersService)}: Aborted."); + return; + } + + foreach (Process pp in ps) + { + Logger.Log(string.Format(CultureInfo.InvariantCulture, "Killing process MouseWithoutBordersSvc {0}.", pp.Id)); + pp.KillProcess(); + } + } + + lastStartServiceTime = DateTime.UtcNow; + ServiceController service = new("MouseWithoutBordersSvc"); + + try + { + Logger.Log("Starting " + service.ServiceName); + } + catch (Exception) + { + if (!shownErrMessage) + { + shownErrMessage = true; + _ = MessageBox.Show( + Application.ProductName + " is not installed yet, please run Setup.exe first!", + Application.ProductName, + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + + return; + } + + try + { + int c = 0; + + while (service.Status != ServiceControllerStatus.Stopped && c++ < 5) + { + Thread.Sleep(1000); + service = new ServiceController("MouseWithoutBordersSvc"); + } + + if (string.IsNullOrWhiteSpace(desktopToRunMouseWithoutBordersOn)) + { + startTag2 ??= Process.GetCurrentProcess().SessionId.ToString(CultureInfo.InvariantCulture); + service.Start(new string[] { startTag1, startTag2 }); + } + else + { + service.Start(new string[] { desktopToRunMouseWithoutBordersOn }); + } + } + catch (Exception e) + { + Logger.Log(e); + + // ERROR_SERVICE_ALREADY_RUNNING + if (!(shownErrMessage || ((e?.InnerException as Win32Exception)?.NativeErrorCode == 1056))) + { + shownErrMessage = true; + _ = MessageBox.Show( + "Cannot start service " + service.ServiceName + ": " + e.Message, + Common.BinaryName, + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + + return; + } + }); + + // Wait for the task while not blocking the UI thread. + do + { + Common.MMSleep(1); + + if (task.IsCanceled || task.IsCompleted || task.IsFaulted) + { + break; + } + } + while (true); + } + + internal static void StartServiceAndSendLogoffSignal() + { + try + { + Process[] p = Process.GetProcessesByName("winlogon"); + Process me = Process.GetCurrentProcess(); + string myWinlogon = p?.FirstOrDefault(item => item.SessionId == me.SessionId)?.Id.ToString(CultureInfo.InvariantCulture) ?? null; + + if (string.IsNullOrWhiteSpace(myWinlogon)) + { + StartMouseWithoutBordersService(null, "logoff"); + } + else + { + StartMouseWithoutBordersService(null, "logoff", myWinlogon); + } + } + catch (Exception e) + { + Logger.Log($"{nameof(StartServiceAndSendLogoffSignal)}: {e.Message}"); + } + } +} diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs index 9f7a59f2fc74..a9ef2dab382e 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs @@ -101,7 +101,7 @@ private void FrmScreen_FormClosing(object sender, FormClosingEventArgs e) } else { - Common.StartServiceAndSendLogoffSignal(); + Service.StartServiceAndSendLogoffSignal(); Quit(true, true); } } @@ -831,7 +831,7 @@ protected override void WndProc(ref Message m) case WM_QUERYENDSESSION: Logger.LogDebug("WM_QUERYENDSESSION..."); - Common.StartServiceAndSendLogoffSignal(); + Service.StartServiceAndSendLogoffSignal(); break; case WM_ENDSESSION: From e4288d08059abd0ae682426e032356c133967978 Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Fri, 21 Feb 2025 18:58:32 +0000 Subject: [PATCH 3/6] [MouseWithoutBorders] - moving Common.Launch.cs -> Core\Launch.cs - #35155 --- .../App/Class/Common.Clipboard.cs | 6 +- .../App/Class/Common.Helper.cs | 4 +- .../App/Class/Common.Launch.cs | 314 ------------------ .../MouseWithoutBorders/App/Class/Common.cs | 4 +- .../App/Class/SocketStuff.cs | 6 +- .../MouseWithoutBorders/App/Core/DragDrop.cs | 2 +- .../MouseWithoutBorders/App/Core/Launch.cs | 312 +++++++++++++++++ .../MouseWithoutBorders/App/Core/Service.cs | 8 +- 8 files changed, 327 insertions(+), 329 deletions(-) delete mode 100644 src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs create mode 100644 src/modules/MouseWithoutBorders/App/Core/Launch.cs diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs index 9ab32388942a..51be48ec5a24 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs @@ -153,7 +153,7 @@ internal static bool CheckClipboardEx(ByteArrayOrString data, bool isFilePath) string filePath = stringData; - _ = Common.ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { if (File.Exists(filePath) || Directory.Exists(filePath)) { @@ -579,7 +579,7 @@ internal static void ReceiveAndProcessClipboardData(string remoteMachine, Socket { if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase)) { - _ = ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { savingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MouseWithoutBorders\\"; @@ -696,7 +696,7 @@ internal static void ReceiveAndProcessClipboardData(string remoteMachine, Socket Path.GetFileName(fileName), remoteMachine); - _ = ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { ProcessStartInfo startInfo = new(); startInfo.UseShellExecute = true; diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs index 5bfafcc782c4..3e95ca6e2f6e 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs @@ -310,7 +310,7 @@ internal static void RunDDHelper(bool cleanUp = false) if (h.ToInt32() <= 0) { - _ = Common.CreateProcessInInputDesktopSession( + _ = Launch.CreateProcessInInputDesktopSession( $"\"{Path.GetDirectoryName(Application.ExecutablePath)}\\{HelperProcessName}.exe\"", string.Empty, Common.GetInputDesktop(), @@ -442,7 +442,7 @@ internal static bool GetUserName() { if (Program.User.Contains("system", StringComparison.CurrentCultureIgnoreCase)) { - _ = Common.ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { // See: https://stackoverflow.com/questions/19487541/how-to-get-windows-user-name-from-sessionid static string GetUsernameBySessionId(int sessionId) diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs deleted file mode 100644 index 76b811b8f8ef..000000000000 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs +++ /dev/null @@ -1,314 +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.ComponentModel; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Security.Principal; - -// -// Impersonation. -// -// -// 2008 created by Truong Do (ductdo). -// 2009-... modified by Truong Do (TruongDo). -// 2023- Included in PowerToys. -// -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; - -namespace MouseWithoutBorders -{ - internal partial class Common - { - internal static bool RunElevated() - { - return WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid); - } - - internal static bool ImpersonateLoggedOnUserAndDoSomething(Action targetFunc) - { - if (Common.RunWithNoAdminRight) - { - targetFunc(); - return true; - } - else - { - // SuppressFlow fixes an issue on service mode, where WTSQueryUserToken runs successfully once and then fails - // on subsequent calls. The reason appears to be an unknown issue with reverting the impersonation, - // meaning that subsequent impersonation attempts run as the logged-on user and fail. - // This is a workaround. - using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow(); - - uint dwSessionId; - IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero; - try - { - dwSessionId = (uint)Process.GetCurrentProcess().SessionId; - uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken); - var lastError = rv == 0 ? Marshal.GetLastWin32Error() : 0; - - Logger.LogDebug($"{nameof(NativeMethods.WTSQueryUserToken)} returned {rv.ToString(CultureInfo.CurrentCulture)}"); - - if (rv == 0) - { - Logger.Log($"{nameof(NativeMethods.WTSQueryUserToken)} failed with: {lastError}."); - return false; - } - - if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup)) - { - Logger.TelemetryLogTrace($"{nameof(NativeMethods.DuplicateToken)} Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - return false; - } - - if (NativeMethods.ImpersonateLoggedOnUser(hUserTokenDup)) - { - targetFunc(); - _ = NativeMethods.RevertToSelf(); - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - return true; - } - else - { - Logger.Log("ImpersonateLoggedOnUser Failed!"); - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - return false; - } - } - catch (Exception e) - { - Logger.Log(e); - return false; - } - } - } - - internal static int CreateProcessInInputDesktopSession(string commandLine, string arg, string desktop, short wShowWindow, bool lowIntegrity = false) - - // As user who runs explorer.exe - { - if (!Program.User.Contains("system", StringComparison.InvariantCultureIgnoreCase)) - { - ProcessStartInfo s = new(commandLine, arg); - s.WindowStyle = wShowWindow != 0 ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden; - Process p = Process.Start(s); - - return p == null ? 0 : p.Id; - } - - string commandLineWithArg = commandLine + " " + arg; - int lastError; - int dwSessionId; - IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero; - - Logger.LogDebug("CreateProcessInInputDesktopSession called, launching " + commandLineWithArg + " on " + desktop); - - try - { - dwSessionId = Process.GetCurrentProcess().SessionId; - - // Get the user token used by DuplicateTokenEx - lastError = (int)NativeMethods.WTSQueryUserToken((uint)dwSessionId, ref hUserToken); - - NativeMethods.STARTUPINFO si = default; - si.cb = Marshal.SizeOf(si); - si.lpDesktop = "winsta0\\" + desktop; - si.wShowWindow = wShowWindow; - - NativeMethods.SECURITY_ATTRIBUTES sa = default; - sa.Length = Marshal.SizeOf(sa); - - if (!NativeMethods.DuplicateTokenEx(hUserToken, NativeMethods.MAXIMUM_ALLOWED, ref sa, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)NativeMethods.TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) - { - lastError = Marshal.GetLastWin32Error(); - Logger.Log(string.Format(CultureInfo.CurrentCulture, "DuplicateTokenEx error: {0} Token does not have the privilege.", lastError)); - _ = NativeMethods.CloseHandle(hUserToken); - return 0; - } - - if (lowIntegrity) - { - NativeMethods.TOKEN_MANDATORY_LABEL tIL; - - // Low - string sIntegritySid = "S-1-16-4096"; - - bool rv = NativeMethods.ConvertStringSidToSid(sIntegritySid, out IntPtr pIntegritySid); - - if (!rv) - { - Logger.Log("ConvertStringSidToSid failed"); - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - return 0; - } - - tIL.Label.Attributes = NativeMethods.SE_GROUP_INTEGRITY; - tIL.Label.Sid = pIntegritySid; - - rv = NativeMethods.SetTokenInformation(hUserTokenDup, NativeMethods.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, ref tIL, (uint)Marshal.SizeOf(tIL) + (uint)IntPtr.Size); - - if (!rv) - { - Logger.Log("SetTokenInformation failed"); - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - return 0; - } - } - - uint dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS | NativeMethods.CREATE_NEW_CONSOLE; - IntPtr pEnv = IntPtr.Zero; - - if (NativeMethods.CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true)) - { - dwCreationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT; - } - else - { - pEnv = IntPtr.Zero; - } - - _ = NativeMethods.CreateProcessAsUser( - hUserTokenDup, // client's access token - null, // file to execute - commandLineWithArg, // command line - ref sa, // pointer to process SECURITY_ATTRIBUTES - ref sa, // pointer to thread SECURITY_ATTRIBUTES - false, // handles are not inheritable - (int)dwCreationFlags, // creation flags - pEnv, // pointer to new environment block - null, // name of current directory - ref si, // pointer to STARTUPINFO structure - out NativeMethods.PROCESS_INFORMATION pi); // receives information about new process - - // GetLastError should be 0 - int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error(); - Logger.LogDebug("CreateProcessAsUser returned " + iResultOfCreateProcessAsUser.ToString(CultureInfo.CurrentCulture)); - - // Close handles task - _ = NativeMethods.CloseHandle(hUserToken); - _ = NativeMethods.CloseHandle(hUserTokenDup); - - return (iResultOfCreateProcessAsUser == 0) ? (int)pi.dwProcessId : 0; - } - catch (Exception e) - { - Logger.Log(e); - return 0; - } - } - -#if CUSTOMIZE_LOGON_SCREEN - internal static bool CreateLowIntegrityProcess(string commandLine, string args, int wait, bool killIfTimedOut, long limitedMem, short wShowWindow = 0) - { - int processId = CreateProcessInInputDesktopSession(commandLine, args, "default", wShowWindow, true); - - if (processId <= 0) - { - return false; - } - - if (wait > 0) - { - if (limitedMem > 0) - { - int sec = 0; - while (true) - { - Process p; - - try - { - if ((p = Process.GetProcessById(processId)) == null) - { - Logger.Log("Process exited!"); - break; - } - } - catch (ArgumentException) - { - Logger.Log("GetProcessById.ArgumentException"); - break; - } - - if ((!p.HasExited && p.PrivateMemorySize64 > limitedMem) || (++sec > (wait / 1000))) - { - Logger.Log(string.Format(CultureInfo.CurrentCulture, "Process log (mem): {0}, {1}", sec, p.PrivateMemorySize64)); - return false; - } - - Thread.Sleep(1000); - } - } - else - { - Process p; - - if ((p = Process.GetProcessById(processId)) == null) - { - Logger.Log("Process exited!"); - } - else if (NativeMethods.WaitForSingleObject(p.Handle, wait) != NativeMethods.WAIT_OBJECT_0 && killIfTimedOut) - { - Logger.Log("Process log (time)."); - TerminateProcessTree(p.Handle, (uint)processId, -1); - return false; - } - } - } - - return true; - } - - internal static void TerminateProcessTree(IntPtr hProcess, uint processID, int exitCode) - { - if (processID > 0 && hProcess.ToInt32() > 0) - { - Process[] processes = Process.GetProcesses(); - int dwSessionId = Process.GetCurrentProcess().SessionId; - - foreach (Process p in processes) - { - if (p.SessionId == dwSessionId) - { - NativeMethods.PROCESS_BASIC_INFORMATION processBasicInformation = default; - - try - { - if (NativeMethods.NtQueryInformationProcess(p.Handle, 0, ref processBasicInformation, (uint)Marshal.SizeOf(processBasicInformation), out uint bytesWritten) >= 0) - {// NT_SUCCESS(...) - if (processBasicInformation.InheritedFromUniqueProcessId == processID) - { - TerminateProcessTree(p.Handle, processBasicInformation.UniqueProcessId, exitCode); - } - } - } - catch (InvalidOperationException e) - { - Logger.Log(e); - continue; - } - catch (Win32Exception e) - { - Logger.Log(e); - continue; - } - } - } - - _ = NativeMethods.TerminateProcess(hProcess, (IntPtr)exitCode); - } - } -#endif - } -} diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs index 549390bc467f..54e12c7dcd12 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.cs @@ -700,7 +700,7 @@ internal static void OpenImage(string file) // { // Process.Start("explorer", "\"" + file + "\""); // }); - _ = CreateProcessInInputDesktopSession( + _ = Launch.CreateProcessInInputDesktopSession( "\"" + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") + "\"", "\"" + file + "\"", @@ -1316,7 +1316,7 @@ private static string GetMyStorageDir() } else { - _ = ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { st = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\" + Common.BinaryName; if (!Directory.Exists(st)) diff --git a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs index 3f848edf769c..8796f61dfb92 100644 --- a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs +++ b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs @@ -1684,7 +1684,7 @@ internal static void SendClipboardData(Socket s, Stream ecStream) { string fileName = null; - if (!Common.ImpersonateLoggedOnUserAndDoSomething(() => + if (!Launch.ImpersonateLoggedOnUserAndDoSomething(() => { if (!File.Exists(Common.LastDragDropFile)) { @@ -1873,7 +1873,7 @@ private static bool SendFile(Socket s, Stream ecStream, string fileName) } else { - _ = Common.ImpersonateLoggedOnUserAndDoSomething(() => { r = SendFileEx(s, ecStream, fileName); }); + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { r = SendFileEx(s, ecStream, fileName); }); } return r; @@ -2111,7 +2111,7 @@ private void PreventDoS(List sockets) } } - _ = Common.CreateLowIntegrityProcess( + _ = Launch.CreateLowIntegrityProcess( "\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", "InternalError" + " \"" + msg + "\"", 0, diff --git a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs index bf52717dfb62..713dad774479 100644 --- a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs +++ b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs @@ -189,7 +189,7 @@ internal static void DragDropStep05Ex(string dragFileName) if (!IsDropping) { - _ = Common.ImpersonateLoggedOnUserAndDoSomething(() => + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => { if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName))) { diff --git a/src/modules/MouseWithoutBorders/App/Core/Launch.cs b/src/modules/MouseWithoutBorders/App/Core/Launch.cs new file mode 100644 index 000000000000..56067909693d --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/Launch.cs @@ -0,0 +1,312 @@ +// 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.ComponentModel; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Security.Principal; + +// +// Impersonation. +// +// +// 2008 created by Truong Do (ductdo). +// 2009-... modified by Truong Do (TruongDo). +// 2023- Included in PowerToys. +// +using MouseWithoutBorders.Class; + +namespace MouseWithoutBorders.Core; + +internal static class Launch +{ + private static bool RunElevated() + { + return WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid); + } + + internal static bool ImpersonateLoggedOnUserAndDoSomething(Action targetFunc) + { + if (Common.RunWithNoAdminRight) + { + targetFunc(); + return true; + } + else + { + // SuppressFlow fixes an issue on service mode, where WTSQueryUserToken runs successfully once and then fails + // on subsequent calls. The reason appears to be an unknown issue with reverting the impersonation, + // meaning that subsequent impersonation attempts run as the logged-on user and fail. + // This is a workaround. + using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow(); + + uint dwSessionId; + IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero; + try + { + dwSessionId = (uint)Process.GetCurrentProcess().SessionId; + uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken); + var lastError = rv == 0 ? Marshal.GetLastWin32Error() : 0; + + Logger.LogDebug($"{nameof(NativeMethods.WTSQueryUserToken)} returned {rv.ToString(CultureInfo.CurrentCulture)}"); + + if (rv == 0) + { + Logger.Log($"{nameof(NativeMethods.WTSQueryUserToken)} failed with: {lastError}."); + return false; + } + + if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup)) + { + Logger.TelemetryLogTrace($"{nameof(NativeMethods.DuplicateToken)} Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + return false; + } + + if (NativeMethods.ImpersonateLoggedOnUser(hUserTokenDup)) + { + targetFunc(); + _ = NativeMethods.RevertToSelf(); + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + return true; + } + else + { + Logger.Log("ImpersonateLoggedOnUser Failed!"); + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + return false; + } + } + catch (Exception e) + { + Logger.Log(e); + return false; + } + } + } + + internal static int CreateProcessInInputDesktopSession(string commandLine, string arg, string desktop, short wShowWindow, bool lowIntegrity = false) + + // As user who runs explorer.exe + { + if (!Program.User.Contains("system", StringComparison.InvariantCultureIgnoreCase)) + { + ProcessStartInfo s = new(commandLine, arg); + s.WindowStyle = wShowWindow != 0 ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden; + Process p = Process.Start(s); + + return p == null ? 0 : p.Id; + } + + string commandLineWithArg = commandLine + " " + arg; + int lastError; + int dwSessionId; + IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero; + + Logger.LogDebug("CreateProcessInInputDesktopSession called, launching " + commandLineWithArg + " on " + desktop); + + try + { + dwSessionId = Process.GetCurrentProcess().SessionId; + + // Get the user token used by DuplicateTokenEx + lastError = (int)NativeMethods.WTSQueryUserToken((uint)dwSessionId, ref hUserToken); + + NativeMethods.STARTUPINFO si = default; + si.cb = Marshal.SizeOf(si); + si.lpDesktop = "winsta0\\" + desktop; + si.wShowWindow = wShowWindow; + + NativeMethods.SECURITY_ATTRIBUTES sa = default; + sa.Length = Marshal.SizeOf(sa); + + if (!NativeMethods.DuplicateTokenEx(hUserToken, NativeMethods.MAXIMUM_ALLOWED, ref sa, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)NativeMethods.TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) + { + lastError = Marshal.GetLastWin32Error(); + Logger.Log(string.Format(CultureInfo.CurrentCulture, "DuplicateTokenEx error: {0} Token does not have the privilege.", lastError)); + _ = NativeMethods.CloseHandle(hUserToken); + return 0; + } + + if (lowIntegrity) + { + NativeMethods.TOKEN_MANDATORY_LABEL tIL; + + // Low + string sIntegritySid = "S-1-16-4096"; + + bool rv = NativeMethods.ConvertStringSidToSid(sIntegritySid, out IntPtr pIntegritySid); + + if (!rv) + { + Logger.Log("ConvertStringSidToSid failed"); + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + return 0; + } + + tIL.Label.Attributes = NativeMethods.SE_GROUP_INTEGRITY; + tIL.Label.Sid = pIntegritySid; + + rv = NativeMethods.SetTokenInformation(hUserTokenDup, NativeMethods.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, ref tIL, (uint)Marshal.SizeOf(tIL) + (uint)IntPtr.Size); + + if (!rv) + { + Logger.Log("SetTokenInformation failed"); + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + return 0; + } + } + + uint dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS | NativeMethods.CREATE_NEW_CONSOLE; + IntPtr pEnv = IntPtr.Zero; + + if (NativeMethods.CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true)) + { + dwCreationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT; + } + else + { + pEnv = IntPtr.Zero; + } + + _ = NativeMethods.CreateProcessAsUser( + hUserTokenDup, // client's access token + null, // file to execute + commandLineWithArg, // command line + ref sa, // pointer to process SECURITY_ATTRIBUTES + ref sa, // pointer to thread SECURITY_ATTRIBUTES + false, // handles are not inheritable + (int)dwCreationFlags, // creation flags + pEnv, // pointer to new environment block + null, // name of current directory + ref si, // pointer to STARTUPINFO structure + out NativeMethods.PROCESS_INFORMATION pi); // receives information about new process + + // GetLastError should be 0 + int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error(); + Logger.LogDebug("CreateProcessAsUser returned " + iResultOfCreateProcessAsUser.ToString(CultureInfo.CurrentCulture)); + + // Close handles task + _ = NativeMethods.CloseHandle(hUserToken); + _ = NativeMethods.CloseHandle(hUserTokenDup); + + return (iResultOfCreateProcessAsUser == 0) ? (int)pi.dwProcessId : 0; + } + catch (Exception e) + { + Logger.Log(e); + return 0; + } + } + +#if CUSTOMIZE_LOGON_SCREEN + internal static bool CreateLowIntegrityProcess(string commandLine, string args, int wait, bool killIfTimedOut, long limitedMem, short wShowWindow = 0) + { + int processId = CreateProcessInInputDesktopSession(commandLine, args, "default", wShowWindow, true); + + if (processId <= 0) + { + return false; + } + + if (wait > 0) + { + if (limitedMem > 0) + { + int sec = 0; + while (true) + { + Process p; + + try + { + if ((p = Process.GetProcessById(processId)) == null) + { + Logger.Log("Process exited!"); + break; + } + } + catch (ArgumentException) + { + Logger.Log("GetProcessById.ArgumentException"); + break; + } + + if ((!p.HasExited && p.PrivateMemorySize64 > limitedMem) || (++sec > (wait / 1000))) + { + Logger.Log(string.Format(CultureInfo.CurrentCulture, "Process log (mem): {0}, {1}", sec, p.PrivateMemorySize64)); + return false; + } + + Thread.Sleep(1000); + } + } + else + { + Process p; + + if ((p = Process.GetProcessById(processId)) == null) + { + Logger.Log("Process exited!"); + } + else if (NativeMethods.WaitForSingleObject(p.Handle, wait) != NativeMethods.WAIT_OBJECT_0 && killIfTimedOut) + { + Logger.Log("Process log (time)."); + TerminateProcessTree(p.Handle, (uint)processId, -1); + return false; + } + } + } + + return true; + } + + private static void TerminateProcessTree(IntPtr hProcess, uint processID, int exitCode) + { + if (processID > 0 && hProcess.ToInt32() > 0) + { + Process[] processes = Process.GetProcesses(); + int dwSessionId = Process.GetCurrentProcess().SessionId; + + foreach (Process p in processes) + { + if (p.SessionId == dwSessionId) + { + NativeMethods.PROCESS_BASIC_INFORMATION processBasicInformation = default; + + try + { + if (NativeMethods.NtQueryInformationProcess(p.Handle, 0, ref processBasicInformation, (uint)Marshal.SizeOf(processBasicInformation), out uint bytesWritten) >= 0) + {// NT_SUCCESS(...) + if (processBasicInformation.InheritedFromUniqueProcessId == processID) + { + TerminateProcessTree(p.Handle, processBasicInformation.UniqueProcessId, exitCode); + } + } + } + catch (InvalidOperationException e) + { + Logger.Log(e); + continue; + } + catch (Win32Exception e) + { + Logger.Log(e); + continue; + } + } + } + + _ = NativeMethods.TerminateProcess(hProcess, (IntPtr)exitCode); + } + } +#endif +} diff --git a/src/modules/MouseWithoutBorders/App/Core/Service.cs b/src/modules/MouseWithoutBorders/App/Core/Service.cs index 129d941512fe..e8585220c87c 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Service.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Service.cs @@ -12,6 +12,10 @@ using System.Threading.Tasks; using System.Windows.Forms; +using MouseWithoutBorders.Class; + +[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] + // // Service control code. // @@ -20,10 +24,6 @@ // 2009-... modified by Truong Do (TruongDo). // 2023- Included in PowerToys. // -using MouseWithoutBorders.Class; - -[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")] - namespace MouseWithoutBorders.Core; internal static class Service From f2087948a6828a088a796d67227d259c9b2d3904 Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Fri, 21 Feb 2025 19:12:18 +0000 Subject: [PATCH 4/6] [MouseWithoutBorders] - moving Common.Helper.cs -> Core\Helper.cs - #35155 --- .../App/Class/Common.Helper.cs | 526 ------------------ .../App/Class/Common.InitAndCleanup.cs | 14 +- .../App/Class/Common.WinAPI.cs | 2 +- .../MouseWithoutBorders/App/Class/Common.cs | 12 +- .../App/Class/InputHook.cs | 2 +- .../App/Class/InputSimulation.cs | 2 +- .../MouseWithoutBorders/App/Class/Program.cs | 5 +- .../MouseWithoutBorders/App/Class/Setting.cs | 3 +- .../MouseWithoutBorders/App/Core/DragDrop.cs | 2 +- .../MouseWithoutBorders/App/Core/Helper.cs | 526 ++++++++++++++++++ .../MouseWithoutBorders/App/Core/Receiver.cs | 6 +- .../MouseWithoutBorders/App/Form/frmMatrix.cs | 6 +- .../MouseWithoutBorders/App/Form/frmScreen.cs | 34 +- 13 files changed, 572 insertions(+), 568 deletions(-) delete mode 100644 src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs create mode 100644 src/modules/MouseWithoutBorders/App/Core/Helper.cs diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs deleted file mode 100644 index 3e95ca6e2f6e..000000000000 --- a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs +++ /dev/null @@ -1,526 +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.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Security.Principal; -using System.Windows.Forms; - -// -// Some other helper methods. -// -// -// 2008 created by Truong Do (ductdo). -// 2009-... modified by Truong Do (TruongDo). -// 2023- Included in PowerToys. -// -using Microsoft.Win32; -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Core; -using static System.Windows.Forms.Control; - -namespace MouseWithoutBorders -{ - internal partial class Common - { - internal const string HELPER_FORM_TEXT = "Mouse without Borders Helper"; - internal const string HelperProcessName = "PowerToys.MouseWithoutBordersHelper"; - private static bool signalHelperToExit; - private static bool signalWatchDogToExit; - internal static long WndProcCounter; - - private static void WatchDogThread() - { - long oldCounter = WndProcCounter; - - do - { - for (int i = 0; i < 10; i++) - { - Thread.Sleep(1000); - - if (signalWatchDogToExit) - { - break; - } - } - - while (BlockingUI) - { - Thread.Sleep(1000); - } - - if (WndProcCounter == oldCounter) - { - Process p = Process.GetCurrentProcess(); - string procInfo = $"{p.PrivateMemorySize64 / 1024 / 1024}MB, {p.TotalProcessorTime}, {Environment.ProcessorCount}."; - string threadStacks = $"{procInfo} {Thread.DumpThreadsStack()}"; - Logger.TelemetryLogTrace(threadStacks, SeverityLevel.Error); - break; - } - - oldCounter = WndProcCounter; - } - while (true); - } - - private static void HelperThread() - { - // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. - // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 - using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow(); - - try - { - while (true) - { - _ = EvSwitch.WaitOne(); // Switching to another machine? - - if (signalHelperToExit) - { - break; - } - - if (MachineStuff.NewDesMachineID != Common.MachineID && MachineStuff.NewDesMachineID != ID.ALL) - { - HideMouseCursor(false); - Common.MainFormDotEx(true); - } - else - { - if (MachineStuff.SwitchLocation.Count > 0) - { - MachineStuff.SwitchLocation.Count--; - - // When we want to move mouse by pixels, we add 300k to x and y (search for XY_BY_PIXEL for other related code). - Logger.LogDebug($"+++++ Moving mouse to {MachineStuff.SwitchLocation.X}, {MachineStuff.SwitchLocation.Y}"); - - // MaxXY = 65535 so 100k is safe. - if (MachineStuff.SwitchLocation.X > Event.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Event.XY_BY_PIXEL - 100000) - { - InputSimulation.MoveMouse(MachineStuff.SwitchLocation.X - Event.XY_BY_PIXEL, MachineStuff.SwitchLocation.Y - Event.XY_BY_PIXEL); - } - else - { - InputSimulation.MoveMouseEx(MachineStuff.SwitchLocation.X, MachineStuff.SwitchLocation.Y); - } - - Common.MainFormDot(); - } - } - - if (MachineStuff.NewDesMachineID == Common.MachineID) - { - ReleaseAllKeys(); - } - } - } - catch (Exception e) - { - Logger.Log(e); - } - - signalHelperToExit = false; - Logger.LogDebug("^^^Helper Thread exiting...^^^"); - } - - internal static void MainFormDotEx(bool bCheckTS) - { - Logger.LogDebug("***** MainFormDotEx:"); - - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) - { - int left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1; - int top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2); - - Common.MainFormVisible = true; - - if (Setting.Values.HideMouse && Setting.Values.StealFocusWhenSwitchingMachine && Common.SendMessageToHelper(0x407, new IntPtr(left), new IntPtr(top), true) == 0) - { - try - { - /* When user just switches to the Logon desktop, user is actually on the "Windows Default Lock Screen" (LockApp). - * If a click is sent to this during switch, it actually triggers a desktop switch on the local machine causing a reconnection affecting the machine switch. - * We can detect and skip in this case. - * */ - IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow(); - string foreGroundWindowText = GetText(foreGroundWindow); - - bool mouseClick = true; - - if (foreGroundWindowText.Equals("Windows Default Lock Screen", StringComparison.OrdinalIgnoreCase)) - { - mouseClick = false; - } - - // Window title may be localized, check process name: - if (mouseClick) - { - _ = NativeMethods.GetWindowThreadProcessId(foreGroundWindow, out uint pid); - - if (pid > 0) - { - string foreGroundWindowProcess = Process.GetProcessById((int)pid)?.ProcessName; - - if (foreGroundWindowProcess.Equals("LockApp", StringComparison.OrdinalIgnoreCase)) - { - mouseClick = false; - } - } - } - - if (mouseClick) - { - InputSimulation.MouseClickDotForm(left + 1, top + 1); - } - } - catch (Exception e) - { - Logger.Log(e); - } - } - } - - CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); - } - - internal static void MainForm3Pixels() - { - Logger.LogDebug("***** MainFormDotLarge:"); - - DoSomethingInUIThread( - () => - { - MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 2; - MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2) - 1; - MainForm.Width = 3; - MainForm.Height = 3; - MainForm.Opacity = 0.11D; - MainForm.TopMost = true; - - if (Setting.Values.HideMouse) - { - MainForm.BackColor = Color.Black; - MainForm.Show(); - Common.MainFormVisible = true; - } - else - { - MainForm.BackColor = Color.White; - MainForm.Hide(); - Common.MainFormVisible = false; - } - }, - true); - - CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); - } - - internal static void MainFormDot() - { - DoSomethingInUIThread( - () => - { - _ = Common.SendMessageToHelper(0x408, IntPtr.Zero, IntPtr.Zero, false); - - MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1; - MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2); - MainForm.Width = 1; - MainForm.Height = 1; - MainForm.Opacity = 0.15; - MainForm.Hide(); - Common.MainFormVisible = false; - }, - true); - - CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); - } - - internal static void ToggleIcon() - { - try - { - if (toggleIconsIndex < TOGGLE_ICONS_SIZE) - { - Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(toggleIcons[toggleIconsIndex++])); - } - else - { - toggleIconsIndex = 0; - toggleIcons = null; - } - } - catch (Exception e) - { - Logger.Log(e); - } - } - - internal static void RunDDHelper(bool cleanUp = false) - { - if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop) - { - return; - } - - if (cleanUp) - { - try - { - Process[] ps = Process.GetProcessesByName(HelperProcessName); - foreach (Process p in ps) - { - p.KillProcess(); - } - } - catch (Exception e) - { - Logger.Log(e); - _ = Common.SendMessageToHelper(SharedConst.QUIT_CMD, IntPtr.Zero, IntPtr.Zero); - } - - return; - } - - if (!Common.IsMyDesktopActive()) - { - return; - } - - if (!Common.IpcChannelCreated) - { - Logger.TelemetryLogTrace($"{nameof(Common.IpcChannelCreated)} = {Common.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); - return; - } - - if (!MainForm.IsDisposed) - { - MainForm.NotifyIcon.Visible = false; - MainForm.NotifyIcon.Visible = Setting.Values.ShowOriginalUI; - } - - IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT); - - if (h.ToInt32() <= 0) - { - _ = Launch.CreateProcessInInputDesktopSession( - $"\"{Path.GetDirectoryName(Application.ExecutablePath)}\\{HelperProcessName}.exe\"", - string.Empty, - Common.GetInputDesktop(), - 0); - - HasSwitchedMachineSinceLastCopy = true; - - // Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0); - var processes = Process.GetProcessesByName(HelperProcessName); - if (processes?.Length == 0) - { - Logger.Log("Unable to start helper process."); - Common.ShowToolTip("Error starting Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error); - } - else - { - Logger.Log("Helper process started."); - } - } - else - { - var processes = Process.GetProcessesByName(HelperProcessName); - if (processes?.Length > 0) - { - Logger.Log("Helper process found running."); - } - else - { - Logger.Log("Invalid helper process found running."); - Common.ShowToolTip("Error finding Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error); - } - } - } - - internal static int SendMessageToHelper(int msg, IntPtr wparam, IntPtr lparam, bool wait = true, bool log = true) - { - int h = NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT); - int rv = -1; - - if (h > 0) - { - rv = wait - ? (int)NativeMethods.SendMessage((IntPtr)h, msg, wparam, lparam) - : NativeMethods.PostMessage((IntPtr)h, msg, wparam, lparam) ? 1 : 0; - } - - if (log) - { - Logger.LogDebug($"SendMessageToHelper: HelperWindow={h}, Return={rv}, msg={msg}, w={wparam.ToInt32()}, l={lparam.ToInt32()}, Post={!wait}"); - } - - return rv; - } - - internal static bool IsWindows8AndUp() - { - return (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2) - || Environment.OSVersion.Version.Major > 6; - } - - internal static string GetMiniLog(IEnumerable optionControls) - { - string log = string.Empty; - - log += "=============================================================================================================================\r\n"; - log += $"{Application.ProductName} version {Application.ProductVersion}\r\n"; - - log += $"{Setting.Values.Username}/{GetDebugInfo(MyKey)}\r\n"; - log += $"{MachineName}/{MachineID}/{DesMachineID}\r\n"; - log += $"Id: {Setting.Values.DeviceId}\r\n"; - log += $"Matrix: {string.Join(",", MachineStuff.MachineMatrix)}\r\n"; - log += $"McPool: {Setting.Values.MachinePoolString}\r\n"; - - log += "\r\nOPTIONS:\r\n"; - - foreach (ControlCollection controlCollection in optionControls) - { - foreach (object c in controlCollection) - { - if (c is CheckBox checkBox) - { - log += $"({(checkBox.Checked ? 1 : 0)}) {checkBox.Text}\r\n"; - continue; - } - - if (c is RadioButton radioButton) - { - log += $"({(radioButton.Checked ? 1 : 0)}) {radioButton.Name}.[{radioButton.Text}]\r\n"; - continue; - } - - if (c is ComboBox comboBox) - { - log += $"{comboBox.Name} = {comboBox.Text}\r\n"; - continue; - } - } - } - - log += "\r\n"; - - SocketStuff sk = Sk; - - if (sk?.TcpSockets != null) - { - foreach (TcpSk tcp in sk.TcpSockets) - { - log += $"{Common.MachineName}{(tcp.IsClient ? "=>" : "<=")}{tcp.MachineName}({tcp.MachineId}):{tcp.Status}\r\n"; - } - } - - log += string.Format(CultureInfo.CurrentCulture, "Helper:{0}\r\n", SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)); - - log += Setting.Values.LastPersonalizeLogonScr + "\r\n"; - log += "Name2IP =\r\n" + Setting.Values.Name2IP + "\r\n"; - - log += "Last 10 trace messages:\r\n"; - - log += string.Join(Environment.NewLine, Logger.LogCounter.Select(item => $"({item.Value}): {item.Key}").Take(10)); - - log += "\r\n============================================================================================================================="; - - return log; - } - - internal static bool GetUserName() - { - if (string.IsNullOrEmpty(Setting.Values.Username) && !Common.RunOnLogonDesktop) - { - if (Program.User.Contains("system", StringComparison.CurrentCultureIgnoreCase)) - { - _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => - { - // See: https://stackoverflow.com/questions/19487541/how-to-get-windows-user-name-from-sessionid - static string GetUsernameBySessionId(int sessionId) - { - string username = "SYSTEM"; - if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSUserName, out nint buffer, out int strLen) && strLen > 1) - { - username = Marshal.PtrToStringAnsi(buffer); - NativeMethods.WTSFreeMemory(buffer); - - if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1) - { - username = @$"{Marshal.PtrToStringAnsi(buffer)}\{username}"; - NativeMethods.WTSFreeMemory(buffer); - } - } - - return username; - } - - // The most direct way to fetch the username is WindowsIdentity.GetCurrent(true).Name - // but GetUserName can run within an ExecutionContext.SuppressFlow block, which creates issues - // with WindowsIdentity.GetCurrent. - // See: https://stackoverflow.com/questions/76998988/exception-when-using-executioncontext-suppressflow-in-net-7 - // So we use WTSQuerySessionInformation as a workaround. - Setting.Values.Username = GetUsernameBySessionId(Process.GetCurrentProcess().SessionId); - }); - } - else - { - Setting.Values.Username = Program.User; - } - - Logger.LogDebug("[Username] = " + Setting.Values.Username); - } - - return !string.IsNullOrEmpty(Setting.Values.Username); - } - - internal static void ShowOneWayModeMessage() - { - ToggleShowTopMostMessage( - @" -Due to Security Controls, a remote device cannot control a SAW device. -Please use the keyboard and Mouse from the SAW device. -(Press Esc to hide this message) -", - string.Empty, - 10); - } - - internal static void ApplyCADSetting() - { - try - { - if (Setting.Values.DisableCAD) - { - RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"); - if (k != null) - { - k.SetValue("DisableCAD", 1, RegistryValueKind.DWord); - k.Close(); - } - } - else - { - RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"); - if (k != null) - { - k.SetValue("DisableCAD", 0, RegistryValueKind.DWord); - k.Close(); - } - } - } - catch (Exception e) - { - Logger.Log(e); - } - } - } -} diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs b/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs index 0b2b651060bb..44861926e9c9 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs @@ -93,7 +93,7 @@ internal static void SetupMachineNameAndID() internal static void Init() { - _ = Common.GetUserName(); + _ = Helper.GetUserName(); Common.GeneratedKey = true; try @@ -148,7 +148,7 @@ internal static void Init() private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) { - Common.WndProcCounter++; + Helper.WndProcCounter++; if (e.Mode is PowerModes.Resume or PowerModes.Suspend) { @@ -167,21 +167,21 @@ private static void CreateHelperThreads() watchDogThread.Start(); */ - helper = new Thread(new ThreadStart(HelperThread), "Helper Thread"); + helper = new Thread(new ThreadStart(Helper.HelperThread), "Helper Thread"); helper.SetApartmentState(ApartmentState.STA); helper.Start(); } private static void AskHelperThreadsToExit(int waitTime) { - signalHelperToExit = true; - signalWatchDogToExit = true; + Helper.signalHelperToExit = true; + Helper.signalWatchDogToExit = true; _ = EvSwitch.Set(); int c = 0; if (helper != null && c < waitTime) { - while (signalHelperToExit) + while (Helper.signalHelperToExit) { Thread.Sleep(1); } @@ -251,7 +251,7 @@ internal static void ReleaseAllKeys() private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) { Logger.LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture)); - Common.WndProcCounter++; + Helper.WndProcCounter++; ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable); } diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs index 0e6e84760997..ed5610193073 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs @@ -279,7 +279,7 @@ internal static void CheckForDesktopSwitchEvent(bool cleanupIfExit) { if (!IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId()) { - Common.RunDDHelper(true); + Helper.RunDDHelper(true); int waitCount = 20; while (NativeMethods.WTSGetActiveConsoleSessionId() == 0xFFFFFFFF && waitCount > 0) diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs index 54e12c7dcd12..8d4ff7f326c3 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Common.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Common.cs @@ -101,8 +101,10 @@ internal Common() private static bool runOnLogonDesktop; private static bool runOnScrSaverDesktop; - private static int[] toggleIcons; - private static int toggleIconsIndex; +#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; @@ -667,7 +669,7 @@ internal static void PrepareScreenCapture() { Common.DoSomethingInUIThread(() => { - if (!DragDrop.MouseDown && Common.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0) + if (!DragDrop.MouseDown && Helper.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0) { Common.MMSleep(0.2); InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT }); @@ -676,14 +678,14 @@ internal static void PrepareScreenCapture() Logger.LogDebug("PrepareScreenCapture: SNAPSHOT simulated."); _ = NativeMethods.MoveWindow( - (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT), + (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); - _ = Common.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false); + _ = Helper.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false); } else { diff --git a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs index 35a70572e3da..33cbe77e890a 100644 --- a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs +++ b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs @@ -227,7 +227,7 @@ private int MouseHookProc(int nCode, int wParam, IntPtr lParam) local = true; if (Common.MainFormVisible && !DragDrop.IsDropping) { - Common.MainFormDot(); + Helper.MainFormDot(); } } diff --git a/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs index 6641655ad43c..a991c7f64f91 100644 --- a/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs +++ b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs @@ -223,7 +223,7 @@ internal static uint SendMouse(MOUSEDATA md) if (Common.MainFormVisible && !DragDrop.IsDropping) { - Common.MainFormDot(); + Helper.MainFormDot(); } return rv; diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs index 1e5543ca02e6..2fd8357e2490 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Program.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs @@ -36,6 +36,7 @@ using StreamJsonRpc; using Logger = MouseWithoutBorders.Core.Logger; +using SettingsHelper = Microsoft.PowerToys.Settings.UI.Library.Utilities.Helper; using Thread = MouseWithoutBorders.Core.Thread; [module: SuppressMessage("Microsoft.MSInternal", "CA904:DeclareTypesInMicrosoftOrSystemNamespace", Scope = "namespace", Target = "MouseWithoutBorders", Justification = "Dotnet port with style preservation")] @@ -128,7 +129,7 @@ private static void Main() { if (args.Length > 2) { - Helper.UserLocalAppDataPath = args[2].Trim(); + SettingsHelper.UserLocalAppDataPath = args[2].Trim(); } } @@ -235,7 +236,7 @@ private static void Main() Application.SetCompatibleTextRenderingDefault(false); Common.Init(); - Common.WndProcCounter++; + Core.Helper.WndProcCounter++; var formScreen = new FrmScreen(); diff --git a/src/modules/MouseWithoutBorders/App/Class/Setting.cs b/src/modules/MouseWithoutBorders/App/Class/Setting.cs index 31d9a50049ad..72365fe4787b 100644 --- a/src/modules/MouseWithoutBorders/App/Class/Setting.cs +++ b/src/modules/MouseWithoutBorders/App/Class/Setting.cs @@ -33,6 +33,7 @@ using Settings.UI.Library.Attributes; using Lock = System.Threading.Lock; +using SettingsHelper = Microsoft.PowerToys.Settings.UI.Library.Utilities.Helper; [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#LoadIntSetting(System.String,System.Int32)", Justification = "Dotnet port with style preservation")] [module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#SaveSetting(System.String,System.Object)", Justification = "Dotnet port with style preservation")] @@ -193,7 +194,7 @@ internal Settings() { _settingsUtils = new SettingsUtils(); - _watcher = Helper.GetFileWatcher("MouseWithoutBorders", "settings.json", () => + _watcher = SettingsHelper.GetFileWatcher("MouseWithoutBorders", "settings.json", () => { try { diff --git a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs index 713dad774479..7fb32b50fba5 100644 --- a/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs +++ b/src/modules/MouseWithoutBorders/App/Core/DragDrop.cs @@ -132,7 +132,7 @@ internal static void DragDropStep04() { if (!IsDropping) { - IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT); + IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT); if (h.ToInt32() > 0) { _ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 0); diff --git a/src/modules/MouseWithoutBorders/App/Core/Helper.cs b/src/modules/MouseWithoutBorders/App/Core/Helper.cs new file mode 100644 index 000000000000..bb8e686271da --- /dev/null +++ b/src/modules/MouseWithoutBorders/App/Core/Helper.cs @@ -0,0 +1,526 @@ +// 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.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security.Principal; +using System.Windows.Forms; + +// +// Some other helper methods. +// +// +// 2008 created by Truong Do (ductdo). +// 2009-... modified by Truong Do (TruongDo). +// 2023- Included in PowerToys. +// +using Microsoft.Win32; +using MouseWithoutBorders.Class; +using static System.Windows.Forms.Control; + +namespace MouseWithoutBorders.Core; + +internal static class Helper +{ + internal const string HELPER_FORM_TEXT = "Mouse without Borders Helper"; + internal const string HelperProcessName = "PowerToys.MouseWithoutBordersHelper"; +#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter + internal static bool signalHelperToExit; + internal static bool signalWatchDogToExit; +#pragma warning restore SA1307 + internal static long WndProcCounter; + + private static void WatchDogThread() + { + long oldCounter = WndProcCounter; + + do + { + for (int i = 0; i < 10; i++) + { + Thread.Sleep(1000); + + if (signalWatchDogToExit) + { + break; + } + } + + while (Common.BlockingUI) + { + Thread.Sleep(1000); + } + + if (WndProcCounter == oldCounter) + { + Process p = Process.GetCurrentProcess(); + string procInfo = $"{p.PrivateMemorySize64 / 1024 / 1024}MB, {p.TotalProcessorTime}, {Environment.ProcessorCount}."; + string threadStacks = $"{procInfo} {Thread.DumpThreadsStack()}"; + Logger.TelemetryLogTrace(threadStacks, SeverityLevel.Error); + break; + } + + oldCounter = WndProcCounter; + } + while (true); + } + + internal static void HelperThread() + { + // SuppressFlow fixes an issue on service mode, where the helper process can't get enough permissions to be started again. + // More details can be found on: https://github.com/microsoft/PowerToys/pull/36892 + using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow(); + + try + { + while (true) + { + _ = Common.EvSwitch.WaitOne(); // Switching to another machine? + + if (signalHelperToExit) + { + break; + } + + if (MachineStuff.NewDesMachineID != Common.MachineID && MachineStuff.NewDesMachineID != ID.ALL) + { + Common.HideMouseCursor(false); + Helper.MainFormDotEx(true); + } + else + { + if (MachineStuff.SwitchLocation.Count > 0) + { + MachineStuff.SwitchLocation.Count--; + + // When we want to move mouse by pixels, we add 300k to x and y (search for XY_BY_PIXEL for other related code). + Logger.LogDebug($"+++++ Moving mouse to {MachineStuff.SwitchLocation.X}, {MachineStuff.SwitchLocation.Y}"); + + // MaxXY = 65535 so 100k is safe. + if (MachineStuff.SwitchLocation.X > Event.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Event.XY_BY_PIXEL - 100000) + { + InputSimulation.MoveMouse(MachineStuff.SwitchLocation.X - Event.XY_BY_PIXEL, MachineStuff.SwitchLocation.Y - Event.XY_BY_PIXEL); + } + else + { + InputSimulation.MoveMouseEx(MachineStuff.SwitchLocation.X, MachineStuff.SwitchLocation.Y); + } + + Helper.MainFormDot(); + } + } + + if (MachineStuff.NewDesMachineID == Common.MachineID) + { + Common.ReleaseAllKeys(); + } + } + } + catch (Exception e) + { + Logger.Log(e); + } + + signalHelperToExit = false; + Logger.LogDebug("^^^Helper Thread exiting...^^^"); + } + + internal static void MainFormDotEx(bool bCheckTS) + { + Logger.LogDebug("***** MainFormDotEx:"); + + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) + { + int left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1; + int top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2); + + Common.MainFormVisible = true; + + if (Setting.Values.HideMouse && Setting.Values.StealFocusWhenSwitchingMachine && Helper.SendMessageToHelper(0x407, new IntPtr(left), new IntPtr(top), true) == 0) + { + try + { + /* When user just switches to the Logon desktop, user is actually on the "Windows Default Lock Screen" (LockApp). + * If a click is sent to this during switch, it actually triggers a desktop switch on the local machine causing a reconnection affecting the machine switch. + * We can detect and skip in this case. + * */ + IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow(); + string foreGroundWindowText = Common.GetText(foreGroundWindow); + + bool mouseClick = true; + + if (foreGroundWindowText.Equals("Windows Default Lock Screen", StringComparison.OrdinalIgnoreCase)) + { + mouseClick = false; + } + + // Window title may be localized, check process name: + if (mouseClick) + { + _ = NativeMethods.GetWindowThreadProcessId(foreGroundWindow, out uint pid); + + if (pid > 0) + { + string foreGroundWindowProcess = Process.GetProcessById((int)pid)?.ProcessName; + + if (foreGroundWindowProcess.Equals("LockApp", StringComparison.OrdinalIgnoreCase)) + { + mouseClick = false; + } + } + } + + if (mouseClick) + { + InputSimulation.MouseClickDotForm(left + 1, top + 1); + } + } + catch (Exception e) + { + Logger.Log(e); + } + } + } + + CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); + } + + internal static void MainForm3Pixels() + { + Logger.LogDebug("***** MainFormDotLarge:"); + + Common.DoSomethingInUIThread( + () => + { + Common.MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 2; + Common.MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2) - 1; + Common.MainForm.Width = 3; + Common.MainForm.Height = 3; + Common.MainForm.Opacity = 0.11D; + Common.MainForm.TopMost = true; + + if (Setting.Values.HideMouse) + { + Common.MainForm.BackColor = Color.Black; + Common.MainForm.Show(); + Common.MainFormVisible = true; + } + else + { + Common.MainForm.BackColor = Color.White; + Common.MainForm.Hide(); + Common.MainFormVisible = false; + } + }, + true); + + CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); + } + + internal static void MainFormDot() + { + Common.DoSomethingInUIThread( + () => + { + _ = Helper.SendMessageToHelper(0x408, IntPtr.Zero, IntPtr.Zero, false); + + Common.MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1; + Common.MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2); + Common.MainForm.Width = 1; + Common.MainForm.Height = 1; + Common.MainForm.Opacity = 0.15; + Common.MainForm.Hide(); + Common.MainFormVisible = false; + }, + true); + + CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue); + } + + internal static void ToggleIcon() + { + try + { + if (Common.toggleIconsIndex < Common.TOGGLE_ICONS_SIZE) + { + Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(Common.toggleIcons[Common.toggleIconsIndex++])); + } + else + { + Common.toggleIconsIndex = 0; + Common.toggleIcons = null; + } + } + catch (Exception e) + { + Logger.Log(e); + } + } + + internal static void RunDDHelper(bool cleanUp = false) + { + if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop) + { + return; + } + + if (cleanUp) + { + try + { + Process[] ps = Process.GetProcessesByName(HelperProcessName); + foreach (Process p in ps) + { + p.KillProcess(); + } + } + catch (Exception e) + { + Logger.Log(e); + _ = Helper.SendMessageToHelper(SharedConst.QUIT_CMD, IntPtr.Zero, IntPtr.Zero); + } + + return; + } + + if (!Common.IsMyDesktopActive()) + { + return; + } + + if (!Common.IpcChannelCreated) + { + Logger.TelemetryLogTrace($"{nameof(Common.IpcChannelCreated)} = {Common.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning); + return; + } + + if (!Common.MainForm.IsDisposed) + { + Common.MainForm.NotifyIcon.Visible = false; + Common.MainForm.NotifyIcon.Visible = Setting.Values.ShowOriginalUI; + } + + IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT); + + if (h.ToInt32() <= 0) + { + _ = Launch.CreateProcessInInputDesktopSession( + $"\"{Path.GetDirectoryName(Application.ExecutablePath)}\\{HelperProcessName}.exe\"", + string.Empty, + Common.GetInputDesktop(), + 0); + + Common.HasSwitchedMachineSinceLastCopy = true; + + // Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0); + var processes = Process.GetProcessesByName(HelperProcessName); + if (processes?.Length == 0) + { + Logger.Log("Unable to start helper process."); + Common.ShowToolTip("Error starting Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error); + } + else + { + Logger.Log("Helper process started."); + } + } + else + { + var processes = Process.GetProcessesByName(HelperProcessName); + if (processes?.Length > 0) + { + Logger.Log("Helper process found running."); + } + else + { + Logger.Log("Invalid helper process found running."); + Common.ShowToolTip("Error finding Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error); + } + } + } + + internal static int SendMessageToHelper(int msg, IntPtr wparam, IntPtr lparam, bool wait = true, bool log = true) + { + int h = NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT); + int rv = -1; + + if (h > 0) + { + rv = wait + ? (int)NativeMethods.SendMessage((IntPtr)h, msg, wparam, lparam) + : NativeMethods.PostMessage((IntPtr)h, msg, wparam, lparam) ? 1 : 0; + } + + if (log) + { + Logger.LogDebug($"SendMessageToHelper: HelperWindow={h}, Return={rv}, msg={msg}, w={wparam.ToInt32()}, l={lparam.ToInt32()}, Post={!wait}"); + } + + return rv; + } + + internal static bool IsWindows8AndUp() + { + return (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2) + || Environment.OSVersion.Version.Major > 6; + } + + internal static string GetMiniLog(IEnumerable optionControls) + { + string log = string.Empty; + + log += "=============================================================================================================================\r\n"; + log += $"{Application.ProductName} version {Application.ProductVersion}\r\n"; + + log += $"{Setting.Values.Username}/{Common.GetDebugInfo(Common.MyKey)}\r\n"; + log += $"{Common.MachineName}/{Common.MachineID}/{Common.DesMachineID}\r\n"; + log += $"Id: {Setting.Values.DeviceId}\r\n"; + log += $"Matrix: {string.Join(",", MachineStuff.MachineMatrix)}\r\n"; + log += $"McPool: {Setting.Values.MachinePoolString}\r\n"; + + log += "\r\nOPTIONS:\r\n"; + + foreach (ControlCollection controlCollection in optionControls) + { + foreach (object c in controlCollection) + { + if (c is CheckBox checkBox) + { + log += $"({(checkBox.Checked ? 1 : 0)}) {checkBox.Text}\r\n"; + continue; + } + + if (c is RadioButton radioButton) + { + log += $"({(radioButton.Checked ? 1 : 0)}) {radioButton.Name}.[{radioButton.Text}]\r\n"; + continue; + } + + if (c is ComboBox comboBox) + { + log += $"{comboBox.Name} = {comboBox.Text}\r\n"; + continue; + } + } + } + + log += "\r\n"; + + SocketStuff sk = Common.Sk; + + if (sk?.TcpSockets != null) + { + foreach (TcpSk tcp in sk.TcpSockets) + { + log += $"{Common.MachineName}{(tcp.IsClient ? "=>" : "<=")}{tcp.MachineName}({tcp.MachineId}):{tcp.Status}\r\n"; + } + } + + log += string.Format(CultureInfo.CurrentCulture, "Helper:{0}\r\n", SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)); + + log += Setting.Values.LastPersonalizeLogonScr + "\r\n"; + log += "Name2IP =\r\n" + Setting.Values.Name2IP + "\r\n"; + + log += "Last 10 trace messages:\r\n"; + + log += string.Join(Environment.NewLine, Logger.LogCounter.Select(item => $"({item.Value}): {item.Key}").Take(10)); + + log += "\r\n============================================================================================================================="; + + return log; + } + + internal static bool GetUserName() + { + if (string.IsNullOrEmpty(Setting.Values.Username) && !Common.RunOnLogonDesktop) + { + if (Program.User.Contains("system", StringComparison.CurrentCultureIgnoreCase)) + { + _ = Launch.ImpersonateLoggedOnUserAndDoSomething(() => + { + // See: https://stackoverflow.com/questions/19487541/how-to-get-windows-user-name-from-sessionid + static string GetUsernameBySessionId(int sessionId) + { + string username = "SYSTEM"; + if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSUserName, out nint buffer, out int strLen) && strLen > 1) + { + username = Marshal.PtrToStringAnsi(buffer); + NativeMethods.WTSFreeMemory(buffer); + + if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1) + { + username = @$"{Marshal.PtrToStringAnsi(buffer)}\{username}"; + NativeMethods.WTSFreeMemory(buffer); + } + } + + return username; + } + + // The most direct way to fetch the username is WindowsIdentity.GetCurrent(true).Name + // but GetUserName can run within an ExecutionContext.SuppressFlow block, which creates issues + // with WindowsIdentity.GetCurrent. + // See: https://stackoverflow.com/questions/76998988/exception-when-using-executioncontext-suppressflow-in-net-7 + // So we use WTSQuerySessionInformation as a workaround. + Setting.Values.Username = GetUsernameBySessionId(Process.GetCurrentProcess().SessionId); + }); + } + else + { + Setting.Values.Username = Program.User; + } + + Logger.LogDebug("[Username] = " + Setting.Values.Username); + } + + return !string.IsNullOrEmpty(Setting.Values.Username); + } + + internal static void ShowOneWayModeMessage() + { + Common.ToggleShowTopMostMessage( +@" +Due to Security Controls, a remote device cannot control a SAW device. +Please use the keyboard and Mouse from the SAW device. +(Press Esc to hide this message) +", +string.Empty, +10); + } + + internal static void ApplyCADSetting() + { + try + { + if (Setting.Values.DisableCAD) + { + RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"); + if (k != null) + { + k.SetValue("DisableCAD", 1, RegistryValueKind.DWord); + k.Close(); + } + } + else + { + RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"); + if (k != null) + { + k.SetValue("DisableCAD", 0, RegistryValueKind.DWord); + k.Close(); + } + } + } + catch (Exception e) + { + Logger.Log(e); + } + } +} diff --git a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs index d7dd3e115adc..303bec4ff0e3 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Receiver.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Receiver.cs @@ -104,7 +104,7 @@ internal static void ProcessPackage(DATA package, TcpSk tcp) { if ((package.Kd.dwFlags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP) { - Common.ShowOneWayModeMessage(); + Helper.ShowOneWayModeMessage(); } return; @@ -133,7 +133,7 @@ internal static void ProcessPackage(DATA package, TcpSk tcp) { if (package.Md.dwFlags is Common.WM_LBUTTONDOWN or Common.WM_RBUTTONDOWN) { - Common.ShowOneWayModeMessage(); + Helper.ShowOneWayModeMessage(); } } else if (package.Md.dwFlags is Common.WM_LBUTTONUP or Common.WM_RBUTTONUP) @@ -383,7 +383,7 @@ internal static void ProcessPackage(DATA package, TcpSk tcp) case PackageType.HideMouse: Common.HasSwitchedMachineSinceLastCopy = true; Common.HideMouseCursor(true); - Common.MainFormDotEx(false); + Helper.MainFormDotEx(false); Common.ReleaseAllKeys(); break; diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs index 8f23dba1a22c..ca095d814000 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs @@ -132,7 +132,7 @@ private void ButtonOK_Click(object sender, EventArgs e) internal void UpdateKeyTextBox() { - _ = Common.GetUserName(); + _ = Helper.GetUserName(); textBoxEnc.Text = Common.MyKey; } @@ -787,7 +787,7 @@ private void CheckBoxDisableCAD_CheckedChanged(object sender, EventArgs e) { if (!Common.RunWithNoAdminRight) { - Common.ApplyCADSetting(); + Helper.ApplyCADSetting(); ShowUpdateMessage(); } } @@ -1163,7 +1163,7 @@ private void CheckBoxVKMap_CheckedChanged(object sender, EventArgs e) private void LinkLabelMiniLog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - string miniLog = Common.GetMiniLog(new[] { groupBoxOtherOptions.Controls, groupBoxShortcuts.Controls }); + string miniLog = Helper.GetMiniLog(new[] { groupBoxOtherOptions.Controls, groupBoxShortcuts.Controls }); Clipboard.SetText(miniLog); Common.ShowToolTip("Log has been placed in the clipboard.", 30000, ToolTipIcon.Info, false); diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs index a9ef2dab382e..b01a653f60e1 100644 --- a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs +++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs @@ -78,7 +78,7 @@ internal FrmScreen() NotifyIcon.BalloonTipTitle = Application.ProductName; menuGenDumpFile.Visible = true; - Common.WndProcCounter++; + Helper.WndProcCounter++; try { @@ -119,7 +119,7 @@ internal void Destroy() NotifyIcon.Dispose(); if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop) { - Common.RunDDHelper(true); + Helper.RunDDHelper(true); } // Common.UnhookClipboard(); @@ -133,7 +133,7 @@ internal void Quit(bool cleanup, bool isFormClosing) Setting.Values.SwitchCount += Common.SwitchCount; Process me = Process.GetCurrentProcess(); - Common.WndProcCounter++; + Helper.WndProcCounter++; try { @@ -142,13 +142,13 @@ internal void Quit(bool cleanup, bool isFormClosing) Common.Cleanup(); } - Common.WndProcCounter++; + Helper.WndProcCounter++; if (!Common.RunOnScrSaverDesktop) { Common.ReleaseAllKeys(); } - Common.RunDDHelper(true); + Helper.RunDDHelper(true); } catch (Exception e) { @@ -285,7 +285,7 @@ private void FrmScreen_Load(object sender, EventArgs e) helperTimer.Interval = 100; helperTimer.Tick += new EventHandler(HelperTimer_Tick); helperTimer.Start(); - Common.WndProcCounter++; + Helper.WndProcCounter++; if (Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)) @@ -307,7 +307,7 @@ private void FrmScreen_Load(object sender, EventArgs e) private void HelperTimer_Tick(object sender, EventArgs e) { - Common.WndProcCounter++; + Helper.WndProcCounter++; if (busy) { @@ -338,7 +338,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) if (Common.MainFormVisible) { - Common.MainFormDot(); + Helper.MainFormDot(); } InputSimulation.ResetSystemKeyFlags(); @@ -357,7 +357,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) { if (!Common.SecondOpenSocketTry) { - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Common.GetUserName()) + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Helper.GetUserName()) { // While Windows 8 is hybrid-shutting down, user name would be empty (as returned from the .Net API), we should not do anything in this case. Logger.LogDebug("No active user."); @@ -407,7 +407,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) // Common.ReHookClipboard(); } - Common.RunDDHelper(); + Helper.RunDDHelper(); } count = 0; @@ -485,7 +485,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) // One more time after 1/3 minutes (Sometimes XP has explorer started late) if (count == 600 || count == 1800) { - Common.RunDDHelper(); + Helper.RunDDHelper(); } if (count == 600) @@ -545,7 +545,7 @@ private void HelperTimer_Tick(object sender, EventArgs e) if (Common.ToggleIcons != null) { - Common.ToggleIcon(); + Helper.ToggleIcon(); } if (count % 20 == 0) @@ -582,9 +582,9 @@ private void HelperTimer_Tick(object sender, EventArgs e) int rv = 0; - if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() && (rv = Common.SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)) <= 0) + if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() && (rv = Helper.SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)) <= 0) { - Logger.TelemetryLogTrace($"{Common.HELPER_FORM_TEXT} not found: {rv}", SeverityLevel.Warning); + Logger.TelemetryLogTrace($"{Helper.HELPER_FORM_TEXT} not found: {rv}", SeverityLevel.Warning); } } } @@ -776,7 +776,7 @@ protected override void WndProc(ref Message m) break; case NativeMethods.WM_HIDE_DRAG_DROP: - Common.MainFormDot(); + Helper.MainFormDot(); /* this.Width = 1; @@ -795,14 +795,14 @@ protected override void WndProc(ref Message m) break; case NativeMethods.WM_HIDE_DD_HELPER: - Common.MainForm3Pixels(); + Helper.MainForm3Pixels(); Common.MMSleep(0.2); if (m.WParam.ToInt32() == 1) { InputSimulation.MouseUp(); // A file is being dragged } - IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT); + IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Helper.HELPER_FORM_TEXT); if (h.ToInt32() > 0) { From dd7c7d2dcbe36f629c64139848cbd0c1164e5d76 Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Sat, 22 Feb 2025 11:10:37 +0000 Subject: [PATCH 5/6] [MouseWithoutBorders] - refactoring and fixes for logger unit test - #35155 --- .../MouseWithoutBorders/App/Core/Logger.cs | 42 ++++-- .../Core/Logger.PrivateDump.expected.txt | 134 ++++++++++-------- .../Core/LoggerTests.cs | 17 +-- 3 files changed, 110 insertions(+), 83 deletions(-) diff --git a/src/modules/MouseWithoutBorders/App/Core/Logger.cs b/src/modules/MouseWithoutBorders/App/Core/Logger.cs index 892d9d233be3..fa59d422c930 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Logger.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Logger.cs @@ -197,15 +197,9 @@ internal static void DumpObjects(int level) myThreads.Add(t); } - _ = Logger.PrivateDump(sb, AllLogs, "[Program logs]\r\n===============\r\n", 0, level, false); - _ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, level, false); - Logger.DumpType(sb, typeof(Logger), 0, level); - sb.AppendLine("[DragDrop]\r\n==============="); - Logger.DumpType(sb, typeof(DragDrop), 0, level); - sb.AppendLine("[MachineStuff]\r\n==============="); - Logger.DumpType(sb, typeof(MachineStuff), 0, level); - sb.AppendLine("[Receiver]\r\n==============="); - Logger.DumpType(sb, typeof(Receiver), 0, level); + Logger.DumpProgramLogs(sb, level); + Logger.DumpOtherLogs(sb, level); + Logger.DumpStaticTypes(sb, level); log = string.Format( CultureInfo.CurrentCulture, @@ -241,6 +235,36 @@ internal static void DumpObjects(int level) } } + internal static void DumpProgramLogs(StringBuilder sb, int level) + { + _ = 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) + { + sb.AppendLine($"[{nameof(DragDrop)}]\r\n==============="); + Logger.DumpType(sb, typeof(DragDrop), 0, level); + sb.AppendLine($"[{nameof(Event)}]\r\n==============="); + Logger.DumpType(sb, typeof(Event), 0, level); + sb.AppendLine($"[{nameof(Helper)}]\r\n==============="); + Logger.DumpType(sb, typeof(Helper), 0, level); + sb.AppendLine($"[{nameof(Launch)}]\r\n==============="); + Logger.DumpType(sb, typeof(Launch), 0, level); + sb.AppendLine($"[{nameof(Logger)}]\r\n==============="); + Logger.DumpType(sb, typeof(Logger), 0, level); + sb.AppendLine($"[{nameof(MachineStuff)}]\r\n==============="); + Logger.DumpType(sb, typeof(MachineStuff), 0, level); + sb.AppendLine($"[{nameof(Receiver)}]\r\n==============="); + Logger.DumpType(sb, typeof(Receiver), 0, level); + sb.AppendLine($"[{nameof(Service)}]\r\n==============="); + Logger.DumpType(sb, typeof(Service), 0, level); + } + internal static bool PrivateDump(StringBuilder sb, object obj, string objName, int level, int maxLevel, bool stop) { Type t; 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 d4cc369a9fad..3c933bfff187 100644 --- a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt +++ b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/Logger.PrivateDump.expected.txt @@ -99,54 +99,6 @@ LegalKeyDictionary = Concurrent.ConcurrentDictionary`2[System.String,System.Byte --_budget = ???????????? --_growLockArray = True --_comparerIsDefaultForClasses = False -KeybdPackage = MouseWithoutBorders.DATA ---Type = 0 ---Id = 0 ---Src = NONE ---Des = NONE ---DateTime = 0 ---Kd = MouseWithoutBorders.KEYBDDATA ---Md = MouseWithoutBorders.MOUSEDATA ---Machine1 = NONE ---Machine2 = NONE ---Machine3 = NONE ---Machine4 = NONE ---PostAction = Other ---machineNameP1 = 0 ---machineNameP2 = 0 ---machineNameP3 = 0 ---machineNameP4 = 0 -MousePackage = MouseWithoutBorders.DATA ---Type = 0 ---Id = 0 ---Src = NONE ---Des = NONE ---DateTime = 0 ---Kd = MouseWithoutBorders.KEYBDDATA ---Md = MouseWithoutBorders.MOUSEDATA ---Machine1 = NONE ---Machine2 = NONE ---Machine3 = NONE ---Machine4 = NONE ---PostAction = Other ---machineNameP1 = 0 ---machineNameP2 = 0 ---machineNameP3 = 0 ---machineNameP4 = 0 -inputEventCount = 0 -invalidPackageCount = 0 -MOVE_MOUSE_RELATIVE = 100000 -XY_BY_PIXEL = 300000 -k__BackingField = 0 -actualLastPos = {X=0,Y=0} ---x = 0 ---y = 0 ---Empty = {X=0,Y=0} -myLastX = 0 -myLastY = 0 -signalHelperToExit = False -signalWatchDogToExit = False -WndProcCounter = 0 initDone = False REOPEN_WHEN_WSAECONNRESET = -10054 REOPEN_WHEN_HOTKEY = -10055 @@ -189,12 +141,6 @@ PackageReceived = MouseWithoutBorders.PackageMonitor --ExplorerDragDrop = 0 --Nil = 0 PackageID = 0 -shownErrMessage = False -lastStartServiceTime = ???????????? ---_dateData = ???????????? ---MinValue = 01/01/0001 00:00:00 ---MaxValue = 31/12/9999 23:59:59 ---UnixEpoch = 01/01/1970 00:00:00 SensitivePoints = Generic.List`1[Point] --_items = Point[] ----System.Drawing.Point[] = Point[]: N/A @@ -223,8 +169,6 @@ JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999 NETWORK_STREAM_BUF_SIZE = 1048576 SymAlBlockSize = 16 PW_LENGTH = 16 -HELPER_FORM_TEXT = Mouse without Borders Helper -HelperProcessName = PowerToys.MouseWithoutBordersHelper PACKAGE_SIZE = 32 PACKAGE_SIZE_EX = 64 WP_PACKAGE_SIZE = 6 @@ -251,6 +195,69 @@ WM_KEYDOWN = 256 WM_KEYUP = 257 WM_SYSKEYDOWN = 260 WM_SYSKEYUP = 261 +[DragDrop] +=============== +isDragging = False +dragDropStep05ExCalledByIpc = 0 +isDropping = False +dragMachine = NONE +k__BackingField = False +[Event] +=============== +KeybdPackage = MouseWithoutBorders.DATA +--Type = 0 +--Id = 0 +--Src = NONE +--Des = NONE +--DateTime = 0 +--Kd = MouseWithoutBorders.KEYBDDATA +--Md = MouseWithoutBorders.MOUSEDATA +--Machine1 = NONE +--Machine2 = NONE +--Machine3 = NONE +--Machine4 = NONE +--PostAction = Other +--machineNameP1 = 0 +--machineNameP2 = 0 +--machineNameP3 = 0 +--machineNameP4 = 0 +MousePackage = MouseWithoutBorders.DATA +--Type = 0 +--Id = 0 +--Src = NONE +--Des = NONE +--DateTime = 0 +--Kd = MouseWithoutBorders.KEYBDDATA +--Md = MouseWithoutBorders.MOUSEDATA +--Machine1 = NONE +--Machine2 = NONE +--Machine3 = NONE +--Machine4 = NONE +--PostAction = Other +--machineNameP1 = 0 +--machineNameP2 = 0 +--machineNameP3 = 0 +--machineNameP4 = 0 +inputEventCount = 0 +invalidPackageCount = 0 +MOVE_MOUSE_RELATIVE = 100000 +XY_BY_PIXEL = 300000 +k__BackingField = 0 +actualLastPos = {X=0,Y=0} +--x = 0 +--y = 0 +--Empty = {X=0,Y=0} +myLastX = 0 +myLastY = 0 +[Helper] +=============== +signalHelperToExit = False +signalWatchDogToExit = False +WndProcCounter = 0 +HELPER_FORM_TEXT = Mouse without Borders Helper +HelperProcessName = PowerToys.MouseWithoutBordersHelper +[Launch] +=============== [Logger] =============== AllLogsLock = Lock @@ -319,13 +326,6 @@ MAX_LOG = 10000 MaxLogExceptionPerHour = 1000 HeaderSENT = Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},Ie{12},Ni{13} HeaderRECEIVED = Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},In{12},Ni{13},Pc{14}/{15} -[DragDrop] -=============== -isDragging = False -dragDropStep05ExCalledByIpc = 0 -isDropping = False -dragMachine = NONE -k__BackingField = False [MachineStuff] =============== McMatrixLock = Lock @@ -424,3 +424,11 @@ lastXY = {X=0,Y=0} --x = 0 --y = 0 --Empty = {X=0,Y=0} +[Service] +=============== +shownErrMessage = False +lastStartServiceTime = ???????????? +--_dateData = ???????????? +--MinValue = 01/01/0001 00:00:00 +--MaxValue = 31/12/9999 23:59:59 +--UnixEpoch = 01/01/1970 00:00:00 diff --git a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs index 2ef14453a00d..6d6b593e8acd 100644 --- a/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs +++ b/src/modules/MouseWithoutBorders/MouseWithoutBorders.UnitTests/Core/LoggerTests.cs @@ -38,11 +38,13 @@ public void PrivateDumpShouldGenerateExpectedOutput() */ [TestMethod] + /* [Ignore( "This test relies on internal details of the dotnet platform and is sensitive to " + "the specific version of dotnet being used. As a result it's likely to fail if the " + "\"expected\" result was generated with a different version to the version used to " + "run the test, so we're going to ignore it in the CI build process.")] + */ public void PrivateDumpShouldGenerateExpectedOutput() { static string NormalizeLog(string log) @@ -114,18 +116,11 @@ static string NormalizeLog(string log) using var streamReader = new StreamReader(stream); var expected = streamReader.ReadToEnd(); - // copied from DumpObjects in Common.Log.cs + // copied from DumpObjects in Logger.cs var sb = new StringBuilder(1000000); - _ = Logger.PrivateDump(sb, Logger.AllLogs, "[Program logs]\r\n===============\r\n", 0, settingsDumpObjectsLevel, false); - _ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, settingsDumpObjectsLevel, false); - sb.AppendLine("[Logger]\r\n==============="); - Logger.DumpType(sb, typeof(Logger), 0, settingsDumpObjectsLevel); - sb.AppendLine("[DragDrop]\r\n==============="); - Logger.DumpType(sb, typeof(DragDrop), 0, settingsDumpObjectsLevel); - sb.AppendLine("[MachineStuff]\r\n==============="); - Logger.DumpType(sb, typeof(MachineStuff), 0, settingsDumpObjectsLevel); - sb.AppendLine("[Receiver]\r\n==============="); - Logger.DumpType(sb, typeof(Receiver), 0, settingsDumpObjectsLevel); + Logger.DumpProgramLogs(sb, settingsDumpObjectsLevel); + Logger.DumpOtherLogs(sb, settingsDumpObjectsLevel); + Logger.DumpStaticTypes(sb, settingsDumpObjectsLevel); var actual = sb.ToString(); expected = NormalizeLog(expected); From 1077d847e40a5af04a7b788ed98fc6879f4eb807 Mon Sep 17 00:00:00 2001 From: mikeclayton Date: Sat, 22 Feb 2025 11:15:59 +0000 Subject: [PATCH 6/6] [MouseWithoutBorders] - cleaning up changes - #35155 --- src/modules/MouseWithoutBorders/App/Core/Event.cs | 5 ++--- src/modules/MouseWithoutBorders/App/Core/Helper.cs | 8 ++++---- src/modules/MouseWithoutBorders/App/Core/Launch.cs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/modules/MouseWithoutBorders/App/Core/Event.cs b/src/modules/MouseWithoutBorders/App/Core/Event.cs index 2766f031215e..7856a64d87f6 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Event.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Event.cs @@ -9,6 +9,8 @@ using System.Threading; using System.Threading.Tasks; +using MouseWithoutBorders.Class; + // // Keyboard/Mouse hook callback implementation. // @@ -17,9 +19,6 @@ // 2009-... modified by Truong Do (TruongDo). // 2023- Included in PowerToys. // -using MouseWithoutBorders.Class; -using MouseWithoutBorders.Form; - namespace MouseWithoutBorders.Core; internal static class Event diff --git a/src/modules/MouseWithoutBorders/App/Core/Helper.cs b/src/modules/MouseWithoutBorders/App/Core/Helper.cs index bb8e686271da..4122fbe31b48 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Helper.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Helper.cs @@ -13,6 +13,10 @@ using System.Security.Principal; using System.Windows.Forms; +using Microsoft.Win32; +using MouseWithoutBorders.Class; +using static System.Windows.Forms.Control; + // // Some other helper methods. // @@ -21,10 +25,6 @@ // 2009-... modified by Truong Do (TruongDo). // 2023- Included in PowerToys. // -using Microsoft.Win32; -using MouseWithoutBorders.Class; -using static System.Windows.Forms.Control; - namespace MouseWithoutBorders.Core; internal static class Helper diff --git a/src/modules/MouseWithoutBorders/App/Core/Launch.cs b/src/modules/MouseWithoutBorders/App/Core/Launch.cs index 56067909693d..f4d9c62a7a52 100644 --- a/src/modules/MouseWithoutBorders/App/Core/Launch.cs +++ b/src/modules/MouseWithoutBorders/App/Core/Launch.cs @@ -9,6 +9,8 @@ using System.Runtime.InteropServices; using System.Security.Principal; +using MouseWithoutBorders.Class; + // // Impersonation. // @@ -17,8 +19,6 @@ // 2009-... modified by Truong Do (TruongDo). // 2023- Included in PowerToys. // -using MouseWithoutBorders.Class; - namespace MouseWithoutBorders.Core; internal static class Launch