Skip to content

Commit 9e1dc0f

Browse files
authored
Merge pull request #131 from VelixoSolutions/bugfix/124-arguments-tooltip-regression-second-attempt
Bugfix/124 arguments tooltip regression second attempt
2 parents 0082e04 + 69dd6f1 commit 9e1dc0f

File tree

4 files changed

+63
-11
lines changed

4 files changed

+63
-11
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace ExcelDna.IntelliSense
3030
// REMEMBER: COM events are not necessarily safe macro contexts.
3131
public static class IntelliSenseServer
3232
{
33-
const string ServerVersion = "1.7.0"; // TODO: Define and manage this somewhere else
33+
const string ServerVersion = "1.7.1"; // TODO: Define and manage this somewhere else
3434

3535
// NOTE: Do not change these constants in custom versions.
3636
// They are part of the co-operative safety mechanism allowing different add-ins providing IntelliSense to work together safely.

Source/ExcelDna.IntelliSense/UIMonitor/WinEvents.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ bool IsSupportedWinEvent(WinEvent winEvent)
219219
winEvent == WinEvent.EVENT_SYSTEM_MOVESIZESTART || // Only for the on-demand hook
220220
winEvent == WinEvent.EVENT_SYSTEM_MOVESIZEEND || // Only for the on-demand hook
221221
winEvent == WinEvent.EVENT_OBJECT_SELECTION || // Only for the PopupList
222+
winEvent == WinEvent.EVENT_OBJECT_LOCATIONCHANGE ||
222223
winEvent == WinEvent.EVENT_SYSTEM_CAPTURESTART;
223224
}
224225

Source/ExcelDna.IntelliSense/UIMonitor/WindowLocationWatcher.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,81 @@ public class WindowLocationWatcher : IDisposable
99
IntPtr _hWnd;
1010
SynchronizationContext _syncContextAuto;
1111
SynchronizationContext _syncContextMain;
12-
WinEventHook _windowLocationChangeHook;
12+
WinEventHook _windowMoveSizeHook;
13+
WinEventHook _locationChangeEventHook;
1314

1415
public event EventHandler LocationChanged;
1516

1617
// NOTE: An earlier attempt was to monitor LOCATIONCHANGE only between EVENT_SYSTEM_MOVESIZESTART and EVENT_SYSTEM_MOVESIZEEND
18+
// (for the purpose of moving the tooltip to the correct position when the user moves the Excel main window)
1719
// This nearly worked, and meant we were watching many fewer events ...
1820
// ...but we missed some of the resizing events for the window, leaving our tooltip stranded.
19-
// So until we can find a workaround for that (perhaps a timer would work fine for this), we watch all the LOCATIONCHANGE events.
21+
// We then started to watch all the LOCATIONCHANGE events, but it caused the Excel main window to lag when dragging.
22+
// (This drag issue seems to have been introduced with an Office update around November 2022)
23+
// So until we can find a workaround for that (perhaps a timer would work fine for this), we decided not to bother
24+
// with tracking the tooltip position (we still update it as soon as the Excel main window moving ends).
25+
// We still need to watch the LOCATIONCHANGE events, otherwise the tooltip is not shown at all in some cases.
26+
// To workaround the Excel main window lagging, we unhook from LOCATIONCHANGE upon encountering EVENT_SYSTEM_MOVESIZESTART
27+
// and then hook again upon encountering EVENT_SYSTEM_MOVESIZEEND (see UnhookFromLocationChangeUponDraggingExcelMainWindow).
2028
public WindowLocationWatcher(IntPtr hWnd, SynchronizationContext syncContextAuto, SynchronizationContext syncContextMain)
2129
{
2230
_hWnd = hWnd;
2331
_syncContextAuto = syncContextAuto;
2432
_syncContextMain = syncContextMain;
25-
_windowLocationChangeHook = new WinEventHook(WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZESTART, WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND, _syncContextAuto, syncContextMain, _hWnd);
26-
_windowLocationChangeHook.WinEventReceived += _windowLocationChangeHook_WinEventReceived;
33+
_windowMoveSizeHook = new WinEventHook(WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZESTART, WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND, _syncContextAuto, syncContextMain, _hWnd);
34+
_windowMoveSizeHook.WinEventReceived += _windowMoveSizeHook_WinEventReceived;
35+
36+
SetUpLocationChangeEventListener();
2737
}
2838

29-
void _windowLocationChangeHook_WinEventReceived(object sender, WinEventHook.WinEventArgs winEventArgs)
39+
void SetUpLocationChangeEventListener()
40+
{
41+
42+
_locationChangeEventHook = new WinEventHook(WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE, _syncContextAuto, _syncContextMain, IntPtr.Zero);
43+
_locationChangeEventHook.WinEventReceived += _windowMoveSizeHook_WinEventReceived;
44+
}
45+
46+
// This allows us to temporarily stop listening to EVENT_OBJECT_LOCATIONCHANGE events when the user is dragging the Excel main window.
47+
// Otherwise we are going to bump into https://github.com/Excel-DNA/IntelliSense/issues/123. The rest of the time we need to stay
48+
// hooked to EVENT_OBJECT_LOCATIONCHANGE for IntelliSense to work correctly (see https://github.com/Excel-DNA/IntelliSense/issues/124).
49+
void UnhookFromLocationChangeUponDraggingExcelMainWindow(WinEventHook.WinEventArgs e)
50+
{
51+
if (e.EventType == WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZESTART)
52+
{
53+
_syncContextMain.Post(_ => _locationChangeEventHook?.Dispose(), null);
54+
}
55+
56+
if (e.EventType == WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND)
57+
{
58+
_syncContextMain.Post(_ => SetUpLocationChangeEventListener(), null);
59+
}
60+
}
61+
62+
void _windowMoveSizeHook_WinEventReceived(object sender, WinEventHook.WinEventArgs winEventArgs)
3063
{
3164
#if DEBUG
3265
Logger.WinEvents.Verbose($"{winEventArgs.EventType} - Window {winEventArgs.WindowHandle:X} ({Win32Helper.GetClassName(winEventArgs.WindowHandle)} - Object/Child {winEventArgs.ObjectId} / {winEventArgs.ChildId} - Thread {winEventArgs.EventThreadId} at {winEventArgs.EventTimeMs}");
3366
#endif
67+
68+
UnhookFromLocationChangeUponDraggingExcelMainWindow(winEventArgs);
69+
3470
LocationChanged?.Invoke(this, EventArgs.Empty);
3571
}
3672

