Multi-target System.Private.Windows.Core#14384
Open
JeremyKuhne wants to merge 6 commits intodotnet:mainfrom
Open
Multi-target System.Private.Windows.Core#14384JeremyKuhne wants to merge 6 commits intodotnet:mainfrom
JeremyKuhne wants to merge 6 commits intodotnet:mainfrom
Conversation
This builds our shared functionality assembly for .NET Framework 4.7.2 as Microsoft.Private.Windows.Core with the same namespaces. This is for internal scenarios where we need this shared functionality on .NET Framework. Static and default interface methods don't work on .NET Framework. For our composition usages of static interfaces we build the same interface with instance methods and constrain the consuming types to `new()` as well so they can create a static instance of the `T` that they need. On Framework we still use direct COM to look at existing COM objects. For CCWs, however, we let `Marshal` provide them on Framework. Most of the complexity around that is with unwrapping DataObject. I believe things should work as expected but it is a particular focus point for both testing and following up with issues when utilizing this code. There are some CsWin32 tweaks that are necessary, notably around `IComIId`. Added partials for the COM classes where we needed them. Framework only code is in the `Framework` subfolder and ingested through the previously committed shared polyfill project. Some tests needed to be tweaked for a few reasons. One in particular was that some validated implementation details rather than functional. Some shared test functionality (notably validators that depend on static numeric interfaces) was simply excluded on .NET Framework as it wasn't being used in the tests that we needed to multitarget. .NET Framework versions can be added if/when needed.
JeremyKuhne
commented
Mar 11, 2026
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/BinaryFormatUtilities.cs
Outdated
Show resolved
Hide resolved
JeremyKuhne
commented
Mar 11, 2026
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/Composition.cs
Outdated
Show resolved
Hide resolved
JeremyKuhne
commented
Mar 11, 2026
...em.Private.Windows.Core/src/System/Private/Windows/Ole/Composition.NativeToManagedAdapter.cs
Outdated
Show resolved
Hide resolved
JeremyKuhne
commented
Mar 11, 2026
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/DragDropHelper.cs
Outdated
Show resolved
Hide resolved
JeremyKuhne
commented
Mar 11, 2026
JeremyKuhne
commented
Mar 11, 2026
src/System.Private.Windows.Core/src/Windows/Win32/System/Com/ComHelpers.cs
Outdated
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment.
Pull request overview
Multi-targets System.Private.Windows.Core for .NET Framework 4.7.2 as Microsoft.Private.Windows.Core, adapting static interface methods to instance methods and handling COM interop differences.
Changes:
- Adds
Microsoft.Private.Windows.Core.csprojtargeting net472 with#if NET/#if NETFRAMEWORKconditionals throughout for static vs instance interface methods, COM interop, and JSON serialization - Adapts test infrastructure and tests to multi-target net481, with Framework-specific workarounds for clipboard, serialization, and COM behaviors
- Adds Framework-only
IComIIDpartials, polyfills (IsSZArray), andDataObjectFactoryhelper for non-static interface consumption
Reviewed changes
Copilot reviewed 110 out of 111 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| Microsoft.Private.Windows.Core.csproj | New project file for .NET Framework build |
| IComIID.cs (Framework) | Instance-based IComIID interface for Framework |
| Framework COM partials | IComIID implementations for IUnknown, IDataObject, IStream, etc. |
| DataObjectFactory.cs | Helper to create data objects via instance methods on Framework |
| IOleServices.cs, INrbfSerializer.cs, IDataFormat.cs, IDataObjectInternal.cs | Conditional static abstract vs instance interface members |
| ClipboardCore.cs, Composition.cs, DataStore.cs, DragDropHelper.cs, BinaryFormatUtilities.cs, TypeBinder.cs | Add s_oleServices/s_nrbfSerializer instances and conditional dispatch |
| ComScope.cs, ComHelpers.cs | Alias IUnknown as ComUnknown for Framework XML doc compatibility |
| IID.cs | Framework path using default(T).Guid instead of T.Guid |
| PInvokeCore.Enum*.cs | Framework callback marshaling via delegate + GetFunctionPointerForDelegate |
| SpanReader.cs, SpanWriter.cs, BinaryReaderExtensions.cs | Framework-safe span/memory operations |
| IHandle.cs, NullHandle.cs, HdcHandle.cs | Add explicit Wrapper property for Framework |
| StreamExtensions.cs | Handle zero-size HGLOBAL allocation |
| Various test files | Multi-target adaptations, conditional test exclusions |
| TestUtilities | Multi-target support, polyfills, NoAssertContext initialization |
| VARIANT.cs | Framework fallback to Marshal.GetObjectForNativeVariant |
| OLE_HANDLE.cs | Fix sign extension with explicit (nint) cast |
| IRecord.cs, NullRecord.cs, etc. | Make Id a required property, remove RecordMap |
| DataObjectExtensions.cs | Convert to C# 14 extension type syntax |
Comments suppressed due to low confidence (3)
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/DataObjectExtensions.cs:1
- This uses C# 14 extension types syntax (
extension(...)), which requires .NET 9+ / C# 14 preview. Since this PR targets .NET Framework 4.7.2, this file would fail to compile on Framework unless it's excluded. Verify this file is excluded from the Framework build, or use a traditional extension method with#ifguards.
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/DragDropHelper.cs:1 - The original code used
Marshal.GetLastSystemError()which was changed toMarshal.GetLastWin32Error().GetLastSystemError()was introduced in .NET 8 and mapserrnoon Unix;GetLastWin32Error()is correct for Windows-only P/Invoke scenarios and works on both .NET and .NET Framework, so this change is appropriate for multi-targeting. However, if the originalGetLastSystemError()was intentional for a reason, this is a behavioral change on .NET.
src/System.Private.Windows.Core/src/System/Private/Windows/Ole/Composition.NativeToManagedAdapter.cs:1 - This null/whitespace guard was added to
GetDataPresentbut not to the other methods that takeformat(e.g.,GetData). If this is needed to prevent a downstream crash on Framework, consider applying it consistently or documenting why onlyGetDataPresentneeds it.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/Common/tests/TestUtilities/FluentAssertions/FluentAssertExtensions.cs
Show resolved
Hide resolved
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This builds our shared functionality assembly for .NET Framework 4.7.2 as Microsoft.Private.Windows.Core with the same namespaces. This is for internal scenarios where we need this shared functionality on .NET Framework.
Static and default interface methods don't work on .NET Framework.
For our composition usages of static interfaces we build the same interface with instance methods and constrain the consuming types to
new()as well so they can create a static instance of theTthat they need.On Framework we still use direct COM to look at existing COM objects. For CCWs, however, we let
Marshalprovide them on Framework. Most of the complexity around that is with unwrapping DataObject. I believe things should work as expected but it is a particular focus point for both testing and following up with issues when utilizing this code.There are some CsWin32 tweaks that are necessary, notably around
IComIId. Added partials for the COM classes where we needed them.Framework only code is in the
Frameworksubfolder and ingested through the previously committed shared polyfill project.Some tests needed to be tweaked for a few reasons. One in particular was that some validated implementation details rather than functional.
Some shared test functionality (notably validators that depend on static numeric interfaces) was simply excluded on .NET Framework as it wasn't being used in the tests that we needed to multitarget. .NET Framework versions can be added if/when needed.
Microsoft Reviewers: Open in CodeFlow