From 8d2a11bc1eecb89eeab28cf6639ca96256ad2cc5 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 28 Jun 2021 18:55:31 -0500 Subject: [PATCH 1/2] Finish migrating System.Drawing.Common to ComWrappers This resolves all ILLink warnings in System.Drawing.Common, making it work in a trimmed application. --- .../Ole32/Interop.IStream.COMWrappers.cs | 61 +++++++++ ...am.cs => Interop.IStream.NoCOMWrappers.cs} | 0 .../src/ILLink/ILLink.Suppressions.xml | 59 -------- .../src/System.Drawing.Common.csproj | 18 ++- .../Drawing/Bitmap.Windows.COMWrappers.cs | 38 ++++++ .../Drawing/Bitmap.Windows.NoCOMWrappers.cs | 28 ++++ .../src/System/Drawing/Bitmap.Windows.cs | 13 +- .../src/System/Drawing/DrawingComWrappers.cs | 30 ++-- .../GdiplusNative.Windows.COMWrappers.cs | 44 ++++++ .../GdiplusNative.Windows.NoCOMWrappers.cs | 44 ++++++ .../System/Drawing/GdiplusNative.Windows.cs | 30 ---- .../Drawing/Icon.Windows.COMWrappers.cs | 9 +- .../Drawing/Image.Windows.COMWrappers.cs | 54 ++++++++ .../Drawing/Image.Windows.NoCOMWrappers.cs | 36 +++++ .../src/System/Drawing/Image.Windows.cs | 23 +--- .../Imaging/Metafile.Windows.COMWrappers.cs | 129 ++++++++++++++++++ .../Imaging/Metafile.Windows.NoCOMWrappers.cs | 78 +++++++++++ .../Drawing/Imaging/Metafile.Windows.cs | 50 +------ .../Drawing/Internal/GPStream.COMWrappers.cs | 82 +++++++++++ .../Internal/GPStream.NoCOMWrappers.cs | 56 ++++++++ .../src/System/Drawing/Internal/GPStream.cs | 49 +------ 21 files changed, 696 insertions(+), 235 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs rename src/libraries/Common/src/Interop/Windows/Ole32/{Interop.IStream.cs => Interop.IStream.NoCOMWrappers.cs} (100%) delete mode 100644 src/libraries/System.Drawing.Common/src/ILLink/ILLink.Suppressions.xml create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.COMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Internal/GPStream.NoCOMWrappers.cs 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 00000000000000..51b7a0be6c405e --- /dev/null +++ b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs @@ -0,0 +1,61 @@ +// 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. + /// + /// + /// The definition in does not lend + /// itself to efficiently accessing / implementing IStream. + /// + /// 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 100% 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 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 a0b7401fb0ac23..00000000000000 --- 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 b02d55a46c6a2b..aee261ab758689 100644 --- a/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj +++ b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj @@ -294,8 +294,6 @@ Link="Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs" /> - - + + + + + + + + + + + + + diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs new file mode 100644 index 00000000000000..7e8ff087bf949e --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs @@ -0,0 +1,38 @@ +// 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; +using Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing +{ + public sealed partial class Bitmap + { + private static unsafe IntPtr CreateGdipBitmapFromStream(GPStream stream, bool useIcm) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr bitmap = IntPtr.Zero; + int status; + if (useIcm) + { + status = Gdip.GdipCreateBitmapFromStreamICM(streamPtr, &bitmap); + } + else + { + status = Gdip.GdipCreateBitmapFromStream(streamPtr, &bitmap); + } + Gdip.CheckStatus(status); + + return bitmap; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + } +} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs new file mode 100644 index 00000000000000..45afbf1f32bb2e --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs @@ -0,0 +1,28 @@ +// 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 Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing +{ + public sealed partial class Bitmap + { + private static unsafe IntPtr CreateGdipBitmapFromStream(GPStream stream, bool useIcm) + { + IntPtr bitmap = IntPtr.Zero; + int status; + if (useIcm) + { + status = Gdip.GdipCreateBitmapFromStreamICM(stream, out bitmap); + } + else + { + status = Gdip.GdipCreateBitmapFromStream(stream, out bitmap); + } + Gdip.CheckStatus(status); + + return bitmap; + } + } +} 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 4fe1b54ae1b836..0d6b556449c52a 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 @@ -16,18 +16,7 @@ public Bitmap(Stream stream, bool useIcm) throw new ArgumentNullException(nameof(stream)); } - IntPtr bitmap = IntPtr.Zero; - int status; - - if (useIcm) - { - status = Gdip.GdipCreateBitmapFromStreamICM(new GPStream(stream), out bitmap); - } - else - { - status = Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out bitmap); - } - Gdip.CheckStatus(status); + IntPtr bitmap = CreateGdipBitmapFromStream(new GPStream(stream), useIcm); ValidateImage(bitmap); diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs index 7895381853c4a4..55acf22daf2900 100644 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/DrawingComWrappers.cs @@ -66,6 +66,20 @@ protected override void ReleaseObjects(IEnumerable objects) throw new NotImplementedException(); } + internal void GetIStreamInterfaces(Interop.Ole32.IStream stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr) + { + streamWrapperPtr = GetOrCreateComInterfaceForObject(stream, CreateComInterfaceFlags.None); + Guid streamIID = IID_IStream; + ThrowExceptionForHR(Marshal.QueryInterface(streamWrapperPtr, ref streamIID, out 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 fpQueryInteface, IntPtr fpAddRef, IntPtr fpRelease) @@ -159,16 +173,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 +261,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 +301,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/GdiplusNative.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs new file mode 100644 index 00000000000000..1094f1b6e8f3f9 --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs @@ -0,0 +1,44 @@ +// 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.Imaging; +using System.Runtime.InteropServices; + +namespace System.Drawing +{ + internal static partial class SafeNativeMethods + { + internal static unsafe partial class Gdip + { + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStream(IntPtr stream, IntPtr* image); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStreamICM(IntPtr stream, IntPtr* image); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipSaveImageToStream(HandleRef image, IntPtr stream, Guid* classId, HandleRef encoderParams); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipGetMetafileHeaderFromStream(IntPtr stream, IntPtr header); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateMetafileFromStream(IntPtr stream, IntPtr* metafile); + + [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] + 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(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(IntPtr stream, IntPtr referenceHdc, EmfType emfType, Rectangle* frameRect, MetafileFrameUnit frameUnit, string? description, IntPtr* metafile); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateBitmapFromStream(IntPtr stream, IntPtr* bitmap); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateBitmapFromStreamICM(IntPtr stream, IntPtr* bitmap); + } + } +} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs new file mode 100644 index 00000000000000..8717fc859bbe68 --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs @@ -0,0 +1,44 @@ +// 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.Imaging; +using System.Runtime.InteropServices; + +namespace System.Drawing +{ + internal static partial class SafeNativeMethods + { + internal static unsafe partial class Gdip + { + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStream(Interop.Ole32.IStream stream, out IntPtr image); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStreamICM(Interop.Ole32.IStream stream, out IntPtr image); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipSaveImageToStream(HandleRef image, Interop.Ole32.IStream stream, ref Guid classId, HandleRef encoderParams); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipGetMetafileHeaderFromStream(Interop.Ole32.IStream stream, IntPtr header); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateMetafileFromStream(Interop.Ole32.IStream stream, out 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); + + [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); + + [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); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateBitmapFromStream(Interop.Ole32.IStream stream, out IntPtr bitmap); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateBitmapFromStreamICM(Interop.Ole32.IStream stream, out IntPtr bitmap); + } + } +} 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 47aeb4f9397c32..05cf9ab72fcf9b 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 @@ -209,21 +209,12 @@ private static void PlatformInitialize() [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipDeleteBrush(HandleRef brush); - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStream(Interop.Ole32.IStream stream, out IntPtr image); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStreamICM(Interop.Ole32.IStream stream, out IntPtr image); - [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipCloneImage(HandleRef image, out IntPtr cloneimage); [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] 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); - [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipSaveAdd(HandleRef image, HandleRef encoderParams); @@ -326,38 +317,17 @@ private static void PlatformInitialize() [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] internal static extern int GdipGetMetafileHeaderFromFile(string filename, IntPtr header); - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipGetMetafileHeaderFromStream(Interop.Ole32.IStream stream, IntPtr header); - [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipGetMetafileHeaderFromMetafile(HandleRef metafile, IntPtr header); [DllImport(LibraryName, ExactSpelling = true)] 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); - - [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); - - [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); - - [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); - [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipComment(HandleRef graphics, int sizeData, byte[] data); [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] 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); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateBitmapFromStreamICM(Interop.Ole32.IStream stream, out 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 a03ad5ed133bbe..68492858171e09 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 @@ -42,7 +42,7 @@ public unsafe void Save(Stream outputStream) var gpStream = new GPStream(outputStream, makeSeekable: false); streamPtr = DrawingComWrappers.Instance.GetOrCreateComInterfaceForObject(gpStream, CreateComInterfaceFlags.None); - CheckSaveAsFileResult(picture.SaveAsFile(streamPtr, -1, null)); + DrawingComWrappers.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.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs new file mode 100644 index 00000000000000..6e8ed404cdcf1f --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs @@ -0,0 +1,54 @@ +// 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.Imaging; +using System.Drawing.Internal; +using System.Runtime.InteropServices; +using Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing +{ + public abstract partial class Image + { + private static unsafe IntPtr LoadGdipImageFromStream(GPStream stream, bool useEmbeddedColorManagement) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr image = IntPtr.Zero; + if (useEmbeddedColorManagement) + { + Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(streamPtr, &image)); + } + else + { + Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(streamPtr, &image)); + } + return image; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + + private unsafe int SaveGdipImageToStream(GPStream stream, Guid g, EncoderParameters? encoderParams, IntPtr encoderParamsMemory) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + return Gdip.GdipSaveImageToStream( + new HandleRef(this, nativeImage), + streamPtr, + &g, + new HandleRef(encoderParams, encoderParamsMemory)); + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + } +} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs new file mode 100644 index 00000000000000..6ae02b68a4dc82 --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs @@ -0,0 +1,36 @@ +// 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.Imaging; +using System.Drawing.Internal; +using System.Runtime.InteropServices; +using Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing +{ + public abstract partial class Image + { + private static IntPtr LoadGdipImageFromStream(GPStream stream, bool useEmbeddedColorManagement) + { + IntPtr image = IntPtr.Zero; + if (useEmbeddedColorManagement) + { + Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(stream, out image)); + } + else + { + Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(stream, out image)); + } + return image; + } + + private int SaveGdipImageToStream(GPStream stream, Guid g, EncoderParameters? encoderParams, IntPtr encoderParamsMemory) + { + return Gdip.GdipSaveImageToStream( + new HandleRef(this, nativeImage), + stream, + ref g, + new HandleRef(encoderParams, encoderParamsMemory)); + } + } +} 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 a6dd53744a9741..9eb41eadd66bc6 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; @@ -240,11 +229,11 @@ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters? encod if (!saved) { - Gdip.CheckStatus(Gdip.GdipSaveImageToStream( - new HandleRef(this, nativeImage), + Gdip.CheckStatus(SaveGdipImageToStream( new GPStream(stream, makeSeekable: false), - ref g, - new HandleRef(encoderParams, encoderParamsMemory))); + g, + encoderParams, + encoderParamsMemory)); } } finally diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs new file mode 100644 index 00000000000000..5fd4eb3983218d --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs @@ -0,0 +1,129 @@ +// 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; +using Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing.Imaging +{ + public sealed partial class Metafile : Image + { + private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr metafile = IntPtr.Zero; + Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(streamPtr, &metafile)); + return metafile; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + + private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, EmfType type, string? description) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr metafile = IntPtr.Zero; + + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamPtr, + referenceHdc, + type, + IntPtr.Zero, + MetafileFrameUnit.GdiCompatible, + description, + &metafile)); + + return metafile; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + + private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr metafile = IntPtr.Zero; + + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamPtr, + referenceHdc, + type, + &frameRect, + frameUnit, + description, + &metafile)); + + return metafile; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + + private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + IntPtr metafile = IntPtr.Zero; + if (frameRect.IsEmpty) + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamPtr, + referenceHdc, + type, + IntPtr.Zero, + frameUnit, + description, + &metafile)); + } + else + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( + streamPtr, + referenceHdc, + type, + &frameRect, + frameUnit, + description, + &metafile)); + } + return metafile; + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + + private static void GetGdipMetafileHeaderFromStream(GPStream stream, IntPtr memory) + { + DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); + try + { + Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(streamPtr, memory)); + } + finally + { + Marshal.Release(streamPtr); + Marshal.Release(streamWrapperPtr); + } + } + } +} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs new file mode 100644 index 00000000000000..7d8518870839ac --- /dev/null +++ b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs @@ -0,0 +1,78 @@ +// 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 Gdip = System.Drawing.SafeNativeMethods.Gdip; + +namespace System.Drawing.Imaging +{ + public sealed partial class Metafile : Image + { + private static IntPtr CreateGdipMetafileFromStream(GPStream stream) + { + Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(stream, out IntPtr metafile)); + return metafile; + } + + private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, EmfType type, string? description) + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + stream, + referenceHdc, + type, + IntPtr.Zero, + MetafileFrameUnit.GdiCompatible, + description, + out IntPtr metafile)); + + return metafile; + } + + private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + stream, + referenceHdc, + type, + ref frameRect, + frameUnit, + description, + out IntPtr metafile)); + + return metafile; + } + + private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) + { + IntPtr metafile = IntPtr.Zero; + if (frameRect.IsEmpty) + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + stream, + referenceHdc, + type, + IntPtr.Zero, + frameUnit, + description, + out metafile)); + } + else + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( + stream, + referenceHdc, + type, + ref frameRect, + frameUnit, + description, + out metafile)); + } + return metafile; + } + + private static void GetGdipMetafileHeaderFromStream(GPStream stream, IntPtr memory) + { + Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(stream, memory)); + } + } +} 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 447799333febf9..c269c180f0776b 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 @@ -34,7 +34,7 @@ public Metafile(Stream stream) throw new ArgumentNullException(nameof(stream)); } - Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(new GPStream(stream), out IntPtr metafile)); + IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream)); SetNativeImage(metafile); } @@ -147,15 +147,7 @@ public Metafile(string fileName, IntPtr referenceHdc, Rectangle frameRect, Metaf /// public Metafile(Stream stream, IntPtr referenceHdc, EmfType type, string? description) { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - new GPStream(stream), - referenceHdc, - type, - IntPtr.Zero, - MetafileFrameUnit.GdiCompatible, - description, - out IntPtr metafile)); - + IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, type, description); SetNativeImage(metafile); } @@ -164,15 +156,7 @@ public Metafile(Stream stream, IntPtr referenceHdc, EmfType type, string? descri /// public Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - new GPStream(stream), - referenceHdc, - type, - ref frameRect, - frameUnit, - description, - out IntPtr metafile)); - + IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, frameRect, frameUnit, type, description); SetNativeImage(metafile); } @@ -181,31 +165,7 @@ public Metafile(Stream stream, IntPtr referenceHdc, RectangleF frameRect, Metafi /// public Metafile(Stream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) { - IntPtr metafile = IntPtr.Zero; - - if (frameRect.IsEmpty) - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - new GPStream(stream), - referenceHdc, - type, - IntPtr.Zero, - frameUnit, - description, - out metafile)); - } - else - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( - new GPStream(stream), - referenceHdc, - type, - ref frameRect, - frameUnit, - description, - out metafile)); - } - + IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, frameRect, frameUnit, type, description); SetNativeImage(metafile); } @@ -292,7 +252,7 @@ public static MetafileHeader GetMetafileHeader(Stream stream) try { - Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(new GPStream(stream), memory)); + GetGdipMetafileHeaderFromStream(new GPStream(stream), 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 00000000000000..94a74d2fbc04c9 --- /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 = DrawingComWrappers.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 00000000000000..0c4e56ef8d685d --- /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 dd6a8a16350ff0..524be173b52cf8 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(); From 897a641744903a86319796ac9aabbcac9a5602ef Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 29 Jun 2021 18:11:32 -0500 Subject: [PATCH 2/2] Respond to PR feedback --- .../Ole32/Interop.IStream.COMWrappers.cs | 5 +- .../Ole32/Interop.IStream.NoCOMWrappers.cs | 2 +- .../src/System.Drawing.Common.csproj | 12 +- .../Drawing/Bitmap.Windows.COMWrappers.cs | 38 ------ .../Drawing/Bitmap.Windows.NoCOMWrappers.cs | 28 ---- .../src/System/Drawing/Bitmap.Windows.cs | 14 +- ...mWrappers.cs => DrawingCom.COMWrappers.cs} | 21 ++- .../Drawing/DrawingCom.NoCOMWrappers.cs | 16 +++ .../src/System/Drawing/DrawingCom.cs | 25 ++++ .../GdiplusNative.Windows.COMWrappers.cs | 44 ------ .../GdiplusNative.Windows.NoCOMWrappers.cs | 44 ------ .../System/Drawing/GdiplusNative.Windows.cs | 30 ++++ .../Drawing/Icon.Windows.COMWrappers.cs | 8 +- .../Drawing/Image.Windows.COMWrappers.cs | 54 -------- .../Drawing/Image.Windows.NoCOMWrappers.cs | 36 ----- .../src/System/Drawing/Image.Windows.cs | 30 +++- .../Imaging/Metafile.Windows.COMWrappers.cs | 129 ------------------ .../Imaging/Metafile.Windows.NoCOMWrappers.cs | 78 ----------- .../Drawing/Imaging/Metafile.Windows.cs | 75 ++++++++-- .../Drawing/Internal/GPStream.COMWrappers.cs | 2 +- 20 files changed, 195 insertions(+), 496 deletions(-) delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs rename src/libraries/System.Drawing.Common/src/System/Drawing/{DrawingComWrappers.cs => DrawingCom.COMWrappers.cs} (94%) create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.NoCOMWrappers.cs create mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/DrawingCom.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs delete mode 100644 src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs 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 index 51b7a0be6c405e..a3ff4e14fb7a7d 100644 --- a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs +++ b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.COMWrappers.cs @@ -9,12 +9,9 @@ internal static partial class Interop internal static partial class Ole32 { /// - /// IStream interface. + /// IStream interface. /// /// - /// The definition in does not lend - /// itself to efficiently accessing / implementing IStream. - /// /// This interface explicitly doesn't use the built-in COM support, but instead is only used with ComWrappers. /// internal interface IStream diff --git a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.cs b/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.cs index 6fdf6718f050a2..b8907e5a33a9fb 100644 --- a/src/libraries/Common/src/Interop/Windows/Ole32/Interop.IStream.NoCOMWrappers.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/System.Drawing.Common.csproj b/src/libraries/System.Drawing.Common/src/System.Drawing.Common.csproj index aee261ab758689..ff707877c2d11c 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 @@ + @@ -318,22 +319,15 @@ - - - - + - - - - + - diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs deleted file mode 100644 index 7e8ff087bf949e..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.COMWrappers.cs +++ /dev/null @@ -1,38 +0,0 @@ -// 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; -using Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing -{ - public sealed partial class Bitmap - { - private static unsafe IntPtr CreateGdipBitmapFromStream(GPStream stream, bool useIcm) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr bitmap = IntPtr.Zero; - int status; - if (useIcm) - { - status = Gdip.GdipCreateBitmapFromStreamICM(streamPtr, &bitmap); - } - else - { - status = Gdip.GdipCreateBitmapFromStream(streamPtr, &bitmap); - } - Gdip.CheckStatus(status); - - return bitmap; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - } -} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs deleted file mode 100644 index 45afbf1f32bb2e..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.Windows.NoCOMWrappers.cs +++ /dev/null @@ -1,28 +0,0 @@ -// 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 Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing -{ - public sealed partial class Bitmap - { - private static unsafe IntPtr CreateGdipBitmapFromStream(GPStream stream, bool useIcm) - { - IntPtr bitmap = IntPtr.Zero; - int status; - if (useIcm) - { - status = Gdip.GdipCreateBitmapFromStreamICM(stream, out bitmap); - } - else - { - status = Gdip.GdipCreateBitmapFromStream(stream, out bitmap); - } - Gdip.CheckStatus(status); - - return bitmap; - } - } -} 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 0d6b556449c52a..84f959f94c2812 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,14 +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 = CreateGdipBitmapFromStream(new GPStream(stream), useIcm); + using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream)); + + IntPtr bitmap = IntPtr.Zero; + if (useIcm) + { + Gdip.CheckStatus(Gdip.GdipCreateBitmapFromStreamICM(streamWrapper.Ptr, &bitmap)); + } + else + { + Gdip.CheckStatus(Gdip.GdipCreateBitmapFromStream(streamWrapper.Ptr, &bitmap)); + } 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 94% 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 55acf22daf2900..a78d88f70bf435 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(fpQueryInteface, 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,11 +66,18 @@ protected override void ReleaseObjects(IEnumerable objects) throw new NotImplementedException(); } - internal void GetIStreamInterfaces(Interop.Ole32.IStream stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr) + internal static IStreamWrapper GetComWrapper(Interop.Ole32.IStream stream) { - streamWrapperPtr = GetOrCreateComInterfaceForObject(stream, CreateComInterfaceFlags.None); + IntPtr streamWrapperPtr = Instance.GetOrCreateComInterfaceForObject(stream, CreateComInterfaceFlags.None); + Guid streamIID = IID_IStream; - ThrowExceptionForHR(Marshal.QueryInterface(streamWrapperPtr, ref streamIID, out streamPtr)); + 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) 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 00000000000000..d3fdd2115bffb9 --- /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 00000000000000..a5b53e65ff5894 --- /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.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs deleted file mode 100644 index 1094f1b6e8f3f9..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.COMWrappers.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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.Imaging; -using System.Runtime.InteropServices; - -namespace System.Drawing -{ - internal static partial class SafeNativeMethods - { - internal static unsafe partial class Gdip - { - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStream(IntPtr stream, IntPtr* image); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStreamICM(IntPtr stream, IntPtr* image); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipSaveImageToStream(HandleRef image, IntPtr stream, Guid* classId, HandleRef encoderParams); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipGetMetafileHeaderFromStream(IntPtr stream, IntPtr header); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateMetafileFromStream(IntPtr stream, IntPtr* metafile); - - [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] - 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(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(IntPtr stream, IntPtr referenceHdc, EmfType emfType, Rectangle* frameRect, MetafileFrameUnit frameUnit, string? description, IntPtr* metafile); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateBitmapFromStream(IntPtr stream, IntPtr* bitmap); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateBitmapFromStreamICM(IntPtr stream, IntPtr* bitmap); - } - } -} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs deleted file mode 100644 index 8717fc859bbe68..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Windows.NoCOMWrappers.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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.Imaging; -using System.Runtime.InteropServices; - -namespace System.Drawing -{ - internal static partial class SafeNativeMethods - { - internal static unsafe partial class Gdip - { - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStream(Interop.Ole32.IStream stream, out IntPtr image); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipLoadImageFromStreamICM(Interop.Ole32.IStream stream, out IntPtr image); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipSaveImageToStream(HandleRef image, Interop.Ole32.IStream stream, ref Guid classId, HandleRef encoderParams); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipGetMetafileHeaderFromStream(Interop.Ole32.IStream stream, IntPtr header); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateMetafileFromStream(Interop.Ole32.IStream stream, out 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); - - [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); - - [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); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateBitmapFromStream(Interop.Ole32.IStream stream, out IntPtr bitmap); - - [DllImport(LibraryName, ExactSpelling = true)] - internal static extern int GdipCreateBitmapFromStreamICM(Interop.Ole32.IStream stream, out IntPtr bitmap); - } - } -} 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 05cf9ab72fcf9b..3edf4a0e7b67ec 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 @@ -209,12 +209,21 @@ private static void PlatformInitialize() [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipDeleteBrush(HandleRef brush); + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStream(IntPtr stream, IntPtr* image); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipLoadImageFromStreamICM(IntPtr stream, IntPtr* image); + [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipCloneImage(HandleRef image, out IntPtr cloneimage); [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] 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, IntPtr stream, Guid* classId, HandleRef encoderParams); + [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipSaveAdd(HandleRef image, HandleRef encoderParams); @@ -317,17 +326,38 @@ private static void PlatformInitialize() [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] internal static extern int GdipGetMetafileHeaderFromFile(string filename, IntPtr header); + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipGetMetafileHeaderFromStream(IntPtr stream, IntPtr header); + [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipGetMetafileHeaderFromMetafile(HandleRef metafile, IntPtr header); [DllImport(LibraryName, ExactSpelling = true)] internal static extern int GdipGetHemfFromMetafile(HandleRef metafile, out IntPtr hEnhMetafile); + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateMetafileFromStream(IntPtr stream, IntPtr* metafile); + + [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] + 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(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(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); [DllImport(LibraryName, ExactSpelling = true, CharSet = CharSet.Unicode)] internal static extern int GdipCreateFontFromLogfontW(IntPtr hdc, ref Interop.User32.LOGFONT lf, out IntPtr font); + + [DllImport(LibraryName, ExactSpelling = true)] + internal static extern int GdipCreateBitmapFromStream(IntPtr stream, IntPtr* bitmap); + + [DllImport(LibraryName, ExactSpelling = true)] + 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 68492858171e09..3d9ad1a3566765 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); - DrawingComWrappers.ThrowExceptionForHR(picture.SaveAsFile(streamPtr, -1, null)); + DrawingCom.ThrowExceptionForHR(picture.SaveAsFile(streamPtr, -1, null)); } finally { diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs deleted file mode 100644 index 6e8ed404cdcf1f..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.COMWrappers.cs +++ /dev/null @@ -1,54 +0,0 @@ -// 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.Imaging; -using System.Drawing.Internal; -using System.Runtime.InteropServices; -using Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing -{ - public abstract partial class Image - { - private static unsafe IntPtr LoadGdipImageFromStream(GPStream stream, bool useEmbeddedColorManagement) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr image = IntPtr.Zero; - if (useEmbeddedColorManagement) - { - Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(streamPtr, &image)); - } - else - { - Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(streamPtr, &image)); - } - return image; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - - private unsafe int SaveGdipImageToStream(GPStream stream, Guid g, EncoderParameters? encoderParams, IntPtr encoderParamsMemory) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - return Gdip.GdipSaveImageToStream( - new HandleRef(this, nativeImage), - streamPtr, - &g, - new HandleRef(encoderParams, encoderParamsMemory)); - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - } -} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs deleted file mode 100644 index 6ae02b68a4dc82..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Image.Windows.NoCOMWrappers.cs +++ /dev/null @@ -1,36 +0,0 @@ -// 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.Imaging; -using System.Drawing.Internal; -using System.Runtime.InteropServices; -using Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing -{ - public abstract partial class Image - { - private static IntPtr LoadGdipImageFromStream(GPStream stream, bool useEmbeddedColorManagement) - { - IntPtr image = IntPtr.Zero; - if (useEmbeddedColorManagement) - { - Gdip.CheckStatus(Gdip.GdipLoadImageFromStreamICM(stream, out image)); - } - else - { - Gdip.CheckStatus(Gdip.GdipLoadImageFromStream(stream, out image)); - } - return image; - } - - private int SaveGdipImageToStream(GPStream stream, Guid g, EncoderParameters? encoderParams, IntPtr encoderParamsMemory) - { - return Gdip.GdipSaveImageToStream( - new HandleRef(this, nativeImage), - stream, - ref g, - new HandleRef(encoderParams, encoderParamsMemory)); - } - } -} 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 9eb41eadd66bc6..ccea5ff42d52e7 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 @@ -48,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); /// @@ -229,11 +245,15 @@ public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters? encod if (!saved) { - Gdip.CheckStatus(SaveGdipImageToStream( - new GPStream(stream, makeSeekable: false), - g, - 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.COMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs deleted file mode 100644 index 5fd4eb3983218d..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.COMWrappers.cs +++ /dev/null @@ -1,129 +0,0 @@ -// 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; -using Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing.Imaging -{ - public sealed partial class Metafile : Image - { - private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr metafile = IntPtr.Zero; - Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(streamPtr, &metafile)); - return metafile; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - - private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, EmfType type, string? description) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr metafile = IntPtr.Zero; - - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - streamPtr, - referenceHdc, - type, - IntPtr.Zero, - MetafileFrameUnit.GdiCompatible, - description, - &metafile)); - - return metafile; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - - private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr metafile = IntPtr.Zero; - - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - streamPtr, - referenceHdc, - type, - &frameRect, - frameUnit, - description, - &metafile)); - - return metafile; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - - private static unsafe IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - IntPtr metafile = IntPtr.Zero; - if (frameRect.IsEmpty) - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - streamPtr, - referenceHdc, - type, - IntPtr.Zero, - frameUnit, - description, - &metafile)); - } - else - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( - streamPtr, - referenceHdc, - type, - &frameRect, - frameUnit, - description, - &metafile)); - } - return metafile; - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - - private static void GetGdipMetafileHeaderFromStream(GPStream stream, IntPtr memory) - { - DrawingComWrappers.Instance.GetIStreamInterfaces(stream, out IntPtr streamWrapperPtr, out IntPtr streamPtr); - try - { - Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(streamPtr, memory)); - } - finally - { - Marshal.Release(streamPtr); - Marshal.Release(streamWrapperPtr); - } - } - } -} diff --git a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs b/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs deleted file mode 100644 index 7d8518870839ac..00000000000000 --- a/src/libraries/System.Drawing.Common/src/System/Drawing/Imaging/Metafile.Windows.NoCOMWrappers.cs +++ /dev/null @@ -1,78 +0,0 @@ -// 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 Gdip = System.Drawing.SafeNativeMethods.Gdip; - -namespace System.Drawing.Imaging -{ - public sealed partial class Metafile : Image - { - private static IntPtr CreateGdipMetafileFromStream(GPStream stream) - { - Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(stream, out IntPtr metafile)); - return metafile; - } - - private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, EmfType type, string? description) - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - stream, - referenceHdc, - type, - IntPtr.Zero, - MetafileFrameUnit.GdiCompatible, - description, - out IntPtr metafile)); - - return metafile; - } - - private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, RectangleF frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - stream, - referenceHdc, - type, - ref frameRect, - frameUnit, - description, - out IntPtr metafile)); - - return metafile; - } - - private static IntPtr CreateGdipMetafileFromStream(GPStream stream, IntPtr referenceHdc, Rectangle frameRect, MetafileFrameUnit frameUnit, EmfType type, string? description) - { - IntPtr metafile = IntPtr.Zero; - if (frameRect.IsEmpty) - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( - stream, - referenceHdc, - type, - IntPtr.Zero, - frameUnit, - description, - out metafile)); - } - else - { - Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( - stream, - referenceHdc, - type, - ref frameRect, - frameUnit, - description, - out metafile)); - } - return metafile; - } - - private static void GetGdipMetafileHeaderFromStream(GPStream stream, IntPtr memory) - { - Gdip.CheckStatus(Gdip.GdipGetMetafileHeaderFromStream(stream, memory)); - } - } -} 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 c269c180f0776b..4d8dccb01e71f9 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)); } - IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream)); + using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream)); + + IntPtr metafile = IntPtr.Zero; + Gdip.CheckStatus(Gdip.GdipCreateMetafileFromStream(streamWrapper.Ptr, &metafile)); + SetNativeImage(metafile); } @@ -145,27 +148,74 @@ 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) { - IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, type, description); + using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream)); + + IntPtr metafile = IntPtr.Zero; + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamWrapper.Ptr, + referenceHdc, + type, + IntPtr.Zero, + MetafileFrameUnit.GdiCompatible, + description, + &metafile)); + SetNativeImage(metafile); } /// /// 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) { - IntPtr metafile = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, frameRect, frameUnit, type, description); + using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream)); + + IntPtr metafile = IntPtr.Zero; + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamWrapper.Ptr, + referenceHdc, + type, + &frameRect, + frameUnit, + description, + &metafile)); + SetNativeImage(metafile); } /// /// 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 = CreateGdipMetafileFromStream(new GPStream(stream), referenceHdc, frameRect, frameUnit, type, description); + using DrawingCom.IStreamWrapper streamWrapper = DrawingCom.GetComWrapper(new GPStream(stream)); + + IntPtr metafile = IntPtr.Zero; + if (frameRect.IsEmpty) + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStream( + streamWrapper.Ptr, + referenceHdc, + type, + IntPtr.Zero, + frameUnit, + description, + &metafile)); + } + else + { + Gdip.CheckStatus(Gdip.GdipRecordMetafileStreamI( + streamWrapper.Ptr, + referenceHdc, + type, + &frameRect, + frameUnit, + description, + &metafile)); + } + SetNativeImage(metafile); } @@ -252,7 +302,8 @@ public static MetafileHeader GetMetafileHeader(Stream stream) try { - GetGdipMetafileHeaderFromStream(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 index 94a74d2fbc04c9..65079d5698a4bb 100644 --- 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 @@ -21,7 +21,7 @@ public unsafe Interop.HRESULT Clone(IntPtr* ppstm) _virtualPosition = _virtualPosition }; - *ppstm = DrawingComWrappers.Instance.GetOrCreateComInterfaceForObject(clone, CreateComInterfaceFlags.None); + *ppstm = DrawingCom.Instance.GetOrCreateComInterfaceForObject(clone, CreateComInterfaceFlags.None); return Interop.HRESULT.S_OK; }