[New Utility]Mouse Without Borders

* Integrate Mouse Without Borders into PowerToys

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
This commit is contained in:
Andrey Nekrasov
2023-05-15 23:32:26 +01:00
committed by Jaime Bernardo
parent a0b9af039d
commit 29eebe16a4
304 changed files with 37234 additions and 133 deletions

View File

@@ -0,0 +1,59 @@
using System.Windows.Forms;
namespace MouseWithoutBorders
{
partial class FormDot
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// FormDot
//
this.BackColor = System.Drawing.Color.Black;
this.ClientSize = new System.Drawing.Size(2, 2);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormDot";
this.Opacity = 0.5D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.TopMost = true;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormDot_FormClosing);
this.Shown += new System.EventHandler(this.FormDot_Shown);
this.VisibleChanged += new System.EventHandler(this.FormDot_VisibleChanged);
this.Click += new System.EventHandler(this.FormDot_Click);
this.ResumeLayout(false);
}
#endregion
}
}

View File

@@ -0,0 +1,84 @@
// 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.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using static MouseWithoutBorders.NativeMethods;
namespace MouseWithoutBorders
{
internal sealed partial class FormDot : System.Windows.Forms.Form
{
private int left;
private int top;
internal FormDot()
{
InitializeComponent();
Cursor = CreateDotCursor();
}
public void SetPosition(int left, int top)
{
this.left = left - 2;
this.top = top - 2;
}
private Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot)
{
IconInfo tmp = default;
tmp.xHotspot = xHotSpot;
tmp.yHotspot = yHotSpot;
tmp.fIcon = false;
tmp.hbmColor = bmp.GetHbitmap();
tmp.hbmMask = bmp.GetHbitmap();
return new Cursor(NativeMethods.CreateIconIndirect(ref tmp));
}
private Cursor CreateDotCursor()
{
Bitmap bitmap = new(32, 32, PixelFormat.Format24bppRgb);
bitmap.MakeTransparent(Color.Black);
Graphics g = Graphics.FromImage(bitmap);
g.DrawLine(Pens.Gray, 0, 0, 1, 1);
Cursor c = CreateCursor(bitmap, 0, 0);
bitmap.Dispose();
return c;
}
private void FormDot_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
}
}
private void FormDot_Shown(object sender, EventArgs e)
{
MoveMe();
}
private void MoveMe()
{
Left = left;
Top = top;
Width = 4;
Height = 4;
}
private void FormDot_Click(object sender, EventArgs e)
{
IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
Program.FormHelper.SendLog($"{nameof(FormDot_Click)}.Foreground window ({foreGroundWindow}) is " + (foreGroundWindow == Handle ? string.Empty : "not ") + $"the dot form: {Program.DotForm.Handle}.");
}
private void FormDot_VisibleChanged(object sender, EventArgs e)
{
MoveMe();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,77 @@
namespace MouseWithoutBorders
{
partial class FormHelper
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormHelper));
this.timerHelper = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// timerHelper
//
this.timerHelper.Interval = 2000;
this.timerHelper.Tick += new System.EventHandler(this.TimerHelper_Tick);
//
// FormHelper
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.ClientSize = new System.Drawing.Size(60, 60);
this.ControlBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.KeyPreview = true;
this.Name = "FormHelper";
this.Opacity = 0.11D;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.Text = "Mouse without Borders Helper";
this.TopMost = true;
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormHelper_FormClosing);
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormHelper_FormClosed);
this.Shown += new System.EventHandler(this.FormHelper_Shown);
this.LocationChanged += new System.EventHandler(this.FormHelper_LocationChanged);
this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FormHelper_DragEnter);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormHelper_KeyDown);
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormHelper_KeyUp);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseUp);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timerHelper;
}
}

View File

