Skip to content

Commit a791c7a

Browse files
author
Antoine Aflalo
committed
Fixes Overflow when converting LParam. See #1
Better handling od the WindowsAPIAdapter Instance.
1 parent 54575ce commit a791c7a

File tree

2 files changed

+70
-34
lines changed

2 files changed

+70
-34
lines changed

SoundSwitch/Properties/AssemblyInfo.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@
3131
// You can specify all the values or you can default the Build and Revision Numbers
3232
// by using the '*' as shown below:
3333
// [assembly: AssemblyVersion("1.0.*")]
34-
[assembly: AssemblyVersion("3.1.1.*")]
34+
[assembly: AssemblyVersion("3.1.2.*")]

SoundSwitch/Util/WindowsAPIAdapter.cs

+69-33
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18+
using System.Diagnostics;
1819
using System.Runtime.InteropServices;
1920
using System.Threading;
2021
using System.Windows.Forms;
@@ -49,12 +50,14 @@ public enum RestartManagerEventType
4950

5051
private WindowsAPIAdapter()
5152
{
53+
CreateHandle();
5254
}
5355

5456
public static event EventHandler<RestartManagerEvent> RestartManagerTriggered;
5557
public static event EventHandler<DeviceChangeEvent> DeviceChanged;
5658
public static event EventHandler<KeyPressedEventArgs> HotKeyPressed;
5759

60+
5861
public static void Start()
5962
{
6063
var t = new Thread(RunForm);
@@ -71,12 +74,24 @@ public static void Stop()
7174
HotKeyPressed = null;
7275

7376
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+
}
7589
}
7690

7791
private static void RunForm()
7892
{
79-
Application.Run(new WindowsAPIAdapter());
93+
_instance = new WindowsAPIAdapter();
94+
Application.Run(_instance);
8095
}
8196

8297
private void EndForm()
@@ -86,9 +101,12 @@ private void EndForm()
86101

87102
protected override void Dispose(bool disposing)
88103
{
89-
foreach (var hotKeyId in _instance._registeredHotkeys.Values)
104+
if (disposing)
90105
{
91-
NativeMethods.UnregisterHotKey(_instance.Handle, hotKeyId);
106+
foreach (var hotKeyId in _instance._registeredHotkeys.Values)
107+
{
108+
NativeMethods.UnregisterHotKey(_instance.Handle, hotKeyId);
109+
}
92110
}
93111
base.Dispose(disposing);
94112
}
@@ -133,47 +151,65 @@ public static void UnRegisterHotKey(HotKeys hotKeys)
133151

134152
protected override void SetVisibleCore(bool value)
135153
{
136-
// Prevent window getting visible
137-
if (_instance == null) CreateHandle();
138-
_instance = this;
139-
value = false;
140-
base.SetVisibleCore(value);
154+
base.SetVisibleCore(false);
141155
}
142156

143157
protected override void WndProc(ref Message m)
144158
{
145159
//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)
153161
{
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)
162164
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)
165171
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;
170174

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+
}
174186

175187
base.WndProc(ref m);
176188
}
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+
}
177213

178214
#region WindowsNativeMethods
179215

0 commit comments

Comments
 (0)