Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions src/Microsoft.Windows.CsWin32/Generator.FriendlyOverloads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,18 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
countParamIndex = nativeArrayInfo.CountParamIndex;
countConst = nativeArrayInfo.CountConst;
}
else if (externParam.Type is PointerTypeSyntax { ElementType: PredefinedTypeSyntax { Keyword.RawKind: (int)SyntaxKind.ByteKeyword } } && this.FindInteropDecorativeAttribute(paramAttributes, MemorySizeAttribute) is CustomAttribute memorySizeAttribute)
else if (externParam.Type is PointerTypeSyntax { ElementType: PredefinedTypeSyntax { Keyword.RawKind: (int)SyntaxKind.ByteKeyword } })
{
// A very special case as documented in https://github.com/microsoft/win32metadata/issues/1555
// where MemorySizeAttribute is applied to byte* parameters to indicate the size of the buffer.
// Also https://github.com/microsoft/CsWin32/issues/1487 showed that byte* parameters are very unlikely to be a
// single byte so it's safer to assume it's an un-annotated array.
isArray = true;
MemorySize memorySize = DecodeMemorySizeAttribute(memorySizeAttribute);
countParamIndex = memorySize.BytesParamIndex;
if (this.FindInteropDecorativeAttribute(paramAttributes, MemorySizeAttribute) is CustomAttribute memorySizeAttribute)
{
MemorySize memorySize = DecodeMemorySizeAttribute(memorySizeAttribute);
countParamIndex = memorySize.BytesParamIndex;
}
}

if (mustRemainAsPointer)
Expand Down Expand Up @@ -301,6 +306,17 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(countConst.Value))),
ThrowStatement(ObjectCreationExpression(IdentifierName(nameof(ArgumentException))).WithArgumentList(ArgumentList()))));
}
else if (!isPointerToPointer && this.canUseSpan && externParam.Type is PointerTypeSyntax)
{
signatureChanged = true;

// Handle the byte* => Span<byte> mapping
parameters[param.SequenceNumber - 1] = parameters[param.SequenceNumber - 1]
.WithType((isConst ? MakeReadOnlySpanOfT(elementType) : MakeSpanOfT(elementType)).WithTrailingTrivia(TriviaList(Space)));
fixedBlocks.Add(VariableDeclaration(externParam.Type).AddVariables(
VariableDeclarator(localName.Identifier).WithInitializer(EqualsValueClause(origName))));
arguments[param.SequenceNumber - 1] = Argument(localName);
}
else if (isNullTerminated && isConst && parameters[param.SequenceNumber - 1].Type is PointerTypeSyntax { ElementType: PredefinedTypeSyntax { Keyword: { RawKind: (int)SyntaxKind.CharKeyword } } })
{
// replace char* with string
Expand Down
1 change: 1 addition & 0 deletions test/CsWin32Generator.Tests/CsWin32GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public async Task TestGenerateSomethingInWin32System()

[Theory]
[InlineData("IMFMediaKeySession", "get_KeySystem", "winmdroot.Foundation.BSTR* keySystem")]
[InlineData("AddPrinterW", "AddPrinter", "winmdroot.Foundation.PWSTR pName, uint Level, Span<byte> pPrinter")]
public async Task VerifySignature(string api, string member, string signature)
{
// If we need CharSet _and_ we generate something in Windows.Win32.System, the partially qualified reference breaks.
Expand Down
10 changes: 10 additions & 0 deletions test/Microsoft.Windows.CsWin32.Tests/ExternMethodTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,16 @@ static void Use()
this.AssertNoDiagnostics(this.compilation, logAllGeneratedCode: false, acceptable: isAcceptable);
}

[Fact]
public void PrinterApiProjectsBytePointerParameter()
{
this.compilation = this.starterCompilations["net35"];
this.GenerateApi("AddPrinter");
var methodSignatures = this.FindGeneratedMethod("AddPrinter_SafeHandle").Select(x => x.ParameterList.ToString());
Assert.Contains("(winmdroot.Foundation.PWSTR pName, uint Level, byte* pPrinter)", methodSignatures);
}


private static AttributeSyntax? FindDllImportAttribute(SyntaxList<AttributeListSyntax> attributeLists) => attributeLists.SelectMany(al => al.Attributes).FirstOrDefault(a => a.Name.ToString() == "DllImport");

private IEnumerable<MethodDeclarationSyntax> GenerateMethod(string methodName)
Expand Down
Loading