|
Make sure to call CoInitialize
Creative minds - create creative creations!
|
|
|
|
|
|
hi alex
i think i may have discovered a memory issue relating to releasing the underlying interfaces that you may want to document.
when initializing an implict _com_ptr_t (as happens everywhere) with an interface pointer, _com_ptr_t constructor AddRef 's as you would expect.
The problem occurs when the wrapper functions call Detach internally on those _com_ptr_t because now the interface has an extra AddRef on it and unless I call Release explicitly on the interface it will not get released until the application ends.
ie.
CXmlDocumentWrapper doc;<br />
<br />
:<br />
<br />
CXmlNodeWrapper node(doc.AsNode());<br />
<br />
:
will leave the document interface hanging around. what's needed is an extra Release like this:
CXmlDocumentWrapper doc;<br />
<br />
:<br />
<br />
IXMLDOMNode* pNode = pDoc->AsNode(); <br />
CXmlNodeWrapper node(pNode);<br />
<br />
:<br />
<br />
pNode->Release();
note: i'm working with large xml files (500k+) where the memory increase is very significant. with the changes i've suggested, the 'leak' goes away.
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Yes you aer right!!!
Also i beleave that just removing Detach() from the function will do the trick.
The returned _com_ptr will be cast to pointer thus returning the interface and then destroyed thus releasing the interface.
i.e.
Instead of:
MSXML2::IXMLDOMNode* CXmlDocumentWrapper::AsNode()
{
if (!IsValid())
return NULL;
return m_xmldoc->GetdocumentElement().Detach();
}
change to:
MSXML2::IXMLDOMNode* CXmlDocumentWrapper::AsNode()
{
if (!IsValid())
return NULL;
return m_xmldoc->GetdocumentElement();
}
Creative minds - create creative creations!
|
|
|
|
|
thanks. i'll try your suggestion because keeping such details hidden is vastly preferable to my solution of always having to remember.
however, is there not a risk that when the _com_ptr goes out of scope it will release the interface and COM will blitz it before it can be used.
.dan.g.
AbstractSpoon Software
|
|
|
|
|
The memory leak issue is finaly resolved!
The problem is that several functions in the wrapper returns an interface pointer, when in fact they should return com wrapper i.e. : xxxPtr
The only functions that should return raw pointers are Interface() and Detach()
Until I update the article with the required changes you can solve the problem by replacing ALL
IXMLDOMNode* with IXMLDOMNodePtr except in Inetrface() and Detach() function
same goes for IXMLDOMDocument and IXMLDOMNodeList
Of course there will be some errors on compilation, to resolve the errors:
In the insert function like insert before use: _variant_t(refNode.GetInterfacePtr())
For example:
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertBefore(MSXML2::IXMLDOMNodePtr refNode, LPCTSTR nodeName)<br />
{<br />
MSXML2::IXMLDOMDocumentPtr xmlDocument = m_xmlnode->GetownerDocument();<br />
if (xmlDocument)<br />
{<br />
MSXML2::IXMLDOMNodePtr newNode = xmlDocument->createNode(_variant_t((short)MSXML2::NODE_ELEMENT),nodeName,"");<br />
newNode = m_xmlnode->insertBefore(newNode,_variant_t(refNode.GetInterfacePtr()));<br />
return newNode;<br />
}<br />
return NULL;<br />
}
Creative minds - create creative creations!
|
|
|
|
|
Ok, the only bug to be fixed is your signature.. my version is :
Creative creatures - create creative creations!
Thanks for the wrapper class!
|
|
|
|
|
Hi dear, thanks for this usefull code.
I had memory allocation problem. My application it's a relatime application 24h/7 day active, there a thread thata create an xml statistic file. After some one day or 2 the application has an exception for out of memory. I create a test platform and increase the frequency of creation of statisti and after 1 hour i have the same proble.
I put the code FROM IXMLDOMNode* TO IXMLDOMNodePtr but the proble is the same. I create a big file about 120kbyte.
I put some code for example
m_xmlDoc = new CXmlDocumentWrapper();
m_xmlDoc->Load(_T("Statistic.xml"));
if(m_xmlDoc->IsValid())
{
CXmlNodeWrapper pNode(m_xmlDoc->AsNode(),TRUE);
if(pNode.IsValid())
{
for (int i = 0; i < pNode.NumNodes(); i++)
{
CXmlNodeWrapper node(pNode.GetNode(i),TRUE);
CString tmpVal = node.Name();
if(tmpVal == _T("CONFIGURATION"))
{
CXmlNodeWrapper childNodeConf(node.InsertNode(node.NumNodes(),"SourceName"),TRUE);
childNodeConf.SetText(strFileName);
childNodeConf = (node.InsertNode(node.NumNodes(),"Site"));
childNodeConf.SetText(_T("01"));
.......
.......
}
}
}
thanks
|
|
|
|
|
Dan, gospodin Hazanov's solution worked perfectly for me as it was,
Many, many thanks to him to share with us his xml in native(“unmanaged”) c++ experience
As suggested by your discussion, I modified the XmlNodeWrapper.cpp/.h files.
The project compiles and continues to work perfectly... (?!?) No leaks, nothing
Can you please say us if it changed something :
(To save Chris's server, I compressed a little the texts + Apologizes..)
===================== XmlNodeWrapper.h ===================
#pragma once
#import "MSXML3.dll" named_guids
using namespace MSXML2;
class CXmlNodeWrapper
{
public:
CString NodeType();
CString GetAttribVal(int index);
CString GetAttribName(int index);
int NumAttributes();
void ReplaceNode(MSXML2::IXMLDOMNodePtr pOldNode,MSXML2::IXMLDOMNodePtr pNewNode);
CString GetText();
void SetText(LPCTSTR text);
MSXML2::IXMLDOMNodePtr InsertAfter(MSXML2::IXMLDOMNodePtr refNode, MSXML2::IXMLDOMNodePtr pNode);
CString Name();
MSXML2::IXMLDOMNodeListPtr FindNodes(LPCTSTR searchStr);
MSXML2::IXMLDOMNodePtr Parent();
void RemoveNodes(LPCTSTR searchStr);
MSXML2::IXMLDOMNodePtr InsertAfter(MSXML2::IXMLDOMNodePtr refNode, LPCTSTR nodeName);
MSXML2::IXMLDOMNodePtr InsertBefore(MSXML2::IXMLDOMNodePtr refNode, LPCTSTR nodeName);
MSXML2::IXMLDOMNode* Interface();
MSXML2::IXMLDOMDocumentPtr ParentDocument();
CString GetXML();
MSXML2::IXMLDOMNodePtr RemoveNode(MSXML2::IXMLDOMNodePtr pNode);
MSXML2::IXMLDOMNodePtr InsertNode(int index,LPCTSTR nodeName);
MSXML2::IXMLDOMNodePtr InsertNode(int index,MSXML2::IXMLDOMNodePtr pNode);
long NumNodes();
MSXML2::IXMLDOMNode* Detach();
MSXML2::IXMLDOMNodePtr GetNode(LPCTSTR nodeName);
MSXML2::IXMLDOMNodePtr GetNode(int nodeIndex);
MSXML2::IXMLDOMNodePtr FindNode(LPCTSTR searchString);
MSXML2::IXMLDOMNodePtr GetPrevSibling();
MSXML2::IXMLDOMNodePtr GetNextSibling();
void SetValue(LPCTSTR valueName,LPCTSTR value);
void SetValue(LPCTSTR valueName,int value);
void SetValue(LPCTSTR valueName,short value);
void SetValue(LPCTSTR valueName,double value);
void SetValue(LPCTSTR valueName,float value);
void SetValue(LPCTSTR valueName,bool value);
BOOL IsValid();
CString GetValue(LPCTSTR valueName);
CXmlNodeWrapper();
CXmlNodeWrapper(MSXML2::IXMLDOMNodePtr pNode,BOOL bAutoRelease = TRUE);
void operator=(MSXML2::IXMLDOMNodePtr pNode);
virtual ~CXmlNodeWrapper();
private:
BOOL m_bAutoRelease;
MSXML2::IXMLDOMNodePtr m_xmlnode;
};
class CXmlDocumentWrapper
{
public:
CString GetUrl();
CString GetXML();
BOOL IsValid();
BOOL Load(LPCTSTR path);
BOOL LoadXML(LPCTSTR xml);
BOOL Save(LPCTSTR path = "");
MSXML2::IXMLDOMDocument* Detach();
MSXML2::IXMLDOMDocumentPtr Clone();
CXmlDocumentWrapper();
CXmlDocumentWrapper(MSXML2::IXMLDOMDocumentPtr pDoc);
MSXML2::IXMLDOMNodePtr AsNode();
virtual ~CXmlDocumentWrapper();
private:
MSXML2::IXMLDOMDocumentPtr m_xmldoc;
};
class CXmlNodeListWrapper
{
public:
MSXML2::IXMLDOMDocumentPtr AsDocument();
MSXML2::IXMLDOMNodePtr Node(int index);
void Start();
MSXML2::IXMLDOMNodePtr Next();
BOOL IsValid();
int Count();
CXmlNodeListWrapper();
CXmlNodeListWrapper(MSXML2::IXMLDOMNodeListPtr pList);
void operator=(MSXML2::IXMLDOMNodeListPtr pList);
virtual ~CXmlNodeListWrapper();
private:
MSXML2::IXMLDOMNodeListPtr m_xmlnodelist;
};
===================== XmlNodeWrapper.cpp =================
#include "stdafx.h"
#include "XmlNodeWrapper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXmlNodeWrapper::CXmlNodeWrapper() {}
CXmlNodeWrapper::CXmlNodeWrapper(MSXML2::IXMLDOMNodePtr pNode,BOOL bAutoRelease) {
m_xmlnode = pNode;
m_bAutoRelease = bAutoRelease;
}
void CXmlNodeWrapper::operator=(MSXML2::IXMLDOMNodePtr pNode) {
if (IsValid())
m_xmlnode.Release();
m_xmlnode = pNode;
}
CXmlNodeWrapper::~CXmlNodeWrapper() {
if (!m_bAutoRelease)
m_xmlnode.Detach();
}
CString CXmlNodeWrapper::GetValue(LPCTSTR valueName) {
if (!IsValid())
return "";
MSXML2::IXMLDOMNodePtr attribute = m_xmlnode->Getattributes()->getNamedItem(valueName);
if (attribute) {
return (LPCSTR)attribute->Gettext();
}
return "";
}
BOOL CXmlNodeWrapper::IsValid() {
if (m_xmlnode == NULL)
return FALSE;
if (m_xmlnode.GetInterfacePtr() == NULL)
return FALSE;
return TRUE;
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::GetPrevSibling() {
if (!IsValid())
return NULL;
return m_xmlnode->GetpreviousSibling(); //.Detach();
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::GetNextSibling() {
if (!IsValid())
return NULL;
return m_xmlnode->GetnextSibling(); //.Detach();
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::GetNode(LPCTSTR nodeName) {
if (!IsValid())
return NULL;
try{
return m_xmlnode->selectSingleNode(nodeName); //.Detach();
}
catch (_com_error e) {
CString err = e.ErrorMessage();
}
return NULL;
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::GetNode(int nodeIndex) {
if (!IsValid())
return NULL;
return m_xmlnode->GetchildNodes()->Getitem(nodeIndex); //.Detach();
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::FindNode(LPCTSTR searchString) {
if (!IsValid())
return NULL;
try{
return m_xmlnode->selectSingleNode(searchString); //.Detach();
}
catch (_com_error e) {
CString err = e.ErrorMessage();
}
return NULL;
}
MSXML2::IXMLDOMNode* CXmlNodeWrapper::Detach() {
if (IsValid()) {
return m_xmlnode.Detach();
}
else
return NULL;
}
long CXmlNodeWrapper::NumNodes() {
if (IsValid()) {
return m_xmlnode->GetchildNodes()->Getlength();
}
else
return 0;
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,LPCTSTR value) {
MSXML2::IXMLDOMDocumentPtr xmlDocument = m_xmlnode->GetownerDocument();
if (xmlDocument) {
MSXML2::IXMLDOMNamedNodeMapPtr attributes = m_xmlnode->Getattributes();
if (attributes) {
MSXML2::IXMLDOMAttributePtr attribute = xmlDocument->createAttribute(valueName);
if (attribute) {
attribute->Puttext(value);
attributes->setNamedItem(attribute);
}
}
}
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,int value) {
CString str;
str.Format("%ld",value);
SetValue(valueName,str);
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,short value) {
CString str;
str.Format("%hd",value);
SetValue(valueName,str);
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,double value) {
CString str;
str.Format("%f",value);
SetValue(valueName,str);
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,float value) {
CString str;
str.Format("%f",value);
SetValue(valueName,str);
}
void CXmlNodeWrapper::SetValue(LPCTSTR valueName,bool value) {
CString str;
if (value)
str = "True";
else
str = "False";
SetValue(valueName,str);
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertNode(int index,LPCTSTR nodeName) {
MSXML2::IXMLDOMDocumentPtr xmlDocument = m_xmlnode->GetownerDocument();
if (xmlDocument) {
MSXML2::IXMLDOMNodePtr newNode = xmlDocument->createNode(_variant_t((short)MSXML2::NODE_ELEMENT),nodeName,"");
MSXML2::IXMLDOMNodePtr refNode = GetNode(index);
if (refNode)
// newNode = m_xmlnode->insertBefore(newNode.Detach(),refNode);
newNode = m_xmlnode->insertBefore(newNode,(const _variant_t &)refNode);
else
newNode = m_xmlnode->appendChild(newNode); //.Detach());
return newNode; //.Detach();
}
return NULL;
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertNode(int index,MSXML2::IXMLDOMNodePtr pNode) {
MSXML2::IXMLDOMNodePtr newNode = pNode->cloneNode(VARIANT_TRUE);
if (newNode) {
MSXML2::IXMLDOMNodePtr refNode = GetNode(index);
if (refNode)
newNode = m_xmlnode->insertBefore(newNode,(const _variant_t &)refNode);
else
newNode = m_xmlnode->appendChild(newNode); //.Detach());
return newNode; //.Detach();
}
else
return NULL;
}
CString CXmlNodeWrapper::GetXML() {
if (IsValid())
return (LPCSTR)m_xmlnode->Getxml();
else
return "";
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::RemoveNode(MSXML2::IXMLDOMNodePtr pNode) {
if (!IsValid())
return NULL;
return m_xmlnode->removeChild(pNode); //.Detach();
}
/* ************************************************ (vive CodeProject! ... etc..) */
CXmlDocumentWrapper::CXmlDocumentWrapper() {
m_xmldoc.CreateInstance(MSXML2::CLSID_DOMDocument);
}
CXmlDocumentWrapper::CXmlDocumentWrapper(MSXML2::IXMLDOMDocumentPtr pDoc) {
m_xmldoc = pDoc;
}
CXmlDocumentWrapper::~CXmlDocumentWrapper() {
}
BOOL CXmlDocumentWrapper::IsValid() {
if (m_xmldoc == NULL)
return FALSE;
if (m_xmldoc.GetInterfacePtr() == NULL)
return FALSE;
return TRUE;
}
MSXML2::IXMLDOMDocument* CXmlDocumentWrapper::Detach() {
if (!IsValid())
return NULL;
return m_xmldoc.Detach();
}
MSXML2::IXMLDOMDocumentPtr CXmlDocumentWrapper::Clone() {
if (!IsValid())
return NULL;
MSXML2::IXMLDOMDocumentPtr xmldoc;
xmldoc.CreateInstance(MSXML2::CLSID_DOMDocument);
_variant_t v(xmldoc.GetInterfacePtr());
m_xmldoc->save(v);
return xmldoc; //.Detach();
}
BOOL CXmlDocumentWrapper::Load(LPCTSTR path) {
if (!IsValid())
return FALSE;
_variant_t v(path);
m_xmldoc->put_async(VARIANT_FALSE);
VARIANT_BOOL success = m_xmldoc->load(v);
if (success == VARIANT_TRUE)
return TRUE;
else
return FALSE;
}
BOOL CXmlDocumentWrapper::LoadXML(LPCTSTR xml) {
if (!IsValid())
return FALSE;
VARIANT_BOOL success = m_xmldoc->loadXML(xml);
if (success == VARIANT_TRUE)
return TRUE;
else
return FALSE;
}
BOOL CXmlDocumentWrapper::Save(LPCTSTR path) {
try
{
if (!IsValid())
return FALSE;
CString szPath(path);
if (szPath == "") {
_bstr_t curPath = m_xmldoc->Geturl();
szPath = (LPSTR)curPath;
}
_variant_t v(szPath);
if (FAILED(m_xmldoc->save(v)))
return FALSE;
else
return TRUE;
}
catch(...) {
return FALSE;
}
}
MSXML2::IXMLDOMNodePtr CXmlDocumentWrapper::AsNode() {
if (!IsValid())
return NULL;
// plante ! : return m_xmldoc->GetdocumentElement(); //.Detach(); modif ... sans Detach
return m_xmldoc->GetdocumentElement(); //.Detach();
}
CString CXmlDocumentWrapper::GetXML() {
if (IsValid())
return (LPCSTR)m_xmldoc->Getxml();
else
return "";
}
CString CXmlDocumentWrapper::GetUrl() {
return (LPSTR)m_xmldoc->Geturl();
}
MSXML2::IXMLDOMDocumentPtr CXmlNodeWrapper::ParentDocument() {
return m_xmlnode->GetownerDocument(); //.Detach();
}
MSXML2::IXMLDOMNode* CXmlNodeWrapper::Interface() {
if (IsValid())
return m_xmlnode;
return NULL;
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertBefore(MSXML2::IXMLDOMNodePtr refNode, LPCTSTR nodeName) {
MSXML2::IXMLDOMDocumentPtr xmlDocument = m_xmlnode->GetownerDocument();
if (xmlDocument) {
MSXML2::IXMLDOMNodePtr newNode = xmlDocument->createNode(_variant_t((short)MSXML2::NODE_ELEMENT),nodeName,"");
newNode = m_xmlnode->insertBefore(newNode,_variant_t(refNode.GetInterfacePtr()));
return newNode;
}
return NULL;
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertAfter(MSXML2::IXMLDOMNodePtr refNode, LPCTSTR nodeName) {
MSXML2::IXMLDOMDocumentPtr xmlDocument = m_xmlnode->GetownerDocument();
if (xmlDocument) {
MSXML2::IXMLDOMNodePtr newNode = xmlDocument->createNode(_variant_t((short)MSXML2::NODE_ELEMENT),nodeName,"");
MSXML2::IXMLDOMNodePtr nextNode = refNode->GetnextSibling();
if (nextNode.GetInterfacePtr() != NULL)
newNode = m_xmlnode->insertBefore(newNode,_variant_t(nextNode.GetInterfacePtr()));
else
newNode = m_xmlnode->appendChild(newNode);
return newNode;
}
return NULL;
}
void CXmlNodeWrapper::RemoveNodes(LPCTSTR searchStr) {
if (!IsValid())
return;
MSXML2::IXMLDOMNodeListPtr nodeList = m_xmlnode->selectNodes(searchStr);
for (int i = 0; i < nodeList->Getlength(); i++) {
try
{
MSXML2::IXMLDOMNodePtr pNode = nodeList->Getitem(i); //.Detach();
pNode->GetparentNode()->removeChild(pNode);
}
catch (_com_error er) {
AfxMessageBox(er.ErrorMessage());
}
}
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::Parent() {
if (IsValid())
return m_xmlnode->GetparentNode(); //.Detach();
return NULL;
}
CXmlNodeListWrapper::CXmlNodeListWrapper() {
}
CXmlNodeListWrapper::CXmlNodeListWrapper(MSXML2::IXMLDOMNodeListPtr pList) {
m_xmlnodelist = pList;
}
void CXmlNodeListWrapper::operator=(MSXML2::IXMLDOMNodeListPtr pList) {
if (IsValid())
m_xmlnodelist.Release();
m_xmlnodelist = pList;
}
CXmlNodeListWrapper::~CXmlNodeListWrapper() {
}
int CXmlNodeListWrapper::Count() {
if (IsValid())
return m_xmlnodelist->Getlength();
else
return 0;
}
BOOL CXmlNodeListWrapper::IsValid() {
if (m_xmlnodelist == NULL)
return FALSE;
if (m_xmlnodelist.GetInterfacePtr() == NULL)
return FALSE;
return TRUE;
}
MSXML2::IXMLDOMNodePtr CXmlNodeListWrapper::Next() {
if (IsValid())
return m_xmlnodelist->nextNode(); //.Detach();
else
return NULL;
}
void CXmlNodeListWrapper::Start() {
if (IsValid())
m_xmlnodelist->reset();
}
MSXML2::IXMLDOMNodePtr CXmlNodeListWrapper::Node(int index) {
if (IsValid())
return m_xmlnodelist->Getitem(index); //.Detach();
else
return NULL;
}
MSXML2::IXMLDOMDocumentPtr CXmlNodeListWrapper::AsDocument() {
if (IsValid()) {
CXmlDocumentWrapper doc;
doc.LoadXML("<NodeList></NodeList>");
CXmlNodeWrapper root(doc.AsNode());
for (int i = 0; i < m_xmlnodelist->Getlength(); i++) {
root.InsertNode(root.NumNodes(),m_xmlnodelist->Getitem(i)->cloneNode(VARIANT_TRUE));
}
return doc.Detach();
}
else
return NULL;
}
MSXML2::IXMLDOMNodeListPtr CXmlNodeWrapper::FindNodes(LPCTSTR searchStr) {
if(IsValid()) {
try{
return m_xmlnode->selectNodes(searchStr); //.Detach();
}
catch (_com_error e) {
CString err = e.ErrorMessage();
return NULL;
}
}
else
return NULL;
}
CString CXmlNodeWrapper::Name() {
if (IsValid())
return (LPCSTR)m_xmlnode->GetbaseName();
return "";
}
MSXML2::IXMLDOMNodePtr CXmlNodeWrapper::InsertAfter(MSXML2::IXMLDOMNodePtr refNode, MSXML2::IXMLDOMNodePtr pNode) {
MSXML2::IXMLDOMNodePtr nextNode = refNode->GetnextSibling();
MSXML2::IXMLDOMNodePtr newNode;
if (nextNode.GetInterfacePtr() != NULL)
newNode = m_xmlnode->insertBefore(pNode,_variant_t(nextNode.GetInterfacePtr()));
else
newNode = m_xmlnode->appendChild(pNode);
return newNode;
}
void CXmlNodeWrapper::SetText(LPCTSTR text) {
if (IsValid())
m_xmlnode->Puttext(text);
}
CString CXmlNodeWrapper::GetText() {
if (IsValid())
return (LPCSTR)m_xmlnode->Gettext();
else
return "";
}
void CXmlNodeWrapper::ReplaceNode(MSXML2::IXMLDOMNodePtr pOldNode, MSXML2::IXMLDOMNodePtr pNewNode) {
if (IsValid()) {
m_xmlnode->replaceChild(pNewNode,pOldNode);
}
}
int CXmlNodeWrapper::NumAttributes() {
if (IsValid()) {
MSXML2::IXMLDOMNamedNodeMapPtr attribs = m_xmlnode->Getattributes();
if (attribs)
return attribs->Getlength();
}
return 0;
}
CString CXmlNodeWrapper::GetAttribName(int index) {
if (IsValid()) {
MSXML2::IXMLDOMNamedNodeMapPtr attribs = m_xmlnode->Getattributes();
if (attribs) {
MSXML2::IXMLDOMAttributePtr attrib = attribs->Getitem(index);
if (attrib)
return (LPCSTR)attrib->Getname();
}
}
return "";
}
CString CXmlNodeWrapper::GetAttribVal(int index) {
if (IsValid()) {
MSXML2::IXMLDOMNamedNodeMapPtr attribs = m_xmlnode->Getattributes();
if (attribs) {
MSXML2::IXMLDOMAttributePtr attrib = attribs->Getitem(index);
if (attrib)
return (LPCSTR)attrib->Gettext();
}
}
return "";
}
CString CXmlNodeWrapper::NodeType() {
if (IsValid())
return (LPCSTR)m_xmlnode->GetnodeTypeString();
return "";
}
|
|
|
|
|
both alex's and my solution were essentially the same, although i haven't tried alex's because of a number of other additions that i had already made to his work. as a result i'm unable to say whether what you've posted here is correct or not. my experiance though is that if it works functionally and there are no apparent leaks (or increases in the working memory as reported by TaskMgr.exe) then its probably okay.
i will probably merge alex's fix into my version as soon as my current software is released so that i can ensure that it works as expected before i release it on unsuspecting users.
.dan.g.
AbstractSpoon Software
|
|
|
|
|
hi alex,
can i ask why the destructors of the wrappers do not Release the underlying COM pointers? i would have thought that unless the user explicitly calls Detach or m_bAutoDelete is FALSE then the COM pointers need be cleaned up.
your thoughts?
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Notice the:
if (!m_bAutoRelease)
m_xmlnode.Detach();
in the destructor.
Also notice that m_xmlnode is of type: IXMLDOMNodePtr
IXMLDOMNodePtr is of type _com_ptr_t
All of that means that _com_ptr_t will call "Release" on the underlying pointer unless "Detach" was called before.
so if m_bAutoRelease is FALSE I'm calling "Detach" and the "Release" function is not called, otherwise the Release is called in the destructor of IXMLDOMNodePtr.
Creative minds - create creative creations!
|
|
|
|
|
thanks alex.
btw, my question was related to an apparent memory leak in msxml that i was trying to find alternative causes for. i've googled on 'msxml memory leak' and it seems that many people are also experiencing it. do you know anything about this?
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|
Hi, Alex,
Thanks a lot for your article! ^^
But I got a problem...
I Load File failure when I using my own project.
(of course I've added two files in it already.)
But in the demo sample it's okey!
Could you help me @@~ Did I miss something?
Thank you!
|
|
|
|
|
I found adding a line "CoInitialize(NULL);"
in the ProjectName.cpp
It works!!!
Thanks for Alex!
Thanks for my friend debugging with me!
|
|
|
|
|
You just saved me from going crazy. I couldn't understand why it wasn't working for me.
Thanks a lot!
|
|
|
|
|
Huge resource leak (Memory and Handles) with the following code (Checked with the Task Manager's Process List):
void test()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
while(true)
{
CXmlDocumentWrapper xmlDoc;
xmlDoc.LoadXML("<ContactList>\n<ContactList>");
MSXML2::IXMLDOMNodePtr p(xmlDoc.AsNode());
CXmlNodeWrapper root(p);
for(int i=0; i<10; i++)
{
CXmlDocumentWrapper doc;
doc.LoadXML("<C><SomeObject></SomeObject></C>");
CXmlNodeWrapper node(doc.AsNode());
node.SetValue("NAME", "Lei Lei");
root.InsertNode(i, node.Interface());
}
}
}
It's due to the mixed use of smart pointers and raw pointers. A simple workaround is to find/replace all IXMLDOMNode*, IXMLDOMDocument*, and IXMLDOMNodeList* with IXMLDOMNodePtr, IXMLDOMDocumentPtr, and IXMLDOMNodeListPtr respectively, and then remove all ".Detach()".
Anyone noticed this problem?
|
|
|
|
|
This is NOT the correct way to use the API!
The same code should look like this:
CXmlDocumentWrapper xmlDoc;
xmlDoc.LoadXML("<Root/>");
CXmlNodeWrapper root(xmlDoc.AsNode());
for(int i=0; i<10; i++)
{
CXmlNodeWrapper node(root.InsertNode(-1,"NewNode"));
node.SetValue("NAME","lei lei");
}
xmlDoc.Save("D:\\xml.xml");
This way all the pointers gets released and there is no leak.
<span style="border-style: ridge; border-width: 1; background-color:#6699FF; font-weight:bold">
<font color="#FF3300">Creative minds - create creative creations!</font></span>
|
|
|
|
|
Sorry for my ignorance. I'm a newbie to COM and Smart Pointers.
Could you tell me whether it is harmful if I change the wrapper to use MSXML2::IXMLDOMDocumentPtr and not use MSXML2::IXMLDOMDocument*?
|
|
|
|
|
Actually the wrapper releases the interface on destruction.
So you shouldnt worry about it unless you access the direct pointers by ::Interface()
or ::Detach()
The ::Interface() function returns the pointer while calling AddRef on it, meaning it adds a refence count to the pointer so you should call Release() on that pointer later on to decrement the ref count. Or you could let the wrapper to do the work like that:
CXmlNodeWrapper node2(node1.Inteface());
Then when node2 goes out of scope it will automatically release the interface.
Same goes for Detach() only after Detach() the node becomes invalid and the interface is released completely.
There is no need to change anything in the wrapper itself, but you could use smart pointers to rceive the interface pointer when calling ::Interface() or ::Detach().
So that they'll get automatically released in destructor.
Creative minds - create creative creations!
|
|
|
|
|
<?xml version="1.0" encoding="utf-8" ?>
- <root>
- <input>
<nodeid>0</nodeid>
<parentid>0</parentid>
<userinputkey>9167791963</userinputkey>
</input>
- <output>
- <vrurequestscript>
- <datainput>
<mainmsgid>100</mainmsgid>
<correctvalues>1,2</correctvalues>
<charset>12</charset>
<length>1</length>
<timeout>10000</timeout>
<timeoutmsgid>200</timeoutmsgid>
<retrycount>3</retrycount>
<retryexitaction>end</retryexitaction>
<retryexitmsgid>300</retryexitmsgid>
</datainput>
- <confirminput>
<mainmsgid>101</mainmsgid>
<correctvalues>1,2</correctvalues>
<charset>12</charset>
<accept>1</accept>
<reject>2</reject>
<length>1</length>
<timeout>10000</timeout>
<timeoutmsgid>200</timeoutmsgid>
<retrycount>3</retrycount>
<retryexitaction>end</retryexitaction>
<retryexitmsgid>300</retryexitmsgid>
</confirminput>
</vrurequestscript>
<nodeid>0</nodeid>
<parentid>0</parentid>
</output>
</root>
|
|
|
|
|
The usage:
// Create the XML document
CXmlDocumentWrapper xmlDoc;
// Load the document from file
xmlDoc.Load(szFileName);
// Or from string
xmlDoc.LoadXml(szXml);
// Get the refence to the root node
CXmlNodeWrapper root(xmlDoc.AsNode());
// Get the correct node
CXmlNodeWrapper myInputNode(root.FindNode("input/userinputkey");
// Set the new value
myInputNode.SetText(szUserInput);
// Proccess the node
pADOObject->GetNextPrompt(myInputNode->GetXml(),szXml);
// Load the result xml
xmlDoc.LoadXml(szXml);
// Get the root
root = xmlDoc.AsNode();
// Get the output
CXmlNodeWrapper myOutPutNode(root.FindNode("output/messageid");
CString szValue = myOutPutNode.GetText();
Creative minds - create creative creations!
|
|
|
|
|
Hi Alex,
Thanks for your prompt reply. I was wondering if you could build a small module and show me how to get the value from the xml file and modify it. I tried working with the xml file with the way you had described but I didn't get the value from the node I wanted to, after passing the xml as string.
I appreciate any help in this.
Thank you
-Ray
|
|
|
|
|
Hi,
I am trying to parse my XML file using the XML parser pXMLPArser to accomplish the following tasks-
pXMLParser->ReplaceNodeVale("input\userinputkey", szUserInput);
pADOObject->GetNextPrompt(pXMLParser->Getxml(), szxml();
pXMLParser->Release();
pXMLParser->Loadxml(szxml);
pXMLParser->GetNodeValue("output\messageid", szNodeVale);
Here's how my xml file looks like-
- <root>
-
<nodeid>0
<parentid>0
<userinputkey>9167791963
-
- <vrurequestscript>
- <datainput>
<mainmsgid>100
<correctvalues>1,2
<charset>12
<length>1
<timeout>10000
<timeoutmsgid>200
<retrycount>3
<retryexitaction>end
<retryexitmsgid>300
Can someone show me how to write pXMLParser class. I am trying to use 'XmlNodeWrapper' but am confused since this is my first time dealing with xml parsers. Any help is greatly appreciated.
Thank you
Ray
|
|
|
|
|
alex,
i'm trying to build a fresh document from some data. i've instantiated a CXmlDocumentWrapper but when i call AsNode() on that object i get a NULL pointer returned.
i'm probably doing something daft, but can you help pls.
rgds
.dan.g.
AbstractSpoon Software
|
|
|
|
|