Skip to content

Commit 0d6b5a1

Browse files
committed
Use documented invalid handles when SafeHandle is null
Also throw when the handle is not optional, but null is provided. Fixes #755
1 parent 63282ef commit 0d6b5a1

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

src/Microsoft.Windows.CsWin32/Generator.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ internal void RequestMacro(MethodDeclarationSyntax macro)
17561756
// Collect all the known invalid values for this handle.
17571757
// If no invalid values are given (e.g. BSTR), we'll just assume 0 is invalid.
17581758
HashSet<IntPtr> invalidHandleValues = this.GetInvalidHandleValues(((HandleTypeHandleInfo)releaseMethodParameterTypeHandleInfo).Handle);
1759-
long preferredInvalidValue = invalidHandleValues.Contains(new IntPtr(-1)) ? -1 : invalidHandleValues.FirstOrDefault().ToInt64();
1759+
IntPtr preferredInvalidValue = GetPreferredInvalidHandleValue(invalidHandleValues);
17601760

17611761
CustomAttributeHandleCollection? atts = this.GetReturnTypeCustomAttributes(releaseMethodDef);
17621762
TypeSyntaxAndMarshaling releaseMethodReturnType = releaseMethodSignature.ReturnType.ToTypeSyntax(this.externSignatureTypeSettings, atts);
@@ -1767,7 +1767,7 @@ internal void RequestMacro(MethodDeclarationSyntax macro)
17671767

17681768
MemberAccessExpressionSyntax thisHandle = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpression(), IdentifierName("handle"));
17691769
ExpressionSyntax intptrZero = DefaultExpression(IntPtrTypeSyntax);
1770-
ExpressionSyntax invalidHandleIntPtr = ObjectCreationExpression(IntPtrTypeSyntax).AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(preferredInvalidValue))));
1770+
ExpressionSyntax invalidHandleIntPtr = IntPtrExpr(preferredInvalidValue);
17711771

17721772
// private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
17731773
IdentifierNameSyntax invalidValueFieldName = IdentifierName("INVALID_HANDLE_VALUE");
@@ -2249,6 +2249,8 @@ protected virtual void Dispose(bool disposing)
22492249

22502250
private static SyntaxToken TokenWithLineFeed(SyntaxKind syntaxKind) => SyntaxFactory.Token(TriviaList(), syntaxKind, TriviaList(LineFeed));
22512251

2252+
private static IntPtr GetPreferredInvalidHandleValue(HashSet<IntPtr> invalidHandleValues) => invalidHandleValues.Contains(new IntPtr(-1)) ? new IntPtr(-1) : invalidHandleValues.FirstOrDefault();
2253+
22522254
private static bool RequiresUnsafe(TypeSyntax? typeSyntax) => typeSyntax is PointerTypeSyntax || typeSyntax is FunctionPointerTypeSyntax;
22532255

22542256
private static string GetClassNameForModule(string moduleName) =>
@@ -2622,6 +2624,9 @@ private static Guid DecodeGuidFromAttribute(CustomAttribute guidAttribute)
26222624

26232625
private static bool IsHresult(TypeHandleInfo? typeHandleInfo) => typeHandleInfo is HandleTypeHandleInfo handleInfo && handleInfo.IsType("HRESULT");
26242626

2627+
private static ExpressionSyntax IntPtrExpr(IntPtr value) => ObjectCreationExpression(IntPtrTypeSyntax).AddArgumentListArguments(
2628+
Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(value.ToInt64()))));
2629+
26252630
private T AddApiDocumentation<T>(string api, T memberDeclaration)
26262631
where T : MemberDeclarationSyntax
26272632
{
@@ -4717,6 +4722,22 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
47174722
leadingStatements.Add(LocalDeclarationStatement(VariableDeclaration(externParam.Type).AddVariables(
47184723
VariableDeclarator(typeDefHandleName.Identifier))));
47194724

4725+
// throw new ArgumentNullException(nameof(hTemplateFile));
4726+
StatementSyntax nullHandleStatement = ThrowStatement(ObjectCreationExpression(IdentifierName(nameof(ArgumentNullException))).WithArgumentList(ArgumentList().AddArguments(Argument(NameOfExpression(IdentifierName(externParam.Identifier.ValueText))))));
4727+
if (isOptional)
4728+
{
4729+
HashSet<IntPtr> invalidValues = this.GetInvalidHandleValues(parameterHandleTypeInfo.Handle);
4730+
if (invalidValues.Count > 0)
4731+
{
4732+
// (HANDLE)new IntPtr(-1);
4733+
IntPtr invalidValue = GetPreferredInvalidHandleValue(invalidValues);
4734+
ExpressionSyntax invalidExpression = CastExpression(externParam.Type, IntPtrExpr(invalidValue));
4735+
4736+
// hTemplateFileLocal = invalid-handle-value;
4737+
nullHandleStatement = ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, typeDefHandleName, invalidExpression));
4738+
}
4739+
}
4740+
47204741
// if (hTemplateFile is object)
47214742
leadingStatements.Add(IfStatement(
47224743
BinaryExpression(SyntaxKind.IsExpression, origName, PredefinedType(Token(SyntaxKind.ObjectKeyword))),
@@ -4734,7 +4755,7 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
47344755
InvocationExpression(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, origName, IdentifierName(nameof(SafeHandle.DangerousGetHandle))), ArgumentList())))
47354756
.WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken)))),
47364757
//// else hTemplateFileLocal = default;
4737-
ElseClause(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, typeDefHandleName, DefaultExpression(externParam.Type.WithoutTrailingTrivia())).WithOperatorToken(TokenWithSpaces(SyntaxKind.EqualsToken))))));
4758+
ElseClause(nullHandleStatement)));
47384759

47394760
// if (hTemplateFileAddRef)
47404761
// hTemplateFile.DangerousRelease();

test/Microsoft.Windows.CsWin32.Tests/GeneratorTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ public void InterestingAPIs(
297297
"PZZWSTR",
298298
"PCZZSTR",
299299
"PCZZWSTR",
300+
"NCryptImportKey", // friendly overload takes SafeHandle backed by a UIntPtr instead of IntPtr
300301
"IUIAutomation", // non-preservesig retval COM method with a array size index parameter
301302
"IHTMLWindow2", // contains properties named with C# reserved keywords
302303
"CreateFile", // built-in SafeHandle use
@@ -2653,7 +2654,7 @@ internal static unsafe Microsoft.Win32.SafeHandles.SafeFileHandle CreateFile(str
26532654
hTemplateFileLocal = (winmdroot.Foundation.HANDLE)hTemplateFile.DangerousGetHandle();
26542655
}}
26552656
else
2656-
hTemplateFileLocal = default(winmdroot.Foundation.HANDLE);
2657+
hTemplateFileLocal= new winmdroot.Foundation.HANDLE (new IntPtr(-1L));
26572658
winmdroot.Foundation.HANDLE __result = PInvoke.CreateFile(lpFileNameLocal, dwDesiredAccess, dwShareMode, lpSecurityAttributes.HasValue ? &lpSecurityAttributesLocal : null, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFileLocal);
26582659
return new Microsoft.Win32.SafeHandles.SafeFileHandle(__result, ownsHandle: true);
26592660
}}

0 commit comments

Comments
 (0)