Skip to content

Commit d1d7361

Browse files
committed
Implement IntelliSenseServer.Refresh()
1 parent d3b0bed commit d1d7361

File tree

3 files changed

+89
-7
lines changed

3 files changed

+89
-7
lines changed

Source/ExcelDna.IntelliSense/IntelliSenseServer.cs

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public static class IntelliSenseServer
4242

4343
const string ControlMessageActivate = "ACTIVATE";
4444
const string ControlMessageDeactivate = "DEACTIVATE";
45+
const string ControlMessageRefresh = "REFRESH";
4546

4647
// Info for registration
4748
// _serverId is a transient ID to identify this IntelliSense server - we could have used the ExcelDnaUtil.XllGuid one too,
@@ -95,6 +96,25 @@ public static void Register()
9596
Logger.Initialization.Info("IntelliSenseServer.Register End");
9697
}
9798

99+
// Invokes a Refresh on the Active server (if there is on)
100+
// Must be called from a macro context
101+
// Appropriate for calling after registering extra methods in an add-in
102+
public static void Refresh()
103+
{
104+
Logger.Initialization.Info($"IntelliSenseServer.Refresh Begin");
105+
if (_isActive)
106+
{
107+
RefreshProviders();
108+
}
109+
else
110+
{
111+
RegistrationInfo registrationInfo = GetActiveRegistrationInfo();
112+
if (registrationInfo != null)
113+
RefreshServer(registrationInfo);
114+
}
115+
Logger.Initialization.Info($"IntelliSenseServer.Refresh End");
116+
}
117+
98118
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
99119
{
100120
Logger.Initialization.Verbose("IntelliSenseServer ProcessExit Begin");
@@ -170,6 +190,22 @@ internal static bool Deactivate()
170190
}
171191
}
172192

193+
// Called directly from Refresh or via the control function
194+
internal static void RefreshProviders()
195+
{
196+
Logger.Initialization.Info($"IntelliSenseServer.RefreshProviders");
197+
try
198+
{
199+
Debug.Assert(_helper != null);
200+
_helper.RefreshProviders();
201+
}
202+
catch (Exception ex)
203+
{
204+
// TODO: Log
205+
Logger.Initialization.Error($"IntelliSenseServer.RefreshProviders error: {ex}");
206+
}
207+
}
208+
173209
// NOTE: Please do not remove this safety mechanism in custom versions.
174210
// The IntelliSense mechanism is co-operative between independent add-ins.
175211
// Allowing a safe disable options is important to support future versions, and protect against problematic bugs.
@@ -200,7 +236,7 @@ static bool ActivateServer(RegistrationInfo registrationInfo)
200236
// Suppress errors if things go wrong, including unexpected return types.
201237
try
202238
{
203-
var result = ExcelDna.Integration.XlCall.Excel(ExcelDna.Integration.XlCall.xlUDF, registrationInfo.GetControlMacroName(), ControlMessageDeactivate);
239+
var result = ExcelDna.Integration.XlCall.Excel(ExcelDna.Integration.XlCall.xlUDF, registrationInfo.GetControlMacroName(), ControlMessageActivate);
204240
return (bool)result;
205241
}
206242
catch (Exception ex)
@@ -232,6 +268,26 @@ static bool DeactivateServer(RegistrationInfo registrationInfo)
232268
}
233269
}
234270

271+
static bool RefreshServer(RegistrationInfo registrationInfo)
272+
{
273+
// Suppress errors if things go wrong, including unexpected return types.
274+
try
275+
{
276+
var result = ExcelDna.Integration.XlCall.Excel(ExcelDna.Integration.XlCall.xlUDF, registrationInfo.GetControlMacroName(), ControlMessageRefresh);
277+
if (result is ExcelError)
278+
{
279+
Logger.Initialization.Error($"IntelliSenseServer {registrationInfo.ToRegistrationString()} could not be deactivated.");
280+
return false;
281+
}
282+
return (bool)result;
283+
}
284+
catch (Exception ex)
285+
{
286+
Logger.Initialization.Error(ex, $"IntelliSenseServer Deactivate call for {registrationInfo.ToRegistrationString()} failed.");
287+
return false;
288+
}
289+
}
290+
235291
#region Registration
236292

