Skip to content
This repository was archived by the owner on Apr 21, 2021. It is now read-only.

Commit 9a74208

Browse files
committed
Add comments
1 parent 70cd820 commit 9a74208

File tree

6 files changed

+268
-79
lines changed

6 files changed

+268
-79
lines changed

EventHook/ApplicationWatcher.cs

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@
99

1010
namespace EventHook
1111
{
12+
/// <summary>
13+
/// An enum for the type of application event
14+
/// </summary>
1215
public enum ApplicationEvents
1316
{
1417
Launched,
1518
Closed,
1619
Activated
1720

1821
}
22+
23+
/// <summary>
24+
/// An object that holds information on application event
25+
/// </summary>
1926
public class WindowData
2027
{
2128
public IntPtr HWnd;
@@ -26,12 +33,19 @@ public class WindowData
2633
public string AppTitle { get; set; }
2734
}
2835

36+
/// <summary>
37+
/// An event argument object send to user
38+
/// </summary>
2939
public class ApplicationEventArgs : EventArgs
3040
{
3141
public WindowData ApplicationData { get; set; }
3242
public ApplicationEvents Event { get; set; }
3343
}
3444

45+
/// <summary>
46+
/// A wrapper around shell hook to hook application window change events
47+
/// Uses a producer-consumer pattern to improve performance and to avoid operating system forcing unhook on delayed user callbacks
48+
/// </summary>
3549
public class ApplicationWatcher
3650
{
3751
/*Application history*/
@@ -45,6 +59,9 @@ public class ApplicationWatcher
4559

4660
public static event EventHandler<ApplicationEventArgs> OnApplicationWindowChange;
4761

62+
/// <summary>
63+
/// Start to watch
64+
/// </summary>
4865
public static void Start()
4966
{
5067
if (!_IsRunning)
@@ -54,15 +71,16 @@ public static void Start()
5471
_prevTimeApp = DateTime.Now;
5572

5673
appQueue = new AsyncCollection<object>();
57-
5874

75+
//This needs to run on UI thread context
76+
//So use task factory with the shared UI message pump thread
5977
Task.Factory.StartNew(() => { }).ContinueWith(x =>
60-
{
61-
WindowHook.WindowCreated += new GeneralShellHookEventHandler(WindowCreated);
62-
WindowHook.WindowDestroyed += new GeneralShellHookEventHandler(WindowDestroyed);
63-
WindowHook.WindowActivated += new GeneralShellHookEventHandler(WindowActivated);
78+
{
79+
WindowHook.WindowCreated += new GeneralShellHookEventHandler(WindowCreated);
80+
WindowHook.WindowDestroyed += new GeneralShellHookEventHandler(WindowDestroyed);
81+
WindowHook.WindowActivated += new GeneralShellHookEventHandler(WindowActivated);
6482

65-
}, SharedMessagePump.GetTaskScheduler());
83+
}, SharedMessagePump.GetTaskScheduler());
6684

6785
_lastEventWasLaunched = false;
6886
_lastHwndLaunched = IntPtr.Zero;
@@ -72,6 +90,10 @@ public static void Start()
7290
}
7391

7492
}
93+
94+
/// <summary>
95+
/// Quit watching
96+
/// </summary>
7597
public static void Stop()
7698
{
7799
if (_IsRunning)
@@ -86,19 +108,44 @@ public static void Stop()
86108
}
87109

