how can i store xml in buffer using xmlite? - c++

I'm trying to write xml data with XmlLite on buffer but couldn't got any api. writing a xml file works perfect but on a memory stream I can't figure
i am working on follwong link api
http://msdn.microsoft.com/en-us/library/ms752901(v=VS.85).aspx

You can use either SHCreateMemStream or CreateStreamOnHGlobal to create an memory stream. Here is the sample code for your reference:
CComPtr<IStream> spMemoryStream;
CComPtr<IXmlWriter> spWriter;
CComPtr<IXmlWriterOutput> pWriterOutput;
// Opens writeable output stream.
spMemoryStream.Attach(::SHCreateMemStream(NULL, 0));
if (spMemoryStream == NULL)
return E_OUTOFMEMORY;
// Creates the xml writer and generates the content.
CHKHR(::CreateXmlWriter(__uuidof(IXmlWriter), (void**) &spWriter, NULL));
CHKHR(::CreateXmlWriterOutputWithEncodingName(spMemoryStream,
NULL, L"utf-16", &pWriterOutput));
CHKHR(spWriter->SetOutput(pWriterOutput));
CHKHR(spWriter->SetProperty(XmlWriterProperty_Indent, TRUE));
CHKHR(spWriter->WriteStartDocument(XmlStandalone_Omit));
CHKHR(spWriter->WriteStartElement(NULL, L"root", NULL));
CHKHR(spWriter->WriteWhitespace(L"\n"));
CHKHR(spWriter->WriteCData(L"This is CDATA text."));
CHKHR(spWriter->WriteWhitespace(L"\n"));
CHKHR(spWriter->WriteEndDocument());
CHKHR(spWriter->Flush());
// Allocates enough memeory for the xml content.
STATSTG ssStreamData = {0};
CHKHR(spMemoryStream->Stat(&ssStreamData, STATFLAG_NONAME));
SIZE_T cbSize = ssStreamData.cbSize.LowPart;
LPWSTR pwszContent = (WCHAR*) new(std::nothrow) BYTE[cbSize + sizeof(WCHAR)];
if (pwszContent == NULL)
return E_OUTOFMEMORY;
// Copies the content from the stream to the buffer.
LARGE_INTEGER position;
position.QuadPart = 0;
CHKHR(spMemoryStream->Seek(position, STREAM_SEEK_SET, NULL));
SIZE_T cbRead;
CHKHR(spMemoryStream->Read(pwszContent, cbSize, &cbRead));
pwszContent[cbSize / sizeof(WCHAR)] = L'\0';
wprintf(L"%s", pwszContent);
One pretty thing about XmlLite is it works with IStream interface. It really doesn't care what exactly the stream looks like behind the scene.

Related

Media Foundation: Getting a MediaSink from a SinkWriter

I'm trying to add an MP4 file sink to a Topology. When my MediaSource is already MP4, I use MFCreateMPEG4MediaSink and MF_MPEG4SINK_SPSPPS_PASSTHROUGH. When my MediaSource isn't MP4 (so raw YUV from a webcam), I want to use MFCreateSinkWriterFromURL so that I don't have to figure out MP4 headers and other complex stuff.
According to the MSDN Docs I should be able to use GetServiceForStream to get at the MediaSink, since the input type is different from the output type. However it always returns MF_E_UNSUPPORTED_SERVICE.
How can I get the underlying MediaSink out of a MediaSinkWriter?
Alternatively, how can I easily create a MP4 media sink for an arbitrary topology?
HRESULT CreateVideoFileSink(
IMFStreamDescriptor *pSourceSD, // Pointer to the stream descriptor.
LPCWSTR pFilename, // Name of file to save to.
IMFStreamSink **ppStream) // Receives a pointer to the stream sink.
HRESULT hr = S_OK;
CComPtr<IMFAttributes> pAttr;
CComPtr<IMFMediaTypeHandler> pHandler;
CComPtr<IMFMediaType> pType;
CComPtr<IMFMediaSink> pSink;
CComPtr<IMFStreamSink> pStream;
CComPtr<IMFSinkWriter> pSinkWriter;
CComPtr<IMFByteStream> pByteStream;
*ppStream = nullptr;
// Get the media type handler for the stream.
IFR(pSourceSD->GetMediaTypeHandler(&pHandler));
// Get the major media type.
GUID guidMajorType;
IFR(pHandler->GetMajorType(&guidMajorType));
IFR(MFCreateAttributes(&pAttr, 1));
IFR(pAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE));
// Create an output file
if (MFMediaType_Video == guidMajorType)
{
GUID guidSubType;
IFR(pHandler->GetCurrentMediaType(&pType));
IFR(pType->GetGUID(MF_MT_SUBTYPE, &guidSubType));
if (MFVideoFormat_H264 == guidSubType)
{
// ... use MFCreateMPEG4MediaSink
}
else
{
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
}
}
else
{
// Don't use this stream
IFR(E_FAIL)
}
// Return IMFStreamSink pointer to caller.
*ppStream = pStream.Detach();
return S_OK;
}
Figured it out right after writing the question - of course. The SinkWriter doesn't have a MediaSink until you call BeginWriting.
IFR(MFCreateSinkWriterFromURL(pFilename, nullptr, pAttr, &pSinkWriter));
DWORD streamIdx;
IFR(pSinkWriter->AddStream(pType, &streamIdx));
IFR(pSinkWriter->BeginWriting()); // <<----
IFR(pSinkWriter->GetServiceForStream(MF_SINK_WRITER_MEDIASINK, GUID_NULL, IID_PPV_ARGS(&pSink)));
IFR(pSink->GetStreamSinkByIndex(streamIdx, &pStream));
(Make sure you don't let the SinkWriter get Released while you're using the StreamSink)

