Skip to content

Commit 04d1890

Browse files
authored
Merge pull request #240 from tonyhallett/threading
Threading
2 parents 401c45e + d4587e1 commit 04d1890

File tree

9 files changed

+92
-98
lines changed

9 files changed

+92
-98
lines changed

SharedProject/Core/Model/CoverageProject.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.IO;
44
using System.Linq;
55
using System.Threading.Tasks;
6+
using Task = System.Threading.Tasks.Task;
67
using System.Xml.Linq;
78
using System.Xml.XPath;
89
using EnvDTE;
@@ -355,7 +356,7 @@ public XElement ProjectFileXElement
355356
public bool Is64Bit { get; set; }
356357
public string RunSettingsFile { get; set; }
357358

358-
public async System.Threading.Tasks.Task StepAsync(string stepName, Func<ICoverageProject, System.Threading.Tasks.Task> action)
359+
public async Task StepAsync(string stepName, Func<ICoverageProject, Task> action)
359360
{
360361
if (HasFailed)
361362
{
@@ -380,7 +381,7 @@ public async System.Threading.Tasks.Task StepAsync(string stepName, Func<ICovera
380381
}
381382
}
382383

383-
public async System.Threading.Tasks.Task<CoverageProjectFileSynchronizationDetails> PrepareForCoverageAsync()
384+
public async Task<CoverageProjectFileSynchronizationDetails> PrepareForCoverageAsync()
384385
{
385386
EnsureDirectories();
386387
CleanFCCDirectory();
@@ -389,7 +390,7 @@ public async System.Threading.Tasks.Task<CoverageProjectFileSynchronizationDetai
389390
return synchronizationDetails;
390391
}
391392

392-
private async System.Threading.Tasks.Task SetIncludedExcludedReferencedProjectsAsync()
393+
private async Task SetIncludedExcludedReferencedProjectsAsync()
393394
{
394395
List<ReferencedProject> referencedProjects = await GetReferencedProjectsAsync();
395396
SetExcludedReferencedProjects(referencedProjects);

SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Text;
77
using System.Threading.Tasks;
8+
using Task = System.Threading.Tasks.Task;
89
using System.Windows;
910
using ExCSS;
1011
using FineCodeCoverage.Core.Utilities;
@@ -25,8 +26,8 @@ interface IReportGeneratorUtil
2526
string ProcessUnifiedHtml(string htmlForProcessing,string reportOutputFolder);
2627
Task<ReportGeneratorResult> GenerateAsync(IEnumerable<string> coverOutputFiles,string reportOutputFolder, bool throwError = false);
2728
string BlankReport(bool withHistory);
28-
System.Threading.Tasks.Task LogCoverageProcessAsync(string message);
29-
System.Threading.Tasks.Task EndOfCoverageRunAsync();
29+
Task LogCoverageProcessAsync(string message);
30+
Task EndOfCoverageRunAsync();
3031
}
3132

3233
internal class ReportGeneratorResult
@@ -124,12 +125,12 @@ IEventAggregator eventAggregator
124125
scriptManager.ShowFCCOutputPaneEvent += ScriptManager_ShowFCCOutputPaneEvent;
125126
}
126127

127-
private async void ScriptManager_ShowFCCOutputPaneEvent(object sender, EventArgs e)
128+
private void ScriptManager_ShowFCCOutputPaneEvent(object sender, EventArgs e)
128129
{
129-
await showFCCOutputPane.ShowAsync();
130+
_ = ThreadHelper.JoinableTaskFactory.RunAsync(() => showFCCOutputPane.ShowAsync());
130131
}
131132

132-
private void ScriptManager_ClearFCCWindowLogsEvent(object sender, EventArgs e)
133+
private void ScriptManager_ClearFCCWindowLogsEvent(object sender, EventArgs e)
133134
{
134135
logs.Clear();
135136
}
@@ -1686,14 +1687,14 @@ public string BlankReport(bool withHistory)
16861687
return ProcessUnifiedHtml(resourceProvider.ReadResource("dummyReportToProcess.html"),null);
16871688
}
16881689

1689-
public async System.Threading.Tasks.Task LogCoverageProcessAsync(string message)
1690+
public async Task LogCoverageProcessAsync(string message)
16901691
{
16911692
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
16921693
eventAggregator.SendMessage(new InvokeScriptMessage(CoverageLogJSFunctionName, message));
16931694
logs.Add(message);
16941695
}
16951696