88110
}
111+
112+
/// <summary>
113+
/// A windows was created on desktop
114+
/// </summary>
115+
/// <param name="shellObject"></param>
116+
/// <param name="hWnd"></param>
89117
private static void WindowCreated(ShellHook shellObject, IntPtr hWnd)
90118
{
91119
appQueue.Add(new WindowData() { HWnd = hWnd, EventType = 0 });
92120
}
121+
122+
/// <summary>
123+
/// An existing desktop window was destroyed
124+
/// </summary>
125+
/// <param name="shellObject"></param>
126+
/// <param name="hWnd"></param>
93127
private static void WindowDestroyed(ShellHook shellObject, IntPtr hWnd)
94128
{
95129
appQueue.Add(new WindowData() { HWnd = hWnd, EventType = 2 });
96130
}
131+
132+
/// <summary>
133+
/// A windows was brought to foreground
134+
/// </summary>
135+
/// <param name="shellObject"></param>
136+
/// <param name="hWnd"></param>
97137
private static void WindowActivated(ShellHook shellObject, IntPtr hWnd)
98138
{
99139
appQueue.Add(new WindowData() { HWnd = hWnd, EventType = 1 });
100140
}
101-
// This is the method to run when the timer is raised.
141+
142+
/// <summary>
143+
/// This is used to avoid blocking low level hooks
144+
/// Otherwise if user takes long time to return the message
145+
/// OS will unsubscribe the hook
146+
/// Producer-consumer
147+
/// </summary>
148+
/// <returns></returns>
102149
private static async Task AppConsumer()
103150
{
104151
while (_IsRunning)
@@ -123,7 +170,16 @@ private static async Task AppConsumer()
123170

124171
}
125172
}
173+
174+
/// <summary>
175+
/// A handle to keep track of last window launched
176+
/// </summary>
126177
private static IntPtr _lastHwndLaunched;
178+
179+
/// <summary>
180+
/// A window got created
181+
/// </summary>
182+
/// <param name="wnd"></param>
127183
private static void WindowCreated(WindowData wnd)
128184
{
129185

@@ -135,6 +191,11 @@ private static void WindowCreated(WindowData wnd)
135191

136192
}
137193

