Skip to content

Commit 381161c

Browse files
committed
Stop watching for window destroy notifications
1 parent 6b0b7e0 commit 381161c

File tree

6 files changed

+42
-31
lines changed

6 files changed

+42
-31
lines changed

Source/ExcelDna.IntelliSense/UIMonitor/ExcelToolTipWatcher.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Threading;
45

56
namespace ExcelDna.IntelliSense
@@ -57,10 +58,13 @@ void _windowWatcher_ExcelToolTipWindowChanged(object sender, WindowWatcher.Windo
5758
}
5859
break;
5960
case WindowWatcher.WindowChangedEventArgs.ChangeType.Hide:
60-
case WindowWatcher.WindowChangedEventArgs.ChangeType.Destroy:
6161
if (_toolTips.Remove(e.WindowHandle))
6262
ToolTipChanged?.Invoke(this, new ToolTipChangeEventArgs(ToolTipChangeType.Hide, e.WindowHandle));
6363
break;
64+
case WindowWatcher.WindowChangedEventArgs.ChangeType.Destroy:
65+
// Not expecting this anymore - Destroy is no longer routed from the WinEvents.
66+
Debug.Fail("Unexpected ChangeType");
67+
break;
6468
case WindowWatcher.WindowChangedEventArgs.ChangeType.Create:
6569
case WindowWatcher.WindowChangedEventArgs.ChangeType.Focus:
6670
case WindowWatcher.WindowChangedEventArgs.ChangeType.Unfocus:

Source/ExcelDna.IntelliSense/UIMonitor/FormulaEditWatcher.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,8 @@ void _windowWatcher_FormulaBarWindowChanged(object sender, WindowWatcher.WindowC
115115
}
116116
break;
117117
case WindowWatcher.WindowChangedEventArgs.ChangeType.Destroy:
118-
// We expect this for every text change, but ignore since we react to the Create event
119-
//if (_formulaEditFocus == FormulaEditFocus.FormulaBar)
120-
//{
121-
// _formulaEditFocus = FormulaEditFocus.None;
122-
// UpdateEditState();
123-
//}
118+
// Not expecting this anymore - Destroy is no longer routed from the WinEvents.
119+
Debug.Fail("Unexpected ChangeType");
124120
break;
125121
case WindowWatcher.WindowChangedEventArgs.ChangeType.Focus:
126122
if (_formulaEditFocus != FormulaEditFocus.FormulaBar)
@@ -193,12 +189,8 @@ void _windowWatcher_InCellEditWindowChanged(object sender, WindowWatcher.WindowC
193189
}
194190
break;
195191
case WindowWatcher.WindowChangedEventArgs.ChangeType.Destroy:
196-
// We expect this for every text change, but ignore since we react to the Create event
197-
//if (_formulaEditFocus == FormulaEditFocus.FormulaBar)
198-
//{
199-
// _formulaEditFocus = FormulaEditFocus.None;
200-
// UpdateEditState();
201-
//}
192+
// Not expecting this anymore - Destroy is no longer routed from the WinEvents.
193+
Debug.Fail("Unexpected ChangeType");
202194
break;
203195
case WindowWatcher.WindowChangedEventArgs.ChangeType.Focus:
204196
if (_formulaEditFocus != FormulaEditFocus.InCellEdit)