1696-
public async System.Threading.Tasks.Task EndOfCoverageRunAsync()
1697+
public async Task EndOfCoverageRunAsync()
16971698
{
16981699
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
16991700
eventAggregator.SendMessage(new InvokeScriptMessage(ShowFCCWorkingJSFunctionName, false));

SharedProject/Impl/CoverageColorProvider.cs

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,29 +102,33 @@ private void UpdateFromFontsAndColorsIfNecessary()
102102

103103
private void UpdateColoursFromFontsAndColors()
104104
{
105-
ThreadHelper.ThrowIfNotOnUIThread();
106-
var success = fontAndColorStorage.OpenCategory(ref categoryWithCoverage, storeFlags);
107-
if (success == VSConstants.S_OK)
105+
ThreadHelper.JoinableTaskFactory.Run(async () =>
108106
{
109-
CoverageTouchedArea = GetColor("Coverage Touched Area");
110-
CoverageNotTouchedArea = GetColor("Coverage Not Touched Area");
111-
CoveragePartiallyTouchedArea = GetColor("Coverage Partially Touched Area");
112-
}
113-
fontAndColorStorage.CloseCategory();
114-
//throw ?
115-
requiresFromFontsAndColours = false;
116-
}
117-
118-
private System.Windows.Media.Color GetColor(string displayName)
119-
{
120-
ThreadHelper.ThrowIfNotOnUIThread();
121-
var touchAreaInfo = new ColorableItemInfo[1];
122-
var getItemSuccess = fontAndColorStorage.GetItem(displayName, touchAreaInfo);
123-
if (getItemSuccess == VSConstants.S_OK)
124-
{
125-
return ParseColor(touchAreaInfo[0].crBackground);
126-
}
127-
throw new Exception("Failed to get color");
107+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
108+
var success = fontAndColorStorage.OpenCategory(ref categoryWithCoverage, storeFlags);
109+
if (success == VSConstants.S_OK)
110+
{
111+
// https://github.com/microsoft/vs-threading/issues/993
112+
System.Windows.Media.Color GetColor(string displayName)
113+
{
114+
var touchAreaInfo = new ColorableItemInfo[1];
115+
var getItemSuccess = fontAndColorStorage.GetItem(displayName, touchAreaInfo);
116+
if (getItemSuccess == VSConstants.S_OK)
117+
{
118+
return ParseColor(touchAreaInfo[0].crBackground);
119+
}
120+
throw new Exception("Failed to get color");
121+
}
122+
123+
CoverageTouchedArea = GetColor("Coverage Touched Area");
124+
CoverageNotTouchedArea = GetColor("Coverage Not Touched Area");
125+
CoveragePartiallyTouchedArea = GetColor("Coverage Partially Touched Area");
126+
}
127+
fontAndColorStorage.CloseCategory();
128+
//throw ?
129+
requiresFromFontsAndColours = false;
130+
});
131+
128132
}
129133

130134
private System.Windows.Media.Color ParseColor(uint color)
@@ -133,7 +137,6 @@ private System.Windows.Media.Color ParseColor(uint color)
133137
return System.Windows.Media.Color.FromArgb(dcolor.A, dcolor.R, dcolor.G, dcolor.B);
134138
}
135139

136-
137140
}
138141

139142
}

SharedProject/Impl/Logger.cs

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
using System.Linq;
33
using FineCodeCoverage;
44
using System.Diagnostics;
5-
using Microsoft.VisualStudio;
65
using System.Collections.Generic;
76
using Microsoft.VisualStudio.Shell;
87
using System.Diagnostics.CodeAnalysis;
98
using Microsoft.VisualStudio.Shell.Interop;
109
using System.ComponentModel.Composition;
1110
using Microsoft;
12-
using EnvDTE;
11+
using Task = System.Threading.Tasks.Task;
12+
using EnvDTE80;
1313

1414
interface IShowFCCOutputPane
1515
{
16-
System.Threading.Tasks.Task ShowAsync();
16+
Task ShowAsync();
1717
}
1818
[Export(typeof(IShowFCCOutputPane))]
1919
[Export(typeof(ILogger))]
2020
public class Logger : ILogger, IShowFCCOutputPane
2121
{
2222
private IVsOutputWindowPane _pane;
2323
private IVsOutputWindow _outputWindow;
24-
private DTE dte;
24+
private DTE2 dte;
2525
private readonly IServiceProvider _serviceProvider;
2626
private Guid fccPaneGuid = Guid.Parse("3B3C775A-0050-445D-9022-0230957805B2");
2727

@@ -35,33 +35,27 @@ IServiceProvider serviceProvider
3535
staticLogger = this;
3636
}
3737

