780 lines
21 KiB
C++
780 lines
21 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: E V T O B J . C P P
|
|
//
|
|
// Contents: Implements the Eventing Manager object for the UPnP Device
|
|
// Host
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: danielwe 7 Aug 2000
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.h>
|
|
#pragma hdrstop
|
|
|
|
#include <msxml2.h>
|
|
#include <upnpatl.h>
|
|
#include "hostp.h"
|
|
#include "upnphost.h"
|
|
#include "evtobj.h"
|
|
#include "evtapi.h"
|
|
#include "ncbase.h"
|
|
#include "ncxml.h"
|
|
#include "ComUtility.h"
|
|
#include "uhcommon.h"
|
|
|
|
//
|
|
// IUPnPEventingManager
|
|
//
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::Initialize
|
|
//
|
|
// Purpose: Initializes the Eventing Manager object for a hosted service
|
|
//
|
|
// Arguments:
|
|
// szUdn [in] UDN of the device
|
|
// szSid [in] Service identifier of the service within the device
|
|
// puap [in] Interface pointer to the service's automation proxy
|
|
// punkSvc [in] Interface pointer to the service's object
|
|
//
|
|
// Returns: S_OK if success, E_OUTOFMEMORY, or any other OLE interface
|
|
// error code
|
|
//
|
|
// Author: danielwe 8 Aug 2000
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::Initialize(LPCWSTR szUdn,
|
|
LPCWSTR szSid,
|
|
IUPnPAutomationProxy *puap,
|
|
IUnknown *punkSvc,
|
|
BOOL bRunning)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cch;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
Assert(szUdn);
|
|
Assert(szSid);
|
|
Assert(punkSvc);
|
|
Assert(puap);
|
|
|
|
Assert(!m_szEsid);
|
|
Assert(!m_puap);
|
|
Assert(!m_pues);
|
|
|
|
AddRefObj(m_puap = puap);
|
|
|
|
cch = lstrlen(szUdn) + lstrlen(szSid) + lstrlen(L"+") + 1;
|
|
|
|
m_szEsid = new WCHAR[cch];
|
|
if (!m_szEsid)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
// Make the event source identifier by combining the UDN and SID
|
|
|
|
lstrcpy(m_szEsid, szUdn);
|
|
lstrcat(m_szEsid, L"+");
|
|
lstrcat(m_szEsid, szSid);
|
|
|
|
hr = punkSvc->QueryInterface(IID_IUPnPEventSource, (LPVOID *)&m_pues);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if(bRunning)
|
|
{
|
|
hr = HrCopyProxyIdentity(m_pues, punkSvc);
|
|
}
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Get a reference to ourselves to hand out to the hosted service
|
|
//
|
|
hr = m_pues->Advise(this);
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
m_pues->Release();
|
|
m_pues = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceError("CUPnPEventingManager::Initialize - Object passed in"
|
|
" does not support IUPnPEventSource!", hr);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete [] m_szEsid;
|
|
m_szEsid = NULL;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
TraceError("CUPnPEventingManager::Initialize", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::AddSubscriber
|
|
//
|
|
// Purpose:
|
|
//
|
|
// Arguments:
|
|
// cszUrl [in] Count of callback URLs
|
|
// rgszCallbackUrl [in] List of callback URLs to which NOTIFY
|
|
// requests will be sent
|
|
// dwIpAddr [in] Local IP address that the subscribe came in on
|
|
// pcsecTimeout [in out] On entry, this is the requested timeout from
|
|
// the control point.
|
|
// On exit, this is the timeout the device chose
|
|
// pszSid [out] Returns the SID (subscription identifier) for
|
|
// the new subscription
|
|
//
|
|
// Returns:
|
|
//
|
|
// Author: danielwe 2000/12/28
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::AddSubscriber(DWORD cszUrl,
|
|
LPCWSTR *rgszCallbackUrl,
|
|
DWORD dwIpAddr,
|
|
DWORD *pcsecTimeout,
|
|
LPWSTR *pszSid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR szBody = NULL;
|
|
DWORD cVars;
|
|
LPWSTR * rgszNames;
|
|
LPWSTR * rgszTypes;
|
|
VARIANT * rgvarValues;
|
|
DWORD cDispids;
|
|
DISPID * rgDispids = NULL;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
AssertSz(m_szEsid, "What? Did we not get initialized or something?");
|
|
AssertSz(m_puap, "Automation proxy not initialized?");
|
|
Assert(rgszCallbackUrl);
|
|
Assert(cszUrl);
|
|
Assert(pszSid);
|
|
|
|
|
|
*pszSid = NULL;
|
|
|
|
hr = m_puap->GetDispIdsOfEventedVariables(&cDispids, &rgDispids);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_puap->QueryStateVariablesByDispIds(cDispids, rgDispids, &cVars,
|
|
&rgszNames, &rgvarValues,
|
|
&rgszTypes);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrComposeEventBody(m_puap, cVars, rgszNames, rgszTypes,
|
|
rgvarValues, &szBody);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPWSTR szSid;
|
|
|
|
hr = HrAddSubscriber(m_szEsid, dwIpAddr, cszUrl,
|
|
rgszCallbackUrl, szBody,
|
|
pcsecTimeout, &szSid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*pszSid = (LPWSTR)CoTaskMemAlloc(CbOfSzAndTerm(szSid));
|
|
if (*pszSid)
|
|
{
|
|
lstrcpy(*pszSid, szSid);
|
|
}
|
|
else
|
|
{
|
|
TraceError("CUPnPEventingManager::AddSubscriber - "
|
|
"CoTaskMemAlloc()", hr);
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
delete [] szSid;
|
|
}
|
|
|
|
delete [] szBody;
|
|
}
|
|
|
|
DWORD ivar;
|
|
|
|
for (ivar = 0; ivar < cVars; ivar++)
|
|
{
|
|
CoTaskMemFree(rgszTypes[ivar]);
|
|
CoTaskMemFree(rgszNames[ivar]);
|
|
VariantClear(&rgvarValues[ivar]);
|
|
}
|
|
|
|
CoTaskMemFree(rgszTypes);
|
|
CoTaskMemFree(rgszNames);
|
|
CoTaskMemFree(rgvarValues);
|
|
}
|
|
|
|
CoTaskMemFree(rgDispids);
|
|
}
|
|
|
|
TraceError("CUPnPEventingManager::AddSubscriber", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::RenewSubscriber
|
|
//
|
|
// Purpose: Renews an existing subscriber to a hosted service
|
|
//
|
|
// Arguments:
|
|
// pcsecTimeout [in out] On entry, this is the requested timeout from
|
|
// the control point.
|
|
// On exit, this is the timeout the device chose
|
|
// szSid [in] The SID (subscription identifier) of the
|
|
// subscriber to renew
|
|
//
|
|
// Returns: S_OK if success, E_OUTOFMEMORY, or any other OLE interface
|
|
// error code
|
|
//
|
|
// Author: danielwe 8 Aug 2000
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::RenewSubscriber(DWORD *pcsecTimeout,
|
|
LPWSTR szSid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
AssertSz(m_szEsid, "What? Did we not get initialized or something?");
|
|
Assert(szSid);
|
|
|
|
hr = HrRenewSubscriber(m_szEsid, pcsecTimeout, szSid);
|
|
|
|
TraceError("CUPnPEventingManager::RenewSubscriber", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::RemoveSubscriber
|
|
//
|
|
// Purpose: Removes a subscriber from the list of subscribers to a hosted
|
|
// service
|
|
//
|
|
// Arguments:
|
|
// szSid [in] The SID (subscription identifier) of the
|
|
// subscriber to renew
|
|
//
|
|
// Returns: S_OK if success, E_OUTOFMEMORY, or any other OLE interface
|
|
// error code
|
|
//
|
|
// Author: danielwe 8 Aug 2000
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::RemoveSubscriber(LPWSTR szSid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
AssertSz(m_szEsid, "What? Did we not get initialized or something?");
|
|
Assert(szSid);
|
|
|
|
hr = HrRemoveSubscriber(m_szEsid, szSid);
|
|
|
|
TraceError("CUPnPEventingManager::RemoveSubscriber", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// IUPnPEventSink
|
|
//
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::OnStateChanged
|
|
//
|
|
// Purpose: Notifies the eventing manager that the state of a service on
|
|
// a hosted device has changed
|
|
//
|
|
// Arguments:
|
|
// cChanges [in] Number of state variables that have changed
|
|
// rgdispidChanges [in] Array of DISPIDs for those state variables
|
|
//
|
|
// Returns: S_OK if success, E_OUTOFMEMORY, or any other OLE interface
|
|
// error code otherwise.
|
|
//
|
|
// Author: danielwe 2000/09/21
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::OnStateChanged(DWORD cChanges,
|
|
DISPID rgdispidChanges[])
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPWSTR szBody = NULL;
|
|
DWORD cVars;
|
|
LPWSTR * rgszNames;
|
|
LPWSTR * rgszTypes;
|
|
VARIANT * rgvarValues;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
AssertSz(m_szEsid, "What? Did we not get initialized or something?");
|
|
AssertSz(m_puap, "Automation proxy not initialized?");
|
|
|
|
|
|
if (!m_pues)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else if (!cChanges || !rgdispidChanges)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
|
|
TraceError("OnStateChanged() called, but nothing to do.", hr);
|
|
}
|
|
else
|
|
{
|
|
hr = m_puap->QueryStateVariablesByDispIds(cChanges, rgdispidChanges,
|
|
&cVars, &rgszNames,
|
|
&rgvarValues, &rgszTypes);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrComposeEventBody(m_puap, cVars, rgszNames, rgszTypes,
|
|
rgvarValues, &szBody);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrSubmitEvent(m_szEsid, szBody);
|
|
|
|
delete [] szBody;
|
|
}
|
|
|
|
DWORD ivar;
|
|
|
|
for (ivar = 0; ivar < cVars; ivar++)
|
|
{
|
|
CoTaskMemFree(rgszTypes[ivar]);
|
|
CoTaskMemFree(rgszNames[ivar]);
|
|
VariantClear(&rgvarValues[ivar]);
|
|
}
|
|
|
|
CoTaskMemFree(rgvarValues);
|
|
CoTaskMemFree(rgszTypes);
|
|
CoTaskMemFree(rgszNames);
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
TraceError("CUPnPEventingManager::OnStateChanged", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::OnStateChangedSafe
|
|
//
|
|
// Purpose: Same as OnStateChanged, except this is for VB users that need
|
|
// to pass the array of DISPIDs in a SafeArray.
|
|
//
|
|
// Arguments:
|
|
// psa [in] SafeArray of DISPIDs that have changed
|
|
//
|
|
// Returns: Same as OnStateChanged
|
|
//
|
|
// Author: danielwe 2000/09/21
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::OnStateChangedSafe(VARIANT varsadispidChanges)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DISPID HUGEP * rgdispids;
|
|
SAFEARRAY * psa;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
psa = V_ARRAY(&varsadispidChanges);
|
|
|
|
if (psa)
|
|
{
|
|
// Get a pointer to the elements of the array.
|
|
hr = SafeArrayAccessData(psa, (void HUGEP**)&rgdispids);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = OnStateChanged(psa->rgsabound[0].cElements, rgdispids);
|
|
SafeArrayUnaccessData(psa);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
TraceError("CUPnPEventingManager::OnStateChangedSafe", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::Shutdown
|
|
//
|
|
// Purpose: Tells the eventing manager object to go away
|
|
//
|
|
// Arguments:
|
|
// (none)
|
|
//
|
|
// Returns: E_UNEXPECTED if the object was never initialized.
|
|
//
|
|
// Author: danielwe 2000/09/21
|
|
//
|
|
// Notes:
|
|
//
|
|
STDMETHODIMP CUPnPEventingManager::Shutdown()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = HrIsAllowedCOMCallLocality(CALL_LOCALITY_INPROC);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (!m_pues)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
hr = m_pues->Unadvise(this);
|
|
|
|
ReleaseObj(m_pues);
|
|
|
|
m_pues = NULL;
|
|
}
|
|
|
|
Cleanup:
|
|
TraceError("CUPnPEventingManager::Shutdown", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// ATL Methods
|
|
//
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CUPnPEventingManager::FinalRelease
|
|
//
|
|
// Purpose: Called when the Eventing Manager object is released for the
|
|
// last time
|
|
//
|
|
// Arguments:
|
|
// (none)
|
|
//
|
|
// Returns: Not much.
|
|
//
|
|
// Author: danielwe 8 Aug 2000
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT CUPnPEventingManager::FinalRelease()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
delete [] m_szEsid;
|
|
|
|
ReleaseObj(m_puap);
|
|
|
|
TraceError("CUPnPEventingManager::FinalRelease", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Private functions
|
|
//
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrCreateElement
|
|
//
|
|
// Purpose: Creates an element in the specified DOM Document
|
|
//
|
|
// Arguments:
|
|
// pxdd [in] DOM Document to create element in
|
|
// szName [in] Element name
|
|
// ppxdnElement [out] Returns the newly created element
|
|
//
|
|
// Returns: S_OK if successful, E_OUTOFMEMORY, or OLE error code
|
|
//
|
|
// Author: danielwe 16 Aug 2000
|
|
//
|
|
// Notes: The element is NOT automatically inserted into the document
|
|
//
|
|
HRESULT HrCreateElement(IXMLDOMDocument *pxdd, LPCWSTR szName,
|
|
IXMLDOMNode **ppxdnElement)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrElementName;
|
|
|
|
Assert(pxdd);
|
|
Assert(ppxdnElement);
|
|
|
|
*ppxdnElement = NULL;
|
|
|
|
bstrElementName = SysAllocString(szName);
|
|
if (bstrElementName)
|
|
{
|
|
IXMLDOMNode * pxdn;
|
|
BSTR bstrNamespaceURI;
|
|
|
|
bstrNamespaceURI = SysAllocString(L"urn:schemas-upnp-org:event-1-0");
|
|
if (bstrNamespaceURI)
|
|
{
|
|
VARIANT varNodeType;
|
|
|
|
VariantInit(&varNodeType);
|
|
varNodeType.vt = VT_I4;
|
|
V_I4(&varNodeType) = (int) NODE_ELEMENT;
|
|
|
|
hr = pxdd->createNode(varNodeType, bstrElementName,
|
|
bstrNamespaceURI, &pxdn);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppxdnElement = pxdn;
|
|
}
|
|
else
|
|
{
|
|
ReleaseObj(pxdn);
|
|
}
|
|
|
|
SysFreeString(bstrNamespaceURI);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
SysFreeString(bstrElementName);
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
TraceError("HrAddRootElement", hr);
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrComposeEventBody
|
|
//
|
|
// Purpose: Composes the event notification body given a list of names,
|
|
// values, and data types
|
|
//
|
|
// Arguments:
|
|
// cVars [in] Number of state variables to work with
|
|
// rgszNames [in] List of variable names
|
|
// rgszTypes [in] List of variable types
|
|
// rgvarValues [in] List of variable values
|
|
// pszBody [out] Returns newly created XML body as a string
|
|
//
|
|
// Returns: S_OK if successful, E_OUTOFMEMORY, or OLE error code
|
|
//
|
|
// Author: danielwe 16 Aug 2000
|
|
//
|
|
// Notes: pszBody must be freed by the caller with delete []
|
|
//
|
|
HRESULT HrComposeEventBody(IUPnPAutomationProxy* puap, DWORD cVars, LPWSTR *rgszNames,
|
|
LPWSTR *rgszTypes, VARIANT *rgvarValues, LPWSTR *pszBody)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IXMLDOMDocument * pxdd;
|
|
|
|
Assert(pszBody);
|
|
Assert(cVars);
|
|
|
|
*pszBody = NULL;
|
|
|
|
// Create a new XML DOM Document
|
|
//
|
|
|
|
hr = CoCreateInstance(CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IXMLDOMDocument, (LPVOID *) &pxdd);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IXMLDOMNode * pxdnRoot;
|
|
|
|
hr = HrAppendProcessingInstruction(pxdd, L"xml", L"version=\"1.0\"");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrCreateElement(pxdd, L"e:propertyset", &pxdnRoot);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IXMLDOMElement* pxde;
|
|
hr = pxdnRoot->QueryInterface(IID_IXMLDOMElement, (void**)&pxde);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
Assert(puap);
|
|
LPWSTR szServiceType = NULL;
|
|
hr = puap->GetServiceType(&szServiceType);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HrSetTextAttribute(pxde, L"xmlns:s", szServiceType);
|
|
CoTaskMemFree(szServiceType);
|
|
}
|
|
pxde->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD iVar;
|
|
|
|
// Loop thru each passed in variable and create a typed element
|
|
// for each, adding to a new container element for "property" as
|
|
// described in the UPnP architecture 1.0.
|
|
|
|
for (iVar = 0;
|
|
iVar < cVars && SUCCEEDED(hr);
|
|
iVar++)
|
|
{
|
|
IXMLDOMNode * pxdnProp;
|
|
|
|
hr = HrCreateElement(pxdd, L"e:property", &pxdnProp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IXMLDOMElement * pxdeVar;
|
|
|
|
LPWSTR szPrefixedName = new WCHAR[lstrlenW(rgszNames[iVar]) + 3];
|
|
if (szPrefixedName)
|
|
{
|
|
lstrcpyW(szPrefixedName, L"s:");
|
|
lstrcatW(szPrefixedName, rgszNames[iVar]);
|
|
|
|
hr = HrCreateElementWithType(pxdd, szPrefixedName,
|
|
(LPCWSTR)rgszTypes[iVar],
|
|
rgvarValues[iVar], &pxdeVar);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Add both the container "<e:property>" and the
|
|
// variable "<e:[varName]>" to the root
|
|
//
|
|
|
|
hr = pxdnRoot->appendChild(pxdnProp, NULL);
|
|
hr = pxdnProp->appendChild(pxdeVar, NULL);
|
|
|
|
ReleaseObj(pxdeVar);
|
|
}
|
|
|
|
ReleaseObj(pxdnProp);
|
|
delete [] szPrefixedName;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Add the root element to the DOM itself
|
|
hr = pxdd->appendChild(pxdnRoot, NULL);
|
|
}
|
|
|
|
// If all went well, ask the document to give us the XML as a string
|
|
//
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR bstrBody;
|
|
|
|
hr = pxdd->get_xml(&bstrBody);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD cch = SysStringLen(bstrBody) + 1;
|
|
LPWSTR szBody;
|
|
|
|
szBody = new WCHAR[cch];
|
|
if (szBody)
|
|
{
|
|
lstrcpy(szBody, bstrBody);
|
|
|
|
TraceTag(ttidDefault, "Body is %S", szBody);
|
|
|
|
*pszBody = szBody;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
SysFreeString(bstrBody);
|
|
}
|
|
}
|
|
|
|
ReleaseObj(pxdnRoot);
|
|
}
|
|
|
|
ReleaseObj(pxdd);
|
|
}
|
|
|
|
TraceError("HrComposeEventBody", hr);
|
|
return hr;
|
|
}
|