[src] Remove NSPrintPreviewGraphicsContext.#25527
Conversation
NSPrintPreviewGraphicsContext existed in our bindings because we sometimes get instances of this type, and since its parent type is NSProxy, it causes problems at runtime when we try to figure out which managed type to instantiate.
In particular, when:
* The app is trimmed
* The NSProxy type is trimmed away
This happens:
MarshalManagedException: ObjCRuntime.RuntimeException: The ObjectiveC class 'NSPrintPreviewGraphicsContext' could not be registered, it does not seem to derive from any known ObjectiveC class (including NSObject).
at Registrar.DynamicRegistrar.Lookup(IntPtr class, Boolean throw_on_error) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/DynamicRegistrar.cs:line 1069
at ObjCRuntime.Class.Lookup(IntPtr klass, Boolean throw_on_error) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/Class.cs:line 291
at ObjCRuntime.Class.Lookup(IntPtr klass) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/Class.cs:line 272
at ObjCRuntime.Runtime.GetNSObject[T](IntPtr ptr, IntPtr sel, RuntimeMethodHandle method_handle, Boolean evenInFinalizerQueue, Boolean typeSafe) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/Runtime.cs:line 1893
at ObjCRuntime.Runtime.GetNSObject[T](IntPtr ptr) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/Runtime.cs:line 1844
at ObjCRuntime.Runtime.GetNSObject[T](IntPtr ptr, Boolean owns) in /Users/builder/azdo/_work/1/s/macios/src/ObjCRuntime/Runtime.cs:line 1930
at AppKit.NSGraphicsContext.get_CurrentContext() in /Users/builder/azdo/_work/1/s/macios/src/build/dotnet/macos/generated-sources/AppKit/NSGraphicsContext.g.cs:line 411
at PrintableView.DrawPageBorder(CGSize borderSize) in /Users/rolf/test/dotnet/macos-printpreview/Program.cs:line 97
because `NSProxy` doesn't subclass `NSObject`, we can't find a managed type to instantiate.
In the Xamarin days we had custom linker support to keep `NSPrintPreviewGraphicsContext` (xamarin/maccore@d047ee1), but this was never ported to .NET, so this has been broken since forever in .NET.
So fix this by:
* Removing the `NSPrintPreviewGraphicsContext` binding, it causes problems when inlining calls to Class.GetHandle, because it's not part of the public API.
* Ensure `NSProxy` is not trimmed away when `NSGraphicsContext.CurrentContext` is used, this way we'll return an `NSProxy` instance when the native instance is an actual `NSPrintPreviewGraphicsContext`. This required adding support for copying `[DynamicDependency]` attributes from binding code to the generated code.
* Also add unit tests.
This required removing the WebKit_NSProxy unit test, because it doesn't work anymore (it asserts that the `NSProxy` type is trimmed away, but one of the new tests depends on `NSProxy` not being trimmed away).
References:
* https://github.com/xamarin/bugzilla-archives/blob/main/16/16505/bug.html
* xamarin/maccore@d047ee1
There was a problem hiding this comment.
Pull request overview
This PR addresses a longstanding trimming/runtime crash in macOS print preview when NSGraphicsContext.CurrentContext returns an internal NSPrintPreviewGraphicsContext (an NSProxy subclass). The approach is to remove the problematic binding and instead ensure NSProxy is preserved when CurrentContext is used, by flowing [DynamicDependency] from binding definitions into generated code, with accompanying tests.
Changes:
- Removed the
NSPrintPreviewGraphicsContextbinding fromappkit.csand added a[DynamicDependency]onNSGraphicsContext.CurrentContextto keepFoundation.NSProxyfrom being trimmed. - Extended bgen to copy/emit
DynamicDependencyAttributefrom binding members into generated code, and added bgen unit tests for the new behavior. - Updated linker tests and known-failure/ignore lists to reflect the API change and validate the print preview scenario.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore | Removes the ignore entry for NSPrintPreviewGraphicsContext now that it’s no longer bound. |
| tests/linker/link all/LinkAllTest.cs | Removes the WebKit_NSProxy test that assumed NSProxy could be trimmed away. |
| tests/linker/link all/LinkAllMacTest.cs | Adds a new macOS print-preview regression test validating NSGraphicsContext.CurrentContext under linking. |
| tests/cecil-tests/Documentation.KnownFailures.txt | Removes the known failure entry for NSPrintPreviewGraphicsContext documentation. |
| tests/bgen/tests/dynamic-dependency-attribute.cs | New bgen test input exercising multiple DynamicDependencyAttribute constructor shapes. |
| tests/bgen/BGenTests.cs | Adds assertions that bgen emits DynamicDependencyAttribute on generated members as expected. |
| src/frameworks.sources | Adds AppKit/NSPrintPreviewGraphicsContext.cs to the build inputs. |
| src/bgen/Generator.cs | Adds emission of [DynamicDependency] attributes when generating members from bindings. |
| src/bgen/AttributeManager.cs | Ignores DynamicDependencyAttribute in attribute processing to avoid treating it as a binding attribute. |
| src/AppKit/NSPrintPreviewGraphicsContext.cs | Introduces a compatibility stub type for NSPrintPreviewGraphicsContext (but currently has issues called out in comments). |
| src/appkit.cs | Adds [DynamicDependency] to the getter for NSGraphicsContext.CurrentContext and removes the NSPrintPreviewGraphicsContext binding definition. |
| using System; | ||
| using System.ComponentModel; | ||
|
|
||
| #if __MACOS__ && !__XAMCORE_5_0__ |
| [Obsolete ("This class does not form part of the public API in macOS, and will be removed in the future.")] | ||
| public partial class NSPrintPreviewGraphicsContext : NSGraphicsContext { | ||
|
|
||
| public override NativeHandle ClassHandle { get { return default; } } |
| } else if (arg.Value is int intValue) { | ||
| parts.Add (FormatDynamicallyAccessedMemberTypes (intValue)); | ||
| } else if (arg.Value is Type typeValue) { | ||
| parts.Add ($"typeof ({typeValue})"); |
| static string FormatDynamicallyAccessedMemberTypes (int memberTypes) | ||
| { | ||
| if (memberTypes == -1) // All | ||
| return "DynamicallyAccessedMemberTypes.All"; | ||
| if (memberTypes == 0) // None | ||
| return "DynamicallyAccessedMemberTypes.None"; | ||
|
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ntpreviewgraphicscontext
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #41f0a9f] Build passed (Detect API changes) ✅Pipeline on Agent |
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #41f0a9f] Build passed (Build packages) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #41f0a9f] Build passed (Build macOS tests) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
🔥 [CI Build #41f0a9f] Test results 🔥Test results❌ Tests failed on VSTS: test results 0 tests crashed, 40 tests failed, 153 tests passed. Failures❌ monotouch tests (iOS) [attempt 4]20 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (tvOS) [attempt 4]20 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download Successes✅ cecil: All 1 tests passed. [attempt 2] Html Report (VSDrops) Download macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. [attempt 2] Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
NSPrintPreviewGraphicsContext existed in our bindings because we sometimes get instances of this type, and since its parent type is NSProxy, it causes problems at runtime when we try to figure out which managed type to instantiate.
In particular, when:
This happens:
because
NSProxydoesn't subclassNSObject, we can't find a managed type to instantiate.In the Xamarin days we had custom linker support to keep
NSPrintPreviewGraphicsContext(https://github.com/xamarin/maccore/commit/d047ee123f3bfc28126bb9258878fccfed8d1c7a), but this was never ported to .NET, so this has been broken since forever in .NET.So fix this by:
NSPrintPreviewGraphicsContextbinding, it causes problems when inlining calls to Class.GetHandle, because it's not part of the public API.NSProxyis not trimmed away whenNSGraphicsContext.CurrentContextis used, this way we'll return anNSProxyinstance when the native instance is an actualNSPrintPreviewGraphicsContext. This required adding support for copying[DynamicDependency]attributes from binding code to the generated code.This required removing the WebKit_NSProxy unit test, because it doesn't work anymore (it asserts that the
NSProxytype is trimmed away, but one of the new tests depends onNSProxynot being trimmed away).References: