Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[.NET/CoreFoundation] Use [UnmanagedCallersOnly] instead of [MonoPInvokeCallback] for the CGPDFDictionaryApplyFunction function. #12956

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions src/CoreGraphics/CGPDFDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,51 +154,77 @@ public bool GetArray (string key, out CGPDFArray array)
return r;
}

#if NET
[DllImport (Constants.CoreGraphicsLibrary)]
unsafe extern static void CGPDFDictionaryApplyFunction (/* CGPDFDictionaryRef */ IntPtr dic, delegate* unmanaged<IntPtr, IntPtr, IntPtr, void> function, /* void* */ IntPtr info);
#else
// CGPDFDictionaryApplierFunction
delegate void ApplierFunction (/* const char* */ string key, /* CGPDFObjectRef */ IntPtr value, /* void* */ IntPtr info);
delegate void ApplierFunction (/* const char* */ IntPtr key, /* CGPDFObjectRef */ IntPtr value, /* void* */ IntPtr info);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be left as string and add in a [MarhsalAs(UnmanagedType. LPUTF8Str)] to the string parameter?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because parameters and the return type for methods decorated with [UnmanagedCallersOnly] must be blittable, and string isn't blittable (and the MarshalAs attribute doesn't change that fact).

Now technically this delegate could be left with the string argument, because it's only used in legacy Xamarin (and not where we apply the [UnmanagedCallersOnly] attribute), but that would mean we'd have different implementations of the ApplyBridge function between the legacy and .NET - one with a string argument and one with an IntPtr argument. I opted for changing the parameter type in legacy Xamarin to be able to share more code with .NET.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍


[DllImport (Constants.CoreGraphicsLibrary)]
extern static void CGPDFDictionaryApplyFunction (/* CGPDFDictionaryRef */ IntPtr dic, ApplierFunction function, /* void* */ IntPtr info);

static readonly ApplierFunction applyblock_handler = ApplyBridge;
#endif // NET

public delegate void ApplyCallback (string key, object value, object info);

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (ApplierFunction))]
#endif
static void ApplyBridge (string key, IntPtr pdfObject, IntPtr info)
#endif // NET
static void ApplyBridge (IntPtr key, IntPtr pdfObject, IntPtr info)
{
var data = (Tuple<ApplyCallback, object>) GCHandle.FromIntPtr (info).Target;
var callback = data.Item1;

callback (key, CGPDFObject.FromHandle (pdfObject), data.Item2);
callback (Marshal.PtrToStringUTF8 (key), CGPDFObject.FromHandle (pdfObject), data.Item2);
}

public void Apply (ApplyCallback callback, object info = null)
{
var data = new Tuple<ApplyCallback, object> (callback, info);
var gch = GCHandle.Alloc (data);
try {
#if NET
unsafe {
CGPDFDictionaryApplyFunction (Handle, &ApplyBridge, GCHandle.ToIntPtr (gch));
}
#else
CGPDFDictionaryApplyFunction (Handle, applyblock_handler, GCHandle.ToIntPtr (gch));
#endif
} finally {
gch.Free ();
}
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (ApplierFunction))]
#endif
static void ApplyBridge2 (string key, IntPtr pdfObject, IntPtr info)
#endif // NET
static void ApplyBridge2 (IntPtr key, IntPtr pdfObject, IntPtr info)
{
var callback = (Action<string,CGPDFObject>) GCHandle.FromIntPtr (info).Target;

callback (key, new CGPDFObject (pdfObject));
callback (Marshal.PtrToStringUTF8 (key), new CGPDFObject (pdfObject));
}

public void Apply (Action<string,CGPDFObject> callback)
{
GCHandle gch = GCHandle.Alloc (callback);
#if NET
unsafe {
CGPDFDictionaryApplyFunction (Handle, &ApplyBridge2, GCHandle.ToIntPtr (gch));
}
#else
CGPDFDictionaryApplyFunction (Handle, ApplyBridge2, GCHandle.ToIntPtr (gch));
#endif
gch.Free ();
}

Expand Down