194+
/// <summary>
195+
/// invoke user call back
196+
/// </summary>
197+
/// <param name="wnd"></param>
198+
/// <param name="appEvent"></param>
138199
private static void ApplicationStatus(WindowData wnd, ApplicationEvents appEvent)
139200
{
140201
var timeStamp = DateTime.Now;
@@ -143,13 +204,13 @@ private static void ApplicationStatus(WindowData wnd, ApplicationEvents appEvent
143204
wnd.AppPath = appEvent == ApplicationEvents.Closed ? wnd.AppPath : WindowHelper.GetAppPath(wnd.HWnd);
144205
wnd.AppName = appEvent == ApplicationEvents.Closed ? wnd.AppName : WindowHelper.GetAppDescription(wnd.AppPath);
145206

146-
EventHandler<ApplicationEventArgs> handler = OnApplicationWindowChange;
147-
if (handler != null)
148-
{
149-
handler(null, new ApplicationEventArgs() { ApplicationData = wnd, Event = appEvent });
150-
}
207+
OnApplicationWindowChange?.Invoke(null, new ApplicationEventArgs() { ApplicationData = wnd, Event = appEvent });
151208
}
152209

210+
/// <summary>
211+
/// Remove handle from active window collection
212+
/// </summary>
213+
/// <param name="wnd"></param>
153214
private static void WindowDestroyed(WindowData wnd)
154215
{
155216

@@ -160,6 +221,10 @@ private static void WindowDestroyed(WindowData wnd)
160221
}
161222
_lastEventWasLaunched = false;
162223
}
224+
225+
/// <summary>
226+
/// Add window handle to active windows collection
227+
/// </summary>
163228
private static bool _lastEventWasLaunched;
164229
private static void WindowActivated(WindowData wnd)
165230
{

EventHook/ClipboardWatcher.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace EventHook
88
{
9+
/// <summary>
10+
/// Type of clipboard content
11+
/// </summary>
912
public enum ClipboardContentTypes
1013
{
1114
PlainText = 0,
@@ -15,12 +18,19 @@ public enum ClipboardContentTypes
1518
UnicodeText = 4
1619
}
1720

21+
/// <summary>
22+
/// An argument send to user
23+
/// </summary>
1824
public class ClipboardEventArgs : EventArgs
1925
{
2026
public object Data { get; set; }
2127
public ClipboardContentTypes DataFormat { get; set; }
2228
}
2329

30+
/// <summary>
31+
/// Wraps around clipboardHook
32+
/// Uses a producer-consumer pattern to improve performance and to avoid operating system forcing unhook on delayed user callbacks
33+
/// </summary>
2434
public class ClipboardWatcher
2535
{
2636
/*Clip board monitor*/
@@ -32,6 +42,9 @@ public class ClipboardWatcher
3242

3343
public static event EventHandler<ClipboardEventArgs> OnClipboardModified;
3444

45+
/// <summary>
46+
/// Start watching
47+
/// </summary>
3548
public static void Start()
3649
{
3750
if (!_IsRunning)
@@ -41,7 +54,7 @@ public static void Start()
4154
{
4255
_clipQueue = new AsyncCollection<object>();
4356

44-
57+
//Low level hooks need to be run in the context of a UI thread
4558
Task.Factory.StartNew(() => { }).ContinueWith(x =>
4659
{
4760
_clip = new ClipBoardHook();
@@ -66,6 +79,10 @@ public static void Start()
6679
}
6780

6881
}
82+
83+
/// <summary>
84+
/// Stop watching
85+
/// </summary>
6986
public static void Stop()
7087
{
7188
if (_IsRunning)
@@ -89,11 +106,21 @@ public static void Stop()
89106
}
90107

91108
}
109+
110+
/// <summary>
111+
/// Add event to producer queue
112+
/// </summary>
113+
/// <param name="sender"></param>
114+
/// <param name="e"></param>
92115
private static void ClipboardHandler(object sender, EventArgs e)
93116
{
94117
_clipQueue.Add(sender);
95118
}
96119

120+
/// <summary>
121+
/// Consume event from producer queue asynchronously
122+
/// </summary>
123+
/// <returns></returns>
97124
private static async Task ClipConsumerAsync()
98125
{
99126
while (_IsRunning)
@@ -103,11 +130,14 @@ private static async Task ClipConsumerAsync()
103130

104131
ClipboardHandler(item);
105132

106-
107133
}
108134

109135
}
110136

137+
/// <summary>
138+
/// Actuall handler to invoke user call backs
139+
/// </summary>
140+
/// <param name="sender"></param>
111141
private static void ClipboardHandler(object sender)
112142
{
113143

@@ -164,11 +194,7 @@ private static void ClipboardHandler(object sender)
164194

165195
if (!validDataType) return;
166196

167-
EventHandler<ClipboardEventArgs> handler = OnClipboardModified;
168-
if (handler != null)
169-
{
170-
handler(null, new ClipboardEventArgs() { Data = data, DataFormat = format });
171-
}
197+
OnClipboardModified?.Invoke(null, new ClipboardEventArgs() { Data = data, DataFormat = format });
172198

173199
}
174200
}

EventHook/Helpers/WindowHelper.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55

66
namespace EventHook.Helpers
77
{
8+
/// <summary>
9+
/// A helper class to get window names/handles etc
10+
/// </summary>
811
internal class WindowHelper
912
{
13+
/// <summary>
14+
/// Get the handle of current acitive window on screen if any
15+
/// </summary>
16+
/// <returns></returns>
1017
internal static IntPtr GetActiveWindowHandle()
1118
{
1219
try
@@ -20,6 +27,11 @@ internal static IntPtr GetActiveWindowHandle()
2027
return IntPtr.Zero;
2128
}
2229

30+
/// <summary>
31+
/// The the application exe path of this window
32+
/// </summary>
33+
/// <param name="hWnd">window handle</param>
34+
/// <returns></returns>
2335
internal static string GetAppPath(IntPtr hWnd)
2436
{
2537
if (hWnd == IntPtr.Zero) return null;
@@ -35,7 +47,11 @@ internal static string GetAppPath(IntPtr hWnd)
3547
return null;
3648
}
3749
}
38-
50+
/// <summary>
51+
/// Get the title text of this window
52+
/// </summary>
53+
/// <param name="hWnd">widow handle</param>
54+
/// <returns></returns>
3955
internal static string GetWindowText(IntPtr hWnd)
4056
{
4157
try
@@ -51,6 +67,11 @@ internal static string GetWindowText(IntPtr hWnd)
5167
}
5268
}
5369

70+
/// <summary>
71+
/// Get the application description file attribute from path of an executable file
72+
/// </summary>
73+
/// <param name="appPath"></param>
74+
/// <returns></returns>
5475
internal static string GetAppDescription(string appPath)
5576
{
5677
if (appPath == null) return null;

0 commit comments

Comments
 (0)