Create IMFByteStream from byte array

I am trying to adapt a method that originally took a URL from Microsoft's MediaFoundation audio playback sample to instead take a source from a const char* array. Problem is, CreateObjectFromByteStream requires an IMFByteStream, not a const char*. How can I get what I need?
// Create a media source from a byte stream
HRESULT CreateMediaSource(const byte *data, IMFMediaSource **ppSource)
{
MF_OBJECT_TYPE ObjectType = MF_OBJECT_INVALID;
IMFSourceResolver* pSourceResolver = NULL;
IUnknown* pSource = NULL;
// Create the source resolver.
HRESULT hr = MFCreateSourceResolver(&pSourceResolver);
if (FAILED(hr))
{
goto done;
}
// Use the source resolver to create the media source.
// Note: For simplicity this sample uses the synchronous method to create
// the media source. However, creating a media source can take a noticeable
// amount of time, especially for a network source. For a more responsive
// UI, use the asynchronous BeginCreateObjectFromURL method.
hr = pSourceResolver->CreateObjectFromByteStream(data,
NULL, // URL of the source.
MF_RESOLUTION_MEDIASOURCE | MF_BYTESTREAM_CONTENT_TYPE, // Create a source object.
NULL, // Optional property store.
&ObjectType, // Receives the created object type.
&pSource // Receives a pointer to the media source.
);
if (FAILED(hr))
{
goto done;
}
// Get the IMFMediaSource interface from the media source.
hr = pSource->QueryInterface(IID_PPV_ARGS(ppSource));
done:
SafeRelease(&pSourceResolver);
SafeRelease(&pSource);
return hr;
}
I found easiest way to do this to just create tempfile and write *data there. Ugly hack, but worked good enough for me and if needed it can easily replaced by custom inmemory IMFByteStream implementation.
So code would be something like this:
Byte data[] = {'a','b','c','d','e','f'};
HRESULT hr = S_OK;
hr = MFStartup(MF_VERSION);
IMFByteStream *stream = NULL;
hr = MFCreateTempFile(
MF_ACCESSMODE_READWRITE,
MF_OPENMODE_DELETE_IF_EXIST,
MF_FILEFLAGS_NONE,
&stream
);
ULONG wroteBytes = 0;
stream->Write(data, sizeof(data), &wroteBytes);
stream->SetCurrentPosition(0);
// make sure that wroteBytes is equal with data length
You can use MFCreateMFByteStreamOnStream() to create an IMFByteStream from an IStream and you can create and IStream from a byte array using SHCreateMemStream(). The documentation at the time of writing is at https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-mfcreatemfbytestreamonstream and https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-shcreatememstream
Here's a quick example:
// Generate a byte array
int sample_size = 0x100;
BYTE* sample_bytes = (BYTE*)malloc(sample_size)
// Create the IStream from the byte array
IStream* pstm = SHCreateMemStream(sample_bytes, sample_size);
// Create the IMFByteStream from the IStream
IMFByteStream* pibs = NULL;
MFCreateMFByteStreamOnStream(pstm, &pibs);
// Clean up time
if (pibs)
pibs->Close();
if (pstm)
pstm->Release();
if (sample_bytes)
free(sample_bytes)
Having an IStream interface but not a byte array interface seems to be a frequent occurrence in the Microsoft API. Thankfully creating an IStream is easy.

