diff --git a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
index d72c17b401bd..7bfc9fa2442b 100644
--- a/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
+++ b/pkg/Microsoft.Private.PackageBaseline/packageIndex.json
@@ -1709,7 +1709,8 @@
},
"AssemblyVersionInPackageVersion": {
"4.0.0.0": "4.5.0",
- "4.0.0.1": "4.5.1"
+ "4.0.0.1": "4.5.1",
+ "4.0.0.2": "4.5.2"
}
},
"System.Drawing.Design": {
diff --git a/src/System.Drawing.Common/dir.props b/src/System.Drawing.Common/dir.props
index 73d9ff2c9564..88e68540387f 100644
--- a/src/System.Drawing.Common/dir.props
+++ b/src/System.Drawing.Common/dir.props
@@ -2,8 +2,8 @@
- 4.0.0.1
+ 4.0.0.2
Open
- 4.5.1
+ 4.5.2
diff --git a/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
index c7d8c1caf5b3..603977c98060 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Graphics.Unix.cs
@@ -51,6 +51,7 @@ public sealed partial class Graphics : MarshalByRefObject, IDisposable
private static float defDpiX = 0;
private static float defDpiY = 0;
private IntPtr deviceContextHdc;
+ private Metafile.MetafileHolder _metafileHolder;
public delegate bool EnumerateMetafileProc(EmfPlusRecordType recordType,
int flags,
@@ -65,6 +66,14 @@ internal Graphics(IntPtr nativeGraphics)
nativeObject = nativeGraphics;
}
+ internal Graphics(IntPtr nativeGraphics, Image image) : this(nativeGraphics)
+ {
+ if (image is Metafile mf)
+ {
+ _metafileHolder = mf.AddMetafileHolder();
+ }
+ }
+
~Graphics()
{
Dispose();
@@ -287,6 +296,14 @@ public void Dispose()
status = SafeNativeMethods.Gdip.GdipDeleteGraphics(nativeObject);
nativeObject = IntPtr.Zero;
SafeNativeMethods.Gdip.CheckStatus(status);
+
+ if (_metafileHolder != null)
+ {
+ var mh = _metafileHolder;
+ _metafileHolder = null;
+ mh.GraphicsDisposed();
+ }
+
disposed = true;
}
@@ -1735,7 +1752,7 @@ public static Graphics FromImage(Image image)
int status = SafeNativeMethods.Gdip.GdipGetImageGraphicsContext(image.nativeImage, out graphics);
SafeNativeMethods.Gdip.CheckStatus(status);
- Graphics result = new Graphics(graphics);
+ Graphics result = new Graphics(graphics, image);
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
SafeNativeMethods.Gdip.GdipSetVisibleClip_linux(result.NativeObject, ref rect);
diff --git a/src/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs b/src/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs
index d61256ca0a60..0c2520f1d58e 100644
--- a/src/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs
+++ b/src/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Unix.cs
@@ -34,6 +34,7 @@
using System.IO;
using System.Reflection;
using System.ComponentModel;
+using System.Diagnostics;
using System.Runtime.InteropServices;
namespace System.Drawing.Imaging
@@ -47,6 +48,90 @@ namespace System.Drawing.Imaging
public sealed class Metafile : Image
{
+ // Non-null if a graphics instance was created using
+ // Graphics.FromImage(this) The metadata holder is responsible for
+ // freeing the nativeImage if the Metadata instance is disposed before
+ // the Graphics instance.
+ private MetafileHolder _metafileHolder;
+
+ // A class responsible for disposing of the native Metafile instance
+ // if it needs to outlive the managed Metafile instance.
+ //
+ // The following are both legal with win32 GDI+:
+ // Metafile mf = ...; // get a metafile instance
+ // Graphics g = Graphics.FromImage(mf); // get a graphics instance
+ // g.Dispose(); mf.Dispose(); // dispose of the graphics instance first
+ // OR
+ // mf.Dispose(); g.Dispose(); // dispose of the metafile instance first
+ //
+ //
+ // The metafile holder is designed to take ownership of the native metafile image
+ // when the managed Metafile instance is disposed while a Graphics instance is still
+ // not disposed (ie the second code pattern above) and to keep the native image alive until the graphics
+ // instance is disposed.
+ //
+ // Note that the following throws, so we only ever need to keep track of one Graphics
+ // instance at a time:
+ // Metafile mf = ...; // get a metafile instance
+ // Graphics g = Graphics.FromImage(mf);
+ // Graphics g2 = Graphics.FromImage(mf); // throws OutOfMemoryException on GDI+ on Win32
+ internal sealed class MetafileHolder : IDisposable
+ {
+ private bool _disposed;
+ private IntPtr _nativeImage;
+
+
+ internal bool Disposed { get => _disposed; }
+ internal MetafileHolder()
+ {
+ _disposed = false;
+ _nativeImage = IntPtr.Zero;
+ }
+
+ ~MetafileHolder() => Dispose(false);
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ internal void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ IntPtr nativeImage = _nativeImage;
+ _nativeImage = IntPtr.Zero;
+ _disposed = true;
+ if (nativeImage != IntPtr.Zero)
+ {
+ int status = SafeNativeMethods.Gdip.GdipDisposeImage(nativeImage);
+ SafeNativeMethods.Gdip.CheckStatus(status);
+ }
+ }
+ }
+
+ internal void MetafileDisposed(IntPtr nativeImage)
+ {
+ _nativeImage = nativeImage;
+ }
+
+ internal void GraphicsDisposed()
+ {
+ Dispose();
+ }
+ }
+
+ internal MetafileHolder AddMetafileHolder()
+ {
+ // If _metafileHolder is not null and hasn't been disposed yet, there's already a graphics instance associated with
+ // this metafile, the native code will return an error status.
+ if (_metafileHolder != null && !_metafileHolder.Disposed)
+ return null;
+ _metafileHolder = new MetafileHolder();
+ return _metafileHolder;
+ }
+
// constructors
internal Metafile(IntPtr ptr) => SetNativeImage(ptr);
@@ -311,6 +396,21 @@ public Metafile(string fileName, IntPtr referenceHdc, RectangleF frameRect, Meta
SafeNativeMethods.Gdip.CheckStatus(status);
}
+ protected override void Dispose(bool disposing)
+ {
+ if (_metafileHolder != null && !_metafileHolder.Disposed)
+ {
+ // There's a graphics instance created from this Metafile,
+ // transfer responsibility for disposing the nativeImage to the
+ // MetafileHolder
+ _metafileHolder.MetafileDisposed(nativeImage);
+ _metafileHolder = null;
+ nativeImage = IntPtr.Zero;
+ }
+
+ base.Dispose(disposing);
+ }
+
// methods
public IntPtr GetHenhmetafile()
diff --git a/src/packages.builds b/src/packages.builds
index aaf7881718f5..5f4d49c67406 100644
--- a/src/packages.builds
+++ b/src/packages.builds
@@ -24,6 +24,9 @@
$(AdditionalProperties)
+
+ $(AdditionalProperties)
+