Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement IRandomAccessStream in C#?

I would like to implement an instance of IRandomAccessStream in C# (it will be returning data generated in realtime). The stream does not actually need to be writable or seekable, but I want to return my own data in the ReadAsync method (which is actually part of IInputStream).

public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
{
    throw new NotImplementedException("To be done");
}

My two main questions are:

  1. how do I return something that implements IAsyncOperationWithProgress? Is there anything built into the framework to help with this?
  2. how do I write data into the buffer? IBuffer only has Length and Capacity properties (the concrete Buffer class doesn't offer any more either).
like image 417
Mark Heath Avatar asked Dec 05 '12 12:12

Mark Heath


2 Answers

How to Convert byte Array to IRandomAccessStream

I've found this blog article, hopefully this realization of IRandomAccessStream can be a starting point for you.

class MemoryRandomAccessStream : IRandomAccessStream
{
    private Stream m_InternalStream;

    public MemoryRandomAccessStream(Stream stream)
    {
        this.m_InternalStream = stream;
    }

    public MemoryRandomAccessStream(byte[] bytes)
    {
        this.m_InternalStream = new MemoryStream(bytes);
    }

    public IInputStream GetInputStreamAt(ulong position)
    {
        this.m_InternalStream.Seek((long)position, SeekOrigin.Begin);

        return this.m_InternalStream.AsInputStream();
    }

    public IOutputStream GetOutputStreamAt(ulong position)
    {
        this.m_InternalStream.Seek((long)position, SeekOrigin.Begin);

        return this.m_InternalStream.AsOutputStream();
    }

    public ulong Size
    {
        get { return (ulong)this.m_InternalStream.Length; }
        set { this.m_InternalStream.SetLength((long)value); }
    }

    public bool CanRead
    {
        get { return true; }
    }

    public bool CanWrite
    {
        get { return true; }
    }

    public IRandomAccessStream CloneStream()
    {
        throw new NotSupportedException();
    }

    public ulong Position
    {
        get { return (ulong)this.m_InternalStream.Position; }
    }

    public void Seek(ulong position)
    {
        this.m_InternalStream.Seek((long)position, 0);
    }

    public void Dispose()
    {
        this.m_InternalStream.Dispose();
    }

    public Windows.Foundation.IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {
        var inputStream = this.GetInputStreamAt(0);
        return inputStream.ReadAsync(buffer, count, options);
    }

    public Windows.Foundation.IAsyncOperation<bool> FlushAsync()
    {
        var outputStream = this.GetOutputStreamAt(0);
        return outputStream.FlushAsync();
    }

    public Windows.Foundation.IAsyncOperationWithProgress<uint, uint> WriteAsync(IBuffer buffer)
    {
        var outputStream = this.GetOutputStreamAt(0);
        return outputStream.WriteAsync(buffer);
     }
}
like image 184
EugenSoft Avatar answered Oct 23 '22 00:10

EugenSoft


  1. Use AsyncInfo.Run(Func<CancellationToken, IProgress<uint>, Task<IBuffer>>) method to create IAsyncOperationWithProgress instance from a delegate.

    public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {    
        if (buffer == null) throw new ArgumentNullException("buffer");
    
        Func<CancellationToken, IProgress<uint>, Task<IBuffer>> taskProvider =
        (token, progress) => ReadBytesAsync(buffer, count, token, progress, options);
    
        return AsyncInfo.Run(taskProvider);
    }
    
    private async Task<IBuffer> ReadBytesAsync(IBuffer buffer, uint count, CancellationToken token, IProgress<uint> progress, InputStreamOptions options)
    {
    ... Fill the buffer here. Report the progress.
        return buffer;
    }
    
  2. Usually you do not need to access the buffer data directly. But in case you need to do this in c# you can use System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions class to copy data to/from a buffer.

like image 25
maxim pg Avatar answered Oct 22 '22 23:10

maxim pg