Skip to content

Commit ea90428

Browse files
committed
Merge with conflicts
2 parents 868048f + f4cf930 commit ea90428

File tree

360 files changed

+11113
-7494
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

360 files changed

+11113
-7494
lines changed

RetailCoder.VBE/AppMenu.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Threading;
5+
using NLog;
46
using Rubberduck.Parsing;
57
using Rubberduck.Parsing.VBA;
68
using Rubberduck.UI;
@@ -17,6 +19,8 @@ public class AppMenu : IAppMenu, IDisposable
1719
private readonly ISelectionChangeService _selectionService;
1820
private readonly RubberduckCommandBar _stateBar;
1921

22+
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
23+
2024
public AppMenu(IEnumerable<IParentMenuItem> menus, IParseCoordinator parser, ISelectionChangeService selectionService, RubberduckCommandBar stateBar)
2125
{
2226
_menus = menus.ToList();
@@ -77,7 +81,13 @@ private void RemoveMenus()
7781
{
7882
foreach (var menu in _menus.Where(menu => menu.Item != null))
7983
{
84+
_logger.Debug($"Starting removal of top-level menu {menu.GetType()}.");
8085
menu.RemoveMenu();
86+
//We do this here and not in the menu items because we only want to dispose of/release the parents of the top level parent menus.
87+
//The parents further down get disposed of/released as part of the remove chain.
88+
_logger.Trace($"Removing parent menu of top-level menu {menu.GetType()}.");
89+
menu.Parent.Dispose();
90+
menu.Parent = null;
8191
}
8292
}
8393
}

RetailCoder.VBE/Common/Hotkeys/Hotkey.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
34
using System.Windows.Forms;
45
using Rubberduck.Common.WinAPI;
56
using NLog;
@@ -32,7 +33,7 @@ public Hotkey(IntPtr hWndVbe, string key, CommandBase command, Keys secondKey =
3233
public Keys Combo { get; }
3334
public Keys SecondKey { get; }
3435
public bool IsTwoStepHotkey { get; }
35-
public bool IsAttached { get; private set; }
36+
public bool IsAttached => HotkeyInfo.HookId != IntPtr.Zero;
3637

3738
public event EventHandler<HookEventArgs> MessageReceived;
3839

@@ -68,10 +69,19 @@ public void Detach()
6869
return;
6970
}
7071

71-
User32.UnregisterHotKey(_hWndVbe, HotkeyInfo.HookId);
72+
if (!User32.UnregisterHotKey(_hWndVbe, HotkeyInfo.HookId))
73+
{
74+
Logger.Warn($"Error calling UnregisterHotKey on hokey with id {HotkeyInfo.HookId} for command of type {Command.GetType()}; the error was {Marshal.GetLastWin32Error()}; going to delete the atom anyway... The memory may leak.");
75+
}
76+
Kernel32.SetLastError(Kernel32.ERROR_SUCCESS);
7277
Kernel32.GlobalDeleteAtom(HotkeyInfo.HookId);
78+
var lastError = Marshal.GetLastWin32Error();
79+
if (lastError != Kernel32.ERROR_SUCCESS)
80+
{
81+
Logger.Warn($"Error calling DeleteGlobalAtom; the error was {lastError}, the id {HotkeyInfo.HookId} and the type of the associated command {Command.GetType()}.");
82+
}
7383

74-
IsAttached = false;
84+
HotkeyInfo = new HotkeyInfo(IntPtr.Zero, Combo);
7585
ClearCommandShortcutText();
7686
}
7787

@@ -83,14 +93,21 @@ private void HookKey(Keys key, uint shift)
8393
}
8494

8595
var hookId = (IntPtr)Kernel32.GlobalAddAtom(Guid.NewGuid().ToString());
96+
if (hookId == IntPtr.Zero)
97+
{
98+
Logger.Warn($"Error calling GlobalAddAtom; the error was {Marshal.GetLastWin32Error()}; aborting the HookKey operation...");
99+
return;
100+
}
101+
86102
var success = User32.RegisterHotKey(_hWndVbe, hookId, shift, (uint)key);
87103
if (!success)
88104
{
89105
Logger.Debug(RubberduckUI.CommonHotkey_KeyNotRegistered, key);
106+
return;
90107
}
91108

92109
HotkeyInfo = new HotkeyInfo(hookId, Combo);
93-
IsAttached = true;
110+
Logger.Trace($"Hotkey for the associated command {Command.GetType()} was registered with id {HotkeyInfo.HookId}");
94111
}
95112

