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;
}