Skip to content

Commit c1648dc

Browse files
committed
Fix automation event handler threading
Prevent tooltip window from getting focus
1 parent 14a5535 commit c1648dc

File tree

5 files changed

+80
-31
lines changed

5 files changed

+80
-31
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseDisplay.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -167,21 +167,22 @@ void StateUpdate(object sender, UIStateUpdate update)
167167
// Runs on the main thread
168168
void UpdateMainWindow(IntPtr mainWindow)
169169
{
170-
if (_mainWindow != mainWindow &&
171-
(_descriptionToolTip != null ||
172-
_argumentsToolTip != null ))
170+
if (_mainWindow != mainWindow)
173171
{
174-
if (_descriptionToolTip != null)
175-
{
176-
_descriptionToolTip.Dispose();
177-
_descriptionToolTip = new ToolTipForm(_mainWindow);
178-
}
179-
if (_argumentsToolTip != null)
172+
_mainWindow = mainWindow;
173+
if (_descriptionToolTip != null || _argumentsToolTip != null)
180174
{
181-
_argumentsToolTip.Dispose();
182-
_argumentsToolTip = new ToolTipForm(_mainWindow);
175+
if (_descriptionToolTip != null)
176+
{
177+
_descriptionToolTip.Dispose();
178+
_descriptionToolTip = new ToolTipForm(_mainWindow);
179+
}
180+
if (_argumentsToolTip != null)
181+
{
182+
_argumentsToolTip.Dispose();
183+
_argumentsToolTip = new ToolTipForm(_mainWindow);
184+
}
183185
}
184-
_mainWindow = mainWindow;
185186
}
186187
}
187188

