2025-04-27 07:49:33 -04:00

162 lines
6.6 KiB
C++

#ifndef WMI_XML_NODE_FACT_H
#define WMI_XML_NODE_FACT_H
// This is a class that is used to manufacture XML Elements
// from an CMyPendingStream source of data
// This type of elements manufactured from the source of data
// is configurable. It is specified as a list of element names
// that we are interested in manufacturing. The whole purpose of using
// this Node factory is to prevent reading all the XML data from the input
// source (typically a WinInet Socket) and hence reduce memory consumption.
// This is useful in supporting the case where there is a huge amount of data
// in the source, and we dont want to parse all of it at once, and instead want
// to parse it on demand from the user. This typically occurs when
// there is a huge WMI Instance/Class Enumeration. The result of such an
// enumeration is an IEnumWbemClassObject from which the user "pulls"
// data by calling Next(). This user action is used to manufacture
// XML Nodes from the input source. The InputSource is a CMyPendingStream.
// This implements the IStream functions and adds one more function,
// SetPending() its list of members. Once this function is called, all
// subsequent calls to Read() return E_PENDING until the pending state is reset
// This works in conjunction with the IXMLParser implementation from Microsoft
// as follows:
// 1. The user wraps the data source (typically a WinInet Handle) in a CMyPendingStream
// and gives the CMyPendingStream to both the IXMLParser object and
// to this (IXMLNodeFactory) object.
// 2. The user of the Parser calls Run(-1) on it, upon which the Parser asks for data from
// the CMyPendingStream in chunks (the size of which is decided by a static member in CMyPendingStream
// 3. As it reads the data, the IXMLParser also starts calling into the IXMLNodeFactory. The
// IXMLNodeFactory, as soon as the end of an Element that we're interested in is reached, sets
// the state of the CMyPendingStream to "pending". Hence at this point, the IXMLNodeFactory
// has manufactured 1 object (XML Document) of the element that we're interested int.
// 4. Further calls from the IXMLParser to the CMyPendingStream::Read() return E_PENDING and hence
// the IXMLParser::Run() returns to the caller with E_PENDING.
// 5. When the IXMLParser::Run() returns to the user, he calls IXMLNodeFactory::GetDocument() to get
// the XML Object that was just manufactured.
// 6. The user goes back to step 2. if he needs more objects (XML Documents) from the data source
// It is possible that is the XML Elements being manufactured are extremely small, then a given call to
// IXMLParser::Run() by the client will result in more than one object being manufactured by the factory
// This is the case when the amount of data read at a time from CMyPendingStream is much more than the
// encoding of 1 object. Hence we need the m_ppDocuments to store the extra objects that are manufactured
class MyFactory : public IXMLNodeFactory
{
LONG m_cRef; // COM Ref Count
CMyPendingStream *m_pStream; // The stream of XML data. This can be put into a Pending state
IXMLDOMDocument **m_ppDocuments;// The resulting documents
DWORD m_dwMaxNumDocuments; // # of elements in the above array
DWORD m_dwNumDocuments; // # of documents in the above array - ie., #of elements that have data
DWORD m_dwAvailableDocIndex; // If GetDocument() is called we give out this document
IXMLDOMDocument *m_pCurrentDocument; // Just a holder for the current document being parsed
LPWSTR *m_pszElementNames; // The factory manufactures elements of these names. These are the elemtns that we're "interested" in
DWORD m_dwNumElements; // Number of elements in the above array
// These are the values of the last pragma's if any
LONG m_lClassFlags;
LONG m_lInstanceFlags;
BSTR *m_pstrDeleteList;
BSTR m_strNamespace;
// Adds a document to the list in m_ppDocuments
HRESULT AddDocumentToList(IXMLDOMDocument *pNewDocument);
// Helper functions for manufacttring XML DOM Elements, adding attributes, setting element values etc.
HRESULT AddChildNode(IXMLDOMNode *pNodeParent, XML_NODE_INFO **aNodeInfo, USHORT cNumRecs, IXMLDOMNode **ppCurrentNode);
HRESULT AddPCDATA(IXMLDOMNode *pNodeParent, XML_NODE_INFO **aNodeInfo);
HRESULT AddCDATA(IXMLDOMNode *pNodeParent, XML_NODE_INFO **aNodeInfo);
HRESULT AddAttributes(IXMLDOMElement *pElement, XML_NODE_INFO **aNodeInfo, USHORT cNumRecs);
// Checks to see if the specified element is one of the elements
// that needs to be manufactured from the factory
BOOL IsInterestingElement(LPCWSTR pszElementName);
public:
MyFactory(CMyPendingStream *pStream);
virtual ~MyFactory();
// Sets the names of the elements (tag-names) that we're interested in manufacturing
HRESULT SetElementNames(LPCWSTR *pszElementNames, DWORD dwNumElements);
// Get's the next document manufactured by the factory
HRESULT GetDocument(IXMLDOMDocument **ppDocument);
// Manufactures a document and throws it away
HRESULT SkipNextDocument();
// The following are the IXMLNodeFactory functions
//====================================================
HRESULT STDMETHODCALLTYPE NotifyEvent(
IXMLNodeSource* pSource,
XML_NODEFACTORY_EVENT iEvt)
{
// We dont implement this
return S_OK;
}
HRESULT STDMETHODCALLTYPE BeginChildren(
IXMLNodeSource* pSource,
XML_NODE_INFO* pNodeInfo);
HRESULT STDMETHODCALLTYPE EndChildren(
IXMLNodeSource* pSource,
BOOL fEmpty,
XML_NODE_INFO* pNodeInfo);
HRESULT STDMETHODCALLTYPE Error(
IXMLNodeSource* pSource,
HRESULT hrErrorCode,
USHORT cNumRecs,
XML_NODE_INFO __RPC_FAR **aNodeInfo);
HRESULT STDMETHODCALLTYPE CreateNode(
IXMLNodeSource __RPC_FAR *pSource,
PVOID pNodeParent,
USHORT cNumRecs,
XML_NODE_INFO __RPC_FAR **aNodeInfo);
// IUnknown Functions
//=======================================
STDMETHODIMP QueryInterface (
IN REFIID riid,
OUT LPVOID *ppv
)
{
*ppv=NULL;
if (IID_IUnknown==riid)
*ppv = reinterpret_cast<IUnknown*>(this);
else if (IID_IXMLNodeFactory==riid)
*ppv = (IXMLNodeFactory *)this;
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) AddRef(void)
{
InterlockedIncrement(&m_cRef);
return m_cRef;
}
STDMETHODIMP_(ULONG) Release(void)
{
InterlockedDecrement(&m_cRef);
if (0L!=m_cRef)
return m_cRef;
delete this;
return 0;
}
};
#endif