Skip to content

Commit a4369d5

Browse files
authored
Promote handle pointer to an out reference if handle cannot be trivially represented as a SafeHandle (#1672)
1 parent 520eb26 commit a4369d5

2 files changed

Lines changed: 31 additions & 8 deletions

File tree

src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -364,13 +364,13 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverload(
364364
pointedElementInfo.Generator.TryGetHandleReleaseMethod(pointedElementInfo.Handle, paramAttributes, out string? outReleaseMethod) && !this.Reader.StringComparer.Equals(methodDefinition.Name, outReleaseMethod) &&
365365
(memorySize is null) && !isArray)
366366
{
367+
signatureChanged = true;
368+
369+
IdentifierNameSyntax localName = IdentifierName(externParam.Identifier.ValueText + "Local");
370+
367371
// NOTE: We don't handle scenarios where the parameter is [MemorySize] annotated (e.g. EnumProcessModules) or [NativeArrayInfo] (e.g. ITypeInfo.GetNames)
368372
if (this.RequestSafeHandle(outReleaseMethod) is TypeSyntax safeHandleType)
369373
{
370-
signatureChanged = true;
371-
372-
IdentifierNameSyntax typeDefHandleName = IdentifierName(externParam.Identifier.ValueText + "Local");
373-
374374
// out SafeHandle
375375
parameters[paramIndex] = externParam
376376
.WithType(safeHandleType.WithTrailingTrivia(TriviaList(Space)))
@@ -381,7 +381,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverload(
381381
LocalDeclarationStatement(
382382
VariableDeclaration(
383383
pointedElementInfo.ToTypeSyntax(parameterTypeSyntaxSettings, GeneratingElement.FriendlyOverload, null).Type,
384-
[VariableDeclarator(typeDefHandleName.Identifier)])));
384+
[VariableDeclarator(localName.Identifier)])));
385385

386386
ArgumentSyntax ownsHandleArgument = Argument(
387387
NameColon(IdentifierName("ownsHandle")),
@@ -408,7 +408,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverload(
408408
IdentifierName("InitHandle")),
409409
[
410410
Argument(origName),
411-
Argument(this.GetIntPtrFromTypeDef(typeDefHandleName, pointedElementInfo)),
411+
Argument(this.GetIntPtrFromTypeDef(localName, pointedElementInfo)),
412412
])));
413413
}
414414
else
@@ -417,11 +417,32 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverload(
417417
trailingStatements.Add(ExpressionStatement(AssignmentExpression(
418418
SyntaxKind.SimpleAssignmentExpression,
419419
origName,
420-
ObjectCreationExpression(safeHandleType, [Argument(this.GetIntPtrFromTypeDef(typeDefHandleName, pointedElementInfo)), ownsHandleArgument]))));
420+
ObjectCreationExpression(safeHandleType, [Argument(this.GetIntPtrFromTypeDef(localName, pointedElementInfo)), ownsHandleArgument]))));
421421
}
422422

423423
// Argument: &SomeLocal
424-
arguments[paramIndex] = Argument(PrefixUnaryExpression(SyntaxKind.AddressOfExpression, typeDefHandleName));
424+
arguments[paramIndex] = Argument(PrefixUnaryExpression(SyntaxKind.AddressOfExpression, localName));
425+
}
426+
else
427+
{
428+
// If we were not able to upgrade the handle to a SafeHandle, at least make it a managed out reference
429+
TypeSyntax underlyingType = ((PointerTypeSyntax)externParam.Type).ElementType;
430+
431+
// out ORIGINAL_HANDLE_TYPE
432+
parameters[paramIndex] = externParam
433+
.WithType(underlyingType.WithTrailingTrivia(TriviaList(Space)))
434+
.WithModifiers([TokenWithSpace(SyntaxKind.OutKeyword)]);
435+
436+
// fixed (ORIGINAL_HANDLE_TYPE* someHandleLocal = &someHandle)
437+
fixedBlocks.Add(
438+
VariableDeclaration(
439+
externParam.Type,
440+
[VariableDeclarator(
441+
localName.Identifier,
442+
EqualsValueClause(
443+
PrefixUnaryExpression(SyntaxKind.AddressOfExpression, IdentifierName(externParam.Identifier))))]));
444+
445+
arguments[paramIndex] = Argument(localName);
425446
}
426447
}
427448
else if (this.options.UseSafeHandles && isIn && !isOut && !isReleaseMethod && parameterTypeInfo is HandleTypeHandleInfo parameterHandleTypeInfo && this.TryGetHandleReleaseMethod(parameterHandleTypeInfo.Handle, paramAttributes, out string? releaseMethod) && !this.Reader.StringComparer.Equals(methodDefinition.Name, releaseMethod)

test/CsWin32Generator.Tests/CsWin32GeneratorTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ public async Task DelegatesGetStructsGenerated()
223223
["Windows.Win32.NetworkManagement.WindowsFilteringPlatform.FwpmEngineOpen0", "FwpmEngineOpen0", "[Optional] winmdroot.Foundation.PCWSTR serverName, uint authnService, [Optional] winmdroot.System.Rpc.SEC_WINNT_AUTH_IDENTITY_W* authIdentity, [Optional] winmdroot.NetworkManagement.WindowsFilteringPlatform.FWPM_SESSION0* session, winmdroot.NetworkManagement.WindowsFilteringPlatform.FWPM_ENGINE_HANDLE* engineHandle"],
224224
// WlanCloseHandle accepts an additional reserved parameter. We can still generate safe hanlde for WlanOpenHandle then
225225
["WlanOpenHandle", "WlanOpenHandle", "uint dwClientVersion, out uint pdwNegotiatedVersion, out global::Windows.Win32.WlanCloseHandleSafeHandle phClientHandle"],
226+
// Has an out reference of a handle that cannot be trivially converted to a SafeHandle
227+
["Windows.Win32.NetworkManagement.WindowsFilteringPlatform.FwpmFilterCreateEnumHandle0", "FwpmFilterCreateEnumHandle0", "SafeHandle engineHandle, [Optional] winmdroot.NetworkManagement.WindowsFilteringPlatform.FWPM_FILTER_ENUM_TEMPLATE0? enumTemplate, out winmdroot.NetworkManagement.WindowsFilteringPlatform.FWPM_FILTER_ENUM_HANDLE enumHandle"]
226228
];
227229

228230
[Theory]

0 commit comments

Comments
 (0)