Skip to content

Commit 3e99449

Browse files
joelofftmat
authored andcommitted
Work around concurrency issue in COM API
1 parent b12ef3b commit 3e99449

File tree

1 file changed

+34
-26
lines changed

1 file changed

+34
-26
lines changed

src/Cli/dotnet/commands/dotnet-workload/list/VisualStudioWorkloads.cs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ namespace Microsoft.DotNet.Workloads.Workload
1919
#endif
2020
internal static class VisualStudioWorkloads
2121
{
22+
private static readonly object s_guard = new();
23+
2224
private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154);
2325

2426
/// <summary>
@@ -204,44 +206,50 @@ internal static IEnumerable<WorkloadId> WriteSDKInstallRecordsForVSWorkloads(IIn
204206
/// <returns>A list of Visual Studio instances.</returns>
205207
private static List<ISetupInstance> GetVisualStudioInstances()
206208
{
207-
List<ISetupInstance> vsInstances = new();
208-
209-
try
209+
// The underlying COM API has a bug where-by it's not safe for concurrent calls. Until their
210+
// bug fix is rolled out use a lock to ensure we don't concurrently access this API.
211+
// https://dev.azure.com/devdiv/DevDiv/_workitems/edit/2241752/
212+
lock (s_guard)
210213
{
211-
SetupConfiguration setupConfiguration = new();
212-
ISetupConfiguration2 setupConfiguration2 = setupConfiguration;
213-
IEnumSetupInstances setupInstances = setupConfiguration2.EnumInstances();
214-
ISetupInstance[] instances = new ISetupInstance[1];
215-
int fetched = 0;
214+
List<ISetupInstance> vsInstances = new();
216215

217-
do
216+
try
218217
{
219-
setupInstances.Next(1, instances, out fetched);
218+
SetupConfiguration setupConfiguration = new();
219+
ISetupConfiguration2 setupConfiguration2 = setupConfiguration;
220+
IEnumSetupInstances setupInstances = setupConfiguration2.EnumInstances();
221+
ISetupInstance[] instances = new ISetupInstance[1];
222+
int fetched = 0;
220223

221-
if (fetched > 0)
224+
do
222225
{
223-
ISetupInstance2 instance = (ISetupInstance2)instances[0];
226+
setupInstances.Next(1, instances, out fetched);
224227

225-
// .NET Workloads only shipped in 17.0 and later and we should only look at IDE based SKUs
226-
// such as community, professional, and enterprise.
227-
if (Version.TryParse(instance.GetInstallationVersion(), out Version version) &&
228-
version.Major >= 17 &&
229-
s_visualStudioProducts.Contains(instance.GetProduct().GetId()))
228+
if (fetched > 0)
230229
{
231-
vsInstances.Add(instances[0]);
230+
ISetupInstance2 instance = (ISetupInstance2)instances[0];
231+
232+
// .NET Workloads only shipped in 17.0 and later and we should only look at IDE based SKUs
233+
// such as community, professional, and enterprise.
234+
if (Version.TryParse(instance.GetInstallationVersion(), out Version version) &&
235+
version.Major >= 17 &&
236+
s_visualStudioProducts.Contains(instance.GetProduct().GetId()))
237+
{
238+
vsInstances.Add(instances[0]);
239+
}
232240
}
233241
}
242+
while (fetched > 0);
243+
244+
}
245+
catch (COMException e) when (e.ErrorCode == REGDB_E_CLASSNOTREG)
246+
{
247+
// Query API not registered, good indication there are no VS installations of 15.0 or later.
248+
// Other exceptions are passed through since that likely points to a real error.
234249
}
235-
while (fetched > 0);
236250

251+
return vsInstances;
237252
}
238-
catch (COMException e) when (e.ErrorCode == REGDB_E_CLASSNOTREG)
239-
{
240-
// Query API not registered, good indication there are no VS installations of 15.0 or later.
241-
// Other exceptions are passed through since that likely points to a real error.
242-
}
243-
244-
return vsInstances;
245253
}
246254
}
247255
}

0 commit comments

Comments
 (0)