@@ -42,8 +42,27 @@ public partial class Generator
4242 TypeHandleInfo releaseMethodParameterTypeHandleInfo = releaseMethodSignature . ParameterTypes [ 0 ] ;
4343 TypeSyntaxAndMarshaling releaseMethodParameterType = releaseMethodParameterTypeHandleInfo . ToTypeSyntax ( this . externSignatureTypeSettings , GeneratingElement . HelperClassMember , default ) ;
4444
45- // If the release method takes more than one parameter, we can't generate a SafeHandle for it.
46- if ( releaseMethodSignature . RequiredParameterCount != 1 )
45+ var nonReservedParameterCount = 0 ;
46+ var handleParameterName = string . Empty ;
47+ foreach ( ParameterHandle paramHandle in releaseMethodDef . GetParameters ( ) )
48+ {
49+ Parameter param = this . Reader . GetParameter ( paramHandle ) ;
50+ if ( param . SequenceNumber == 0 )
51+ {
52+ continue ;
53+ }
54+
55+ CustomAttributeHandleCollection paramAttributes = param . GetCustomAttributes ( ) ;
56+
57+ if ( this . FindInteropDecorativeAttribute ( paramAttributes , "ReservedAttribute" ) is null )
58+ {
59+ nonReservedParameterCount ++ ;
60+ handleParameterName = this . Reader . GetString ( param . Name ) ;
61+ }
62+ }
63+
64+ // If the release method takes more than one non-reserved parameter, we can't generate a SafeHandle for it.
65+ if ( nonReservedParameterCount != 1 )
4766 {
4867 safeHandleType = null ;
4968 }
@@ -138,13 +157,22 @@ public partial class Generator
138157 . WithExpressionBody ( ArrowExpressionClause ( overallTest ) )
139158 . WithSemicolonToken ( SemicolonWithLineFeed ) ) ;
140159
160+ // If there are more than 1 parameter other parameters are reserved.
161+ // Otherwise we would have quit earlier
162+ var releaseMethodHasReservedParameters = releaseMethodSignature . RequiredParameterCount > 1 ;
163+
141164 // (struct)this.handle or (struct)checked((fieldType)(nint))this.handle, as appropriate.
165+ // If we have other reserved parameters make this a named argument to be extra sure
166+ // we are passing value for correct parameter
142167 bool implicitConversion = typeDefStructFieldType is PrimitiveTypeHandleInfo { PrimitiveTypeCode : PrimitiveTypeCode . IntPtr } or PointerTypeHandleInfo ;
143- ArgumentSyntax releaseHandleArgument = Argument ( CastExpression (
144- releaseMethodParameterType . Type ,
145- implicitConversion ? thisHandle : CheckedExpression ( CastExpression ( typeDefStructFieldType ! . ToTypeSyntax ( this . fieldTypeSettings , GeneratingElement . HelperClassMember , null ) . Type , CastExpression ( IdentifierName ( "nint" ) , thisHandle ) ) ) ) ) ;
146-
147- // protected override bool ReleaseHandle() => ReleaseMethod((struct)this.handle);
168+ ArgumentSyntax releaseHandleArgument = Argument (
169+ releaseMethodHasReservedParameters ? NameColon ( IdentifierName ( handleParameterName ) ) : null ,
170+ default ,
171+ CastExpression (
172+ releaseMethodParameterType . Type ,
173+ implicitConversion ? thisHandle : CheckedExpression ( CastExpression ( typeDefStructFieldType ! . ToTypeSyntax ( this . fieldTypeSettings , GeneratingElement . HelperClassMember , null ) . Type , CastExpression ( IdentifierName ( "nint" ) , thisHandle ) ) ) ) ) ;
174+
175+ // protected override [unsafe] bool ReleaseHandle() => ReleaseMethod((struct)this.handle);
148176 // Special case release functions based on their return type as follows: (https://github.com/microsoft/win32metadata/issues/25)
149177 // * bool => true is success
150178 // * int => zero is success
@@ -157,7 +185,11 @@ public partial class Generator
157185 IdentifierName ( renamedReleaseMethod ?? releaseMethod ) ) ,
158186 ArgumentList ( ) . AddArguments ( releaseHandleArgument ) ) ;
159187 BlockSyntax ? releaseBlock = null ;
160- bool releaseMethodIsUnsafe = false ;
188+
189+ // Reserved parameters can be pointers.
190+ // Thus we need unsafe modifier even though we don't pass values for reserved parameters explicitly.
191+ // As an example of that see WlanCloseHandle function.
192+ var releaseMethodIsUnsafe = releaseMethodHasReservedParameters ;
161193 if ( ! ( releaseMethodReturnType . Type is PredefinedTypeSyntax { Keyword : { RawKind : ( int ) SyntaxKind . BoolKeyword } } ||
162194 releaseMethodReturnType . Type is QualifiedNameSyntax { Right : { Identifier : { ValueText : "BOOL" } } } ) )
163195 {
@@ -241,6 +273,7 @@ public partial class Generator
241273
242274 MethodDeclarationSyntax releaseHandleDeclaration = MethodDeclaration ( PredefinedType ( TokenWithSpace ( SyntaxKind . BoolKeyword ) ) , Identifier ( "ReleaseHandle" ) )
243275 . AddModifiers ( TokenWithSpace ( SyntaxKind . ProtectedKeyword ) , TokenWithSpace ( SyntaxKind . OverrideKeyword ) ) ;
276+
244277 if ( releaseMethodIsUnsafe )
245278 {
246279 releaseHandleDeclaration = releaseHandleDeclaration . AddModifiers ( TokenWithSpace ( SyntaxKind . UnsafeKeyword ) ) ;
@@ -254,14 +287,16 @@ public partial class Generator
254287 . WithBody ( releaseBlock ) ;
255288 members . Add ( releaseHandleDeclaration ) ;
256289
290+ IEnumerable < TypeSyntax > xmlDocParameterTypes = releaseMethodSignature . ParameterTypes . Select ( p => p . ToTypeSyntax ( this . externSignatureTypeSettings , GeneratingElement . HelperClassMember , default ) . Type ) ;
291+
257292 ClassDeclarationSyntax safeHandleDeclaration = ClassDeclaration ( Identifier ( safeHandleClassName ) )
258293 . AddModifiers ( TokenWithSpace ( this . Visibility ) , TokenWithSpace ( SyntaxKind . PartialKeyword ) )
259294 . WithBaseList ( BaseList ( SingletonSeparatedList < BaseTypeSyntax > ( SimpleBaseType ( SafeHandleTypeSyntax ) ) ) )
260295 . AddMembers ( members . ToArray ( ) )
261296 . AddAttributeLists ( AttributeList ( ) . AddAttributes ( GeneratedCodeAttribute ) )
262297 . WithLeadingTrivia ( ParseLeadingTrivia ( $@ "
263298/// <summary>
264- /// Represents a Win32 handle that can be closed with <see cref=""{ this . options . ClassName } .{ renamedReleaseMethod ?? releaseMethod } ({ releaseMethodParameterType . Type } )""/>.
299+ /// Represents a Win32 handle that can be closed with <see cref=""{ this . options . ClassName } .{ renamedReleaseMethod ?? releaseMethod } ({ string . Join ( ", " , xmlDocParameterTypes ) } )""/>.
265300/// </summary>
266301" ) ) ;
267302
0 commit comments