locked
Pass Stream from managed WinRT to native C++

    Question

  • I have a native C++ IStream interface like this:

    class IStream
    {
    public:
        virtual int Read(char* buffer, int offset, int count) = 0;
        virtual int GetLength() = 0;
    };

    I would like to implement this interface in the managed WinRT layer (possibly in C#), and then use it in native C++. So I created a wrapper class implementing the above native interface:

    class StreamWrapper : IStream
    {
    public:
        StreamWrapper(IStreamWinRT^ stream)
    	: wrappedStream(stream)
        {
        };
    		
        virtual int Read(char* buffer, int offset, int count);
        virtual int GetLength();
    
        IStreamWinRT^ GetWrappedStream()
        {  
    	return this->wrappedStream;
        }
    
    private:
        IStreamWinRT^ wrappedStream;
    };

    The implementation of the two methods in the wrapper class would simply pass the calls from the native layer to the WinRT class.

    And I have the IStreamWinRT interface, which would expose the same operations in the WinRT layer, and would be implemented possibly in C#.

    public interface class IStreamWinRT
    {
    public:
        int Read(??? buffer, int offset, int count);
        int GetLength();
    };

    My problem is: what type should I use as a buffer in the managed layer? I can't use byte*, because it's a native type. And in the implementation of the StreamWrapper.Read method, how can I pass the bytes read in the WinRT layer down to the native layer without copying them in memory?

    (the implementation of the StreamWrapper class:

    #include "StreamWrapper.h"
    
    int StreamWrapper::Read(char* buffer, int offset, int count)
    {
        // How should I pass the bytes from the WinRT stream to the native byte* buffer?
    }
    
    int StreamWrapper::GetLength()
    {
        return this->wrappedStream->GetLength();
    }

    )


    • Edited by MarkVincze Friday, July 13, 2012 8:00 AM
    Friday, July 13, 2012 7:59 AM

Answers

  • It would be safer to access it through the IVector<> interface. As far as I know, there is no official/supported way to get the raw pointer to the buffer. So unless you really need that char*, you should just use the IVector<> directly. And if you do need a char*, you may have to do a copy.

    And if you are doing this in C#, there is potentially one more level of marshalling that will be needed if you access it in managed code (example, the IVector<> may get copied into a .NET collection like Collection<> or List<>).  Would be best to try it out and make your decision based on what you observe performance-wise.


    http://blog.voidnish.com

    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Saturday, July 14, 2012 4:08 PM
  • Hello,

     

    I found two thread
    about the transformation between Istream and Ibuffer. Hope them can help you.

    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/5e70aba9-1eb4-4960-88ba-8851bb9df365

     
    IStream* createIStreamFromIBuffer(Streams::IBuffer ^buffer) {
        // convert the IBuffer into an IStream to be used with WIC
        IStream *fileContentsStream;
        HRESULT res = CreateStreamOnHGlobal(NULL, TRUE, &fileContentsStream);
        if (FAILED(res) || !fileContentsStream) {
            throw ref new FailureException();
        }
        Streams::DataReader^ dataReader = Streams::DataReader::FromBuffer(buffer);
        // read the data into the stream in chunks of 1MB to preserve memory
        while (dataReader->UnconsumedBufferLength > 0) {
            UINT chunkSize = min(1024*1024, dataReader->UnconsumedBufferLength);
            auto data = ref new Platform::Array<uint8>(chunkSize);
            dataReader->ReadBytes(data);
            ULONG written;
            res = fileContentsStream->Write(data->Data, chunkSize, &written);
            if (FAILED(res) || written != chunkSize) {
                fileContentsStream->Release();
                throw ref new FailureException();
            }
        }
        return fileContentsStream;
    }

    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/dc39d796-1a3a-48e1-a095-2609600d01b7

     

    Best regards,

    Jesse



    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Monday, July 16, 2012 6:23 AM
  • Hi MarkVincze,

    Following are the datatypes that a C# metro passed to WinRT component.

    From c# you pass a IList and it should be an IVector in WinRT.

    The list is as follows

    http://msdn.microsoft.com/en-us/library/windows/apps/br230301(v=vs.110).aspx#PassingToManaged

    When I develeped a image processing application I passed the image path to the WinRT component.
    The component apply some image processing using Direct2D and returned the output as a imagestream.

    i have used following proto

    IRandomAccessStream^ GetSharpenImage(String imagepath);

    Please have alook this sample http://devhawk.net/2012/06/24/windows-camp-demo-part-two/

    Like you  can take the corresponding datatype according to your need.

    thanks,

    Bhash


    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Monday, July 16, 2012 6:03 PM

All replies

  • WinRT is not managed - it's native and based on COM. So you can write the WinRT component in C++/CX if you don't want to make it managed. And the matching WinRT type for a char* (byte buffer) would most likely be IVector<char>^.

    http://blog.voidnish.com

    Friday, July 13, 2012 1:04 PM
  • I would like it to be managed, because I would like to implement the IStreamWinRT interface in C#.

    And if the signature of the IStreamWinRT::Read method is the following:

    int Read(IVector<char>^ buffer, int offset, int count);

    Then in the implementation of the 

    StreamWrapper::Read(char* buffer, int offset, int count)

    method can I somehow cast the IVector<char>^ to a char* without copying the bytes in memory?

    Friday, July 13, 2012 11:38 PM
  • It would be safer to access it through the IVector<> interface. As far as I know, there is no official/supported way to get the raw pointer to the buffer. So unless you really need that char*, you should just use the IVector<> directly. And if you do need a char*, you may have to do a copy.

    And if you are doing this in C#, there is potentially one more level of marshalling that will be needed if you access it in managed code (example, the IVector<> may get copied into a .NET collection like Collection<> or List<>).  Would be best to try it out and make your decision based on what you observe performance-wise.


    http://blog.voidnish.com

    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Saturday, July 14, 2012 4:08 PM
  • Hello,

     

    I found two thread
    about the transformation between Istream and Ibuffer. Hope them can help you.

    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/5e70aba9-1eb4-4960-88ba-8851bb9df365

     
    IStream* createIStreamFromIBuffer(Streams::IBuffer ^buffer) {
        // convert the IBuffer into an IStream to be used with WIC
        IStream *fileContentsStream;
        HRESULT res = CreateStreamOnHGlobal(NULL, TRUE, &fileContentsStream);
        if (FAILED(res) || !fileContentsStream) {
            throw ref new FailureException();
        }
        Streams::DataReader^ dataReader = Streams::DataReader::FromBuffer(buffer);
        // read the data into the stream in chunks of 1MB to preserve memory
        while (dataReader->UnconsumedBufferLength > 0) {
            UINT chunkSize = min(1024*1024, dataReader->UnconsumedBufferLength);
            auto data = ref new Platform::Array<uint8>(chunkSize);
            dataReader->ReadBytes(data);
            ULONG written;
            res = fileContentsStream->Write(data->Data, chunkSize, &written);
            if (FAILED(res) || written != chunkSize) {
                fileContentsStream->Release();
                throw ref new FailureException();
            }
        }
        return fileContentsStream;
    }

    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/dc39d796-1a3a-48e1-a095-2609600d01b7

     

    Best regards,

    Jesse



    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us

    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Monday, July 16, 2012 6:23 AM
  • Hi MarkVincze,

    Following are the datatypes that a C# metro passed to WinRT component.

    From c# you pass a IList and it should be an IVector in WinRT.

    The list is as follows

    http://msdn.microsoft.com/en-us/library/windows/apps/br230301(v=vs.110).aspx#PassingToManaged

    When I develeped a image processing application I passed the image path to the WinRT component.
    The component apply some image processing using Direct2D and returned the output as a imagestream.

    i have used following proto

    IRandomAccessStream^ GetSharpenImage(String imagepath);

    Please have alook this sample http://devhawk.net/2012/06/24/windows-camp-demo-part-two/

    Like you  can take the corresponding datatype according to your need.

    thanks,

    Bhash


    • Marked as answer by Jesse Jiang Thursday, July 19, 2012 6:56 AM
    Monday, July 16, 2012 6:03 PM