96113
private void SetCommandShortcutText()
@@ -108,8 +125,7 @@ private void ClearCommandShortcutText()
108125
command.ShortcutText = string.Empty;
109126
}
110127
}
111-
112-
128+
113129
private static readonly IDictionary<char,uint> Modifiers = new Dictionary<char, uint>
114130
{
115131
{ '+', (uint)KeyModifier.SHIFT },
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Rubberduck.Settings;
2+
using Rubberduck.UI.Command;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace Rubberduck.Common.Hotkeys
8+
{
9+
public class HotkeyFactory
10+
{
11+
private readonly IEnumerable<CommandBase> _commands;
12+
13+
public HotkeyFactory(IEnumerable<CommandBase> commands)
14+
{
15+
_commands = commands;
16+
}
17+
18+
public Hotkey Create(HotkeySetting setting, IntPtr hWndVbe)
19+
{
20+
if (setting == null)
21+
{
22+
return null;
23+
}
24+
25+
var commandToBind = _commands.FirstOrDefault(command => command.GetType().Name == setting.CommandTypeName);
26+
27+
return commandToBind == null ? null : new Hotkey(hWndVbe, setting.ToString(), commandToBind);
28+
}
29+
}
30+
}

RetailCoder.VBE/Common/RubberduckHooks.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
using System;
22
using System.Collections.Generic;
33
using System.ComponentModel;
4-
using System.Diagnostics;
54
using System.Linq;
65
using Rubberduck.Common.Hotkeys;
76
using Rubberduck.Settings;
8-
using Rubberduck.UI.Command;
97
using NLog;
108
using Rubberduck.VBEditor.SafeComWrappers.Abstract;
119
using Rubberduck.VBEditor.WindowsApi;
@@ -15,20 +13,15 @@ namespace Rubberduck.Common
1513
public class RubberduckHooks : SubclassingWindow, IRubberduckHooks
1614
{
1715
private readonly IGeneralConfigService _config;
18-
private readonly IEnumerable<CommandBase> _commands;
16+
private readonly HotkeyFactory _hotkeyFactory;
1917
private readonly IList<IAttachable> _hooks = new List<IAttachable>();
2018
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
2119

22-
public RubberduckHooks(IVBE vbe, IGeneralConfigService config, IEnumerable<CommandBase> commands)
20+
public RubberduckHooks(IVBE vbe, IGeneralConfigService config, HotkeyFactory hotkeyFactory)
2321
: base((IntPtr)vbe.MainWindow.HWnd, (IntPtr)vbe.MainWindow.HWnd)
2422
{
25-
_commands = commands;
2623
_config = config;
27-
}
28-
29-
private CommandBase Command(RubberduckHotkey hotkey)
30-
{
31-
return _commands.FirstOrDefault(s => s.Hotkey == hotkey);
24+
_hotkeyFactory = hotkeyFactory;
3225
}
3326

3427
public void HookHotkeys()
@@ -39,16 +32,15 @@ public void HookHotkeys()
3932
var config = _config.LoadConfiguration();
4033
var settings = config.UserSettings.HotkeySettings;
4134

42-
foreach (var hotkey in settings.Settings.Where(hotkey => hotkey.IsEnabled))
35+
foreach (var hotkeySetting in settings.Settings.Where(hotkeySetting => hotkeySetting.IsEnabled))
4336
{
44-
if (Enum.TryParse(hotkey.Name, out RubberduckHotkey assigned))
37+
var hotkey = _hotkeyFactory.Create(hotkeySetting, Hwnd);
38+
if (hotkey != null)
4539
{
46-
var command = Command(assigned);
47-
Debug.Assert(command != null);
48-
49-
AddHook(new Hotkey(Hwnd, hotkey.ToString(), command));
40+
AddHook(hotkey);
5041
}
5142
}
43+
5244
Attach();
5345
}
5446

@@ -155,7 +147,6 @@ public override int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr
155147
break;
156148
case WM.CLOSE:
157149
case WM.DESTROY:
158-
case WM.RUBBERDUCK_SINKING:
159150
Detach();
160151
break;
161152
}
@@ -180,5 +171,14 @@ private bool HandleHotkeyMessage(IntPtr wParam)
180171
}
181172
return processed;
182173
}
174+
175+
protected override void Dispose(bool disposing)
176+
{
177+
if (disposing)
178+
{
179+
Detach();
180+
}
181+
base.Dispose(disposing);
182+
}
183183
}
184184
}

RetailCoder.VBE/Common/TimerHook.cs

Lines changed: 0 additions & 85 deletions
This file was deleted.

RetailCoder.VBE/Common/WinAPI/Kernel32.cs

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,14 @@ public static class Kernel32
2929
/// <returns>The function always returns (ATOM) 0.</returns>
3030
[DllImport("kernel32.dll", SetLastError=true, ExactSpelling=true)]
3131
public static extern ushort GlobalDeleteAtom(IntPtr nAtom);
32-
32+
3333
/// <summary>
34-
/// Retrieves a module handle for the specified module.
35-
/// The module must have been loaded by the calling process.
34+
/// Sets the last-error code for the calling thread.
3635
/// </summary>
37-
/// <param name="lpModuleName">The name of the loaded module (either a .dll or .exe file).
38-
/// If the file name extension is omitted, the default library extension .dll is appended.
39-
/// The file name string can include a trailing point character (.) to indicate that the module name has no extension.
40-
/// The string does not have to specify a path. When specifying a path, be sure to use backslashes (\), not forward slashes (/).
41-
/// The name is compared (case independently) to the names of modules currently mapped into the address space of the calling process.</param>
42-
/// <returns>If the function succeeds, the return value is a handle to the specified module.
43-
/// If the function fails, the return value is NULL. To get extended error information, call GetLastError.</returns>
44-
/// <remarks>The returned handle is not global or inheritable. It cannot be duplicated or used by another process.
45-
/// This function must be used carefully in a multithreaded application. There is no guarantee that the module handle remains valid between the time this function returns the handle and the time it is used.
46-
/// For example, suppose that a thread retrieves a module handle, but before it uses the handle, a second thread frees the module.
47-
/// If the system loads another module, it could reuse the module handle that was recently freed.
48-
/// Therefore, the first thread would have a handle to a different module than the one intended.
49-
/// </remarks>
50-
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
51-
public static extern IntPtr GetModuleHandle(string lpModuleName);
52-
36+
/// <param name="dwErrorCode">The last-error code for the thread.</param>
37+
[DllImport("kernel32.dll", SetLastError = true)]
38+
public static extern void SetLastError(uint dwErrorCode);
5339

40+
public static uint ERROR_SUCCESS = 0;
5441
}
5542
}

0 commit comments

Comments
 (0)