Skip to content

Commit 4db9c71

Browse files
Additional try/catch handling in DocumentsSyncService (#392)
Adds defensive try-catch blocks with error logging to three VS event handler methods in DocumentsSyncService to prevent unhandled exceptions from destabilizing Visual Studio. VS extensibility callbacks must not throw exceptions. Unhandled exceptions in IVsRunningDocTableEvents can crash Visual Studio or disable the extension.
1 parent 867f465 commit 4db9c71

File tree

1 file changed

+65
-41
lines changed

1 file changed

+65
-41
lines changed

src/Cody.VisualStudio/Services/DocumentsSyncService.cs

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Cody.Core.DocumentSync;
22
using Cody.Core.Logging;
3+
using Cody.Core.Settings;
34
using Cody.Core.Trace;
45
using Microsoft.VisualStudio;
56
using Microsoft.VisualStudio.Editor;
@@ -12,7 +13,7 @@
1213
using System.Collections.Generic;
1314
using System.Diagnostics;
1415
using System.Linq;
15-
using Cody.Core.Settings;
16+
using System.Threading;
1617

1718
namespace Cody.VisualStudio.Services
1819
{
@@ -248,67 +249,90 @@ int IVsRunningDocTableEvents.OnAfterSave(uint docCookie)
248249

249250
int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int fFirstShow, IVsWindowFrame pFrame)
250251
{
251-
trace.TraceEvent("OnBeforeDocumentWindowShow");
252-
if (lastShowDocCookie != docCookie)
252+
try
253253
{
254-
var path = rdt.GetDocumentInfo(docCookie).Moniker;
255-
if (path == null) return VSConstants.S_OK;
256-
257-
if (!isSubscribed.Contains(docCookie))
254+
trace.TraceEvent("OnBeforeDocumentWindowShow");
255+
if (lastShowDocCookie != docCookie)
258256
{
259-
trace.TraceEvent("OnSubscribeDocument", path);
257+
var path = rdt.GetDocumentInfo(docCookie).Moniker;
258+
if (path == null) return VSConstants.S_OK;
260259

261-
var content = rdt.GetRunningDocumentContents(docCookie);
262-
if (content == null) return VSConstants.S_OK;
263-
264-
var textView = GetVsTextView(pFrame);
265-
if (textView != null)
260+
if (!isSubscribed.Contains(docCookie))
266261
{
267-
var wpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView);
268-
if (wpfTextView != null)
269-
{
270-
Subscribe(wpfTextView);
262+
trace.TraceEvent("OnSubscribeDocument", path);
271263

272-
if (!openNotificationSend.Contains(docCookie))
273-
{
274-
275-
var docRange = GetDocumentSelection(wpfTextView);
276-
var visibleRange = GetVisibleRange(wpfTextView);
264+
var content = rdt.GetRunningDocumentContents(docCookie);
265+
if (content == null) return VSConstants.S_OK;
277266

278-
documentActions.OnOpened(path, content, visibleRange, docRange);
279-
openNotificationSend.Add(docCookie);
267+
var textView = GetVsTextView(pFrame);
268+
if (textView != null)
269+
{
270+
var wpfTextView = editorAdaptersFactoryService.GetWpfTextView(textView);
271+
if (wpfTextView != null)
272+
{
273+
Subscribe(wpfTextView, path, docCookie, content);
280274
}
281-
282-
isSubscribed.Add(docCookie);
283275
}
284276
}
285-
}
286277

287-
trace.TraceEvent("OnDocumentFocus", path);
288-
documentActions.OnFocus(path);
278+
trace.TraceEvent("OnDocumentFocus", path);
279+
documentActions.OnFocus(path);
289280

290-
lastShowDocCookie = docCookie;
281+
lastShowDocCookie = docCookie;
282+
}
283+
}
284+
catch (Exception ex)
285+
{
286+
log.Error("OnBeforeDocumentWindowShow failed", ex);
291287
}
292288

293289
return VSConstants.S_OK;
294290
}
295291

296-
private void Subscribe(IWpfTextView textView)
292+
private void Subscribe(IWpfTextView textView, string path, uint docCookie, string content)
297293
{
298-
textView.TextBuffer.Properties.AddProperty(typeof(IWpfTextView), textView);
299-
textView.Selection.SelectionChanged += OnSelectionChanged;
300-
textView.TextBuffer.ChangedLowPriority += OnTextBufferChanged;
301-
textView.Closed += UnsubscribeOnClosed;
294+
try
295+
{
296+
297+
textView.TextBuffer.Properties.AddProperty(typeof(IWpfTextView), textView);
298+
textView.Selection.SelectionChanged += OnSelectionChanged;
299+
textView.TextBuffer.ChangedLowPriority += OnTextBufferChanged;
300+
textView.Closed += UnsubscribeOnClosed;
301+
302+
if (!openNotificationSend.Contains(docCookie))
303+
{
304+
305+
var docRange = GetDocumentSelection(textView);
306+
var visibleRange = GetVisibleRange(textView);
307+
308+
documentActions.OnOpened(path, content, visibleRange, docRange);
309+
openNotificationSend.Add(docCookie);
310+
}
311+
312+
isSubscribed.Add(docCookie);
313+
314+
}
315+
catch (Exception ex)
316+
{
317+
log.Error("Subscribe failed", ex);
318+
}
302319
}
303320

304321
private void UnsubscribeOnClosed(object sender, EventArgs e)
305322
{
306-
var textView = (IWpfTextView)sender;
323+
try
324+
{
325+
var textView = (IWpfTextView)sender;
307326

308-
textView.TextBuffer.Properties.RemoveProperty(typeof(IWpfTextView));
309-
textView.Selection.SelectionChanged -= OnSelectionChanged;
310-
textView.TextBuffer.ChangedLowPriority -= OnTextBufferChanged;
311-
textView.Closed -= UnsubscribeOnClosed;
327+
textView.TextBuffer.Properties.RemoveProperty(typeof(IWpfTextView));
328+
textView.Selection.SelectionChanged -= OnSelectionChanged;
329+
textView.TextBuffer.ChangedLowPriority -= OnTextBufferChanged;
330+
textView.Closed -= UnsubscribeOnClosed;
331+
}
332+
catch (Exception ex)
333+
{
334+
log.Error("Unsubscribe failed", ex);
335+
}
312336
}
313337

314338
int IVsRunningDocTableEvents.OnAfterDocumentWindowHide(uint docCookie, IVsWindowFrame pFrame) => VSConstants.S_OK;
@@ -422,7 +446,7 @@ public int OnAfterAttributeChangeEx(uint docCookie, uint grfAttribs, IVsHierarch
422446
{
423447
trace.TraceEvent("OnRename");
424448
documentActions.OnRename(pszMkDocumentOld, pszMkDocumentNew);
425-
}
449+
}
426450
return VSConstants.S_OK;
427451
}
428452
}

0 commit comments

Comments
 (0)