What is the preferred way to get a device path for CreateFile() in a UWP C++ App?

I am converting a project to a UWP App, and thus have been following guidelines outlined in the MSDN post here. The existing project heavily relies on CreateFile() to communicate with connected devices.
There are many posts in SO that show us how to get a CreateFile()-accepted device path using SetupAPI's SetupDiGetDeviceInterfaceDetail() Is there an alternative way to do this using the PnP Configuration Manager API? Or an alternative, user-mode way at all?
I had some hope when I saw this example in Windows Driver Samples github, but quickly became dismayed when I saw that the function they used in the sample is ironically not intended for developer use, as noted in this MSDN page.
function GetDevicePath in general correct and can be used as is. about difference between CM_*(..) and CM_*_Ex(.., HMACHINE hMachine) - the CM_*(..) simply call CM_*_Ex(.., NULL) - so for local computer versions with and without _Ex suffix the same.
about concrete GetDevicePath code - call CM_Get_Device_Interface_List_Size and than CM_Get_Device_Interface_List only once not 100% correct - because between this two calls new device with this interface can be arrived to system and buffer size returned by CM_Get_Device_Interface_List_Size can be already not enough for CM_Get_Device_Interface_List. of course possibility of this very low, and you can ignore this. but i prefer make code maximum theoretical correct and call this in loop, until we not receive error other than CR_BUFFER_SMALL. also need understand that CM_Get_Device_Interface_List return multiple, NULL-terminated Unicode strings - so we need iterate here. in [example] always used only first returned symbolic link name of an interface instance. but it can be more than 1 or at all - 0 (empty). so better name function - GetDevicePaths - note s at the end. i be use code like this:
ULONG GetDevicePaths(LPGUID InterfaceClassGuid, PWSTR* pbuf)
{
CONFIGRET err;
ULONG len = 1024;//first try with some reasonable buffer size, without call *_List_SizeW
for(PWSTR buf;;)
{
if (!(buf = (PWSTR)LocalAlloc(0, len * sizeof(WCHAR))))
{
return ERROR_NO_SYSTEM_RESOURCES;
}
switch (err = CM_Get_Device_Interface_ListW(InterfaceClassGuid, 0, buf, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT))
{
case CR_BUFFER_SMALL:
err = CM_Get_Device_Interface_List_SizeW(&len, InterfaceClassGuid, 0, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
default:
LocalFree(buf);
if (err)
{
return CM_MapCrToWin32Err(err, ERROR_UNIDENTIFIED_ERROR);
}
continue;
case CR_SUCCESS:
*pbuf = buf;
return NOERROR;
}
}
}
and usage example:
void example()
{
PWSTR buf, sz;
if (NOERROR == GetDevicePaths((GUID*)&GUID_DEVINTERFACE_VOLUME, &buf))
{
sz = buf;
while (*sz)
{
DbgPrint("%S\n", sz);
HANDLE hFile = CreateFile(sz, FILE_GENERIC_READ, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
// do something
CloseHandle(hFile);
}
sz += 1 + wcslen(sz);
}
LocalFree(buf);
}
}
so we must not simply use in returned DevicePathS (sz) only first string, but iterate it
while (*sz)
{
// use sz
sz += 1 + wcslen(sz);
}
I got a valid Device Path to a USB Hub Device, and used it successfully to get various device descriptors by sending some IOCTLs, by using the function I posted in my own answer to another question
I'm reporting the same function below:
This function returns a list of NULL-terminated Device Paths (that's what we get from CM_Get_Device_Interface_List())
You need to pass it the DEVINST, and the wanted interface GUID.
Since both the DEVINST and interface GUID are specified, it is highly likely that CM_Get_Device_Interface_List() will return a single Device Path for that interface, but technically you should be prepared to get more than one result.
It is responsibility of the caller to delete[] the returned list if the function returns successfully (return code 0)
int GetDevInstInterfaces(DEVINST dev, LPGUID interfaceGUID, wchar_t**outIfaces, ULONG* outIfacesLen)
{
CONFIGRET cres;
if (!outIfaces)
return -1;
if (!outIfacesLen)
return -2;
// Get System Device ID
WCHAR sysDeviceID[256];
cres = CM_Get_Device_ID(dev, sysDeviceID, sizeof(sysDeviceID) / sizeof(sysDeviceID[0]), 0);
if (cres != CR_SUCCESS)
return -11;
// Get list size
ULONG ifaceListSize = 0;
cres = CM_Get_Device_Interface_List_Size(&ifaceListSize, interfaceGUID, sysDeviceID, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS)
return -12;
// Allocate memory for the list
wchar_t* ifaceList = new wchar_t[ifaceListSize];
// Populate the list
cres = CM_Get_Device_Interface_List(interfaceGUID, sysDeviceID, ifaceList, ifaceListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cres != CR_SUCCESS) {
delete[] ifaceList;
return -13;
}
// Return list
*outIfaces = ifaceList;
*outIfacesLen = ifaceListSize;
return 0;
}
Please note that, as RbMm already said in his answer, you may get a CR_BUFFER_SMALL error from the last CM_Get_Device_Interface_List() call, since the device list may have been changed in the time between the CM_Get_Device_Interface_List_Size() and CM_Get_Device_Interface_List() calls.

DecideBufferSize values seem to be ignored

I had the problem that when using a webcam as a source , the input sample was bigger than the size of the buffer provided by the allocator as you can see in the ASSERT statement in this code.
HRESULT MCMyOutputPin::Deliver(IMediaSample* sample)
{
HRESULT hr = NO_ERROR;
myLogger->LogDebug("In Outputpin Deliver", L"D:\\TEMP\\yc.log");
if (sample->GetActualDataLength() > 0)
{
IMediaSample *outsample;
hr = m_pAllocator->GetBuffer(&outsample, NULL, NULL, NULL);
if (FAILED(hr))
{
return hr;
}
BYTE* sampleBuffer = NULL;
BYTE* newBuffer = NULL;
long ulDataLen = sample->GetSize();
long datalenout = outsample->GetSize(); //this is always 92160
outsample->GetPointer(&newBuffer);
ASSERT(datalenout >= ulDataLen); //This fails
memcpy((void *)newBuffer, (void *)sampleBuffer, ulDataLen);
m_pInputPin->Receive(outsample);
outsample->Release();
sample->Release();
}
return hr;
//Forward to filter
}
So memcpy would definitely fails because you can't copy something into a buffer that is smaller than the data.
So I tried adjusting the buffersize in DecideBufferSize:
HRESULT MCMyOutputPin::DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProps)
{
myLogger->LogDebug("On DecideBufferSIze", L"D:\\TEMP\\yc.log");
ALLOCATOR_PROPERTIES act;
HRESULT hr;
// by default we do something like this...
pProps->cbAlign = 1;
pProps->cBuffers = 30;
long buffersize = this->CurrentMediaType().lSampleSize * 3;
pProps->cbBuffer = 10 * 10 * 1000;
pProps->cbPrefix = 0;
hr = pAlloc->SetProperties(pProps, &act);
if (FAILED(hr)) return hr;
// make sure the allocator is OK with it.
if ((pProps->cBuffers > act.cBuffers) ||
(pProps->cbBuffer > act.cbBuffer) ||
(pProps->cbAlign > act.cbAlign))
return E_FAIL;
return NOERROR;
}
which gets ignored. The size of the sample returned by the alocator is always 92160.
I also made sure that the DecideBufferSize method gets actually called.
How do I set the size of the Buffer returned by Allocator->GetBuffer()?
MSDN states it pretty accurately:
Typically, the derived class will honor the input pin's buffer requirements, but it is not required to.
Buffer size decision is a matter of negotiation. Your setting requirements does not mean they will be accepted.
The size of the sample returned by the allocator is always 92160.
How do I set the size of the Buffer returned by Allocator->GetBuffer()?
What is wrong exactly with 92160, what makes you think it's invalid? You are looking for an answer to the wrong question. If you own allocator, then you set its buffer size. If you don't own and manage it, then you have to live with the size it already has.
I gave you MSDN link a few question ago, and it explains why increased size buffers are sometimes valid, and even more so - they are inevitable.

I want to copy the data in (wchar_t *)buffer but i am unable to do so bcz there are other incompatible types,typecasting but not getting the result?

I want to print buffer data at one instance avoiding all other wprintf instances but unable to convert data in compatible type with buffer.
Have a look at code:
Kindly tell me how to get through it:
DWORD PrintEvent(EVT_HANDLE hEvent)
{
DWORD status = ERROR_SUCCESS;
PEVT_VARIANT pRenderedValues = NULL;
WCHAR wsGuid[50];
LPWSTR pwsSid = NULL;
//
// Beginning of functional Logic
//
for (;;)
{
if (!EvtRender(hContext, hEvent, EvtRenderEventValues, dwBufferSize, pRenderedValues, &dwBufferUsed, &dwPropertyCount))
{
if (ERROR_INSUFFICIENT_BUFFER == (status = GetLastError()))
{
dwBufferSize = dwBufferUsed;
dwBytesToWrite = dwBufferSize;
pRenderedValues = (PEVT_VARIANT)malloc(dwBufferSize);
if (pRenderedValues)
{
EvtRender(hContext, hEvent, EvtRenderEventValues, dwBufferSize, pRenderedValues, &dwBufferUsed, &dwPropertyCount);
}
else
{
printf("malloc failed\n");
status = ERROR_OUTOFMEMORY;
break;
}
}
}
Buffer = (wchar_t*) malloc (1*wcslen(pRenderedValues[EvtSystemProviderName].StringVal));
//
// Print the values from the System section of the element.
wcscpy(Buffer,pRenderedValues[EvtSystemProviderName].StringVal);
int i = wcslen(Buffer);
if (NULL != pRenderedValues[EvtSystemProviderGuid].GuidVal)
{
StringFromGUID2(*(pRenderedValues[EvtSystemProviderGuid].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wcscpy(Buffer+i,(wchar_t*)pRenderedValues[EvtSystemProviderGuid].GuidVal);
wprintf(L"Provider Guid: %s\n", wsGuid);
}
//Getting "??????" on screen after inclusion of guidval tell me the correct way to copy it??
wprintf(L"Buffer = %ls",Buffer);
//Also tell the way to copy unsigned values into buffer
wprintf(L"EventID: %lu\n", EventID);
wprintf(L"Version: %u\n", pRenderedValues[EvtSystemVersion].ByteVal);
wprintf(L"Level: %u\n", pRenderedValues[EvtSystemLevel].ByteVal);
wprintf(L"EventRecordID: %I64u\n", pRenderedValues[EvtSystemEventRecordId].UInt64Val);
if (EvtVarTypeNull != pRenderedValues[EvtSystemActivityID].Type)
{
StringFromGUID2(*(pRenderedValues[EvtSystemActivityID].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wprintf(L"Correlation ActivityID: %s\n", wsGuid);
}
if (EvtVarTypeNull != pRenderedValues[EvtSystemRelatedActivityID].Type)
{
StringFromGUID2(*(pRenderedValues[EvtSystemRelatedActivityID].GuidVal), wsGuid, sizeof(wsGuid)/sizeof(WCHAR));
wprintf(L"Correlation RelatedActivityID: %s\n", wsGuid);
}
wprintf(L"Execution ProcessID: %lu\n", pRenderedValues[EvtSystemProcessID].UInt32Val);
wprintf(L"Execution ThreadID: %lu\n", pRenderedValues[EvtSystemThreadID].UInt32Val);
wprintf(L"Channel: %s\n",pRenderedValues[EvtSystemChannel].StringVal);
wprintf(L"Computer: %s\n", pRenderedValues[EvtSystemComputer].StringVal);
//
// Final Break Point
//
break;
}
}
The first error is when starting to write to the buffer:
Buffer = (wchar_t*) malloc (1*wcslen(pRenderedValues[EvtSystemProviderName].StringVal));
wcscpy(Buffer,pRenderedValues[EvtSystemProviderName].StringVal);
StringVal points to a wide character string with a trailing null byte, so you should
Buffer = malloc (sizeof(wchar_t)*(wcslen(pRenderedValues[EvtSystemProviderName].StringVal)+1));
or even better
Buffer = wcsdup(pRenderedValues[EvtSystemProviderName].StringVal);
Second error is when appending the GUID.
You are not allocating enough memory, you are just appending to the already full Buffer. And you are appending the raw GUID, not the GUID string. You should replace
int i = wcslen(Buffer);
wcscpy(Buffer+i,(wchar_t*)pRenderedValues[EvtSystemProviderGuid].GuidVal);
with something like
// Attention: memory leak if realloc returns NULL! So better use a second variable for the return code and check that before assigning to Buffer.
Buffer = realloc(Buffer, wcslen(Buffer) + wcslen(wsGuid) + 1);
wcscat(Buffer,wsGuid);
Also:
Besides, you should do better error checking for EvtRender. And you should check dwPropertyCount before accessing pRenderedValues[i].
BTW, wprintf(L"Buffer = %s",Buffer); (with %s instead of %ls) is sufficient with wprintf.
And to your last question: if you want to append unsigned values to a buffer you can use wsprintf to write to a string. If you can do it C++-only then you should consider using std::wstring. This is much easier for you with regard to allocating the buffers the right size.