Re: Problem with writing XML DOM tree to memory buffer.
Stuart Redmann wrote:
> Hello newsgroup,
>
> I tried to write a small test application that creates an XML DOM tree
> and writes the contents
> into a string buffer (saving to file works perfectly). Unfortunately, I
> seem to go wrong
> at some point (the text displayed contains only question marks :(
>
> Can anybody give me some suggestions?
[snipped erroneous code snippet]
In addition to Igor's reply, you don't need to call
`Detach()' om `CComBSTR' object; it will leak BSTR.
Ok.
`CComBSTR' class already has `operator BSTR'. Also, calling
`GlobalLock' is not enough. You should also call
`GlobalSize' in order to determine actual size of written
data. Stream doesn't append terminating NUL automatically.
Thanks.
Here's working example (made with VC2005, though it should
be easily adaptable to VC6):
<code>
#include <comutil.h>
#include <comdef.h>
#include <atlstr.h>
_COM_SMARTPTR_TYPEDEF(IUnknown, __uuidof(IUnknown));
_COM_SMARTPTR_TYPEDEF(IDispatch, __uuidof(IDispatch));
#import <msxml4.dll>
_COM_SMARTPTR_TYPEDEF(IStream, __uuidof(IStream));
using namespace MSXML2;
int _tmain(int /*argc*/, _TCHAR* /*argv*/[])
{
::CoInitialize(NULL);
try
{
// Create the document and fill it with
// some example data.
IXMLDOMDocument2Ptr spDocument(
__uuidof(DOMDocument40));
IXMLDOMElementPtr spCurrentNode =
spDocument->createElement(L"ExposureTime");
spCurrentNode->setAttribute(L"value", 3.14159);
spDocument->appendChild(spCurrentNode);
// Let the document persist into a memory stream.
IStreamPtr spStream;
HRESULT hr = ::CreateStreamOnHGlobal(
NULL, TRUE, &spStream);
if(FAILED(hr)) _com_issue_error(hr);
_variant_t vtStream(spStream.GetInterfacePtr());
hr = spDocument->save(vtStream);
I should have seen this one (tracing into the save call should have done the trick).
The big question is what IXMLDOMDocument is doing with the Boolean value I have
passed (I would have expected that the save method had fired an E_INVALIDARG).
if(FAILED(hr)) _com_issue_error(hr);
HGLOBAL hMem = NULL;
hr = ::GetHGlobalFromStream(spStream, &hMem);
if(FAILED(hr)) _com_issue_error(hr);
LPVOID lp = ::GlobalLock(hMem);
CStringA strXmlText((LPCSTR)lp, ::GlobalSize(hMem));
::MessageBoxA(NULL, strXmlText, "XML Text",
MB_OK | MB_ICONINFORMATION);
}
catch(const _com_error& e)
{
::MessageBox(NULL, e.ErrorMessage(), _T("Error"),
MB_OK | MB_ICONERROR);
}
::CoUninitialize();
return 0;
}
</code>
Thank you very much (the same for Igor).
Stuart