Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Finish migrating System.Drawing.Common to ComWrappers #54884

Merged
merged 3 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// IStream interface. <see href="https://docs.microsoft.com/windows/desktop/api/objidl/nn-objidl-istream"/>
/// </summary>
/// <remarks>
/// This interface explicitly doesn't use the built-in COM support, but instead is only used with ComWrappers.
/// </remarks>
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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ internal static partial class Interop
internal static partial class Ole32
{
/// <summary>
/// COM IStream interface. <see href="https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-istream"/>
/// COM IStream interface. <see href="https://docs.microsoft.com/windows/desktop/api/objidl/nn-objidl-istream"/>
/// </summary>
/// <remarks>
/// The definition in <see cref="System.Runtime.InteropServices.ComTypes"/> does not lend
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
<Compile Include="System\Drawing\BufferedGraphicsManager.Windows.cs" />
<Compile Include="System\Drawing\Drawing2D\CustomLineCap.Windows.cs" />
<Compile Include="System\Drawing\Drawing2D\GraphicsPath.Windows.cs" />
<Compile Include="System\Drawing\DrawingCom.cs" />
<Compile Include="System\Drawing\Font.Windows.cs" />
<Compile Include="System\Drawing\FontFamily.Windows.cs" />
<Compile Include="System\Drawing\GdiplusNative.Windows.cs" />
Expand Down Expand Up @@ -294,8 +295,6 @@
Link="Common\Interop\Windows\Kernel32\Interop.GlobalLock.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Gdi32\Interop.BitBlt.cs"
Link="Common\Interop\Windows\Gdi32\Interop.BitBlt.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.IStream.cs"
Link="Common\Interop\Windows\Ole32\Interop.IStream.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.STATSTG.cs"
Link="Common\Interop\Windows\Ole32\Interop.STATSTG.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.STGTY.cs"
Expand All @@ -318,11 +317,18 @@
Link="Common\Interop\Windows\Interop.HRESULT.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true' and $([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net5.0'))">
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.IStream.COMWrappers.cs"
Link="Common\Interop\Windows\Ole32\Interop.IStream.COMWrappers.cs" />
<Compile Include="System\Drawing\DrawingCom.COMWrappers.cs" />
<Compile Include="System\Drawing\Icon.Windows.COMWrappers.cs" />
<Compile Include="System\Drawing\DrawingComWrappers.cs" />
<Compile Include="System\Drawing\Internal\GPStream.COMWrappers.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true' and !$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net5.0'))">
<Compile Include="$(CommonPath)Interop\Windows\Ole32\Interop.IStream.NoCOMWrappers.cs"
Link="Common\Interop\Windows\Ole32\Interop.IStream.NoCOMWrappers.cs" />
<Compile Include="System\Drawing\DrawingCom.NoCOMWrappers.cs" />
<Compile Include="System\Drawing\Icon.Windows.NoCOMWrappers.cs" />
<Compile Include="System\Drawing\Internal\GPStream.NoCOMWrappers.cs" />
</ItemGroup>
<!-- Unix specific -->
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@ namespace System.Drawing
///
/// Supports IStream and IPicture COM interfaces.
/// </summary>
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()
{
GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease);

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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -159,16 +180,13 @@ private static int CopyTo(IntPtr thisPtr, IntPtr pstm, ulong cb, ulong* pcbRead,
try
{
Interop.Ole32.IStream inst = ComInterfaceDispatch.GetInstance<Interop.Ole32.IStream>((ComInterfaceDispatch*)thisPtr);
Interop.Ole32.IStream pstmStream = ComInterfaceDispatch.GetInstance<Interop.Ole32.IStream>((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]
Expand Down Expand Up @@ -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<Interop.Ole32.IStream>((ComInterfaceDispatch*)thisPtr);

*ppstm = Instance.GetOrCreateComInterfaceForObject(inst.Clone(), CreateComInterfaceFlags.None);
return (int)inst.Clone(ppstm);
}
catch (Exception e)
{
return e.HResult;
}

return S_OK;
}
}

Expand Down Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
@@ -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<GPStream, Interop.Ole32.IStream>(stream));
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}
Loading