locked
How to convert IBuffer to COM IStream?

    Question

  • I wonder if there is a smart way to convert an IBuffer into an IStream for use with other COM APIs like WIC.

    It seems there is no way than to use CreateStreamOnHGlobal(NULL, TRUE, &stream); and let Windows manage the streams HGLOBAL buffer.

    Then read in the IBuffer via a DataReader chunk by chunk and writing this to the stream.

    There are several questions regarding this:

    1. Whats the optimal size for the chunks to read from the IBuffer and write to the result IStream?
    2. Can we access the bytes provided by the IBuffer directly and therefore implement our own IStream on top of IBuffer?
    3. How does DataReader know how to read from the IBuffer? I assume it QueryInterface for some non-public interface on IBuffer that gives access to the buffers content?

    Thanks!

    Thursday, April 12, 2012 8:26 AM

Answers

  • 1. Ideal chunk size would depend on the specific data and usage.

    2. Yes.

    3. To access the data in the buffer query the IBuffer for its IBufferByteAccess interface.

    --Rob

    • Marked as answer by phil_ke Friday, April 13, 2012 3:08 PM
    Friday, April 13, 2012 2:56 PM
    Owner
  • template <typename T>
    inline Microsoft::WRL::ComPtr<T> com_interface(Platform::Object^ object)
    {
    	Microsoft::WRL::ComPtr<IUnknown> comObject = (IUnknown*)object;
    	Microsoft::WRL::ComPtr<T> iPtr;
    	CheckHResult(comObject.As(&iPtr));
    	return iPtr;
    }

    also gonna need this:

    inline void CheckHResult(HRESULT hResult) { if (FAILED(hResult)) throw ref new Platform::Exception(hResult); }
    

    • Edited by brentAtBrainium Tuesday, April 17, 2012 10:24 PM
    • Marked as answer by phil_ke Wednesday, April 18, 2012 6:11 AM
    Tuesday, April 17, 2012 10:23 PM

All replies

  • Hello,

    I found the way use CreateStreamOnHGlobal to convert IBuffer to IStream. You can check this thread
    http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/5e70aba9-1eb4-4960-88ba-8851bb9df365

    I will involve more experts to investigate it.
     
    Best regards,
    Jesse


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

    Friday, April 13, 2012 7:46 AM
  • Uhmmm Jesse... I was already aware of using CreateStreamOnHGlobal. Did you read my questions even?
    Friday, April 13, 2012 7:50 AM
  • 1. Ideal chunk size would depend on the specific data and usage.

    2. Yes.

    3. To access the data in the buffer query the IBuffer for its IBufferByteAccess interface.

    --Rob

    • Marked as answer by phil_ke Friday, April 13, 2012 3:08 PM
    Friday, April 13, 2012 2:56 PM
    Owner
  • That was very helpful, Rob! Thank you very much. Now I can further optimize my C++ component and consume less memory!
    Friday, April 13, 2012 3:08 PM
  • How would I QI an Windows::Storage::Streams::IBuffer^ buffer for IBufferByteAccess?
    Friday, April 13, 2012 3:18 PM
  • The IBuffer^ is a COM object (with syntactic sugar to hide the COM-ness). You should be able to cast it to IUnknown* and then call QueryInterface on it.

    --Rob

    Friday, April 13, 2012 3:27 PM
    Owner
  • Where can I find the GUID of IBufferByteAccess;Is this a documented way?

    Saturday, April 14, 2012 7:00 AM
  • Where can I find the GUID of IBufferByteAccess;Is this a documented way?

    Its defined in RoBuffer.h

    Use __uuidof(IBufferByteAccess).

    Sunday, April 15, 2012 11:17 AM
  • Thanks for your reply:-)
    Monday, April 16, 2012 9:40 AM
  • Is there any cleaner way than this ugly cast?

    IUnknown* comBuffer = (IUnknown*)buffer;
      ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteBuffer;
      comBuffer->QueryInterface(__uuidof(Windows::Storage::Streams::IBufferByteAccess), (void**)&byteBuffer);

    Monday, April 16, 2012 12:31 PM
  • Use IID_PPV_ARGS:

    IUnknown* pUnk = reinterpret_cast<IUnknown*>(buffer); IBufferByteAccess* pBufferByteAccess = nullptr; HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess);

    --Rob
    Monday, April 16, 2012 5:23 PM
    Owner
  • Rob, why you suggest plain COM Ptrs that are prone to leaks when MSFT even provides a ComPtr helper class?

    Final version:

    Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteBuffer;

    ComPtr<IUnknown> comBuffer((IUnknown*)buffer); comBuffer.As(&byteBuffer);


    Clean and safe.

    Tuesday, April 17, 2012 8:42 AM
  • template <typename T>
    inline Microsoft::WRL::ComPtr<T> com_interface(Platform::Object^ object)
    {
    	Microsoft::WRL::ComPtr<IUnknown> comObject = (IUnknown*)object;
    	Microsoft::WRL::ComPtr<T> iPtr;
    	CheckHResult(comObject.As(&iPtr));
    	return iPtr;
    }

    also gonna need this:

    inline void CheckHResult(HRESULT hResult) { if (FAILED(hResult)) throw ref new Platform::Exception(hResult); }
    

    • Edited by brentAtBrainium Tuesday, April 17, 2012 10:24 PM
    • Marked as answer by phil_ke Wednesday, April 18, 2012 6:11 AM
    Tuesday, April 17, 2012 10:23 PM
  • Sorry Phil,

    In general I avoid smart pointers in sample code since not everybody uses the same smart pointer libraries. For Metro style apps you are probably right that using WRL is reasonable.

    In this case it wasn't relevant to the point of avoiding the ugly cast in QueryInterface by using IID_PPV_ARGS.

    As Brent points out, many smart pointer implementations (including the WRL one) abstract out QueryInterface so you can avoid it altogether.

    I apologize if this confused you.

    --Rob

    Thursday, April 19, 2012 10:01 PM
    Owner