@@ -283,15 +283,78 @@ public async Task DoNotEmitTypesFromInternalsVisibleToReferences(bool strongName
283283 . AddSyntaxTrees (
284284 CSharpSyntaxTree . ParseText (
285285 $@ "
286+ #pragma warning disable CS1591,CS1573,CS0465,CS0649,CS8019,CS1570,CS1584,CS1658,CS0436,CS8981,SYSLIB1092
287+ using global::System;
288+ using global::System.Diagnostics;
289+ using global::System.Diagnostics.CodeAnalysis;
290+ using global::System.Runtime.CompilerServices;
291+ using global::System.Runtime.InteropServices;
292+ using global::System.Runtime.Versioning;
293+
286294 [assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""{ friendName } "")]
287295
288296 namespace Windows.Win32.Foundation
289297 {{
290- internal struct PCWSTR
291- {{
292- // Field exists solely to validate that the containing type is considered non-struct-like.
293- internal unsafe byte* Value;
294- }}
298+ internal unsafe readonly partial struct PCWSTR
299+ : IEquatable<PCWSTR>
300+ {{
301+ internal readonly char* Value;
302+
303+ internal PCWSTR(char* value) => this.Value = value;
304+
305+ public static explicit operator char*(PCWSTR value) => value.Value;
306+
307+ public static implicit operator PCWSTR(char* value) => new PCWSTR(value);
308+
309+ public bool Equals(PCWSTR other) => this.Value == other.Value;
310+
311+ public override bool Equals(object obj) => obj is PCWSTR other && this.Equals(other);
312+
313+ public override int GetHashCode() => unchecked((int)this.Value);
314+
315+ internal int Length
316+ {{
317+ get
318+ {{
319+ char* p = this.Value;
320+ if (p is null)
321+ return 0;
322+ while (*p != '\0')
323+ p++;
324+ return checked((int)(p - this.Value));
325+ }}
326+ }}
327+
328+
329+ public override string ToString() => this.Value is null ? null : new string(this.Value);
330+
331+ internal ReadOnlySpan<char> AsSpan() => this.Value is null ? default(ReadOnlySpan<char>) : new ReadOnlySpan<char>(this.Value, this.Length);
332+
333+ private string DebuggerDisplay => this.ToString();
334+ }}
335+ }}
336+
337+ namespace Windows.Win32
338+ {{
339+ internal partial class SysFreeStringSafeHandle :SafeHandle {{
340+ private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(0L);
341+
342+ internal SysFreeStringSafeHandle():base(INVALID_HANDLE_VALUE, true)
343+ {{
344+ }}
345+
346+ internal SysFreeStringSafeHandle(IntPtr preexistingHandle, bool ownsHandle = true):base(INVALID_HANDLE_VALUE, ownsHandle)
347+ {{
348+ this.SetHandle(preexistingHandle);
349+ }}
350+
351+ public override bool IsInvalid => false;
352+
353+ protected override bool ReleaseHandle()
354+ {{
355+ return true;
356+ }}
357+ }}
295358 }}
296359 " ,
297360 this . parseOptions ,
@@ -314,6 +377,8 @@ internal struct PCWSTR
314377
315378 this . nativeMethods . Add ( "PCWSTR" ) ;
316379 this . nativeMethods . Add ( "GetTickCount" ) ;
380+ this . nativeMethods . Add ( "StrToIntW" ) ; // Method that uses PCWSTR
381+ this . nativeMethods . Add ( "IRestrictedErrorInfo" ) ; // Generates BSTR out params and makes SysFreeStringSafeHandle
317382 this . additionalReferences . Add ( referencedAssemblyPath ) ;
318383 this . assemblyName = referencingAssemblyName ;
319384 this . keyFile = strongNameSign ? strongNameKeyFilePath : null ;
@@ -329,6 +394,7 @@ internal struct PCWSTR
329394 await this . InvokeGeneratorAndCompile ( testCase : $ "{ nameof ( this . DoNotEmitTypesFromInternalsVisibleToReferences ) } _{ strongNameSign } ") ;
330395
331396 Assert . Empty ( this . FindGeneratedType ( "PCWSTR" ) ) ;
397+ Assert . Empty ( this . FindGeneratedType ( "SysFreeStringSafeHandle" ) ) ;
332398
333399 File . Delete ( referencedAssemblyPath ) ;
334400 }
0 commit comments