38-
IVsOutputWindowPane CreatePane(Guid paneGuid, string title,
39-
bool visible, bool clearWithSolution)
40-
{
41-
42-
ThreadHelper.ThrowIfNotOnUIThread();
43-
_outputWindow = (IVsOutputWindow)_serviceProvider.GetService(typeof(SVsOutputWindow));
44-
Assumes.Present(_outputWindow);
45-
dte = (EnvDTE.DTE)_serviceProvider.GetService(typeof(EnvDTE.DTE));
46-
Assumes.Present(dte);
47-
48-
// Create a new pane.
49-
_outputWindow.CreatePane(
50-
ref paneGuid,
51-
title,
52-
Convert.ToInt32(visible),
53-
Convert.ToInt32(clearWithSolution));
54-
55-
// Retrieve the new pane.
56-
_outputWindow.GetPane(ref paneGuid, out IVsOutputWindowPane pane);
57-
return pane;
58-
}
59-
6038
private void SetPane()
6139
{
62-
ThreadHelper.ThrowIfNotOnUIThread();
63-
// do not clear with solution otherwise will not get initialize methods
64-
_pane = CreatePane(fccPaneGuid, "FCC", true, false);
40+
ThreadHelper.JoinableTaskFactory.Run(async () =>
41+
{
42+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
43+
_outputWindow = (IVsOutputWindow)_serviceProvider.GetService(typeof(SVsOutputWindow));
44+
Assumes.Present(_outputWindow);
45+
dte = (DTE2)_serviceProvider.GetService(typeof(EnvDTE.DTE));
46+
Assumes.Present(dte);
47+
48+
// Create a new pane.
49+
_outputWindow.CreatePane(
50+
ref fccPaneGuid,
51+
"FCC",
52+
Convert.ToInt32(true),
53+
Convert.ToInt32(false)); // do not clear with solution otherwise will not get initialize methods
54+
55+
// Retrieve the new pane.
56+
_outputWindow.GetPane(ref fccPaneGuid, out IVsOutputWindowPane pane);
57+
_pane = pane;
58+
});
6559
}
6660

6761
[SuppressMessage("Usage", "VSTHRD102:Implement internal logic asynchronously")]
@@ -154,7 +148,7 @@ public void LogWithoutTitle(IEnumerable<string> message)
154148
LogImpl(message.ToArray(), false);
155149
}
156150

157-
public async System.Threading.Tasks.Task ShowAsync()
151+
public async Task ShowAsync()
158152
{
159153
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
160154

SharedProject/Impl/TestContainerDiscovery/PackageInitializer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@ public void Initialize()
4141

4242
if (File.Exists(outputWindowInitializedFile))
4343
{
44-
OutputToolWindowCommand.Instance.FindToolWindow();
44+
await OutputToolWindowCommand.Instance.FindToolWindowAsync();
4545
}
4646
else
4747
{
4848
// for first time users, the window is automatically docked
49-
OutputToolWindowCommand.Instance.ShowToolWindow();
49+
await OutputToolWindowCommand.Instance.ShowToolWindowAsync();
5050
File.WriteAllText(outputWindowInitializedFile, string.Empty);
5151
}
5252
}

SharedProject/Options/AppOptions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ You can also ignore additional attributes by adding to this list (short name or
175175
[Description("Set to true to hide classes, namespaces and assemblies that are fully covered.")]
176176
public bool HideFullyCovered { get; set; }
177177

178-
[SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")]
179178
public override void SaveSettingsToStorage()
180179
{
181180
AppOptionsStorageProvider.SaveSettingsToStorage(this);

SharedProject/Options/AppOptionsProvider.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,21 @@ public IAppOptions Get()
3535
return options;
3636
}
3737

38-
[SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")]
3938
private WritableSettingsStore EnsureStore()
4039
{
41-
var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider);
42-
var settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
43-
44-
if (!settingsStore.CollectionExists(Vsix.Code))
40+
WritableSettingsStore settingsStore = null;
41+
ThreadHelper.JoinableTaskFactory.Run(async () =>
4542
{
46-
settingsStore.CreateCollection(Vsix.Code);
47-
}
43+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
44+
var settingsManager = new ShellSettingsManager(ServiceProvider.GlobalProvider);
45+
settingsStore = settingsManager.GetWritableSettingsStore(SettingsScope.UserSettings);
46+
47+
if (!settingsStore.CollectionExists(Vsix.Code))
48+
{
49+
settingsStore.CreateCollection(Vsix.Code);
50+
}
51+
});
52+
4853
return settingsStore;
4954
}
5055

@@ -53,7 +58,6 @@ private PropertyInfo[] ReflectProperties()
5358
return AppOptionsType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
5459
}
5560

