9
9
10
10
namespace EventHook
11
11
{
12
+ /// <summary>
13
+ /// An enum for the type of application event
14
+ /// </summary>
12
15
public enum ApplicationEvents
13
16
{
14
17
Launched ,
15
18
Closed ,
16
19
Activated
17
20
18
21
}
22
+
23
+ /// <summary>
24
+ /// An object that holds information on application event
25
+ /// </summary>
19
26
public class WindowData
20
27
{
21
28
public IntPtr HWnd ;
@@ -26,12 +33,19 @@ public class WindowData
26
33
public string AppTitle { get ; set ; }
27
34
}
28
35
36
+ /// <summary>
37
+ /// An event argument object send to user
38
+ /// </summary>
29
39
public class ApplicationEventArgs : EventArgs
30
40
{
31
41
public WindowData ApplicationData { get ; set ; }
32
42
public ApplicationEvents Event { get ; set ; }
33
43
}
34
44
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>
35
49
public class ApplicationWatcher
36
50
{
37
51
/*Application history*/
@@ -45,6 +59,9 @@ public class ApplicationWatcher
45
59
46
60
public static event EventHandler < ApplicationEventArgs > OnApplicationWindowChange ;
47
61
62
+ /// <summary>
63
+ /// Start to watch
64
+ /// </summary>
48
65
public static void Start ( )
49
66
{
50
67
if ( ! _IsRunning )
@@ -54,15 +71,16 @@ public static void Start()
54
71
_prevTimeApp = DateTime . Now ;
55
72
56
73
appQueue = new AsyncCollection < object > ( ) ;
57
-
58
74
75
+ //This needs to run on UI thread context
76
+ //So use task factory with the shared UI message pump thread
59
77
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 ) ;
64
82
65
- } , SharedMessagePump . GetTaskScheduler ( ) ) ;
83
+ } , SharedMessagePump . GetTaskScheduler ( ) ) ;
66
84
67
85
_lastEventWasLaunched = false ;
68
86
_lastHwndLaunched = IntPtr . Zero ;
@@ -72,6 +90,10 @@ public static void Start()
72
90
}
73
91
74
92
}
93
+
94
+ /// <summary>
95
+ /// Quit watching
96
+ /// </summary>
75
97
public static void Stop ( )
76
98
{
77
99
if ( _IsRunning )
@@ -86,19 +108,44 @@ public static void Stop()
86
108
}
87
109
88
110
}
111
+
112
+ /// <summary>
113
+ /// A windows was created on desktop
114
+ /// </summary>
115
+ /// <param name="shellObject"></param>
116
+ /// <param name="hWnd"></param>
89
117
private static void WindowCreated ( ShellHook shellObject , IntPtr hWnd )
90
118
{
91
119
appQueue . Add ( new WindowData ( ) { HWnd = hWnd , EventType = 0 } ) ;
92
120
}
121
+
122
+ /// <summary>
123
+ /// An existing desktop window was destroyed
124
+ /// </summary>
125
+ /// <param name="shellObject"></param>
126
+ /// <param name="hWnd"></param>
93
127
private static void WindowDestroyed ( ShellHook shellObject , IntPtr hWnd )
94
128
{
95
129
appQueue . Add ( new WindowData ( ) { HWnd = hWnd , EventType = 2 } ) ;
96
130
}
131
+
132
+ /// <summary>
133
+ /// A windows was brought to foreground
134
+ /// </summary>
135
+ /// <param name="shellObject"></param>
136
+ /// <param name="hWnd"></param>
97
137
private static void WindowActivated ( ShellHook shellObject , IntPtr hWnd )
98
138
{
99
139
appQueue . Add ( new WindowData ( ) { HWnd = hWnd , EventType = 1 } ) ;
100
140
}
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>
102
149
private static async Task AppConsumer ( )
103
150
{
104
151
while ( _IsRunning )
@@ -123,7 +170,16 @@ private static async Task AppConsumer()
123
170
124
171
}
125
172
}
173
+
174
+ /// <summary>
175
+ /// A handle to keep track of last window launched
176
+ /// </summary>
126
177
private static IntPtr _lastHwndLaunched ;
178
+
179
+ /// <summary>
180
+ /// A window got created
181
+ /// </summary>
182
+ /// <param name="wnd"></param>
127
183
private static void WindowCreated ( WindowData wnd )
128
184
{
129
185
@@ -135,6 +191,11 @@ private static void WindowCreated(WindowData wnd)
135
191
136
192
}
137
193
194
+ /// <summary>
195
+ /// invoke user call back
196
+ /// </summary>
197
+ /// <param name="wnd"></param>
198
+ /// <param name="appEvent"></param>
138
199
private static void ApplicationStatus ( WindowData wnd , ApplicationEvents appEvent )
139
200
{
140
201
var timeStamp = DateTime . Now ;
@@ -143,13 +204,13 @@ private static void ApplicationStatus(WindowData wnd, ApplicationEvents appEvent
143
204
wnd . AppPath = appEvent == ApplicationEvents . Closed ? wnd . AppPath : WindowHelper . GetAppPath ( wnd . HWnd ) ;
144
205
wnd . AppName = appEvent == ApplicationEvents . Closed ? wnd . AppName : WindowHelper . GetAppDescription ( wnd . AppPath ) ;
145
206
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 } ) ;
151
208
}
152
209
210
+ /// <summary>
211
+ /// Remove handle from active window collection
212
+ /// </summary>
213
+ /// <param name="wnd"></param>
153
214
private static void WindowDestroyed ( WindowData wnd )
154
215
{
155
216
@@ -160,6 +221,10 @@ private static void WindowDestroyed(WindowData wnd)
160
221
}
161
222
_lastEventWasLaunched = false ;
162
223
}
224
+
225
+ /// <summary>
226
+ /// Add window handle to active windows collection
227
+ /// </summary>
163
228
private static bool _lastEventWasLaunched ;
164
229
private static void WindowActivated ( WindowData wnd )
165
230
{
0 commit comments