Skip to content

[src] Remove NSPrintPreviewGraphicsContext.#25527

Open
rolfbjarne wants to merge 8 commits into
mainfrom
dev/rolf/appkit-nsprintpreviewgraphicscontext
Open

[src] Remove NSPrintPreviewGraphicsContext.#25527
rolfbjarne wants to merge 8 commits into
mainfrom
dev/rolf/appkit-nsprintpreviewgraphicscontext

Conversation

@rolfbjarne
Copy link
Copy Markdown
Member

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 (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:

  • 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:

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
Copilot AI review requested due to automatic review settings May 26, 2026 14:02
@rolfbjarne rolfbjarne requested a review from dalexsoto as a code owner May 26, 2026 14:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 NSPrintPreviewGraphicsContext binding from appkit.cs and added a [DynamicDependency] on NSGraphicsContext.CurrentContext to keep Foundation.NSProxy from being trimmed.
  • Extended bgen to copy/emit DynamicDependencyAttribute from 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; } }
Comment thread src/bgen/Generator.cs
} else if (arg.Value is int intValue) {
parts.Add (FormatDynamicallyAccessedMemberTypes (intValue));
} else if (arg.Value is Type typeValue) {
parts.Add ($"typeof ({typeValue})");
Comment thread src/bgen/Generator.cs
Comment on lines +5631 to +5637
static string FormatDynamicallyAccessedMemberTypes (int memberTypes)
{
if (memberTypes == -1) // All
return "DynamicallyAccessedMemberTypes.All";
if (memberTypes == 0) // None
return "DynamicallyAccessedMemberTypes.None";

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne rolfbjarne enabled auto-merge (squash) May 27, 2026 06:12
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2
Copy link
Copy Markdown
Collaborator

✅ [PR Build #41f0a9f] Build passed (Detect API changes) ✅

Pipeline on Agent
Hash: 41f0a9fda970add83833ddd81416023de8430899 [PR build]

@vs-mobiletools-engineering-service2
Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 41f0a9fda970add83833ddd81416023de8430899 [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2
Copy link
Copy Markdown
Collaborator

✅ [PR Build #41f0a9f] Build passed (Build packages) ✅

Pipeline on Agent
Hash: 41f0a9fda970add83833ddd81416023de8430899 [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2
Copy link
Copy Markdown
Collaborator

✅ [PR Build #41f0a9f] Build passed (Build macOS tests) ✅

Pipeline on Agent
Hash: 41f0a9fda970add83833ddd81416023de8430899 [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2
Copy link
Copy Markdown
Collaborator

🔥 [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

  • monotouch-test/iOS - simulator/Debug: LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (link sdk): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (link all): LaunchTimedOut
  • monotouch-test/iOS - simulator/Debug (LinkSdk): LaunchTimedOut
  • monotouch-test/iOS - simulator/Debug (static registrar): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (all optimizations): LaunchTimedOut
  • monotouch-test/iOS - simulator/Debug (ARM64): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (NativeAOT, ARM64): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (trimmable static registrar, NativeAOT, ARM64): LaunchTimedOut
  • monotouch-test/iOS - simulator/Debug (managed static registrar): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (managed static registrar, all optimizations): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (NativeAOT, x64): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (trimmable static registrar, NativeAOT, x64): LaunchTimedOut
  • monotouch-test/iOS - simulator/Debug (interpreter): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (interpreter): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (compat inline Class.GetHandle): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (strict inline Class.GetHandle): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (compat inline dlfcn): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (strict inline dlfcn, link sdk): LaunchTimedOut
  • monotouch-test/iOS - simulator/Release (NativeAOT, .NET 11 defaults): LaunchTimedOut

Html Report (VSDrops) Download

❌ monotouch tests (tvOS) [attempt 4]

20 tests failed, 0 tests passed.

Failed tests

  • monotouch-test/tvOS - simulator/Debug: LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (link sdk): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (link all): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Debug (LinkSdk): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Debug (static registrar): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (all optimizations): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Debug (ARM64): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (NativeAOT, ARM64): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (trimmable static registrar, NativeAOT, ARM64): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Debug (managed static registrar): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (managed static registrar, all optimizations): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (NativeAOT, x64): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (trimmable static registrar, NativeAOT, x64): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Debug (interpreter): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (interpreter): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (compat inline Class.GetHandle): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (strict inline Class.GetHandle): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (compat inline dlfcn): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (strict inline dlfcn, link sdk): LaunchTimedOut
  • monotouch-test/tvOS - simulator/Release (NativeAOT, .NET 11 defaults): LaunchTimedOut

Html Report (VSDrops) Download

Successes

✅ cecil: All 1 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. [attempt 2] (⚠️ Html Report Publish failed ⚠️) Download
✅ dotnettests (macOS): All 1 tests passed. [attempt 2] (⚠️ Html Report Publish failed ⚠️) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. [attempt 3] Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ introspection: All 6 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 11 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 11 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ linker (macOS): All 11 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ linker (tvOS): All 11 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 23 tests passed. [attempt 3] (⚠️ Html Report Publish failed ⚠️) Download
✅ monotouch (macOS): All 23 tests passed. [attempt 3] Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. (⚠️ Html Report Publish failed ⚠️) Download
✅ sharpie: All 1 tests passed. [attempt 2] (⚠️ Html Report Publish failed ⚠️) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: 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
✅ Tests on macOS Ventura (13): All 5 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. [attempt 2] Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. [attempt 2] Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 41f0a9fda970add83833ddd81416023de8430899 [PR build]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants