SpyAgent.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using System;
  2. using System.Drawing;
  3. using System.Runtime.InteropServices;
  4. using System.Windows.Forms;
  5. namespace ScreenExtender.Utility.Spy
  6. {
  7. public class SpyAgent
  8. {
  9. private readonly Action<SpiedWindow> _selectedAction;
  10. private readonly Timer _timer;
  11. private SpyAgentLocator _locator;
  12. public SpyAgent(Action<SpiedWindow> selectedAction)
  13. {
  14. _selectedAction = selectedAction;
  15. _timer = new Timer { Interval = 25, Enabled = false };
  16. _timer.Tick += OnTimerTicked;
  17. BeginSpying();
  18. }
  19. private void OnTimerTicked(object sender, EventArgs e)
  20. {
  21. ShowLocator();
  22. if (0 == (Control.MouseButtons & MouseButtons.Left)) return;
  23. EndSpying();
  24. _selectedAction(GetHoveredWindow());
  25. }
  26. private void ShowLocator()
  27. {
  28. var window = GetHoveredWindow();
  29. if (window.Handle == IntPtr.Zero)
  30. {
  31. _locator.Hide();
  32. return;
  33. }
  34. _locator.Location = window.Area.Location;
  35. _locator.Size = window.Area.Size;
  36. _locator.TopLevel = true;
  37. _locator.TopMost = true;
  38. _locator.Show();
  39. }
  40. public void BeginSpying()
  41. {
  42. if (_locator != null)
  43. {
  44. _locator.Close();
  45. _locator.Dispose();
  46. }
  47. _locator = new SpyAgentLocator();
  48. MakePassThrough(_locator.Handle);
  49. _timer.Enabled = true;
  50. }
  51. public void EndSpying()
  52. {
  53. _timer.Enabled = false;
  54. _locator?.Close();
  55. _locator?.Dispose();
  56. _locator = null;
  57. }
  58. private class SpyAgentLocator : Form
  59. {
  60. public SpyAgentLocator()
  61. {
  62. FormBorderStyle = FormBorderStyle.None;
  63. BackColor = Color.OrangeRed;
  64. Opacity = 0.25;
  65. TopLevel = true;
  66. TopMost = true;
  67. }
  68. }
  69. #region Under the Hood
  70. private const int GWL_EXSTYLE = -20;
  71. private const int WS_EX_TRANSPARENT = 0x20;
  72. [DllImport("user32.dll")]
  73. private static extern IntPtr WindowFromPoint(POINT point);
  74. [DllImport("user32.dll")]
  75. private static extern IntPtr ChildWindowFromPoint(IntPtr hWndParent, POINT point);
  76. [DllImport("user32.dll", SetLastError = true)]
  77. private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
  78. [DllImport("user32.dll", SetLastError = true)]
  79. private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
  80. public static SpiedWindow GetHoveredWindow()
  81. {
  82. var handle = WindowFromPoint(Cursor.Position);
  83. return new SpiedWindow(handle);
  84. }
  85. private static void MakePassThrough(IntPtr handle)
  86. {
  87. var exstyle = GetWindowLong(handle, GWL_EXSTYLE);
  88. exstyle |= WS_EX_TRANSPARENT;
  89. SetWindowLong(handle, GWL_EXSTYLE, exstyle);
  90. }
  91. [StructLayout(LayoutKind.Sequential)]
  92. private struct POINT
  93. {
  94. public readonly int X;
  95. public readonly int Y;
  96. public POINT(int x, int y)
  97. {
  98. X = x;
  99. Y = y;
  100. }
  101. public POINT(Point pt)
  102. : this(pt.X, pt.Y)
  103. {
  104. }
  105. public static implicit operator Point(POINT p)
  106. {
  107. return new(p.X, p.Y);
  108. }
  109. public static implicit operator POINT(Point p)
  110. {
  111. return new(p.X, p.Y);
  112. }
  113. }
  114. #endregion Under the Hood
  115. }
  116. }