Source/ExcelDna.IntelliSense/SingleThreadSynchronizationContext.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ namespace ExcelDna.IntelliSense
1212
sealed class SingleThreadSynchronizationContext : SynchronizationContext
1313
{
1414
/// <summary>The queue of work items.</summary>
15-
readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> m_queue =
15+
readonly BlockingCollection<KeyValuePair<SendOrPostCallback, object>> _queue =
1616
new BlockingCollection<KeyValuePair<SendOrPostCallback, object>>();
17+
int _threadId = 0;
1718

1819
// /// <summary>The processing thread.</summary>
1920
// readonly Thread m_thread = Thread.CurrentThread;
@@ -24,19 +25,29 @@ sealed class SingleThreadSynchronizationContext : SynchronizationContext
2425
public override void Post(SendOrPostCallback d, object state)
2526
{
2627
if (d == null) throw new ArgumentNullException("d");
27-
m_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
28+
_queue.Add(new KeyValuePair<SendOrPostCallback, object>(d, state));
2829
}
2930

30-
/// <summary>Not supported.</summary>
3131
public override void Send(SendOrPostCallback d, object state)
3232
{
33-
throw new NotSupportedException("Synchronously sending is not supported.");
33+
if (Thread.CurrentThread.ManagedThreadId == _threadId)
34+
{
35+
d(state);
36+
return;
37+
}
38+
39+
// We're being called on another thread...
40+
AutoResetEvent ev = new AutoResetEvent(false);
41+
Post(d, state);
42+
Post((object are) => ((AutoResetEvent)are).Set(), ev);
43+
ev.WaitOne();
3444
}
3545

3646
/// <summary>Runs a loop to process all queued work items.</summary>
3747
public void RunOnCurrentThread()
3848
{
39-
foreach (var workItem in m_queue.GetConsumingEnumerable())
49+
_threadId = Thread.CurrentThread.ManagedThreadId;
50+
foreach (var workItem in _queue.GetConsumingEnumerable())
4051
{
4152
try
4253
{
@@ -52,6 +63,6 @@ public void RunOnCurrentThread()
5263
}
5364

5465
/// <summary>Notifies the context that no more work will arrive.</summary>
55-
public void Complete() { m_queue.CompleteAdding(); }
66+
public void Complete() { _queue.CompleteAdding(); }
5667
}
5768
}

Source/ExcelDna.IntelliSense/ToolTipForm.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,28 @@ class ToolTipForm : Form
1919

2020
public ToolTipForm(IntPtr hwndOwner)
2121
{
22+
Debug.Assert(hwndOwner != IntPtr.Zero);
2223
InitializeComponent();
2324
_owner = new Win32Window(hwndOwner);
2425
// _owner = new NativeWindow();
2526
// _owner.AssignHandle(hwndParent); (...with ReleaseHandle in Dispose)
2627
Debug.Print($"Created ToolTipForm with owner {hwndOwner}");
2728
}
2829

30+
protected override void DefWndProc(ref Message m)
31+
{
32+
const int WM_MOUSEACTIVATE = 0x21;
33+
const int MA_NOACTIVATE = 0x0003;
34+
35+
switch(m.Msg)
36+
{
37+
case WM_MOUSEACTIVATE:
38+
m.Result = (IntPtr)MA_NOACTIVATE;
39+
return;
40+
}
41+
base.DefWndProc(ref m);
42+
}
43+
2944
public void ShowToolTip()
3045
{
3146
try
@@ -85,16 +100,19 @@ protected override bool ShowWithoutActivation
85100
// }
86101
//}
87102

88-
const int CS_DROPSHADOW = 0x00020000;
89-
const int WS_EX_TOOLWINDOW = 0x00000080;
90-
const int WS_EX_NOACTIVATE = 0x08000000;
103+
91104
protected override CreateParams CreateParams
92105
{
93106
get
94107
{
108+
const int CS_DROPSHADOW = 0x00020000;
109+
const int WS_CHILD = 0x40000000;
110+
const int WS_EX_TOOLWINDOW = 0x00000080;
111+
const int WS_EX_NOACTIVATE = 0x08000000;
95112
// NOTE: I've seen exception with invalid handle in the base.CreateParams call here...
96113
CreateParams baseParams = base.CreateParams;
97114
baseParams.ClassStyle |= CS_DROPSHADOW;
115+
baseParams.Style |= WS_CHILD;
98116
baseParams.ExStyle |= ( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );
99117
return baseParams;
100118
}

Source/ExcelDna.IntelliSense/ToolTipForm.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,7 @@
120120
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
121121
<value>17, 17</value>
122122
</metadata>
123+
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
124+
<value>17, 17</value>
125+
</metadata>
123126
</root>

Source/ExcelDna.IntelliSense/Watchers.cs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ void _windowWatcher_MainWindowChanged(object sender, EventArgs args)
592592
}
593593
catch (Exception ex)
594594
{
595-
Debug.Print("!!! Error gettting main window from handle");
595+
Debug.Print($"!!! Error gettting main window from handle: {ex.Message}");
596596
}
597597
}
598598
}
@@ -670,11 +670,19 @@ void PopupListStructureChangedHandler(object sender, StructureChangedEventArgs e
670670
var selPat = listElement.GetCurrentPattern(SelectionPattern.Pattern) as SelectionPattern;
671671
Debug.Assert(selPat != null);
672672

673-
_syncContextAuto.Send( _ =>
674-
{
675-
Automation.AddAutomationEventHandler(
676-
SelectionItemPattern.ElementSelectedEvent, _popupListList, TreeScope.Descendants /* was .Children */, PopupListElementSelectedHandler);
677-
}, null);
673+
// CONSIDER: Send might be a bit disruptive here / might not be necessary...
674+
// _syncContextAuto.Send( _ =>
675+
//{
676+
try
677+
{
678+
Automation.AddAutomationEventHandler(
679+
SelectionItemPattern.ElementSelectedEvent, _popupListList, TreeScope.Descendants /* was .Children */, PopupListElementSelectedHandler);
680+
}
681+
catch (Exception ex)
682+
{
683+
Debug.Print("Error during AddAutomationEventHandler! " + ex);
684+
}
685+
//}, null);
678686

679687
// Update the current selection, if any
680688
var curSel = selPat.Current.GetSelection();
@@ -700,10 +708,18 @@ void PopupListStructureChangedHandler(object sender, StructureChangedEventArgs e
700708
{
701709
if (_popupListList != null)
702710
{
703-
_syncContextAuto.Send( _ =>
704-
{
705-
Automation.RemoveAutomationEventHandler(SelectionItemPattern.ElementSelectedEvent, _popupListList, PopupListElementSelectedHandler);
706-
}, null);
711+
// CONSIDER: Send might be a bit disruptive here / might not be necessary...
712+
//_syncContextAuto.Send( _ =>
713+
//{
714+
try
715+
{
716+
Automation.RemoveAutomationEventHandler(SelectionItemPattern.ElementSelectedEvent, _popupListList, PopupListElementSelectedHandler);
717+
}
718+
catch (Exception ex)
719+
{
720+
Debug.Print("Error during RemoveAutomationEventHandler! " + ex);
721+
}
722+
//}, null);
707723
_popupListList = null;
708724
}
709725
_selectedItem = null;

0 commit comments

Comments
 (0)