3773
// Runs on the Main thread, perhaps during shutdown
3874
public void Dispose()
3975
{
4076
Debug.Assert(Thread.CurrentThread.ManagedThreadId == 1);
41-
if (_windowLocationChangeHook != null)
77+
if (_windowMoveSizeHook != null)
78+
{
79+
_windowMoveSizeHook.Dispose();
80+
_windowMoveSizeHook = null;
81+
}
82+
83+
if (_locationChangeEventHook != null)
4284
{
43-
_windowLocationChangeHook.Dispose();
44-
_windowLocationChangeHook = null;
85+
_locationChangeEventHook.Dispose();
86+
_locationChangeEventHook = null;
4587
}
4688
}
4789
}

Source/ExcelDna.IntelliSense/UIMonitor/WindowWatcher.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ internal WindowChangedEventArgs(IntPtr windowHandle, WinEventHook.WinEvent winEv
6969
case WinEventHook.WinEvent.EVENT_OBJECT_FOCUS:
7070
Type = ChangeType.Focus;
7171
break;
72+
case WinEventHook.WinEvent.EVENT_OBJECT_LOCATIONCHANGE:
73+
Type = ChangeType.LocationChange;
74+
ObjectId = ChangeObjectId.Caret;
75+
break;
7276
case WinEventHook.WinEvent.EVENT_SYSTEM_MOVESIZEEND:
7377
Type = ChangeType.LocationChange;
7478
break;
@@ -113,6 +117,9 @@ internal WindowChangedEventArgs(IntPtr windowHandle, WinEventHook.WinEvent winEv
113117
const string _nuiDialogClass = "NUIDialog";
114118
const string _selectDataSourceTitle = "Select Data Source"; // TODO: How does localization work?
115119

120+
readonly SynchronizationContext _syncContextAuto;
121+
readonly SynchronizationContext _syncContextMain;
122+
116123
List<WinEventHook> _windowStateChangeHooks = new List<WinEventHook>();
117124

118125
// These track keyboard focus for Windows in the Excel process
@@ -134,6 +141,9 @@ internal WindowChangedEventArgs(IntPtr windowHandle, WinEventHook.WinEvent winEv
134141

135142
public WindowWatcher(SynchronizationContext syncContextAuto, SynchronizationContext syncContextMain)
136143
{
144+
_syncContextAuto = syncContextAuto;
145+
_syncContextMain = syncContextMain;
146+
137147
#pragma warning disable CS0618 // Type or member is obsolete (GetCurrentThreadId) - But for debugging we want to monitor this anyway
138148
// Debug.Print($"### WindowWatcher created on thread: Managed {Thread.CurrentThread.ManagedThreadId}, Native {AppDomain.GetCurrentThreadId()}");
139149
#pragma warning restore CS0618 // Type or member is obsolete
@@ -151,8 +161,6 @@ public WindowWatcher(SynchronizationContext syncContextAuto, SynchronizationCont
151161
// EVENT_OBJECT_SELECTIONREMOVE
152162
// EVENT_OBJECT_SELECTIONWITHIN
153163
// EVENT_OBJECT_STATECHANGE (0x800A = 32778)
154-
// NB: Including the next event 'EVENT_OBJECT_LOCATIONCHANGE (0x800B = 32779)' will cause the Excel main window to lag when dragging.
155-
// This drag issue seems to have been introduced with an Office update around November 2022.
156164
_windowStateChangeHooks.Add(new WinEventHook(WinEventHook.WinEvent.EVENT_OBJECT_CREATE, WinEventHook.WinEvent.EVENT_OBJECT_STATECHANGE, syncContextAuto, syncContextMain, IntPtr.Zero));
157165
_windowStateChangeHooks.Add(new WinEventHook(WinEventHook.WinEvent.EVENT_SYSTEM_CAPTURESTART, WinEventHook.WinEvent.EVENT_SYSTEM_CAPTURESTART, syncContextAuto, syncContextMain, IntPtr.Zero));
158166

@@ -220,6 +228,7 @@ void _windowStateChangeHook_WinEventReceived(object sender, WinEventHook.WinEven
220228
{
221229
Debug.Fail("WinEvent with window 0!?");
222230
}
231+
223232
if (e.EventType == WinEventHook.WinEvent.EVENT_OBJECT_FOCUS)
224233
{
225234
// Might raise change event for Unfocus

0 commit comments

Comments
 (0)