Trước hết, không phải là bản sao của Does a wrapper class for a COM interop IStream already exist? vì tôi cần triển khai theo hướng khác. Tôi cần tạo một triển khai IStream từ IO.Stream thành IStream. Nhưng trước khi tôi bắt đầu cố gắng làm điều đó, muốn hỏi xem có ai biết một sự thực hiện đã tồn tại hay bất kỳ bài viết nào về điều đó không. Tôi không thể tìm thấy bất cứ điều gì trong khuôn khổ. Net và google chỉ cho tôi kết quả của implemenations từ IStream để IO.Stream. Vì vậy, có ai có một mẹo tốt đẹp cho tôi? Tôi thực sự không biết bắt đầu như thế nào bởi vì thành viên đầu tiên (Clone -> Tạo một đối tượng stream mới tham chiếu cùng các byte với luồng gốc nhưng cung cấp một con trỏ tìm kiếm riêng biệt cho các byte đó) khiến tôi gặp khó khăn. Tôi không có ý tưởng làm thế nào để làm điều đó dựa trên một IO.Stream.C# Triển khai IStream của IStream
8
A
Trả lời
5
Cuối cùng, tôi đã thực hiện nó bằng bản thân mình (bạn có thể sao chép và sửa đổi nó):
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("0000000c-0000-0000-C000-000000000046")]
public interface IStream
{
[PreserveSig]
HResult Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] [Out] byte[] pv, int cb, IntPtr pcbRead);
[PreserveSig]
HResult Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] byte[] pv, int cb, IntPtr pcbWritten);
[PreserveSig]
HResult Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition);
[PreserveSig]
HResult SetSize(long libNewSize);
HResult CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten);
[PreserveSig]
HResult Commit(int grfCommitFlags);
[PreserveSig]
HResult Revert();
[PreserveSig]
HResult LockRegion(long libOffset, long cb, int dwLockType);
[PreserveSig]
HResult UnlockRegion(long libOffset, long cb, int dwLockType);
[PreserveSig]
HResult Stat(out comtypes.STATSTG pstatstg, int grfStatFlag);
[PreserveSig]
HResult Clone(out IStream ppstm);
}
/// <summary>
/// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms752876(v=vs.85).aspx
/// </summary>
public class ComStream : Stream, IStream
{
private Stream _stream;
public ComStream(Stream stream)
: this(stream, true)
{
}
internal ComStream(Stream stream, bool sync)
{
if (stream == null)
throw new ArgumentNullException("stream");
if (sync)
{
stream = Stream.Synchronized(stream);
}
_stream = stream;
}
HResult IStream.Clone(out IStream ppstm)
{
//ComStream newstream = new ComStream(_stream, false);
//ppstm = newstream;
ppstm = null;
return HResult.E_NOTIMPL;
}
HResult IStream.Commit(int grfCommitFlags)
{
return HResult.E_NOTIMPL;
}
HResult IStream.CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
return HResult.E_NOTIMPL;
}
HResult IStream.LockRegion(long libOffset, long cb, int dwLockType)
{
return HResult.E_NOTIMPL;
}
HResult IStream.Read(byte[] pv, int cb, IntPtr pcbRead)
{
if (!CanRead)
throw new InvalidOperationException("Stream not readable");
int read = Read(pv, 0, cb);
if (pcbRead != IntPtr.Zero)
Marshal.WriteInt64(pcbRead, read);
return HResult.S_OK;
}
HResult IStream.Revert()
{
return HResult.E_NOTIMPL;
}
HResult IStream.Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
SeekOrigin origin = (SeekOrigin)dwOrigin; //hope that the SeekOrigin enumeration won't change
long pos = Seek(dlibMove, origin);
if (plibNewPosition != IntPtr.Zero)
Marshal.WriteInt64(plibNewPosition, pos);
return HResult.S_OK;
}
HResult IStream.SetSize(long libNewSize)
{
return HResult.E_NOTIMPL;
}
HResult IStream.Stat(out comtypes.STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new comtypes.STATSTG();
pstatstg.cbSize = Length;
return HResult.S_OK;
}
HResult IStream.UnlockRegion(long libOffset, long cb, int dwLockType)
{
return HResult.E_NOTIMPL;
}
HResult IStream.Write(byte[] pv, int cb, IntPtr pcbWritten)
{
if (!CanWrite)
throw new InvalidOperationException("Stream is not writeable.");
Write(pv, 0, cb);
if (pcbWritten != null)
Marshal.WriteInt32(pcbWritten, cb);
return HResult.S_OK;
}
public override bool CanRead
{
get { return _stream.CanRead; }
}
public override bool CanSeek
{
get { return _stream.CanSeek; }
}
public override bool CanWrite
{
get { return _stream.CanWrite; }
}
public override void Flush()
{
_stream.Flush();
}
public override long Length
{
get { return _stream.Length; }
}
public override long Position
{
get
{
return _stream.Position;
}
set
{
_stream.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return _stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
_stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
_stream.Write(buffer, offset, count);
}
protected override void Dispose(bool disposing)
{
if (_stream != null)
{
_stream.Dispose();
_stream = null;
}
}
}
client COM sẽ kết thúc gọi :: Release() trên IUnknown COM-interface/CCW, nhưng không có cách nào để kết nối nó với .Dispose()? – toong
Không hoạt động như hiện trạng, ngay cả khi nó xuất hiện: System.IO.Stream.Read() được phép trả lại sớm và cho biết nó chưa đọc tất cả các byte, nhưng chỉ một hoặc nhiều byte. IStream :: Đọc() * luôn * đọc tất cả các byte được yêu cầu trừ khi kết thúc luồng. Các hợp đồng không tương thích khác nhau: bạn phải thêm một vòng lặp đọc trong việc triển khai IStream.Read() và đọc/điền vào bộ đệm cho đến khi bạn nhận được tất cả các byte được yêu cầu, hoặc không còn đọc được nữa. –