@@ -101,20 +101,24 @@ public IEnumerable<FunctionInfo> GetFunctionInfos()
101101 }
102102 }
103103
104- ExcelSynchronizationContext _syncContextExcel ;
105- XmlIntelliSenseProvider _xmlProvider ;
106- Dictionary < string , XllRegistrationInfo > _xllRegistrationInfos = new Dictionary < string , XllRegistrationInfo > ( ) ;
104+ readonly SynchronizationContext _syncContextMain ; // Main thread, not macro context
105+ readonly ExcelSynchronizationContext _syncContextExcel ; // Proper macro context
106+ readonly XmlIntelliSenseProvider _xmlProvider ;
107+ readonly Dictionary < string , XllRegistrationInfo > _xllRegistrationInfos = new Dictionary < string , XllRegistrationInfo > ( ) ;
107108 LoaderNotification _loaderNotification ;
108109 bool _isDirty ;
110+ SendOrPostCallback _processLoadNotification ;
109111 public event EventHandler Invalidate ;
110112
111- public ExcelDnaIntelliSenseProvider ( )
113+ public ExcelDnaIntelliSenseProvider ( SynchronizationContext syncContextMain )
112114 {
113115 _loaderNotification = new LoaderNotification ( ) ;
114116 _loaderNotification . LoadNotification += loaderNotification_LoadNotification ;
117+ _syncContextMain = syncContextMain ;
115118 _syncContextExcel = new ExcelSynchronizationContext ( ) ;
116119 _xmlProvider = new XmlIntelliSenseProvider ( ) ;
117120 _xmlProvider . Invalidate += ( sender , e ) => OnInvalidate ( null ) ;
121+ _processLoadNotification = ProcessLoadNotification ;
118122 }
119123
120124 #region IIntelliSenseProvider implementation
@@ -188,19 +192,17 @@ public IList<FunctionInfo> GetFunctionInfos()
188192 // TODO: Consider Load/Unload done when AddIns is enumerated...
189193 void loaderNotification_LoadNotification ( object sender , LoaderNotification . NotificationEventArgs e )
190194 {
191- // Debug.Print($"@>@>@>@> LoadNotification: {e.Reason} - {e.FullDllName}");
195+ Debug . Print ( $ "@>@>@>@> LoadNotification: { e . Reason } - { e . FullDllName } ") ;
192196 if ( e . FullDllName . EndsWith ( ".xll" , StringComparison . OrdinalIgnoreCase ) )
193- _syncContextExcel . Post ( ProcessLoadNotification , e ) ;
197+ _syncContextMain . Post ( _processLoadNotification , e ) ;
194198 }
195199
196- // Runs on the main thread, in a macro context
200+ // Runs on the main thread, but not in a macro context
197201 // WARNING: The sequence of calls here, between queued
198202 // instances of ProcessLoadNotification, Refresh and OnInvalidate
199203 // is quite fragile.
200204 void ProcessLoadNotification ( object state )
201205 {
202- Debug . Assert ( Thread . CurrentThread . ManagedThreadId == 1 ) ;
203- // we might want to introduce a delay here, so that the .xll can complete loading...
204206 var notification = ( LoaderNotification . NotificationEventArgs ) state ;
205207 var xllPath = notification . FullDllName ;
206208
@@ -222,7 +224,9 @@ void ProcessLoadNotification(object state)
222224 if ( ! _isDirty )
223225 {
224226 _isDirty = true ;
225- _syncContextExcel . Post ( OnInvalidate , null ) ;
227+ // This call would case trouble while Excel is shutting down.
228+ // CONSIDER: Is there a check we might do.... (and do we in fact get .xll loads during shutdown?)
229+ _syncContextExcel . Post ( OnInvalidate , null ) ;
226230 }
227231
228232 }
@@ -259,8 +263,10 @@ IEnumerable<string> GetLoadedXllPaths()
259263 }
260264 }
261265
266+ // Must be called on the main thread, in a macro context
262267 void OnInvalidate ( object _unused_ )
263268 {
269+ Debug . Assert ( Thread . CurrentThread . ManagedThreadId == 1 ) ;
264270 Invalidate ? . Invoke ( this , EventArgs . Empty ) ;
265271 }
266272
0 commit comments