@@ -0,0 +1,782 @@
// 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.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace MouseWithoutBorders
{
public partial class FormHelper : System.Windows.Forms.Form
{
private readonly List<FocusArea> focusZone = new();
private readonly object bmScreenLock = new();
private long lastClipboardEventTime;
private IClipboardHelper remoteClipboardHelper;
private const string TEXT_TYPE_SEP = "{4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}";
private const int MAX_TEXT_SIZE = 20 * 1024 * 1024;
private const int MAX_IMAGE_SIZE = 50 * 1024 * 1024;
private struct FocusArea
{
internal RectangleF Rec;
internal Color Color;
internal FocusArea(RectangleF rec, Color color)
{
Rec = rec;
Color = color;
}
}
private Point focus1 = Point.Empty;
private Point focus2 = Point.Empty;
public FormHelper()
{
remoteClipboardHelper = IpcHelper.CreateIpcClient();
if (remoteClipboardHelper == null)
{
QuitDueToCommunicationError();
return;
}
SetDPIAwareness();
InitializeComponent();
lastClipboardEventTime = GetTick();
ClipboardMMHelper.HookClipboard(this);
}
private void SetDPIAwareness()
{
int setProcessDpiAwarenessResult = -1;
try
{
setProcessDpiAwarenessResult = NativeMethods.SetProcessDpiAwareness(2);
SendLog(string.Format(CultureInfo.InvariantCulture, "SetProcessDpiAwareness: {0}.", setProcessDpiAwarenessResult));
}
catch (DllNotFoundException)
{
SendLog("SetProcessDpiAwareness is unsupported in Windows 7 and lower.");
}
catch (Exception e)
{
SendLog(e.ToString());
}
try
{
if (setProcessDpiAwarenessResult != 0)
{
SendLog(string.Format(CultureInfo.InvariantCulture, "SetProcessDPIAware: {0}.", NativeMethods.SetProcessDPIAware()));
}
}
catch (Exception e)
{
SendLog(e.ToString());
}
}
private bool quitDueToCommunicationError;
private void QuitDueToCommunicationError()
{
if (!quitDueToCommunicationError)
{
quitDueToCommunicationError = true;
if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
{
Logger.LogEvent(Application.ProductName + " cannot be used in a remote desktop or virtual machine session.");
}
else
{
_ = MessageBox.Show(
"Unable to connect to Mouse Without Borders process, clipboard sharing is no longer working.\r\nSee EventLog for more information.",
Text,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
Process.GetCurrentProcess().Kill();
}
}
private void FormHelper_DragEnter(object sender, DragEventArgs e)
{
object o = e.Data.GetData(DataFormats.FileDrop);
if (o != null)
{
e.Effect = DragDropEffects.Copy;
Array ar = (string[])o;
if (ar.Length > 0)
{
string fileName = ar.GetValue(0).ToString();
Hide();
try
{
remoteClipboardHelper.SendDragFile(fileName);
}
catch (Exception ex)
{
Logger.LogEvent("FormHelper_DragEnter: " + ex.Message, EventLogEntryType.Error);
QuitDueToCommunicationError();
}
}
}
}
private void TimerHelper_Tick(object sender, EventArgs e)
{
lock (bmScreenLock)
{
if (picScr == null)
{
timerHelper.Stop();
Hide();
}
}
}
private void FormHelper_Shown(object sender, EventArgs e)
{
timerHelper.Start(); // To be sure.
Hide();
}
internal void SendLog(string log)
{
try
{
Logger.LogEvent(log, EventLogEntryType.Warning);
}
catch (Exception e)
{
Logger.LogEvent(log + " ==> SendLog Exception: " + e.Message, EventLogEntryType.Warning);
}
}
private long GetTick() // ms
{
return DateTime.Now.Ticks / 10000;
}
private string GetClipboardText()
{
string st = string.Empty, tmp = ClipboardMMHelper.GetText(TextDataFormat.UnicodeText);
int txtL = 0, rtfL = 0, htmL = 0;
if (tmp != null && (txtL = tmp.Length) > 0)
{
st += "TXT" + tmp + TEXT_TYPE_SEP;
}
tmp = ClipboardMMHelper.GetText(TextDataFormat.Rtf);
if (tmp != null && (rtfL = tmp.Length) > 0)
{
st += "RTF" + tmp + TEXT_TYPE_SEP;
}
tmp = ClipboardMMHelper.GetText(TextDataFormat.Html);
if (tmp != null && (htmL = tmp.Length) > 0)
{
st += "HTM" + tmp + TEXT_TYPE_SEP;
}
if (st.Length > 0)
{
if (st.Length > MAX_TEXT_SIZE)
{
st = null;
SendLog(string.Format(CultureInfo.CurrentCulture, "GetClipboardText, Text too big: TXT = {0}, RTF = {1}, HTM = {2}.", txtL, rtfL, htmL));
}
else
{
SendLog(string.Format(CultureInfo.CurrentCulture, "GetClipboardText: TXT = {0}, RTF = {1}, HTM = {2}.", txtL, rtfL, htmL));
}
}
return st;
}
#pragma warning disable CA2213 // Disposing is done by ComponentResourceManager
private Image bmScreen;
private Point startOrg;
private Point start;
private Point stop;
private PictureBox left;
private PictureBox top;
private PictureBox right;
private PictureBox bottom;
private PictureBox picScr;
#pragma warning restore CA2213
private int customScreenCaptureInProgress;
private int screenLeft;
private int screenTop;
protected override void WndProc(ref Message m)
{
const int WM_DRAWCLIPBOARD = 0x0308;
const int WM_CHANGECBCHAIN = 0x030D;
const int WM_CLIPBOARDUPDATE = 0x031D;
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
case WM_CLIPBOARDUPDATE:
ClipboardMMHelper.PassMessageToTheNextViewer(m);
if (GetTick() - lastClipboardEventTime < 1000)
{
lastClipboardEventTime = GetTick();
return;
}
if (customScreenCaptureInProgress > 0)
{
// 10 secs timeout for a failed capture.
if (GetTick() - lastClipboardEventTime < 10000)
{
return;
}
else
{
customScreenCaptureInProgress = 0;
}
}
lastClipboardEventTime = GetTick();
ByteArrayOrString? data = null;
bool isFile = false;
if (ClipboardMMHelper.ContainsText())
{
data = GetClipboardText();
}
else if (ClipboardMMHelper.ContainsImage())
{
MemoryStream ms = new();
Image im = ClipboardMMHelper.GetImage();
if (im != null)
{
im.Save(ms, ImageFormat.Png);
if (ms.Length > 0)
{
if (ms.Length > MAX_IMAGE_SIZE)
{
SendLog("Image from clipboard, image too big: " + ms.Length.ToString(CultureInfo.InvariantCulture));
}
else
{
data = ms.GetBuffer();
SendLog("Image from clipboard: " + ms.Length.ToString(CultureInfo.InvariantCulture));
}
}
else
{
SendLog("ClipboardMMHelper image is 0 in length.");
}
}
else
{
SendLog("ClipboardMMHelper image (GetImage) is null.");
}
ms.Dispose();
}
else if (ClipboardMMHelper.ContainsFileDropList())
{
StringCollection files = ClipboardMMHelper.GetFileDropList();
if (files != null)
{
if (files.Count > 0)
{
data = files[0];
isFile = true;
SendLog("File from clipboard: " + files[0]);
}
else
{
SendLog("GetFileDropList returned no file.");
}
}
else
{
SendLog("GetFileDropList returned null.");
}
}
else
{
SendLog("ClipboardMMHelper does not have text/image/file data.");
return;
}
if (data != null)
{
try
{
remoteClipboardHelper.SendClipboardData((ByteArrayOrString)data, isFile);
}
catch (Exception ex)
{
Logger.LogEvent("WM_DRAWCLIPBOARD: " + ex.Message, EventLogEntryType.Error);
QuitDueToCommunicationError();
}
GC.Collect();
}
else
{
SendLog("Null clipboard data returned. See previous messages (if any) for more information.");
}
break;
case WM_CHANGECBCHAIN:
if (!ClipboardMMHelper.UpdateNextClipboardViewer(m))
{
ClipboardMMHelper.PassMessageToTheNextViewer(m);
}
break;
case 0x401:
screenLeft = 0;
screenTop = 0;
foreach (Screen s in Screen.AllScreens)
{
if (s.Bounds.Left < screenLeft)
{
screenLeft = s.Bounds.Left;
}
if (s.Bounds.Top < screenTop)
{
screenTop = s.Bounds.Top;
}
}
customScreenCaptureInProgress = 1;
lastClipboardEventTime = GetTick();
SendLog("**************************************************\r\nScreen capture triggered.");
m.Result = new IntPtr(1);
break;
case 0x406:
if (m.Msg == 0x406)
{
lock (bmScreenLock)
{
bmScreen = null;
for (int i = 0; i < 30; i++)
{
Thread.Sleep(100);
if (ClipboardMMHelper.ContainsImage())
{
bmScreen = ClipboardMMHelper.GetImage();
customScreenCaptureInProgress = 1;
break;
}
}
if (bmScreen == null)
{
customScreenCaptureInProgress = 0;
SendLog("No image found in the clipboard.");
}
else
{
Opacity = 1;
picScr = new PictureBox();
picScr.Dock = DockStyle.Fill;
picScr.SizeMode = PictureBoxSizeMode.StretchImage;
picScr.Image = bmScreen;
picScr.Refresh();
Controls.Add(picScr);
AssignEventHandlers(picScr);
}
}
}
MouseMoveHandler();
break;
case 0x407:
Program.DotForm.SetPosition(m.WParam.ToInt32(), m.LParam.ToInt32());
Program.DotForm.TopMost = true;
Program.DotForm.Show();
Application.DoEvents();
m.Result = SetForeGround() ? new IntPtr(1) : IntPtr.Zero;
break;
case 0x408:
Program.DotForm.Hide();
break;
case 0x400:
m.Result = Handle;
break;
case SharedConst.QUIT_CMD:
Process.GetCurrentProcess().Kill();
break;
default:
base.WndProc(ref m);
break;
}
}
private bool SetForeGround()
{
string logTag = nameof(SetForeGround);
IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
if (foreGroundWindow == Program.DotForm.Handle)
{
SendLog($"{logTag}.Foreground window is already the dot form: {foreGroundWindow}.");
return true;
}
Program.DotForm.Activate();
bool setForegroundWindow = NativeMethods.SetForegroundWindow(Program.DotForm.Handle);
SendLog($"{logTag}.{nameof(NativeMethods.SetForegroundWindow)}({Program.DotForm.Handle}) returned: {setForegroundWindow}.");
return LogForeGroundWindow(logTag);
}
private bool LogForeGroundWindow(string logTag)
{
IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
if (foreGroundWindow == Program.DotForm.Handle)
{
SendLog($"{logTag}.Foreground window is now the dot form: {Program.DotForm.Handle}.");
return true;
}
else
{
SendLog($"{logTag}.Foreground window is: [{foreGroundWindow}].");
return false;
}
}
private void AssignEventHandlers(PictureBox p)
{
p.MouseDown += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseDown);
p.MouseMove += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseMove);
p.MouseUp += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseUp);
}
private void MouseMoveHandler()
{
lock (bmScreenLock)
{
if (bmScreen != null && Opacity == 1)
{
focusZone.Clear();
TopMost = true;
Show();
startOrg = new Point(MousePosition.X - screenLeft, MousePosition.Y - screenTop);
if (left == null)
{
left = new PictureBox();
left.BackColor = Color.Red;
Controls.Add(left);
left.BringToFront();
AssignEventHandlers(left);
}
left.Left = startOrg.X;
left.Top = startOrg.Y;
left.Width = 2;
left.Height = 100;
left.Show();
left.Refresh();
if (top == null)
{
top = new PictureBox();
top.BackColor = Color.Red;
Controls.Add(top);
top.BringToFront();
AssignEventHandlers(top);
}
top.Left = startOrg.X;
top.Top = startOrg.Y;
top.Height = 2;
top.Width = 100;
top.Show();
top.Refresh();
}
}
}
private void MouseDownMoveHandler()
{
lock (bmScreenLock)
{
if (bmScreen != null && left != null && top != null)
{
int x = MousePosition.X - screenLeft;
int y = MousePosition.Y - screenTop;
start = new Point(startOrg.X < x ? startOrg.X : x, startOrg.Y < y ? startOrg.Y : y);
stop = new Point(startOrg.X > x ? startOrg.X : x, startOrg.Y > y ? startOrg.Y : y);
left.Left = start.X;
left.Top = start.Y;
left.Width = 2;
left.Height = stop.Y - start.Y;
left.Show();
top.Left = start.X;
top.Top = start.Y;
top.Height = 2;
top.Width = stop.X - start.X;
top.Show();
if (right == null)
{
right = new PictureBox();
right.BackColor = Color.Red;
Controls.Add(right);
right.BringToFront();
AssignEventHandlers(right);
}
right.Left = stop.X;
right.Top = start.Y;
right.Width = 2;
right.Height = stop.Y - start.Y;
right.Show();
if (bottom == null)
{
bottom = new PictureBox();
bottom.BackColor = Color.Red;
Controls.Add(bottom);
bottom.BringToFront();
AssignEventHandlers(bottom);
}
bottom.Left = start.X;
bottom.Top = stop.Y;
bottom.Height = 2;
bottom.Width = stop.X - start.X;
bottom.Show();
TopMost = true;
Show();
}
}
}
private void MouseUpHandler(bool canceled = false, bool rightMouseButton = false)
{
lock (bmScreenLock)
{
MouseDownMoveHandler();
customScreenCaptureInProgress = 0;
if (!canceled && bmScreen != null && left != null && top != null && right != null && bottom != null
&& stop.X - start.X > 0 && stop.Y - start.Y > 0)
{
start = PointInStandardDPI(start);
stop = PointInStandardDPI(stop);
Bitmap bm = new(stop.X - start.X, stop.Y - start.Y);
Graphics g = Graphics.FromImage(bm);
try
{
g.DrawImage(bmScreen, 0, 0, new Rectangle(start, bm.Size), GraphicsUnit.Pixel);
g.DrawRectangle(Pens.DarkOrange, 0, 0, stop.X - start.X - 1, stop.Y - start.Y - 1);
foreach (FocusArea f in focusZone)
{
RectangleF rec = RectangleFInStandardDPI(f.Rec);
rec.X -= start.X;
rec.Y -= start.Y;
g.DrawEllipse(new Pen(f.Color, 2), rec);
}
if (rightMouseButton)
{
try
{
string tempFile = Path.GetTempPath() + Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".png";
SendLog(tempFile);
bm.Save(tempFile, ImageFormat.Png);
lastClipboardEventTime = GetTick();
ClipboardMMHelper.SetText(tempFile);
}
catch (IOException ioException)
{
SendLog("IO!Exception!: " + ioException.Message);
}
catch (ArgumentNullException argException)
{
SendLog("ArgNull!Exception!: " + argException.Message);
}
catch (ExternalException internalException)
{
SendLog("Internal!Exception!: " + internalException.Message);
}
}
else
{
lastClipboardEventTime = GetTick() - 10000;
ClipboardMMHelper.SetImage(bm);
}
}
finally
{
g.Dispose();
bm.Dispose();
bmScreen.Dispose();
bmScreen = null;
}
}
ShowInTaskbar = false;
Hide();
Controls.Clear();
Opacity = 0.11;
left?.Dispose();
top?.Dispose();
right?.Dispose();
bottom?.Dispose();
picScr?.Dispose();
left = top = right = bottom = picScr = null;
SendLog("Screen capture ended.\r\n**************************************************");
}
}
private void FormHelper_FormClosed(object sender, FormClosedEventArgs e)
{
ClipboardMMHelper.UnhookClipboard();
}
private void FormHelper_LocationChanged(object sender, EventArgs e)
{
lock (bmScreenLock)
{
if (picScr == null && !timerHelper.Enabled)
{
Opacity = 0.11;
timerHelper.Start();
}
}
}
private void FormHelper_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
MouseUpHandler(true);
}
if (focus1.IsEmpty)
{
focus1 = stop;
}
}
private void FormHelper_KeyUp(object sender, KeyEventArgs e)
{
focus2 = stop;
float x = Math.Min(focus1.X, focus2.X);
float y = Math.Min(focus1.Y, focus2.Y);
float w = Math.Abs(focus1.X - focus2.X);
float h = Math.Abs(focus1.Y - focus2.Y);
x -= 0.25F * w;
y -= 0.25F * h;
w *= 1.5F;
h *= 1.5F;
focusZone.Add(new FocusArea(new RectangleF(x, y, w, h), e.KeyCode == Keys.B ? Color.Blue : e.KeyCode == Keys.G ? Color.Green : Color.Red));
focus1 = focus2 = Point.Empty;
}
private void FormHelper_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
}
}
private void FormHelper_MouseDown(object sender, MouseEventArgs e)
{
SendLog("Screen capture Mouse down.");
MouseMoveHandler();
customScreenCaptureInProgress = 2;
}
private void FormHelper_MouseMove(object sender, MouseEventArgs e)
{
if (customScreenCaptureInProgress == 1)
{
MouseMoveHandler();
}
else if (customScreenCaptureInProgress == 2)
{
MouseDownMoveHandler();
}
}
private void FormHelper_MouseUp(object sender, MouseEventArgs e)
{
MouseUpHandler(false, e.Button == MouseButtons.Right);
}
private Point PointInStandardDPI(Point p)
{
// Since the process is DPI awareness, just log and return.
// TODO: Test in Win8/7/XP.
SendLog(string.Format(CultureInfo.CurrentCulture, "this.Width={0}, this.Height={1}, bmScreen.Width={2}, bmScreen.Height={3}, x={4}, y={5}", Width, Height, bmScreen.Width, bmScreen.Height, p.X, p.Y));
return p;
}
private RectangleF RectangleFInStandardDPI(RectangleF r)
{
// Since the process is DPI awareness, just return.
return r;
}
}
}

