Answered by:
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.
- 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.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; }
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>^.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.
- 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.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; }
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