diff --git a/.agents/skills/cswin32-com/SKILL.md b/.agents/skills/cswin32-com/SKILL.md index ae6a1c0..4727ad9 100644 --- a/.agents/skills/cswin32-com/SKILL.md +++ b/.agents/skills/cswin32-com/SKILL.md @@ -52,7 +52,11 @@ attaches it to every generated COM struct **only on .NET 7+**. On net472: public unsafe partial struct IUnknown : IComIID { - readonly Guid IComIID.Guid => IID_Guid; // CsWin32-emitted field, always present + readonly ref readonly Guid IComIID.Guid + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Unsafe.AsRef(in IID_Guid); // CsWin32-emitted field, always present + } } ``` diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index bacadc6..5744d00 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -98,7 +98,12 @@ jobs: uses: codecov/codecov-action@v5 with: files: artifacts/coverage/Cobertura.xml - fail_ci_if_error: true + # Coverage upload is informational and must not gate the build. The + # Codecov uploader has an intermittent sha256/GPG signature race on the + # CDN that hard-fails otherwise unrelated PRs (Codecov-side bug, "no + # security issue" per the maintainers): + # https://github.com/codecov/codecov-action/issues/1940 + fail_ci_if_error: false disable_search: true token: ${{ secrets.CODECOV_TOKEN }} - name: Upload raw logs diff --git a/Directory.Packages.props b/Directory.Packages.props index 2dfd7f8..101aa4e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,21 +4,21 @@ true - - + + - + - - + + - + diff --git a/madowaku/Framework/Windows/Win32/IComIID.cs b/madowaku/Framework/Windows/Win32/IComIID.cs index 2795677..3b65b07 100644 --- a/madowaku/Framework/Windows/Win32/IComIID.cs +++ b/madowaku/Framework/Windows/Win32/IComIID.cs @@ -17,6 +17,6 @@ public interface IComIID /// /// The identifier (IID) GUID for this interface. /// - Guid Guid { get; } + ref readonly Guid Guid { get; } } } diff --git a/madowaku/Framework/Windows/Win32/System/Com/IUnknown.cs b/madowaku/Framework/Windows/Win32/System/Com/IUnknown.cs index 3ea8957..f6832b9 100644 --- a/madowaku/Framework/Windows/Win32/System/Com/IUnknown.cs +++ b/madowaku/Framework/Windows/Win32/System/Com/IUnknown.cs @@ -9,5 +9,9 @@ namespace Windows.Win32.System.Com; /// public unsafe partial struct IUnknown : IComIID { - readonly Guid IComIID.Guid => IID_Guid; + readonly ref readonly Guid IComIID.Guid + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Unsafe.AsRef(in IID_Guid); + } } diff --git a/madowaku/Framework/Windows/Win32/System/Ole/IRecordInfo.cs b/madowaku/Framework/Windows/Win32/System/Ole/IRecordInfo.cs index f8571a5..8854927 100644 --- a/madowaku/Framework/Windows/Win32/System/Ole/IRecordInfo.cs +++ b/madowaku/Framework/Windows/Win32/System/Ole/IRecordInfo.cs @@ -9,5 +9,9 @@ namespace Windows.Win32.System.Ole; /// public partial struct IRecordInfo : IComIID { - readonly Guid IComIID.Guid => IID_Guid; + readonly ref readonly Guid IComIID.Guid + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Unsafe.AsRef(in IID_Guid); + } } diff --git a/madowaku/Windows/Win32/Foundation/IID.cs b/madowaku/Windows/Win32/Foundation/IID.cs index cad4515..c8b92df 100644 --- a/madowaku/Windows/Win32/Foundation/IID.cs +++ b/madowaku/Windows/Win32/Foundation/IID.cs @@ -28,19 +28,37 @@ private static ref readonly Guid IID_NULL } } + // We cast away the "readonly" here as there is no way to communicate that through a pointer and + // Marshal APIs take the Guid as ref. Even though none of our usages actually change the state. + + /// + /// Gets a pointer to the IID for the given . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Guid* Get() where T : unmanaged, IComIID + { +#if NET + return (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in T.Guid)); +#else + return (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in default(T).Guid)); +#endif + } + + /// + /// Gets a reference to the IID for the given . + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Guid Get() where T : unmanaged, IComIID + public static ref readonly Guid GetRef() where T : unmanaged, IComIID { -#if NETFRAMEWORK - // In .NET Framework we need to use the interface to get the Guid. - return default(T).Guid; +#if NET + return ref T.Guid; #else - return T.Guid; + return ref default(T).Guid; #endif } /// - /// Empty . + /// Empty (GUID_NULL in docs). /// - public static Guid* Empty() => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID_NULL)); + public static Guid* NULL() => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID_NULL)); } diff --git a/madowaku/Windows/Win32/System/Com/ComClassFactory.cs b/madowaku/Windows/Win32/System/Com/ComClassFactory.cs index ae54565..519d4f3 100644 --- a/madowaku/Windows/Win32/System/Com/ComClassFactory.cs +++ b/madowaku/Windows/Win32/System/Com/ComClassFactory.cs @@ -113,9 +113,8 @@ public ComScope CreateInstance() public ComScope TryCreateInstance(out HRESULT result) where TInterface : unmanaged, IComIID { - Guid iid = IID.Get(); ComScope scope = default; - result = _classFactory->CreateInstance(null, &iid, scope); + result = _classFactory->CreateInstance(null, IID.Get(), scope); return scope; } diff --git a/madowaku/Windows/Win32/System/Com/ComScope{T}.cs b/madowaku/Windows/Win32/System/Com/ComScope{T}.cs index 34d9595..42a0703 100644 --- a/madowaku/Windows/Win32/System/Com/ComScope{T}.cs +++ b/madowaku/Windows/Win32/System/Com/ComScope{T}.cs @@ -100,9 +100,8 @@ public ComScope QueryInterface() where TInterface : unma /// public ComScope TryQueryInterface(out HRESULT result) where TInterface : unmanaged, IComIID { - Guid iid = IID.Get(); ComScope scope = new(null); - result = ((IUnknown*)Pointer)->QueryInterface(&iid, scope); + result = ((IUnknown*)Pointer)->QueryInterface(IID.Get(), scope); return scope; } diff --git a/madowaku/Windows/Win32/System/Com/GlobalInterfaceTable.cs b/madowaku/Windows/Win32/System/Com/GlobalInterfaceTable.cs index 19b4ec1..15da364 100644 --- a/madowaku/Windows/Win32/System/Com/GlobalInterfaceTable.cs +++ b/madowaku/Windows/Win32/System/Com/GlobalInterfaceTable.cs @@ -44,11 +44,9 @@ public static uint RegisterInterface(TInterface* @interface) where TInterface : unmanaged, IComIID { uint cookie; - Guid iid = IID.Get(); - s_globalInterfaceTable->RegisterInterfaceInGlobal( (IUnknown*)@interface, - &iid, + IID.Get(), &cookie).ThrowOnFailure(); return cookie; @@ -61,9 +59,8 @@ public static uint RegisterInterface(TInterface* @interface) public static ComScope GetInterface(uint cookie, out HRESULT result) where TInterface : unmanaged, IComIID { - Guid iid = IID.Get(); ComScope @interface = new(null); - result = s_globalInterfaceTable->GetInterfaceFromGlobal(cookie, &iid, (void**)&@interface); + result = s_globalInterfaceTable->GetInterfaceFromGlobal(cookie, IID.Get(), (void**)&@interface); return @interface; }