View File

@@ -0,0 +1,198 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timerHelper.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
//jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
/j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
AAD//wAA//8AAA==
</value>
</data>
</root>

View File

@@ -0,0 +1,84 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Version.props" />
<PropertyGroup>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<OutputType>WinExe</OutputType>
<UseWindowsForms>true</UseWindowsForms>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AssemblyName>PowerToys.MouseWithoutBordersHelper</AssemblyName>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\modules\MouseWithoutBorders</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SelfContained>true</SelfContained>
<Version>$(Version).0</Version>
</PropertyGroup>
<!-- SelfContained=true requires RuntimeIdentifier to be set -->
<PropertyGroup Condition="'$(Platform)'=='x64'">
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Platform)'=='ARM64'">
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>MM_HELPER;TRACE;DEBUG;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN</DefineConstants>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DefineConstants>MM_HELPER;TRACE;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN</DefineConstants>
<UseVSHostingProcess>false</UseVSHostingProcess>
<NoWarn>
</NoWarn>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>..\Logo.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<!-- See https://learn.microsoft.com/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component for more info -->
<PropertyGroup>
<CsWinRTIncludes>PowerToys.GPOWrapper</CsWinRTIncludes>
<CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Resources\**" />
<Compile Remove="Service\**" />
<EmbeddedResource Remove="Resources\**" />
<EmbeddedResource Remove="Service\**" />
<ExcludeFromStyleCop Remove="Service\**" />
<None Remove="Resources\**" />
<None Remove="Service\**" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Class\IClipboardHelper.cs">
<Link>IClipboardHelper.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="MouseWithoutBordersHelper.exe.manifest">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT"/>
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.Compatibility" />
<PackageReference Include="StreamJsonRpc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\common\GPOWrapper\GPOWrapper.vcxproj" />
<ProjectReference Include="..\..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
</ItemGroup>
<PropertyGroup>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,874 @@
// 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.
// <summary>
// Windows APIs.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
using System;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
// We are sure we dont have managed resource in KEYBDINPUT, IntPtr just holds a value
[module: SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", Scope = "type", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT", Justification = "Dotnet port with style preservation")]
// Some other minor issues
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#ConvertStringSidToSid(System.String,System.IntPtr&)", MessageId = "0", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#DrawText(System.IntPtr,System.String,System.Int32,MouseWithoutBorders.NativeMethods+RECT&,System.UInt32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SetWindowText(System.IntPtr,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "0", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#keybd_event(System.Byte,System.Byte,System.UInt32,System.Int32)", MessageId = "3", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT.#dwExtraInfo", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+INPUT64.#type", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#TerminateProcess(System.IntPtr,System.IntPtr)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "return", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "0", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
namespace MouseWithoutBorders
{
internal sealed partial class NativeMethods
{
internal struct IconInfo
{
internal bool fIcon;
internal int xHotspot;
internal int yHotspot;
internal IntPtr hbmMask;
internal IntPtr hbmColor;
}
[DllImport("user32.dll")]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
internal static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern IntPtr CreateIconIndirect(ref IconInfo icon);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool SetProcessDPIAware();
[DllImport("Shcore.dll", SetLastError = true)]
internal static extern int SetProcessDpiAwareness(uint type); // Win 8.1 and up, DPI can be per monitor.
[DllImport("kernel32.dll")]
internal static extern uint WTSGetActiveConsoleSessionId();
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, int action, IntPtr changeInfo);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = false)]
internal static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
internal static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);
[DllImport("gdi32.dll")]
internal static extern uint SetTextColor(IntPtr hdc, int crColor);
[DllImport("gdi32.dll")]
internal static extern uint SetBkColor(IntPtr hdc, int crColor);
[DllImport("user32.dll")]
internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetWindowText(IntPtr hWnd, string lpString);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DestroyIcon(IntPtr handle);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetCursorPos(int X, int Y);
[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Point p);
[DllImport("advapi32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DuplicateTokenEx(
IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
int TokenType,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ConvertStringSidToSid(string StringSid, out IntPtr ptrSid);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_MANDATORY_LABEL TokenInformation, uint TokenInformationLength);
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")]
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
int dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumDisplayMonitors(
IntPtr hdc,
IntPtr lprcClip,
EnumMonitorsDelegate lpfnEnum,
IntPtr dwData);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi);
[DllImport("User32.dll")]
internal static extern int FindWindow(string ClassName, string WindowName);
[DllImport("kernel32.dll")]
internal static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr GetThreadDesktop(uint dwThreadId);
[DllImport("user32.dll")]
internal static extern short GetAsyncKeyState(IntPtr vKey);
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[StructLayout(LayoutKind.Sequential)]
internal struct POINT
{
internal int x;
internal int y;
}
[StructLayout(LayoutKind.Sequential)]
internal struct CURSORINFO
{
public int cbSize;
public int flags;
public IntPtr hCursor;
public POINT ptScreenPos;
}
[DllImport("user32.dll")]
internal static extern bool GetCursorInfo(out CURSORINFO ci);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
#if USE_GetSecurityDescriptorSacl
internal enum SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE = 0,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32KEY
}
[Flags]
internal enum SECURITY_INFORMATION : uint
{
LABEL_SECURITY_INFORMATION = 0x00000010
}
[StructLayoutAttribute(LayoutKind.Explicit)]
internal struct SECURITY_DESCRIPTOR
{
[FieldOffset(0)]
public byte revision;
[FieldOffset(1)]
public byte size;
[FieldOffset(2)]
public short control;
[FieldOffset(4)]
public IntPtr owner;
[FieldOffset(8)]
public IntPtr group;
[FieldOffset(12)]
public IntPtr sacl;
[FieldOffset(16)]
public IntPtr dacl;
}
[StructLayout(LayoutKind.Sequential)]
internal struct ACL { public byte AclRevision; public byte Sbz1; public int AclSize; public int AceCount; public int Sbz2; }
[DllImport("advapi32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor,
UInt32 StringSDRevision, out SECURITY_DESCRIPTOR SecurityDescriptor, out UInt64 SecurityDescriptorSize);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int GetSecurityDescriptorSacl([MarshalAs(UnmanagedType.Struct)] ref SECURITY_DESCRIPTOR pSecurityDescriptor, int lpbSaclPresent, [MarshalAs(UnmanagedType.Struct)] ref ACL pSacl, int lpbSaclDefaulted);
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
internal static extern uint SetNamedSecurityInfo(
string pObjectName,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
IntPtr psidOwner,
IntPtr psidGroup,
IntPtr pDacl,
IntPtr pSacl);
#endif
#if SINGLE_PROCESS
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetThreadDesktop(IntPtr hDesktop);
#endif
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr OpenInputDesktop(uint dwFlags, [MarshalAs(UnmanagedType.Bool)] bool fInherit, uint dwDesiredAccess);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out uint lpnLengthNeeded);
[DllImport("gdi32.dll")]
internal static extern uint SetPixel(IntPtr hdc, int X, int Y, uint crColor);
internal const int WM_SHOW_DRAG_DROP = 0x400;
internal const int WM_HIDE_DRAG_DROP = 0x401;
internal const int WM_CHECK_EXPLORER_DRAG_DROP = 0x402;
internal const int WM_QUIT = 0x403;
internal const int WM_SWITCH = 0x404;
internal const int WM_HIDE_DD_HELPER = 0x405;
internal const int WM_SHOW_SETTINGS_FORM = 0x406;
internal static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
// internal static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
// internal static readonly IntPtr HWND_TOP = new IntPtr(0);
// internal static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
internal const uint SWP_NOSIZE = 0x0001;
internal const uint SWP_NOMOVE = 0x0002;
internal const uint SWP_NOZORDER = 0x0004;
internal const uint SWP_NOREDRAW = 0x0008;
internal const uint SWP_SHOWWINDOW = 0x0040;
internal const uint SWP_HIDEWINDOW = 0x0080;
internal const int UOI_FLAGS = 1;
internal const int UOI_NAME = 2;
internal const int UOI_TYPE = 3;
internal const int UOI_USER_SID = 4;
internal const uint DESKTOP_WRITEOBJECTS = 0x0080;
internal const uint DESKTOP_READOBJECTS = 0x0001;
internal const uint DF_ALLOWOTHERACCOUNTHOOK = 0x0001;
// internal const UInt32 GENERIC_READ = 0x80000000;
internal const uint GENERIC_WRITE = 0x40000000;
// internal const UInt32 GENERIC_EXECUTE = 0x20000000;
internal const uint GENERIC_ALL = 0x10000000;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct RECT
{
internal int Left;
internal int Top;
internal int Right;
internal int Bottom;
}
// size of a device name string
internal const int CCHDEVICENAME = 32;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct MonitorInfoEx
{
internal int cbSize;
internal RECT rcMonitor;
internal RECT rcWork;
internal uint dwFlags;
// [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
// internal string szDeviceName;
}
// We are WOW
[SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Justification = "Dotnet port with style preservation")]
[DllImport(
"user32.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
internal static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
[DllImport(
"user32.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
internal static extern int UnhookWindowsHookEx(int idHook);
// In X64, we are running WOW
[SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Justification = "Dotnet port with style preservation")]
[DllImport(
"user32.dll",
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
internal static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
private enum InputType
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 2,
}
[Flags]
internal enum MOUSEEVENTF
{
MOVE = 0x0001,
LEFTDOWN = 0x0002,
LEFTUP = 0x0004,
RIGHTDOWN = 0x0008,
RIGHTUP = 0x0010,
MIDDLEDOWN = 0x0020,
MIDDLEUP = 0x0040,
XDOWN = 0x0080,
XUP = 0x0100,
WHEEL = 0x0800,
VIRTUALDESK = 0x4000,
ABSOLUTE = 0x8000,
}
[Flags]
internal enum KEYEVENTF
{
KEYDOWN = 0x0000,
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
UNICODE = 0x0004,
SCANCODE = 0x0008,
}
// http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
[SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Justification = "Dotnet port with style preservation")]
[StructLayout(LayoutKind.Explicit)]
internal struct INPUT
{
[FieldOffset(0)]
internal int type;
[FieldOffset(4)]
internal MOUSEINPUT mi;
[FieldOffset(4)]
internal KEYBDINPUT ki;
}
[StructLayout(LayoutKind.Explicit)]
internal struct INPUT64
{
[FieldOffset(0)]
internal int type;
[FieldOffset(8)]
internal MOUSEINPUT mi;
[FieldOffset(8)]
internal KEYBDINPUT ki;
}
[DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
internal static extern uint SendInput64(uint nInputs, INPUT64[] pInputs, int cbSize);
[DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
internal static extern IntPtr GetMessageExtraInfo();
[DllImport("user32.dll", EntryPoint = "LockWorkStation", SetLastError = true)]
internal static extern uint LockWorkStation();
// [DllImport("user32.dll")]
// internal static extern void keybd_event(byte bVk, byte bScan, UInt32 dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
[StructLayout(LayoutKind.Sequential)]
internal struct LUID
{
internal int LowPart;
internal int HighPart;
}// end struct
[StructLayout(LayoutKind.Sequential)]
internal struct LUID_AND_ATTRIBUTES
{
internal LUID Luid;
internal int Attributes;
}// end struct
[StructLayout(LayoutKind.Sequential)]
internal struct TOKEN_PRIVILEGES
{
internal int PrivilegeCount;
// LUID_AND_ATTRIBUTES
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
internal int[] Privileges;
}
internal const int READ_CONTROL = 0x00020000;
internal const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
internal const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
internal const int STANDARD_RIGHTS_ALL = 0x001F0000;
internal const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
internal const int TOKEN_IMPERSONATE = 0x0004;
internal const int TOKEN_QUERY_SOURCE = 0x0010;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
internal const int TOKEN_ADJUST_GROUPS = 0x0040;
internal const int TOKEN_ADJUST_SESSIONID = 0x0100;
internal const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT;
internal const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
internal const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
internal const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT;
internal const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
internal const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
internal const int IDLE_PRIORITY_CLASS = 0x40;
internal const int NORMAL_PRIORITY_CLASS = 0x20;
internal const int HIGH_PRIORITY_CLASS = 0x80;
internal const int REALTIME_PRIORITY_CLASS = 0x100;
internal const int CREATE_NEW_CONSOLE = 0x00000010;
internal const string SE_DEBUG_NAME = "SeDebugPrivilege";
internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
internal const string SE_BACKUP_NAME = "SeBackupPrivilege";
internal const int SE_PRIVILEGE_ENABLED = 0x0002;
internal const int ERROR_NOT_ALL_ASSIGNED = 1300;
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESSENTRY32
{
internal uint dwSize;
internal uint cntUsage;
internal uint th32ProcessID;
internal IntPtr th32DefaultHeapID;
internal uint th32ModuleID;
internal uint cntThreads;
internal uint th32ParentProcessID;
internal int pcPriClassBase;
internal uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
internal string szExeFile;
}
internal const uint TH32CS_SNAPPROCESS = 0x00000002;
// internal static int INVALID_HANDLE_VALUE = -1;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseHandle(IntPtr hSnapshot);
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
internal int Length;
internal IntPtr lpSecurityDescriptor;
internal bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
internal IntPtr hProcess;
internal IntPtr hThread;
internal uint dwProcessId;
internal uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct STARTUPINFO
{
internal int cb;
internal string lpReserved;
internal string lpDesktop;
internal string lpTitle;
internal uint dwX;
internal uint dwY;
internal uint dwXSize;
internal uint dwYSize;
internal uint dwXCountChars;
internal uint dwYCountChars;
internal uint dwFillAttribute;
internal uint dwFlags;
internal short wShowWindow;
internal short cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SID_AND_ATTRIBUTES
{
internal IntPtr Sid;
internal int Attributes;
}
[StructLayout(LayoutKind.Sequential)]
internal struct TOKEN_MANDATORY_LABEL
{
internal SID_AND_ATTRIBUTES Label;
}
internal const int TOKEN_DUPLICATE = 0x0002;
internal const int TOKEN_QUERY = 0x0008;
internal const int TOKEN_ADJUST_DEFAULT = 0x0080;
internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;
internal const uint MAXIMUM_ALLOWED = 0x2000000;
internal const int SE_GROUP_INTEGRITY = 0x00000020;
internal enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
internal enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2,
}
internal enum TOKEN_INFORMATION_CLASS : int
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass,
}
// [DllImport("kernel32.dll")]
// internal static extern int Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
// [DllImport("kernel32.dll")]
// internal static extern int Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
// [DllImport("kernel32.dll", SetLastError = true)]
// internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
[DllImport("Wtsapi32.dll")]
internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
// [DllImport("kernel32.dll")]
// [return: MarshalAs(UnmanagedType.Bool)]
// static extern bool ProcessIdToSessionId(UInt32 dwProcessId, ref UInt32 pSessionId);
[DllImport("kernel32.dll")]
internal static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool RevertToSelf();
internal delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeMethods.RECT lprcMonitor, IntPtr dwData);
internal delegate int HookProc(int nCode, int wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
}
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
/*
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
internal extern static int NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[MarshalAs(UnmanagedType.LPWStr)] string UserName, int level,out IntPtr BufPtr);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct USER_INFO_10
{
[MarshalAs(UnmanagedType.LPWStr)]
public string usri10_name;
[MarshalAs(UnmanagedType.LPWStr)]
public string usri10_comment;
[MarshalAs(UnmanagedType.LPWStr)]
public string usri10_usr_comment;
[MarshalAs(UnmanagedType.LPWStr)]
public string usri10_full_name;
}
[DllImport("Netapi32.dll", SetLastError = true)]
internal static extern int NetApiBufferFree(IntPtr Buffer);
*/
internal enum EXTENDED_NAME_FORMAT
{
NameUnknown = 0,
NameFullyQualifiedDN = 1,
NameSamCompatible = 2,
NameDisplay = 3,
NameUniqueId = 6,
NameCanonical = 7,
NameUserPrincipal = 8,
NameCanonicalEx = 9,
NameServicePrincipal = 10,
NameDnsDomain = 12,
}
[DllImport("secur32.dll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool GetUserNameEx(int nameFormat, StringBuilder userName, ref uint userNameSize);
[DllImport("Shcore.dll", SetLastError = true)]
internal static extern int GetDpiForMonitor(IntPtr hMonitor, uint dpiType, out uint dpiX, out uint dpiY);
private static string GetDNSDomain()
{
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
return null;
}
StringBuilder userName = new StringBuilder(1024);
uint userNameSize = (uint)userName.Capacity;
if (GetUserNameEx((int)EXTENDED_NAME_FORMAT.NameDnsDomain, userName, ref userNameSize))
{
string[] nameParts = userName.ToString().Split('\\');
if (nameParts.Length != 2)
{
return null;
}
return nameParts[0];
}
return null;
}
/// <summary>
/// Use this method to figure out if your code is running on a Microsoft computer.
/// </summary>
internal static bool IsRunningAtMicrosoft()
{
string domain = GetDNSDomain();
if (!string.IsNullOrEmpty(domain) && domain.EndsWith("microsoft.com", true, System.Globalization.CultureInfo.CurrentCulture))
{
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using ManagedCommon;
namespace MouseWithoutBorders
{
internal static class Program
{
internal static FormHelper FormHelper;
private static FormDot dotForm;
internal static FormDot DotForm
{
get
{
return dotForm != null && !dotForm.IsDisposed ? dotForm : (dotForm = new FormDot());
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main()
{
if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
{
// TODO: Add logging.
// Logger.LogWarning("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
return;
}
RunnerHelper.WaitForPowerToysRunnerExitFallback(() =>
{
Application.Exit();
});
string[] args = Environment.GetCommandLineArgs();
if (args.Length > 1 && !string.IsNullOrEmpty(args[1]))
{
string command = args[1];
string arg = args.Length > 2 && !string.IsNullOrEmpty(args[2]) ? args[2] : string.Empty;
if (command.Equals("SvcExec", StringComparison.OrdinalIgnoreCase))
{
Process.Start(Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBorders.exe", "\"" + arg + "\"");
}
else if (command.Equals("install", StringComparison.OrdinalIgnoreCase))
{
Process.Start(Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBorders.exe");
}
else if (command.Equals("help-ex", StringComparison.OrdinalIgnoreCase))
{
Process.Start(@"http://www.aka.ms/mm");
}
else if (command.Equals("InternalError", StringComparison.OrdinalIgnoreCase))
{
MessageBox.Show(arg, Application.ProductName);
}
return;
}
Application.EnableVisualStyles();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.SetCompatibleTextRenderingDefault(false);
dotForm = new FormDot();
Application.Run(FormHelper = new FormHelper());
}
}
}