237293
// NOTE: We have to be really careful about compatibility across versions here...
@@ -434,15 +490,28 @@ static void RegisterControlMacro()
434490
// NOTE: The name here is used by Reflection above (when registering the method with Excel)
435491
static object IntelliSenseServerControl(object control)
436492
{
437-
if (control is string && (string)control == ControlMessageActivate)
493+
string controlMessage = control as string;
494+
if (controlMessage == ControlMessageActivate)
438495
{
439496
Debug.Print("IntelliSenseServer.Activate in AppDomain: " + AppDomain.CurrentDomain.FriendlyName);
440-
return IntelliSenseServer.Activate();
497+
return Activate();
441498
}
442-
else if (control is string && (string)control == ControlMessageDeactivate)
499+
else if (controlMessage == ControlMessageDeactivate)
443500
{
444501
Debug.Print("IntelliSenseServer.Deactivate in AppDomain: " + AppDomain.CurrentDomain.FriendlyName);
445-
return IntelliSenseServer.Deactivate();
502+
return Deactivate();
503+
}
504+
else if (controlMessage == ControlMessageRefresh)
505+
{
506+
Debug.Print("IntelliSenseServer.Refresh in AppDomain: " + AppDomain.CurrentDomain.FriendlyName);
507+
if (!_isActive)
508+
{
509+
// Something went wrong...
510+
Logger.Initialization.Error("IntelliSenseServer Refresh call on inactive server.");
511+
return false;
512+
}
513+
RefreshProviders();
514+
return true;
446515
}
447516
return false;
448517
}

Source/ExcelDna.IntelliSense/IntellisenseHelper.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ void UpdateDisplay(IIntelliSenseProvider provider)
6868
_display.UpdateFunctionInfos(functionInfos);
6969
}
7070

71+
// Must be called on the main thread, in a macro context
72+
// TODO: Still not sure how to delete / unregister...
73+
internal void RefreshProviders()
74+
{
75+
foreach (var provider in _providers)
76+
{
77+
RefreshProvider(provider);
78+
}
79+
}
80+
7181
public void Dispose()
7282
{
7383
Logger.Initialization.Verbose("IntelliSenseHelper Dispose Start");

Source/ExcelDna.IntelliSense/Providers/ExcelDnaIntelliSenseProvider.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void Refresh()
3434
if (regInfoResponse.Equals(ExcelError.ExcelErrorNA))
3535
{
3636
_regInfoNotAvailable = true;
37-
Logger.Provider.Verbose($"XllRegistrationInfo not available for {_xllPath}");
37+
Logger.Provider.Info($"XllRegistrationInfo not available for {_xllPath}");
3838
return;
3939
}
4040

@@ -175,7 +175,7 @@ public IList<FunctionInfo> GetFunctionInfos()
175175

176176
#endregion
177177

178-
// DANGER: Still subject to LoaderLock problem...
178+
// DANGER: Still subject to LoaderLock warning ...
179179
// TODO: Consider Load/Unload done when AddIns is enumerated...
180180
void loaderNotification_LoadNotification(object sender, LoaderNotification.NotificationEventArgs e)
181181
{
@@ -185,6 +185,9 @@ void loaderNotification_LoadNotification(object sender, LoaderNotification.Notif
185185
}
186186

187187
// Runs on the main thread, in a macro context
188+
// WARNING: The sequence of calls here, between queued
189+
// instances of ProcessLoadNotification, Refresh and OnInvalidate
190+
// is quite fragile.
188191
void ProcessLoadNotification(object state)
189192
{
190193
Debug.Assert(Thread.CurrentThread.ManagedThreadId == 1);

0 commit comments

Comments
 (0)