Source/ExcelDna.IntelliSense/UIMonitor/PopupListWatcher.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ void _windowWatcher_PopupListWindowChanged(object sender, WindowWatcher.WindowCh
5353
_hwndPopupList = e.WindowHandle;
5454
break;
5555
case WindowWatcher.WindowChangedEventArgs.ChangeType.Destroy:
56-
// We expect this only when shutting down
57-
Logger.WindowWatcher.Info($"PopupList window destroyed: {e.WindowHandle}");
56+
// Not expecting this anymore - Destroy is no longer routed from the WinEvents.
57+
Debug.Fail("Unexpected ChangeType");
5858
break;
5959
case WindowWatcher.WindowChangedEventArgs.ChangeType.Show:
6060
Logger.WindowWatcher.Verbose($"PopupList window show");

Source/ExcelDna.IntelliSense/UIMonitor/WinEvents.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ public class WinEventArgs : EventArgs
1717
{
1818
public WinEvent EventType;
1919
public IntPtr WindowHandle;
20+
public string WindowClassName;
2021
public WinEventObjectId ObjectId;
2122
public int ChildId;
2223
public uint EventThreadId;
2324
public uint EventTimeMs;
2425

25-
public WinEventArgs(WinEvent eventType, IntPtr hWnd, WinEventObjectId idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
26+
public WinEventArgs(WinEvent eventType, IntPtr hWnd, string windowClassName, WinEventObjectId idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
2627
{
2728
EventType = eventType;
2829
WindowHandle = hWnd;
30+
WindowClassName = windowClassName;
2931
ObjectId = idObject;
3032
ChildId = idChild;
3133
EventThreadId = dwEventThread;
@@ -187,11 +189,14 @@ void HandleWinEvent(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd,
187189
if (_hWndFilterOrZero != IntPtr.Zero && hWnd != _hWndFilterOrZero)
188190
return;
189191

190-
if (!IsSupportedWinEvent(eventType))
192+
if (!IsSupportedWinEvent(eventType) || idObject == WinEventObjectId.OBJID_CURSOR)
191193
return;
192194

195+
// Moving the GetClassName call here where the main thread is running.
196+
var windowClassName = Win32Helper.GetClassName(hWnd);
197+
193198
// CONSIDER: We might add some filtering here... maybe only interested in some of the window / event combinations
194-
_syncContextAuto.Post(OnWinEventReceived, new WinEventArgs(eventType, hWnd, idObject, idChild, dwEventThread, dwmsEventTime));
199+
_syncContextAuto.Post(OnWinEventReceived, new WinEventArgs(eventType, hWnd, windowClassName, idObject, idChild, dwEventThread, dwmsEventTime));
195200
}
196201
catch (Exception ex)
197202
{
@@ -203,7 +208,7 @@ void HandleWinEvent(IntPtr hWinEventHook, WinEvent eventType, IntPtr hWnd,
203208
bool IsSupportedWinEvent(WinEvent winEvent)
204209
{
205210
return winEvent == WinEvent.EVENT_OBJECT_CREATE ||
206-
winEvent == WinEvent.EVENT_OBJECT_DESTROY ||
211+
// winEvent == WinEvent.EVENT_OBJECT_DESTROY || // Stopped watching for this, because we can't route using the ClassName and don't really need anymore
207212
winEvent == WinEvent.EVENT_OBJECT_SHOW ||
208213
winEvent == WinEvent.EVENT_OBJECT_HIDE ||
209214
winEvent == WinEvent.EVENT_OBJECT_FOCUS ||
@@ -217,9 +222,10 @@ bool IsSupportedWinEvent(WinEvent winEvent)
217222
void OnWinEventReceived(object winEventArgsObj)
218223
{
219224
var winEventArgs = (WinEventArgs)winEventArgsObj;
225+
if (winEventArgs.ObjectId == WinEventObjectId.OBJID_CURSOR)
226+
return;
220227
#if DEBUG
221-
if (winEventArgs.ObjectId != WinEventObjectId.OBJID_CURSOR)
222-
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}");
228+
Logger.WinEvents.Verbose($"{winEventArgs.EventType} - Window {winEventArgs.WindowHandle:X} {(winEventArgs.WindowHandle != IntPtr.Zero ? Win32Helper.GetClassName(winEventArgs.WindowHandle) : "")} - Object/Child {winEventArgs.ObjectId} / {winEventArgs.ChildId} - Thread {winEventArgs.EventThreadId} at {winEventArgs.EventTimeMs}");
223229
#endif
224230
WinEventReceived?.Invoke(this, winEventArgs);
225231
}

Source/ExcelDna.IntelliSense/UIMonitor/WindowWatcher.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,11 @@ public void TryInitialize()
153153

154154
bool UpdateFocus(IntPtr windowHandle, string windowClassName)
155155
{
156-
if (windowHandle == _focusedWindowHandle)
157-
{
158-
Debug.Assert(_focusedWindowClassName == windowClassName); // I've seen this, with _focusedWindowClassName == "" and windowClassName == "EXCEL7".
159-
return false;
160-
}
156+
if (windowHandle == _focusedWindowHandle && _focusedWindowClassName == windowClassName)
157+
return false;
161158

159+
// We see a change in the WindowClassName often - handle that as a focus change too
160+
162161
Debug.Assert(_focusedWindowClassName != _excelToolTipClass); // We don't expect the ToolTip to ever get the focus
163162
Logger.WindowWatcher.Verbose($"Focus lost by {_focusedWindowHandle} ({_focusedWindowClassName})");
164163
// It has changed - raise an event for the old window
@@ -191,21 +190,25 @@ bool UpdateFocus(IntPtr windowHandle, string windowClassName)
191190
// CONSIDER: We would be able to run all the watcher updates from WinEvents, including Location and Selection changes,
192191
// but since WinEvents have no hwnd filter, UIAutomation events might be more efficient.
193192
// CONSIDER: Performance optimisation would keep a list of window handles we know about, preventing the class name check every time
193+
// NOTE: We are not getting OBJID_CURSOR events here - that means we expect to have a valid WindowHandle except when destroyed
194194
void _windowStateChangeHook_WinEventReceived(object sender, WinEventHook.WinEventArgs e)
195195
{
196-
var className = Win32Helper.GetClassName(e.WindowHandle);
196+
if (e.WindowHandle == IntPtr.Zero)
197+
{
198+
Debug.Fail("WinEvent with window 0!?");
199+
}
197200
if (e.EventType == WinEventHook.WinEvent.EVENT_OBJECT_FOCUS)
198201
{
199202
// Might raise change event for Unfocus
200-
if (!UpdateFocus(e.WindowHandle, className))
203+
if (!UpdateFocus(e.WindowHandle, e.WindowClassName))
201204
{
202205
// We already have the right focus
203206
return;
204207
}
205208
}
206209

207210
// Debug.Print("### Thread receiving WindowStateChange: " + Thread.CurrentThread.ManagedThreadId);
208-
switch (className)
211+
switch (e.WindowClassName)
209212
{
210213
//case _sheetWindowClass:
211214
// if (e.EventType == WinEventHook.WinEvent.EVENT_OBJECT_SHOW)

Source/ExcelDna.IntelliSense/Win32Helper.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ enum WM : uint
2929
public static extern IntPtr GetModuleHandle(string lpModuleName);
3030
[DllImport("kernel32.dll")]
3131
static extern uint GetCurrentProcessId();
32-
[DllImport("user32.dll")]
32+
[DllImport("user32.dll", SetLastError = true)]
3333
static extern int GetClassNameW(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder buf, int nMaxCount);
3434

3535
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
@@ -228,7 +228,13 @@ public static uint GetExcelProcessId()
228228
public static string GetClassName(IntPtr hWnd)
229229
{
230230
_buffer.Length = 0;
231-
GetClassNameW(hWnd, _buffer, _buffer.Capacity);
231+
int result = GetClassNameW(hWnd, _buffer, _buffer.Capacity);
232+
if (result == 0)
233+
{
234+
// It failed!?
235+
int error = Marshal.GetLastWin32Error();
236+
Debug.Print($"GetClassName failed on {hWnd}(0x{hWnd:x}) - Error {error}");
237+
}
232238
return _buffer.ToString();
233239
}
234240

0 commit comments

Comments
 (0)