4

I am working with a sample UWP C++/CX program that creates two UDP network communication threads which are sending data to each other using Windows::Storage::Streams::DataWriter and Windows::Storage::Streams::DataReader while updating a displayed window showing the data going back and forth.

The initial implementation using Platform::String variables along with DataWriter->WriteString() worked fine. However now I want to implement a binary protocol that has variable length buffers containing various types of information.

DataReader->ReadBuffer() and DataWriter->WriteBuffer() requires a Windows::Storage::Streams::Buffer.

To access the Buffer returned by ReadBuffer() I am using a function whose source if found on the web at Obtaining pointers to data buffers (C++/CX) which is similar to an answer in Getting an array of bytes out of Windows::Storage::Streams::IBuffer

#include <robuffer.h>  

byte* GetPointerToPixelData(IBuffer^ pixelBuffer, unsigned int *length)
{
    if (length != nullptr)
    {
        *length = pixelBuffer->Length;
    }
    // Query the IBufferByteAccess interface.  
    Microsoft::WRL::ComPtr<IBufferByteAccess> bufferByteAccess;
    reinterpret_cast<IInspectable*>(pixelBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));

    // Retrieve the buffer data.  
    byte* pixels = nullptr;
    bufferByteAccess->Buffer(&pixels);
    return pixels;
}

However I have been unable to find out how to copy a native struct into a Buffer so that it can be sent out using DataWriter->WriteBuffer().

If I have some struct of binary data, how can I copy the contents of this struct into the output Windows::Storage::Streams::Buffer for use with DataWriter->WriteBuffer()?

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106

1 Answers1

0

It appears that the same function that can be used to obtain a pointer to the Buffer memory area to copy data from the Buffer into a native memory area can also be used to obtain a pointer that can be used to copy data into the Buffer. See Obtaining pointers to data buffers (C++/CX). and see as well COM Coding Practices for information about the IID_PPV_ARGS() macro and the ATL smart pointer class CComPtr. See QueryInterface: Navigating in an Object as well.

ComPtr is the WRL version of the ATL CComPtr (see Native WinRT Inheritance as well as Windows Runtime C++ Template Library (WRL) which has links to a variety of supporting topics for WRL and WinRT).

(ComPtr is a WRL smart pointer. It automates some aspects of COM that otherwise get tedious fast. It’s similar to ATL’s CComPtr, although some operations that CComPtr performed implicitly now require explicit code, largely because those implicit operations were responsible for a lot of bugs in code written by people who didn’t really understand how CComPtr works. With the new ComPtr, a failure to understand how it works is more likely to lead to a compiler error than a runtime bug.)

as well as ComPtr in the DirectXTK wiki

Microsoft::WRL::ComPtr is a C++ template smart-pointer for COM objects that is used extensively in Windows Runtime (WinRT) C++ programming. It works in Win32 desktop applications as well. It is similar to ATL's CComPtr with some useful improvements. Microsoft::WRL:::ComPtr is in the Windows 8.x SDK and Windows 10 SDK, which, unlike ATL, is available when using the Express versions of Visual Studio. It is used extensively in DirectX Tool Kit to properly handle COM reference counting maintenance.

#include <robuffer.h>  

byte* GetPointerToPixelData(IBuffer^ pixelBuffer, unsigned int *length)
{
    if (length != nullptr)
    {
        *length = pixelBuffer->Length;
    }
    // Query the IBufferByteAccess interface.  
    Microsoft::WRL::ComPtr<IBufferByteAccess> bufferByteAccess;
    reinterpret_cast<IInspectable*>(pixelBuffer)->QueryInterface(IID_PPV_ARGS(&bufferByteAccess));

    // Retrieve the buffer data.  
    byte* pixels = nullptr;
    bufferByteAccess->Buffer(&pixels);
    return pixels;
}

Warning: You must ensure that you do not exceed the capacity of the memory allocated to the Buffer (you can check the Capacity attribute of the buffer). After copying from a native variable into the Buffer you must also set the Length attribute to the actual number of bytes of data set into the Buffer.

For example:

// test structs for binary data to parse.
struct struct1 {
    unsigned char uchMajorClass;
    unsigned char uchMinorClass;
    long  lVal1;
};

void testfunc (IOutputStream^ outputStream)
{
    auto dataWriter = ref new DataWriter(outputStream);

    struct1 myStruct1 = { 1, 11,0 };

    Buffer ^myBuffer = ref new Buffer(sizeof(struct1));  // allocate Buffer of desired size

    unsigned int  len;
    struct1 *sp = (struct1 *)GetPointerToPixelData(myBuffer, &len);  // get native pointer

    // we could use myBuffer->Capacity at this point to check the capacity or
    // max size in bytes of the buffer.
    *sp = myStruct1;                // copy data from native into the Buffer
    myBuffer->Length = sizeof(*sp); // set the data length
    dataWriter->WriteBuffer(myBuffer);

}
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
  • 1
    You could also just use `dataWriter->WriteBytes()` to write out bytes, and use `Platform::Array` to hold the data. – Peter Torr - MSFT Apr 17 '18 at 23:44
  • @PeterTorr-MSFT thank you for the suggestion. Is there a `ReadBytes()` as well? It looks like there is one with arguments of a `Byte` array and a max size or capacity. I guess I got fixed on the `Buffer` approach working with an example that started with `String`. I suppose the nice thing about the `Buffer` approach is that dealing with variable packet sizes, this is a UDP client/server, `Buffer` may be easier. However the original application I am replicating used a single large buffer size for the UDP network traffic. – Richard Chambers Apr 18 '18 at 02:10
  • Yes, there is a [`ReadBytes()` method on the `DataReader`](https://learn.microsoft.com/en-us/uwp/api/windows.storage.streams.datareader.readbytes). In IDL it is represented as a {pointer, size} pair of arguments, but it should project as `Platform::Array` as well. – Peter Torr - MSFT Apr 19 '18 at 02:31
  • @PeterTorr-MSFT thanks for the link as there is a link on that page to a [Microsoft GitHub area with sample applications](https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DataReaderWriter). – Richard Chambers Apr 19 '18 at 03:02