15
15
16
16
using System ;
17
17
using System . Collections . Generic ;
18
+ using System . Diagnostics ;
18
19
using System . Runtime . InteropServices ;
19
20
using System . Threading ;
20
21
using System . Windows . Forms ;
@@ -49,12 +50,14 @@ public enum RestartManagerEventType
49
50
50
51
private WindowsAPIAdapter ( )
51
52
{
53
+ CreateHandle ( ) ;
52
54
}
53
55
54
56
public static event EventHandler < RestartManagerEvent > RestartManagerTriggered ;
55
57
public static event EventHandler < DeviceChangeEvent > DeviceChanged ;
56
58
public static event EventHandler < KeyPressedEventArgs > HotKeyPressed ;
57
59
60
+
58
61
public static void Start ( )
59
62
{
60
63
var t = new Thread ( RunForm ) ;
@@ -71,12 +74,24 @@ public static void Stop()
71
74
HotKeyPressed = null ;
72
75
73
76
if ( ! _instance . IsDisposed )
74
- _instance . Invoke ( new MethodInvoker ( _instance . EndForm ) ) ;
77
+ {
78
+ try
79
+ {
80
+ _instance . Invoke ( new MethodInvoker ( _instance . EndForm ) ) ;
81
+ }
82
+ catch ( Exception ex )
83
+ {
84
+ //Can happen when the instance got dispose in its own thread
85
+ //when in the same time the Application thread call the Stop() method.
86
+ Trace . WriteLine ( "Thread Race Condition: " + ex ) ;
87
+ }
88
+ }
75
89
}
76
90
77
91
private static void RunForm ( )
78
92
{
79
- Application . Run ( new WindowsAPIAdapter ( ) ) ;
93
+ _instance = new WindowsAPIAdapter ( ) ;
94
+ Application . Run ( _instance ) ;
80
95
}
81
96
82
97
private void EndForm ( )
@@ -86,9 +101,12 @@ private void EndForm()
86
101
87
102
protected override void Dispose ( bool disposing )
88
103
{
89
- foreach ( var hotKeyId in _instance . _registeredHotkeys . Values )
104
+ if ( disposing )
90
105
{
91
- NativeMethods . UnregisterHotKey ( _instance . Handle , hotKeyId ) ;
106
+ foreach ( var hotKeyId in _instance . _registeredHotkeys . Values )
107
+ {
108
+ NativeMethods . UnregisterHotKey ( _instance . Handle , hotKeyId ) ;
109
+ }
92
110
}
93
111
base . Dispose ( disposing ) ;
94
112
}
@@ -133,47 +151,65 @@ public static void UnRegisterHotKey(HotKeys hotKeys)
133
151
134
152
protected override void SetVisibleCore ( bool value )
135
153
{
136
- // Prevent window getting visible
137
- if ( _instance == null ) CreateHandle ( ) ;
138
- _instance = this ;
139
- value = false ;
140
- base . SetVisibleCore ( value ) ;
154
+ base . SetVisibleCore ( false ) ;
141
155
}
142
156
143
157
protected override void WndProc ( ref Message m )
144
158
{
145
159
//Check for shutdown message from windows
146
- if ( m . Msg == WM_QUERYENDSESSION && m . LParam . ToInt32 ( ) == ENDSESSION_CLOSEAPP )
147
- {
148
- var closingEvent = new RestartManagerEvent ( RestartManagerEventType . Query ) ;
149
- RestartManagerTriggered ? . Invoke ( this , closingEvent ) ;
150
- m . Result = closingEvent . Result ;
151
- }
152
- else if ( m . Msg == WM_ENDSESSION && m . LParam . ToInt32 ( ) == ENDSESSION_CLOSEAPP )
160
+ switch ( m . Msg )
153
161
{
154
- RestartManagerTriggered ? . Invoke ( this , new RestartManagerEvent ( RestartManagerEventType . EndSession ) ) ;
155
- }
156
- else
157
- switch ( m . Msg )
158
- {
159
- case WM_CLOSE :
160
- RestartManagerTriggered ? . Invoke ( this ,
161
- new RestartManagerEvent ( RestartManagerEventType . ForceClose ) ) ;
162
+ case WM_QUERYENDSESSION :
163
+ if ( ConvertLParam ( m . LParam ) != ENDSESSION_CLOSEAPP )
162
164
break ;
163
- case WM_DEVICECHANGE :
164
- DeviceChanged ? . Invoke ( this , new DeviceChangeEvent ( ) ) ;
165
+ var closingEvent = new RestartManagerEvent ( RestartManagerEventType . Query ) ;
166
+ RestartManagerTriggered ? . Invoke ( this , closingEvent ) ;
167
+ m . Result = closingEvent . Result ;
168
+ break ;
169
+ case WM_ENDSESSION :
170
+ if ( ConvertLParam ( m . LParam ) != ENDSESSION_CLOSEAPP )
165
171
break ;
166
- case WM_HOTKEY :
167
- // get the keys.
168
- var key = ( Keys ) ( ( ( int ) m . LParam >> 16 ) & 0xFFFF ) ;
169
- var modifier = ( HotKeys . ModifierKeys ) ( ( int ) m . LParam & 0xFFFF ) ;
172
+ RestartManagerTriggered ? . Invoke ( this , new RestartManagerEvent ( RestartManagerEventType . EndSession ) ) ;
173
+ break ;
170
174
171
- HotKeyPressed ? . Invoke ( this , new KeyPressedEventArgs ( new HotKeys ( key , modifier ) ) ) ;
172
- break ;
173
- }
175
+ case WM_CLOSE :
176
+ RestartManagerTriggered ? . Invoke ( this ,
177
+ new RestartManagerEvent ( RestartManagerEventType . ForceClose ) ) ;
178
+ break ;
179
+ case WM_DEVICECHANGE :
180
+ DeviceChanged ? . Invoke ( this , new DeviceChangeEvent ( ) ) ;
181
+ break ;
182
+ case WM_HOTKEY :
183
+ ProcessHotKeyEvent ( m ) ;
184
+ break ;
185
+ }
174
186
175
187
base . WndProc ( ref m ) ;
176
188
}
189
+ /// <summary>
190
+ /// To avoid overflow on 64 bit platform use this method
191
+ /// </summary>
192
+ /// <param name="lParam"></param>
193
+ /// <returns></returns>
194
+ private long ConvertLParam ( IntPtr lParam )
195
+ {
196
+ try
197
+ {
198
+ return lParam . ToInt32 ( ) ;
199
+ }
200
+ catch ( OverflowException )
201
+ {
202
+ return lParam . ToInt64 ( ) ;
203
+ }
204
+ }
205
+
206
+ private void ProcessHotKeyEvent ( Message m )
207
+ {
208
+ var key = ( Keys ) ( ( ConvertLParam ( m . LParam ) >> 16 ) & 0xFFFF ) ;
209
+ var modifier = ( HotKeys . ModifierKeys ) ( ConvertLParam ( m . LParam ) & 0xFFFF ) ;
210
+
211
+ HotKeyPressed ? . Invoke ( this , new KeyPressedEventArgs ( new HotKeys ( key , modifier ) ) ) ;
212
+ }
177
213
178
214
#region WindowsNativeMethods
179
215
0 commit comments