Skip to content

Commit 095410a

Browse files
ResultProvider: Consume DkmClrModuleInstance.GetMetaDataImportHolder (#76395)
Previous to this change, the ResultProvider would use `DkmClrModuleInstance.GetMetaDataImport`, but did NOT use Marshal.ReleaseComObject on the result. This could result in locked files if the RCW took a long time to be finalized. This PR switches to use a new `GetMetaDataImportHolder` API that adds an IDisposable wrapper struct to take care of this cleanup. This PR requires VS 17.13 Build 35612.30 or newer.
1 parent a3723c4 commit 095410a

File tree

4 files changed

+44
-6
lines changed

4 files changed

+44
-6
lines changed

eng/Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@
122122
VS Debugger
123123
-->
124124
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Contracts" Version="17.13.0-beta.24561.1" />
125-
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Engine-implementation" Version="17.13.1110101-preview" />
126-
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Metadata-implementation" Version="17.13.1110101-preview" />
125+
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Engine-implementation" Version="17.13.1121201-preview" />
126+
<PackageVersion Include="Microsoft.VisualStudio.Debugger.Metadata-implementation" Version="17.13.1121201-preview" />
127127

128128
<!--
129129
VS .NET Runtime

src/ExpressionEvaluator/Core/Source/ResultProvider/Formatter.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,18 @@ string IDkmClrFullNameProvider2.GetClrNameForLocalVariable(DkmInspectionContext
182182

183183
string IDkmClrFullNameProvider2.GetClrNameForField(DkmInspectionContext inspectionContext, DkmClrModuleInstance moduleInstance, int fieldToken)
184184
{
185-
var import = (IMetadataImport)moduleInstance.GetMetaDataImport();
185+
using var importHolder = moduleInstance.GetMetaDataImportHolder();
186186

187187
// Just get some of information about properties. Get rest later only if needed.
188-
int hr = import.GetFieldProps(fieldToken, out _, null, 0, out var nameLength, out _, out _, out _, out _, out _, out _);
188+
int hr = importHolder.Value.GetFieldProps(fieldToken, out _, null, 0, out var nameLength, out _, out _, out _, out _, out _, out _);
189189
const int S_OK = 0;
190190
if (hr != S_OK)
191191
{
192192
throw new ArgumentException("Invalid field token.", nameof(fieldToken));
193193
}
194194

195195
var sb = new StringBuilder(nameLength);
196-
hr = import.GetFieldProps(fieldToken, out _, sb, sb.Capacity, out _, out _, out _, out _, out _, out _, out _);
196+
hr = importHolder.Value.GetFieldProps(fieldToken, out _, sb, sb.Capacity, out _, out _, out _, out _, out _, out _, out _);
197197
if (hr != S_OK)
198198
{
199199
throw new DkmException((DkmExceptionCode)hr);

src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrModuleInstance.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ internal int ResolveTypeNameFailures
6666
get { return _resolveTypeNameFailures; }
6767
}
6868

69-
public object GetMetaDataImport() => new MetadataImportMock(Assembly);
69+
public DkmMetadataImportHolder GetMetaDataImportHolder() => new DkmMetadataImportHolder(new MetadataImportMock(Assembly));
7070

7171
private class MetadataImportMock : IMetadataImport
7272
{
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using Microsoft.MetadataReader;
7+
8+
#nullable enable
9+
10+
namespace Microsoft.VisualStudio.Debugger.Clr
11+
{
12+
/// <summary>
13+
/// Wrapper around a <see cref="Microsoft.MetadataReader.IMetadataImport"/> interface
14+
/// reference that provides a easy way to release the reference to the underlying
15+
/// COM object. Instances of this struct should always be disposed.
16+
/// </summary>
17+
public readonly struct DkmMetadataImportHolder : IDisposable
18+
{
19+
/// <summary>
20+
/// The underlying IMetaDataImport interface reference
21+
/// </summary>
22+
public IMetadataImport Value { get; }
23+
24+
/// <summary>
25+
/// Creates a new instance of <see cref="DkmMetadataImportHolder"/>.
26+
/// </summary>
27+
/// <param name="value">[In] Implementation of IMetadataImport to wrap</param>
28+
public DkmMetadataImportHolder(IMetadataImport value)
29+
{
30+
this.Value = value ?? throw new ArgumentNullException(nameof(value));
31+
}
32+
33+
void IDisposable.Dispose()
34+
{
35+
// Mock implementation does nothing
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)