<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.1.25080.3" />

ComManagedStream

using System; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Windows.Win32.Foundation; namespace Windows.Win32.System.Com { internal sealed class ComManagedStream : IStream.Interface, ISequentialStream.Interface, IManagedWrapper<IStream, ISequentialStream>, IManagedWrapper { [Nullable(1)] private readonly Stream _dataStream; private long _virtualPosition = -1; [NullableContext(1)] internal ComManagedStream(Stream stream, bool makeSeekable = false) { if (makeSeekable && !stream.CanSeek) { MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); _dataStream = memoryStream; } else _dataStream = stream; } private void ActualizeVirtualPosition() { if (_virtualPosition != -1) { if (_virtualPosition > _dataStream.Length) _dataStream.SetLength(_virtualPosition); _dataStream.Position = _virtualPosition; _virtualPosition = -1; } } [NullableContext(1)] public Stream GetDataStream() { return _dataStream; } unsafe HRESULT IStream.Interface.Clone(IStream** ppstm) { if (ppstm == null) return HRESULT.E_POINTER; *ppstm = ComHelpers.GetComPointer<IStream>(new ComManagedStream(_dataStream, false) { _virtualPosition = _virtualPosition }); return HRESULT.S_OK; } HRESULT IStream.Interface.Commit(uint grfCommitFlags) { _dataStream.Flush(); ActualizeVirtualPosition(); return HRESULT.S_OK; } unsafe HRESULT IStream.Interface.CopyTo(IStream* pstm, ulong cb, ulong* pcbRead, ulong* pcbWritten) { if (pstm != null) { BufferScope<byte> bufferScope = new BufferScope<byte>(4096); try { ulong num = cb; ulong num2 = 0; ulong num3 = 0; HRESULT result; fixed (byte* pv = &bufferScope.GetPinnableReference()) { while (num != 0) { uint num4 = (uint)((num < (ulong)bufferScope.Length) ? ((int)num) : bufferScope.Length); ((IStream.Interface)this).Read((void*)pv, num4, &num4); num -= num4; num3 += num4; if (num4 == 0) break; uint num5 = default(uint); result = pstm->Write(pv, num4, &num5); result.ThrowOnFailure((IntPtr)0); num2 += num5; } } if (pcbRead != null) *pcbRead = num3; if (pcbWritten != null) *pcbWritten = num2; result = HRESULT.S_OK; return result; } finally { bufferScope.Dispose(); } } return HRESULT.STG_E_INVALIDPOINTER; } unsafe HRESULT ISequentialStream.Interface.Read(void* pv, uint cb, uint* pcbRead) { if (pv == null) return HRESULT.STG_E_INVALIDPOINTER; ActualizeVirtualPosition(); Span<byte> buffer = new Span<byte>(pv, checked((int)cb)); int num = _dataStream.Read(buffer); if (pcbRead != null) *pcbRead = (uint)num; return HRESULT.S_OK; } unsafe HRESULT IStream.Interface.Read(void* pv, uint cb, uint* pcbRead) { return ((ISequentialStream.Interface)this).Read(pv, cb, pcbRead); } unsafe HRESULT IStream.Interface.Seek(long dlibMove, SeekOrigin dwOrigin, ulong* plibNewPosition) { long num = (_virtualPosition == -1) ? _dataStream.Position : _virtualPosition; long length = _dataStream.Length; switch (dwOrigin) { case SeekOrigin.Begin: if (dlibMove <= length) { _dataStream.Position = dlibMove; _virtualPosition = -1; } else _virtualPosition = dlibMove; break; case SeekOrigin.End: if (dlibMove <= 0) { _dataStream.Position = length + dlibMove; _virtualPosition = -1; } else _virtualPosition = length + dlibMove; break; case SeekOrigin.Current: if (dlibMove + num <= length) { _dataStream.Position = num + dlibMove; _virtualPosition = -1; } else _virtualPosition = dlibMove + num; break; } if (plibNewPosition == null) return HRESULT.S_OK; *plibNewPosition = (ulong)((_virtualPosition == -1) ? _dataStream.Position : _virtualPosition); return HRESULT.S_OK; } HRESULT IStream.Interface.SetSize(ulong libNewSize) { _dataStream.SetLength(checked((long)libNewSize)); return HRESULT.S_OK; } unsafe HRESULT IStream.Interface.Stat(STATSTG* pstatstg, uint grfStatFlag) { if (pstatstg == null) return HRESULT.STG_E_INVALIDPOINTER; *pstatstg = new STATSTG { cbSize = _dataStream.Length, type = 2, grfMode = (_dataStream.CanWrite ? ((!_dataStream.CanRead) ? STGM.STGM_WRITE : STGM.STGM_READWRITE) : STGM.STGM_DIRECT) }; if (grfStatFlag == 0) { FileStream fileStream = _dataStream as FileStream; pstatstg->pwcsName = (char*)(long)Marshal.StringToCoTaskMemUni((fileStream != null) ? fileStream.Name : _dataStream.ToString()); } return HRESULT.S_OK; } HRESULT IStream.Interface.LockRegion(ulong libOffset, ulong cb, uint dwLockType) { return HRESULT.STG_E_INVALIDFUNCTION; } HRESULT IStream.Interface.Revert() { return HRESULT.S_OK; } HRESULT IStream.Interface.UnlockRegion(ulong libOffset, ulong cb, uint dwLockType) { return HRESULT.STG_E_INVALIDFUNCTION; } unsafe HRESULT ISequentialStream.Interface.Write(void* pv, uint cb, uint* pcbWritten) { if (pv == null) return HRESULT.STG_E_INVALIDPOINTER; ActualizeVirtualPosition(); ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(pv, checked((int)cb)); _dataStream.Write(buffer); if (pcbWritten != null) *pcbWritten = cb; return HRESULT.S_OK; } unsafe HRESULT IStream.Interface.Write(void* pv, uint cb, uint* pcbWritten) { return ((ISequentialStream.Interface)this).Write(pv, cb, pcbWritten); } } }