diff --git a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs
new file mode 100644
index 0000000000000..a3ff4e14fb7a7
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.IO;
+
+internal static partial class Interop
+{
+ internal static partial class Ole32
+ {
+ ///
+ /// IStream interface.
+ ///
+ ///
+ /// This interface explicitly doesn't use the built-in COM support, but instead is only used with ComWrappers.
+ ///
+ internal interface IStream
+ {
+ // pcbRead is optional
+ unsafe void Read(byte* pv, uint cb, uint* pcbRead);
+
+ // pcbWritten is optional
+ unsafe void Write(byte* pv, uint cb, uint* pcbWritten);
+
+ // SeekOrgin matches the native values, plibNewPosition is optional
+ unsafe void Seek(long dlibMove, SeekOrigin dwOrigin, ulong* plibNewPosition);
+
+ void SetSize(ulong libNewSize);
+
+ // pcbRead and pcbWritten are optional
+ unsafe HRESULT CopyTo(
+ IntPtr pstm,
+ ulong cb,
+ ulong* pcbRead,
+ ulong* pcbWritten);
+
+ void Commit(uint grfCommitFlags);
+
+ void Revert();
+
+ HRESULT LockRegion(
+ ulong libOffset,
+ ulong cb,
+ uint dwLockType);
+
+ HRESULT UnlockRegion(
+ ulong libOffset,
+ ulong cb,
+ uint dwLockType);
+
+ unsafe void Stat(
+ STATSTG* pstatstg,
+ STATFLAG grfStatFlag);
+
+ unsafe HRESULT Clone(IntPtr* ppstm);
+ }
+ }
+}
diff --git a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.cs b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.cs
similarity index 97%
rename from src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.cs
rename to src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.cs
index 6fdf6718f050a..b8907e5a33a9f 100644
--- a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.cs
+++ b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.cs
@@ -9,7 +9,7 @@ internal static partial class Interop
internal static partial class Ole32
{
///
- /// COM IStream interface.
+ /// COM IStream interface.
///
///
/// The definition in does not lend
diff --git a/src/libraries/System.Drawing.Common/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Drawing.Common/src/ILLink/ILLink.Suppressions.xml
deleted file mode 100644
index a0b7401fb0ac2..0000000000000
--- a/src/libraries/System.Drawing.Common/src/ILLink/ILLink.Suppressions.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Bitmap.#ctor(System.IO.Stream,System.Boolean)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Image.FromStream(System.IO.Stream,System.Boolean,System.Boolean)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Image.InitializeFromStream(System.IO.Stream)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Image.Save(System.IO.Stream,System.Drawing.Imaging.ImageCodecInfo,System.Drawing.Imaging.EncoderParameters)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Imaging.Metafile.#ctor(System.IO.Stream,System.IntPtr,System.Drawing.Imaging.EmfType,System.String)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Imaging.Metafile.#ctor(System.IO.Stream,System.IntPtr,System.Drawing.Rectangle,System.Drawing.Imaging.MetafileFrameUnit,System.Drawing.Imaging.EmfType,System.String)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Imaging.Metafile.#ctor(System.IO.Stream,System.IntPtr,System.Drawing.RectangleF,System.Drawing.Imaging.MetafileFrameUnit,System.Drawing.Imaging.EmfType,System.String)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Imaging.Metafile.#ctor(System.IO.Stream)
-
-
- ILLink
- IL2050
- member
- M:System.Drawing.Imaging.Metafile.GetMetafileHeader(System.IO.Stream)
-
-
-
diff --git a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
index b02d55a46c6a2..ff707877c2d11 100644
--- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
+++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj
@@ -192,6 +192,7 @@
+
@@ -294,8 +295,6 @@
Link="Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs" />
-
+
+
-
+
+
+
+
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.cs
index 4fe1b54ae1b83..84f959f94c281 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.cs
@@ -9,25 +9,24 @@ namespace System.Drawing
{
public sealed partial class Bitmap
{
- public Bitmap(Stream stream, bool useIcm)
+ public unsafe Bitmap(Stream stream, bool useIcm)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
- IntPtr bitmap = IntPtr.Zero;
- int status;
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+ IntPtr bitmap = IntPtr.Zero;
if (useIcm)
{
- status = Gdip.GdipCreateBitmapFromStreamICM(new GPStream(stream), out bitmap);
+ Gdip.CheckStatus(Gdip.GdipCreateBitmapFromStreamICM(streamWrapper.Ptr, &bitmap));
}
else
{
- status = Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out bitmap);
+ Gdip.CheckStatus(Gdip.GdipCreateBitmapFromStream(streamWrapper.Ptr, &bitmap));
}
- Gdip.CheckStatus(status);
ValidateImage(bitmap);
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.COMWrappers.cs
similarity index 89%
rename from src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs
rename to src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.COMWrappers.cs
index 236ae1be2aa03..5889a4ac704b4 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.COMWrappers.cs
@@ -14,16 +14,16 @@ namespace System.Drawing
///
/// Supports IStream and IPicture COM interfaces.
///
- internal unsafe class DrawingComWrappers : ComWrappers
+ internal unsafe partial class DrawingCom : ComWrappers
{
private const int S_OK = (int)Interop.HRESULT.S_OK;
private static readonly Guid IID_IStream = new Guid(0x0000000C, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
private static readonly ComInterfaceEntry* s_wrapperEntry = InitializeComInterfaceEntry();
- internal static DrawingComWrappers Instance { get; } = new DrawingComWrappers();
+ internal static DrawingCom Instance { get; } = new DrawingCom();
- private DrawingComWrappers() { }
+ private DrawingCom() { }
private static ComInterfaceEntry* InitializeComInterfaceEntry()
{
@@ -31,7 +31,7 @@ private DrawingComWrappers() { }
IntPtr iStreamVtbl = IStreamVtbl.Create(fpQueryInterface, fpAddRef, fpRelease);
- ComInterfaceEntry* wrapperEntry = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(DrawingComWrappers), sizeof(ComInterfaceEntry));
+ ComInterfaceEntry* wrapperEntry = (ComInterfaceEntry*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(DrawingCom), sizeof(ComInterfaceEntry));
wrapperEntry->IID = IID_IStream;
wrapperEntry->Vtable = iStreamVtbl;
return wrapperEntry;
@@ -66,6 +66,27 @@ protected override void ReleaseObjects(IEnumerable objects)
throw new NotImplementedException();
}
+ internal static IStreamWrapper GetComWrapper(Interop.Ole32.IStream stream)
+ {
+ IntPtr streamWrapperPtr = Instance.GetOrCreateComInterfaceForObject(stream, CreateComInterfaceFlags.None);
+
+ Guid streamIID = IID_IStream;
+ int result = Marshal.QueryInterface(streamWrapperPtr, ref streamIID, out IntPtr streamPtr);
+
+ Marshal.Release(streamWrapperPtr);
+
+ ThrowExceptionForHR(result);
+
+ return new IStreamWrapper(streamPtr);
+ }
+
+ internal static void ThrowExceptionForHR(int errorCode)
+ {
+ // Pass -1 for errorInfo to indicate that Windows' GetErrorInfo shouldn't be called, and only
+ // throw the Exception corresponding to the specified errorCode.
+ Marshal.ThrowExceptionForHR(errorCode, errorInfo: new IntPtr(-1));
+ }
+
internal static class IStreamVtbl
{
public static IntPtr Create(IntPtr fpQueryInterface, IntPtr fpAddRef, IntPtr fpRelease)
@@ -159,16 +180,13 @@ private static int CopyTo(IntPtr thisPtr, IntPtr pstm, ulong cb, ulong* pcbRead,
try
{
Interop.Ole32.IStream inst = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr);
- Interop.Ole32.IStream pstmStream = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)pstm);
- inst.CopyTo(pstmStream, cb, pcbRead, pcbWritten);
+ return (int)inst.CopyTo(pstm, cb, pcbRead, pcbWritten);
}
catch (Exception e)
{
return e.HResult;
}
-
- return S_OK;
}
[UnmanagedCallersOnly]
@@ -250,23 +268,16 @@ private static int Stat(IntPtr thisPtr, Interop.Ole32.STATSTG* pstatstg, Interop
[UnmanagedCallersOnly]
private static int Clone(IntPtr thisPtr, IntPtr* ppstm)
{
- if (ppstm == null)
- {
- return (int)Interop.HRESULT.STG_E_INVALIDPOINTER;
- }
-
try
{
Interop.Ole32.IStream inst = ComInterfaceDispatch.GetInstance((ComInterfaceDispatch*)thisPtr);
- *ppstm = Instance.GetOrCreateComInterfaceForObject(inst.Clone(), CreateComInterfaceFlags.None);
+ return (int)inst.Clone(ppstm);
}
catch (Exception e)
{
return e.HResult;
}
-
- return S_OK;
}
}
@@ -297,7 +308,7 @@ public unsafe int SaveAsFile(IntPtr pstm, int fSaveMemCopy, int* pcbSize)
{
// Get the IStream implementation, since the ComWrappers runtime returns a pointer to the IUnknown interface implementation
Guid streamIID = IID_IStream;
- Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pstm, ref streamIID, out IntPtr pstmImpl));
+ ThrowExceptionForHR(Marshal.QueryInterface(pstm, ref streamIID, out IntPtr pstmImpl));
try
{
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.NoCOMWrappers.cs
new file mode 100644
index 0000000000000..d3fdd2115bffb
--- /dev/null
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.NoCOMWrappers.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Drawing.Internal;
+using System.Runtime.InteropServices;
+
+namespace System.Drawing
+{
+ internal static partial class DrawingCom
+ {
+ internal static IStreamWrapper GetComWrapper(GPStream stream)
+ {
+ return new IStreamWrapper(Marshal.GetComInterfaceForObject(stream));
+ }
+ }
+}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.cs
new file mode 100644
index 0000000000000..a5b53e65ff589
--- /dev/null
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+
+namespace System.Drawing
+{
+ internal partial class DrawingCom
+ {
+ internal readonly struct IStreamWrapper : IDisposable
+ {
+ public readonly IntPtr Ptr;
+
+ public IStreamWrapper(IntPtr ptr)
+ {
+ Ptr = ptr;
+ }
+
+ public void Dispose()
+ {
+ Marshal.Release(Ptr);
+ }
+ }
+ }
+}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
index 47aeb4f9397c3..3edf4a0e7b67e 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.cs
@@ -210,10 +210,10 @@ private static void PlatformInitialize()
internal static extern int GdipDeleteBrush(HandleRef brush);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipLoadImageFromStream(Interop.Ole32.IStream stream, out IntPtr image);
+ internal static extern int GdipLoadImageFromStream(IntPtr stream, IntPtr* image);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipLoadImageFromStreamICM(Interop.Ole32.IStream stream, out IntPtr image);
+ internal static extern int GdipLoadImageFromStreamICM(IntPtr stream, IntPtr* image);
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipCloneImage(HandleRef image, out IntPtr cloneimage);
@@ -222,7 +222,7 @@ private static void PlatformInitialize()
internal static extern int GdipSaveImageToFile(HandleRef image, string filename, ref Guid classId, HandleRef encoderParams);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipSaveImageToStream(HandleRef image, Interop.Ole32.IStream stream, ref Guid classId, HandleRef encoderParams);
+ internal static extern int GdipSaveImageToStream(HandleRef image, IntPtr stream, Guid* classId, HandleRef encoderParams);
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipSaveAdd(HandleRef image, HandleRef encoderParams);
@@ -327,7 +327,7 @@ private static void PlatformInitialize()
internal static extern int GdipGetMetafileHeaderFromFile(string filename, IntPtr header);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipGetMetafileHeaderFromStream(Interop.Ole32.IStream stream, IntPtr header);
+ internal static extern int GdipGetMetafileHeaderFromStream(IntPtr stream, IntPtr header);
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipGetMetafileHeaderFromMetafile(HandleRef metafile, IntPtr header);
@@ -336,16 +336,16 @@ private static void PlatformInitialize()
internal static extern int GdipGetHemfFromMetafile(HandleRef metafile, out IntPtr hEnhMetafile);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipCreateMetafileFromStream(Interop.Ole32.IStream stream, out IntPtr metafile);
+ internal static extern int GdipCreateMetafileFromStream(IntPtr stream, IntPtr* metafile);
[DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)]
- internal static extern int GdipRecordMetafileStream(Interop.Ole32.IStream stream, IntPtr referenceHdc, EmfType emfType, ref RectangleF frameRect, MetafileFrameUnit frameUnit, string? description, out IntPtr metafile);
+ internal static extern int GdipRecordMetafileStream(IntPtr stream, IntPtr referenceHdc, EmfType emfType, RectangleF* frameRect, MetafileFrameUnit frameUnit, string? description, IntPtr* metafile);
[DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)]
- internal static extern int GdipRecordMetafileStream(Interop.Ole32.IStream stream, IntPtr referenceHdc, EmfType emfType, IntPtr pframeRect, MetafileFrameUnit frameUnit, string? description, out IntPtr metafile);
+ internal static extern int GdipRecordMetafileStream(IntPtr stream, IntPtr referenceHdc, EmfType emfType, IntPtr pframeRect, MetafileFrameUnit frameUnit, string? description, IntPtr* metafile);
[DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)]
- internal static extern int GdipRecordMetafileStreamI(Interop.Ole32.IStream stream, IntPtr referenceHdc, EmfType emfType, ref Rectangle frameRect, MetafileFrameUnit frameUnit, string? description, out IntPtr metafile);
+ internal static extern int GdipRecordMetafileStreamI(IntPtr stream, IntPtr referenceHdc, EmfType emfType, Rectangle* frameRect, MetafileFrameUnit frameUnit, string? description, IntPtr* metafile);
[DllImport(LibraryName, ExactSpelling = true)]
internal static extern int GdipComment(HandleRef graphics, int sizeData, byte[] data);
@@ -354,10 +354,10 @@ private static void PlatformInitialize()
internal static extern int GdipCreateFontFromLogfontW(IntPtr hdc, ref Interop.User32.LOGFONT lf, out IntPtr font);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipCreateBitmapFromStream(Interop.Ole32.IStream stream, out IntPtr bitmap);
+ internal static extern int GdipCreateBitmapFromStream(IntPtr stream, IntPtr* bitmap);
[DllImport(LibraryName, ExactSpelling = true)]
- internal static extern int GdipCreateBitmapFromStreamICM(Interop.Ole32.IStream stream, out IntPtr bitmap);
+ internal static extern int GdipCreateBitmapFromStreamICM(IntPtr stream, IntPtr* bitmap);
}
}
}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.COMWrappers.cs
index a03ad5ed133bb..3d9ad1a356676 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.COMWrappers.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Icon.Windows.COMWrappers.cs
@@ -28,7 +28,7 @@ public unsafe void Save(Stream outputStream)
// But, in the interest of simplicity, we just call to
// OLE to do it for us.
PICTDESC pictdesc = PICTDESC.CreateIconPICTDESC(Handle);
- Guid iid = DrawingComWrappers.IPicture.IID;
+ Guid iid = DrawingCom.IPicture.IID;
IntPtr lpPicture;
Marshal.ThrowExceptionForHR(OleCreatePictureIndirect(&pictdesc, &iid, fOwn: 0, &lpPicture));
@@ -36,13 +36,13 @@ public unsafe void Save(Stream outputStream)
try
{
// Use UniqueInstance here because we never want to cache the wrapper. It only gets used once and then disposed.
- using DrawingComWrappers.IPicture picture = (DrawingComWrappers.IPicture)DrawingComWrappers.Instance
+ using DrawingCom.IPicture picture = (DrawingCom.IPicture)DrawingCom.Instance
.GetOrCreateObjectForComInstance(lpPicture, CreateObjectFlags.UniqueInstance);
var gpStream = new GPStream(outputStream, makeSeekable: false);
- streamPtr = DrawingComWrappers.Instance.GetOrCreateComInterfaceForObject(gpStream, CreateComInterfaceFlags.None);
+ streamPtr = DrawingCom.Instance.GetOrCreateComInterfaceForObject(gpStream, CreateComInterfaceFlags.None);
- CheckSaveAsFileResult(picture.SaveAsFile(streamPtr, -1, null));
+ DrawingCom.ThrowExceptionForHR(picture.SaveAsFile(streamPtr, -1, null));
}
finally
{
@@ -61,13 +61,6 @@ public unsafe void Save(Stream outputStream)
}
}
- private static void CheckSaveAsFileResult(int errorCode)
- {
- // Pass -1 for errorInfo to indicate that Windows' GetErrorInfo shouldn't be called, and only
- // throw the Exception corresponding to the specified errorCode.
- Marshal.ThrowExceptionForHR(errorCode, errorInfo: new IntPtr(-1));
- }
-
[DllImport(Interop.Libraries.Oleaut32)]
private static unsafe extern int OleCreatePictureIndirect(PICTDESC* pictdesc, Guid* refiid, int fOwn, IntPtr* lplpvObj);
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
index a6dd53744a974..ccea5ff42d52e 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.cs
@@ -23,16 +23,7 @@ public static Image FromStream(Stream stream, bool useEmbeddedColorManagement, b
if (stream == null)
throw new ArgumentNullException(nameof(stream));
- IntPtr image = IntPtr.Zero;
-
- if (useEmbeddedColorManagement)
- {
- Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(new GPStream(stream), out image));
- }
- else
- {
- Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(new GPStream(stream), out image));
- }
+ IntPtr image = LoadGdipImageFromStream(new GPStream(stream), useEmbeddedColorManagement);
if (validateImageData)
ValidateImage(image);
@@ -45,9 +36,7 @@ public static Image FromStream(Stream stream, bool useEmbeddedColorManagement, b
// Used for serialization
private IntPtr InitializeFromStream(Stream stream)
{
- IntPtr image = IntPtr.Zero;
-
- Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(new GPStream(stream), out image));
+ IntPtr image = LoadGdipImageFromStream(new GPStream(stream), useEmbeddedColorManagement: false);
ValidateImage(image);
nativeImage = image;
@@ -59,6 +48,22 @@ private IntPtr InitializeFromStream(Stream stream)
return image;
}
+ private static unsafe IntPtr LoadGdipImageFromStream(GPStream stream, bool useEmbeddedColorManagement)
+ {
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(stream);
+
+ IntPtr image = IntPtr.Zero;
+ if (useEmbeddedColorManagement)
+ {
+ Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(streamWrapper.Ptr, &image));
+ }
+ else
+ {
+ Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(streamWrapper.Ptr, &image));
+ }
+ return image;
+ }
+
internal Image(IntPtr nativeImage) => SetNativeImage(nativeImage);
///
@@ -240,11 +245,15 @@ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters? encod
if (!saved)
{
- Gdip.CheckStatus(Gdip.GdipSaveImageToStream(
- new HandleRef(this, nativeImage),
- new GPStream(stream, makeSeekable: false),
- ref g,
- new HandleRef(encoderParams, encoderParamsMemory)));
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream, makeSeekable: false));
+ unsafe
+ {
+ Gdip.CheckStatus(Gdip.GdipSaveImageToStream(
+ new HandleRef(this, nativeImage),
+ streamWrapper.Ptr,
+ &g,
+ new HandleRef(encoderParams, encoderParamsMemory)));
+ }
}
}
finally
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.cs
index 447799333febf..4d8dccb01e71f 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.cs
@@ -1,11 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Runtime.InteropServices;
-using System.IO;
using System.Drawing.Internal;
+using System.IO;
+using System.Runtime.InteropServices;
using Gdip = System.Drawing.SafeNativeMethods.Gdip;
-using System.Runtime.Serialization;
namespace System.Drawing.Imaging
{
@@ -27,14 +26,18 @@ public Metafile(IntPtr hmetafile, WmfPlaceableFileHeader wmfHeader) :
///
/// Initializes a new instance of the class from the specified stream.
///
- public Metafile(Stream stream)
+ public unsafe Metafile(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
- Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(new GPStream(stream), out IntPtr metafile));
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+
+ IntPtr metafile = IntPtr.Zero;
+ Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(streamWrapper.Ptr, &metafile));
+
SetNativeImage(metafile);
}
@@ -145,16 +148,19 @@ public Metafile(string fileName, IntPtr referenceHdc, Rectangle frameRect, Metaf
///
/// Initializes a new instance of the class from the specified data stream.
///
- public Metafile(Stream stream, IntPtr referenceHdc, EmfType type, string? description)
+ public unsafe Metafile(Stream stream, IntPtr referenceHdc, EmfType type, string? description)
{
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+
+ IntPtr metafile = IntPtr.Zero;
Gdip.CheckStatus(Gdip.GdipRecordMetafileStream(
- new GPStream(stream),
+ streamWrapper.Ptr,
referenceHdc,
type,
IntPtr.Zero,
MetafileFrameUnit.GdiCompatible,
description,
- out IntPtr metafile));
+ &metafile));
SetNativeImage(metafile);
}
@@ -162,16 +168,19 @@ public Metafile(Stream stream, IntPtr referenceHdc, EmfType type, string? descri
///
/// Initializes a new instance of the class with the specified filename.
///
- public Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description)
+ public unsafe Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description)
{
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+
+ IntPtr metafile = IntPtr.Zero;
Gdip.CheckStatus(Gdip.GdipRecordMetafileStream(
- new GPStream(stream),
+ streamWrapper.Ptr,
referenceHdc,
type,
- ref frameRect,
+ &frameRect,
frameUnit,
description,
- out IntPtr metafile));
+ &metafile));
SetNativeImage(metafile);
}
@@ -179,31 +188,32 @@ public Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, Metafi
///
/// Initializes a new instance of the class with the specified filename.
///
- public Metafile(Stream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description)
+ public unsafe Metafile(Stream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description)
{
- IntPtr metafile = IntPtr.Zero;
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+ IntPtr metafile = IntPtr.Zero;
if (frameRect.IsEmpty)
{
Gdip.CheckStatus(Gdip.GdipRecordMetafileStream(
- new GPStream(stream),
+ streamWrapper.Ptr,
referenceHdc,
type,
IntPtr.Zero,
frameUnit,
description,
- out metafile));
+ &metafile));
}
else
{
Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI(
- new GPStream(stream),
+ streamWrapper.Ptr,
referenceHdc,
type,
- ref frameRect,
+ &frameRect,
frameUnit,
description,
- out metafile));
+ &metafile));
}
SetNativeImage(metafile);
@@ -292,7 +302,8 @@ public static MetafileHeader GetMetafileHeader(Stream stream)
try
{
- Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(new GPStream(stream), memory));
+ using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream));
+ Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(streamWrapper.Ptr, memory));
int[] type = new int[] { 0 };
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.COMWrappers.cs
new file mode 100644
index 0000000000000..65079d5698a4b
--- /dev/null
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.COMWrappers.cs
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Buffers;
+using System.Runtime.InteropServices;
+
+namespace System.Drawing.Internal
+{
+ internal sealed partial class GPStream : Interop.Ole32.IStream
+ {
+ public unsafe Interop.HRESULT Clone(IntPtr* ppstm)
+ {
+ if (ppstm == null)
+ {
+ return Interop.HRESULT.STG_E_INVALIDPOINTER;
+ }
+
+ // The cloned object should have the same current "position"
+ var clone = new GPStream(_dataStream)
+ {
+ _virtualPosition = _virtualPosition
+ };
+
+ *ppstm = DrawingCom.Instance.GetOrCreateComInterfaceForObject(clone, CreateComInterfaceFlags.None);
+
+ return Interop.HRESULT.S_OK;
+ }
+
+ public unsafe Interop.HRESULT CopyTo(IntPtr pstm, ulong cb, ulong* pcbRead, ulong* pcbWritten)
+ {
+ byte[] buffer = ArrayPool.Shared.Rent(4096);
+
+ ulong remaining = cb;
+ ulong totalWritten = 0;
+ ulong totalRead = 0;
+
+ fixed (byte* b = buffer)
+ {
+ while (remaining > 0)
+ {
+ uint read = remaining < (ulong)buffer.Length ? (uint)remaining : (uint)buffer.Length;
+ Read(b, read, &read);
+ remaining -= read;
+ totalRead += read;
+
+ if (read == 0)
+ {
+ break;
+ }
+
+ uint written;
+ Interop.HRESULT hr = (Interop.HRESULT)WriteToStream(pstm, b, read, &written);
+ if (hr != Interop.HRESULT.S_OK)
+ {
+ return hr;
+ }
+ totalWritten += written;
+ }
+ }
+
+ ArrayPool.Shared.Return(buffer);
+
+ if (pcbRead != null)
+ {
+ *pcbRead = totalRead;
+ }
+
+ if (pcbWritten != null)
+ {
+ *pcbWritten = totalWritten;
+ }
+
+ return Interop.HRESULT.S_OK;
+ }
+
+ private static unsafe int WriteToStream(IntPtr pstm, byte* pv, uint cb, uint* pcbWritten)
+ {
+ return ((delegate* unmanaged)(*(*(void***)pstm + 4 /* IStream.Write slot */)))
+ (pstm, pv, cb, pcbWritten);
+ }
+ }
+}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.NoCOMWrappers.cs
new file mode 100644
index 0000000000000..0c4e56ef8d685
--- /dev/null
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.NoCOMWrappers.cs
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Buffers;
+
+namespace System.Drawing.Internal
+{
+ internal sealed partial class GPStream : Interop.Ole32.IStream
+ {
+ public Interop.Ole32.IStream Clone()
+ {
+ // The cloned object should have the same current "position"
+ return new GPStream(_dataStream)
+ {
+ _virtualPosition = _virtualPosition
+ };
+ }
+
+ public unsafe void CopyTo(Interop.Ole32.IStream pstm, ulong cb, ulong* pcbRead, ulong* pcbWritten)
+ {
+ byte[] buffer = ArrayPool.Shared.Rent(4096);
+
+ ulong remaining = cb;
+ ulong totalWritten = 0;
+ ulong totalRead = 0;
+
+ fixed (byte* b = buffer)
+ {
+ while (remaining > 0)
+ {
+ uint read = remaining < (ulong)buffer.Length ? (uint)remaining : (uint)buffer.Length;
+ Read(b, read, &read);
+ remaining -= read;
+ totalRead += read;
+
+ if (read == 0)
+ {
+ break;
+ }
+
+ uint written;
+ pstm.Write(b, read, &written);
+ totalWritten += written;
+ }
+ }
+
+ ArrayPool.Shared.Return(buffer);
+
+ if (pcbRead != null)
+ *pcbRead = totalRead;
+
+ if (pcbWritten != null)
+ *pcbWritten = totalWritten;
+ }
+ }
+}
diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.cs
index dd6a8a16350ff..524be173b52cf 100644
--- a/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.cs
+++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.cs
@@ -1,12 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Buffers;
using System.IO;
namespace System.Drawing.Internal
{
- internal sealed class GPStream : Interop.Ole32.IStream
+ internal sealed partial class GPStream : Interop.Ole32.IStream
{
private readonly Stream _dataStream;
@@ -41,15 +40,6 @@ private void ActualizeVirtualPosition()
_virtualPosition = -1;
}
- public Interop.Ole32.IStream Clone()
- {
- // The cloned object should have the same current "position"
- return new GPStream(_dataStream)
- {
- _virtualPosition = _virtualPosition
- };
- }
-
public void Commit(uint grfCommitFlags)
{
_dataStream.Flush();
@@ -58,43 +48,6 @@ public void Commit(uint grfCommitFlags)
ActualizeVirtualPosition();
}
- public unsafe void CopyTo(Interop.Ole32.IStream pstm, ulong cb, ulong* pcbRead, ulong* pcbWritten)
- {
- byte[] buffer = ArrayPool.Shared.Rent(4096);
-
- ulong remaining = cb;
- ulong totalWritten = 0;
- ulong totalRead = 0;
-
- fixed (byte* b = buffer)
- {
- while (remaining > 0)
- {
- uint read = remaining < (ulong)buffer.Length ? (uint)remaining : (uint)buffer.Length;
- Read(b, read, &read);
- remaining -= read;
- totalRead += read;
-
- if (read == 0)
- {
- break;
- }
-
- uint written;
- pstm.Write(b, read, &written);
- totalWritten += written;
- }
- }
-
- ArrayPool.Shared.Return(buffer);
-
- if (pcbRead != null)
- *pcbRead = totalRead;
-
- if (pcbWritten != null)
- *pcbWritten = totalWritten;
- }
-
public unsafe void Read(byte* pv, uint cb, uint* pcbRead)
{
ActualizeVirtualPosition();