@@ -5,6 +5,8 @@ namespace Microsoft.Windows.CsWin32;
5
5
6
6
public partial class Generator
7
7
{
8
+ private static readonly TypeSyntax PCWSTRTypeSyntax = QualifiedName ( QualifiedName ( IdentifierName ( GlobalWinmdRootNamespaceAlias ) , IdentifierName ( "Foundation" ) ) , IdentifierName ( "PCWSTR" ) ) ;
9
+
8
10
private enum FriendlyOverloadOf
9
11
{
10
12
ExternMethod ,
@@ -268,9 +270,6 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
268
270
{
269
271
// TODO: add support for in/out size parameters. (e.g. RSGetViewports)
270
272
// TODO: add support for lists of pointers via a generated pointer-wrapping struct (e.g. PSSetSamplers)
271
-
272
- // It is possible that countParamIndex points to a parameter that is not on the extern method
273
- // when the parameter is the last one and was moved to a return value.
274
273
if ( ! isPointerToPointer && TryHandleCountParam ( elementType , nullableSource : true ) )
275
274
{
276
275
// This block intentionally left blank.
@@ -305,6 +304,136 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
305
304
VariableDeclarator ( localName . Identifier ) . WithInitializer ( EqualsValueClause ( origName ) ) ) ) ;
306
305
arguments [ param . SequenceNumber - 1 ] = Argument ( localName ) ;
307
306
}
307
+
308
+ // Translate ReadOnlySpan<PCWSTR> to ReadOnlySpan<string>
309
+ if ( isIn && ! isOut && isConst && externParam . Type is PointerTypeSyntax { ElementType : QualifiedNameSyntax { Right : { Identifier : { ValueText : "PCWSTR" } } } } )
310
+ {
311
+ signatureChanged = true ;
312
+
313
+ // Change the parameter type to ReadOnlySpan<string>
314
+ parameters [ param . SequenceNumber - 1 ] = externParam
315
+ . WithType ( MakeReadOnlySpanOfT ( PredefinedType ( Token ( SyntaxKind . StringKeyword ) ) ) ) ;
316
+
317
+ IdentifierNameSyntax gcHandlesLocal = IdentifierName ( $ "{ origName } GCHandles") ;
318
+ IdentifierNameSyntax pcwstrLocal = IdentifierName ( $ "{ origName } Pointers") ;
319
+
320
+ // var paramNameGCHandles = ArrayPool<GCHandle>.Shared.Rent(paramName.Length);
321
+ var gcHandlesArrayDecl = LocalDeclarationStatement ( VariableDeclaration (
322
+ ArrayType ( IdentifierName ( "var" ) ) ) . AddVariables (
323
+ VariableDeclarator ( gcHandlesLocal . Identifier ) . WithInitializer ( EqualsValueClause (
324
+ InvocationExpression (
325
+ MemberAccessExpression (
326
+ SyntaxKind . SimpleMemberAccessExpression ,
327
+ MemberAccessExpression (
328
+ SyntaxKind . SimpleMemberAccessExpression ,
329
+ ParseTypeName ( "global::System.Buffers.ArrayPool<global::System.Runtime.InteropServices.GCHandle>" ) ,
330
+ IdentifierName ( "Shared" ) ) ,
331
+ IdentifierName ( "Rent" ) ) )
332
+ . WithArgumentList ( ArgumentList ( ) . AddArguments ( Argument ( GetSpanLength ( origName , false ) ) ) ) ) ) ) ) ;
333
+
334
+ // var paramNamePointers = ArrayPool<PCWSTR>.Shared.Rent(paramName.Length);
335
+ var strsArrayDecl = LocalDeclarationStatement ( VariableDeclaration (
336
+ ArrayType ( IdentifierName ( "var" ) ) ) . AddVariables (
337
+ VariableDeclarator ( pcwstrLocal . Identifier ) . WithInitializer ( EqualsValueClause (
338
+ InvocationExpression (
339
+ MemberAccessExpression (
340
+ SyntaxKind . SimpleMemberAccessExpression ,
341
+ MemberAccessExpression (
342
+ SyntaxKind . SimpleMemberAccessExpression ,
343
+ ParseTypeName ( $ "global::System.Buffers.ArrayPool<{ PCWSTRTypeSyntax . ToString ( ) } >") ,
344
+ IdentifierName ( "Shared" ) ) ,
345
+ IdentifierName ( "Rent" ) ) )
346
+ . WithArgumentList ( ArgumentList ( ) . AddArguments ( Argument ( GetSpanLength ( origName , false ) ) ) ) ) ) ) ) ;
347
+
348
+ // for (int i = 0; i < paramName.Length; i++)
349
+ // {
350
+ // paramNameGCHandles[i] = GCHandle.Alloc(paramName[i], GCHandleType.Pinned);
351
+ // paramNamePointers[i] = (char*)paramNameGCHandles[i].AddrOfPinnedObject();
352
+ // }
353
+ IdentifierNameSyntax loopVariable = IdentifierName ( "i" ) ;
354
+ var forLoop = ForStatement (
355
+ VariableDeclaration ( PredefinedType ( Token ( SyntaxKind . IntKeyword ) ) ) . AddVariables (
356
+ VariableDeclarator ( loopVariable . Identifier ) . WithInitializer ( EqualsValueClause ( LiteralExpression ( SyntaxKind . NumericLiteralExpression , Literal ( 0 ) ) ) ) ) ,
357
+ BinaryExpression ( SyntaxKind . LessThanExpression , loopVariable , GetSpanLength ( origName , false ) ) ,
358
+ SingletonSeparatedList < ExpressionSyntax > ( PostfixUnaryExpression ( SyntaxKind . PostIncrementExpression , loopVariable ) ) ,
359
+ Block ( ) . AddStatements (
360
+ ExpressionStatement ( AssignmentExpression (
361
+ SyntaxKind . SimpleAssignmentExpression ,
362
+ ElementAccessExpression ( gcHandlesLocal ) . AddArgumentListArguments ( Argument ( loopVariable ) ) ,
363
+ InvocationExpression (
364
+ MemberAccessExpression (
365
+ SyntaxKind . SimpleMemberAccessExpression ,
366
+ ParseTypeName ( "global::System.Runtime.InteropServices.GCHandle" ) ,
367
+ IdentifierName ( "Alloc" ) ) )
368
+ . WithArgumentList ( ArgumentList ( ) . AddArguments (
369
+ Argument ( ElementAccessExpression ( origName ) . AddArgumentListArguments ( Argument ( loopVariable ) ) ) ,
370
+ Argument ( MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , ParseTypeName ( "global::System.Runtime.InteropServices.GCHandleType" ) , IdentifierName ( "Pinned" ) ) ) ) ) ) ) ,
371
+ ExpressionStatement ( AssignmentExpression (
372
+ SyntaxKind . SimpleAssignmentExpression ,
373
+ ElementAccessExpression ( pcwstrLocal ) . AddArgumentListArguments ( Argument ( loopVariable ) ) ,
374
+ CastExpression (
375
+ PointerType ( PredefinedType ( Token ( SyntaxKind . CharKeyword ) ) ) ,
376
+ InvocationExpression (
377
+ MemberAccessExpression (
378
+ SyntaxKind . SimpleMemberAccessExpression ,
379
+ ElementAccessExpression ( gcHandlesLocal ) . AddArgumentListArguments ( Argument ( loopVariable ) ) ,
380
+ IdentifierName ( "AddrOfPinnedObject" ) ) ) . WithArgumentList ( ArgumentList ( ) ) ) ) ) ) ) ;
381
+
382
+ leadingOutsideTryStatements . AddRange ( [ gcHandlesArrayDecl , strsArrayDecl , forLoop ] ) ;
383
+
384
+ // foreach (var gcHandle in paramNameGCHandles) gcHandle.Free();
385
+ var freeHandleStatement = ForEachStatement (
386
+ IdentifierName ( "var" ) . WithTrailingTrivia ( Space ) ,
387
+ Identifier ( "gcHandle" ) . WithTrailingTrivia ( Space ) ,
388
+ gcHandlesLocal . WithLeadingTrivia ( Space ) ,
389
+ ExpressionStatement (
390
+ InvocationExpression (
391
+ MemberAccessExpression (
392
+ SyntaxKind . SimpleMemberAccessExpression ,
393
+ IdentifierName ( "gcHandle" ) ,
394
+ IdentifierName ( "Free" ) ) ) ) . WithLeadingTrivia ( LineFeed ) ) ;
395
+
396
+ // ArrayPool<GCHandle>.Shared.Return(gcHandlesArray);
397
+ var returnGCHandlesArray = ExpressionStatement (
398
+ InvocationExpression (
399
+ MemberAccessExpression (
400
+ SyntaxKind . SimpleMemberAccessExpression ,
401
+ ParseTypeName ( "global::System.Buffers.ArrayPool<global::System.Runtime.InteropServices.GCHandle>" ) ,
402
+ IdentifierName ( "Shared.Return" ) ) )
403
+ . WithArgumentList ( ArgumentList ( ) . AddArguments ( Argument ( gcHandlesLocal ) ) ) ) ;
404
+
405
+ // ArrayPool<PCWSTR>.Shared.Return(paramNamePointers);
406
+ var returnStrsArray = ExpressionStatement (
407
+ InvocationExpression (
408
+ MemberAccessExpression (
409
+ SyntaxKind . SimpleMemberAccessExpression ,
410
+ ParseTypeName ( $ "global::System.Buffers.ArrayPool<{ PCWSTRTypeSyntax . ToString ( ) } > ") ,
411
+ IdentifierName ( "Shared.Return" ) ) )
412
+ . WithArgumentList ( ArgumentList ( ) . AddArguments ( Argument ( pcwstrLocal ) ) ) ) ;
413
+
414
+ finallyStatements . AddRange ( [ freeHandleStatement , returnGCHandlesArray , returnStrsArray ] ) ;
415
+
416
+ // Update fixed blocks already created to consume our array of pinned pointers
417
+ bool found = false ;
418
+ for ( int i = 0 ; i < fixedBlocks . Count ; i ++ )
419
+ {
420
+ if ( fixedBlocks [ i ] is VariableDeclarationSyntax { Variables : [ VariableDeclaratorSyntax { Initializer : { Value : IdentifierNameSyntax { Identifier : SyntaxToken id } } initializer } variable ] } declaration
421
+ && id . ValueText == externParam . Identifier . ValueText )
422
+ {
423
+ // fixed (PCWSTR* paramNamePointersPtr = strsArray)
424
+ fixedBlocks [ i ] = declaration . WithVariables ( SingletonSeparatedList ( variable . WithInitializer ( initializer . WithValue ( pcwstrLocal ) ) ) ) ;
425
+ found = true ;
426
+ break ;
427
+ }
428
+ }
429
+
430
+ if ( ! found )
431
+ {
432
+ throw new GenerationFailedException ( "Unable to find existing fixed block to change." ) ;
433
+ }
434
+
435
+ arguments [ param . SequenceNumber - 1 ] = Argument ( localName ) ;
436
+ }
308
437
}
309
438
else if ( isIn && isOptional && ! isOut && ! isPointerToPointer )
310
439
{
@@ -485,6 +614,9 @@ private IEnumerable<MethodDeclarationSyntax> DeclareFriendlyOverloads(MethodDefi
485
614
bool TryHandleCountParam ( TypeSyntax elementType , bool nullableSource )
486
615
{
487
616
IdentifierNameSyntax localName = IdentifierName ( origName + "Local" ) ;
617
+
618
+ // It is possible that countParamIndex points to a parameter that is not on the extern method
619
+ // when the parameter is the last one and was moved to a return value.
488
620
if ( countParamIndex . HasValue
489
621
&& this . canUseSpan
490
622
&& externMethodDeclaration . ParameterList . Parameters . Count > countParamIndex . Value
0 commit comments