56-
[SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")]
5761
public void LoadSettingsFromStorage(AppOptions instance)
5862
{
5963
var settingsStore = EnsureStore();
@@ -85,7 +89,7 @@ public void LoadSettingsFromStorage(AppOptions instance)
8589
}
8690
}
8791
}
88-
[SuppressMessage("Usage", "VSTHRD010:Invoke single-threaded types on Main thread")]
92+
8993
public void SaveSettingsToStorage(AppOptions appOptions)
9094
{
9195
var settingsStore = EnsureStore();

SharedProject/Output/OutputToolWindowCommand.cs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.ComponentModel.Design;
33
using Microsoft.VisualStudio.Shell;
4+
using System.Threading.Tasks;
45
using Task = System.Threading.Tasks.Task;
56

67
namespace FineCodeCoverage.Output
@@ -82,39 +83,29 @@ public static async Task InitializeAsync(AsyncPackage package)
8283
/// <param name="e">The event args.</param>
8384
public void Execute(object sender, EventArgs e)
8485
{
85-
ShowToolWindow();
86+
_ = ThreadHelper.JoinableTaskFactory.RunAsync(ShowToolWindowAsync);
8687
}
8788

88-
public ToolWindowPane ShowToolWindow()
89+
public async Task<ToolWindowPane> ShowToolWindowAsync()
8990
{
90-
ToolWindowPane window = null;
91+
ToolWindowPane window = await package.ShowToolWindowAsync(typeof(OutputToolWindow), 0, true, package.DisposalToken);
9192

92-
package.JoinableTaskFactory.RunAsync(async delegate
93+
if ((null == window) || (null == window.Frame))
9394
{
94-
window = await package.ShowToolWindowAsync(typeof(OutputToolWindow), 0, true, package.DisposalToken);
95-
96-
if ((null == window) || (null == window.Frame))
97-
{
98-
throw new NotSupportedException($"Cannot create '{Vsix.Name}' output window");
99-
}
100-
});
95+
throw new NotSupportedException($"Cannot create '{Vsix.Name}' output window");
96+
}
10197

10298
return window;
10399
}
104100

105-
public ToolWindowPane FindToolWindow()
101+
public async Task<ToolWindowPane> FindToolWindowAsync()
106102
{
107-
ToolWindowPane window = null;
103+
ToolWindowPane window = await package.FindToolWindowAsync(typeof(OutputToolWindow), 0, true, package.DisposalToken);
108104

109-
package.JoinableTaskFactory.RunAsync(async delegate
105+
if ((null == window) || (null == window.Frame))
110106
{
111-
window = await package.FindToolWindowAsync(typeof(OutputToolWindow), 0, true, package.DisposalToken);
112-
113-
if ((null == window) || (null == window.Frame))
114-
{
115-
throw new NotSupportedException($"Cannot create '{Vsix.Name}' output window");
116-
}
117-
});
107+
throw new NotSupportedException($"Cannot create '{Vsix.Name}' output window");
108+
}
118109

119110
return window;
120111
}

SharedProject/Output/OutputToolWindowPackage.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Runtime.InteropServices;
66
using System.Diagnostics.CodeAnalysis;
77
using System.ComponentModel.Composition;
8+
using System.Threading.Tasks;
89
using Task = System.Threading.Tasks.Task;
910
using Microsoft.VisualStudio.Shell.Interop;
1011
using EnvDTE80;
@@ -91,9 +92,9 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
9192
await ClearUICommand.InitializeAsync(this, componentModel.GetService<IFCCEngine>());
9293
}
9394

94-
protected override System.Threading.Tasks.Task<object> InitializeToolWindowAsync(Type toolWindowType, int id, CancellationToken cancellationToken)
95+
protected override Task<object> InitializeToolWindowAsync(Type toolWindowType, int id, CancellationToken cancellationToken)
9596
{
96-
return System.Threading.Tasks.Task.FromResult<object>(GetOutputToolWindowContext());
97+
return Task.FromResult<object>(GetOutputToolWindowContext());
9798
}
9899
public override IVsAsyncToolWindowFactory GetAsyncToolWindowFactory(Guid toolWindowType)
99100
{

0 commit comments

Comments
 (0)