Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2623 lines
78 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 2000.
//
// File: D E S C R I P T I O N M A N A G E R . C P P
//
// Contents: Process UPnP Description document
//
// Notes:
//
// Author: mbend 18 Aug 2000
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <msxml2.h>
#include "uhbase.h"
#include "hostp.h"
#include "DescriptionManager.h"
#include "uhsync.h"
#include "upfile.h"
#include "ncreg.h"
#include "ssdpapi.h"
#include "evtapi.h"
#include "uhutil.h"
#include "udhhttp.h" // remove this if you are moving the function for presentation virtual directory.
#include "ncxml.h"
#include "ssdpapi.h"
#include "uhcommon.h"
// String constants
const wchar_t c_szDescription[] = L"Description";
const wchar_t c_szUDNMappings[] = L"UDN Mappings";
const wchar_t c_szFiles[] = L"Files";
const wchar_t c_szFilename[] = L"Filename";
const wchar_t c_szMimetype[] = L"Mimetype";
const wchar_t c_szDescriptionDocuments[] = L"Description Documents";
const wchar_t c_szRemoveId[] = L"REMOVE";
CDescriptionManager::CDescriptionManager ()
{
}
CDescriptionManager::~CDescriptionManager ()
{
// Free description documents
BSTR bstr = NULL;
long n;
long nCount = m_documentTable.Values().GetCount();
for(n = 0; n < nCount; ++n)
{
bstr = const_cast<BSTR>(m_documentTable.Values()[n]);
SysFreeString(bstr);
}
m_documentTable.Clear();
// Unpublish and free the arrays for all publications
HandleList * pHandleList = NULL;
nCount = m_ssdpRegistrationTable.Values().GetCount();
for(n = 0; n < nCount; ++n)
{
pHandleList = const_cast<HandleList*>(m_ssdpRegistrationTable.Values()[n]);
if(pHandleList)
{
long nHandleLists = pHandleList->GetCount();
for(long n = 0; n < nHandleLists; ++n)
{
DeregisterService((*pHandleList)[n], TRUE);
}
delete pHandleList;
}
}
m_ssdpRegistrationTable.Clear();
}
STDMETHODIMP CDescriptionManager::GetContent(
/*[in]*/ REFGUID guidContent,
/*[out]*/ long * pnHeaderCount,
/*[out, string, size_is(,*pnHeaderCount,)]*/ wchar_t *** parszHeaders,
/*[out]*/ long * pnBytes,
/*[out, size_is(,*pnBytes)]*/ byte ** parBytes)
{
CALock lock(*this);
HRESULT hr = S_OK;
wchar_t ** arszHeaders = NULL;
long nHeaderCount = 2;
long nBytes = 0;
byte * arBytes = NULL;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
// Allocate the header array
hr = HrCoTaskMemAllocArray(2, &arszHeaders);
}
// Other header variables, filled in body and copied to [out]
// or cleaned up up at end of function
if(SUCCEEDED(hr))
{
// Set header initially to NULL;
arszHeaders[0] = NULL;
arszHeaders[1] = NULL;
// See if it is a description document
BSTR * pbstr = m_documentTable.Lookup(guidContent);
if(pbstr)
{
// This GUID is a description document
// Allocate the content-type
hr = HrCoTaskMemAllocString(L"content-type: text/xml", arszHeaders);
if(SUCCEEDED(hr))
{
// Copy the document as ansi
// nLength is the number of (wide)chars in the source
// dSpace is the space reserved for the UTF-8 destination
long nLength = SysStringLen(*pbstr);
int dSpace = WideCharToMultiByte(CP_UTF8, 0, *pbstr, nLength, NULL, 0, NULL, NULL) + 1; // add 1 for NULL
char * szBody = NULL;
hr = HrCoTaskMemAllocArray(dSpace, &szBody);
if(SUCCEEDED(hr))
{
if(!WideCharToMultiByte(CP_UTF8, 0, *pbstr, nLength, szBody, dSpace, NULL, NULL))
{
hr = HrFromLastWin32Error();
}
if(SUCCEEDED(hr))
{
arBytes = reinterpret_cast<byte*>(szBody);
nBytes = dSpace-1; // number of bytes less the terminating nul
arBytes[nBytes] = 0; // add NULL terminator
}
if(FAILED(hr))
{
CoTaskMemFree(szBody);
szBody = NULL;
}
}
}
}
else
{
// See if it is in the file table
FileInfo * pFileInfo = m_fileTable.Lookup(guidContent);
if(pFileInfo)
{
// Allocate the content type
CUString strContentType;
hr = strContentType.HrAssign(L"content-type:");
if(SUCCEEDED(hr))
{
hr = strContentType.HrAppend(pFileInfo->m_mimetype);
if(SUCCEEDED(hr))
{
hr = strContentType.HrGetCOM(arszHeaders);
if(SUCCEEDED(hr))
{
// Load the file from disk
hr = HrLoadFileFromDisk(pFileInfo->m_filename, &nBytes, &arBytes);
}
}
}
}
else
{
// This provider didn't process it
hr = S_FALSE;
}
}
if(S_OK == hr)
{
wchar_t szBuf[128];
wsprintf(szBuf, L"content-length: %d", nBytes);
hr = HrCoTaskMemAllocString(szBuf, &arszHeaders[1]);
}
if(FAILED(hr) || S_FALSE == hr)
{
// Centralized cleanup code
if(arszHeaders)
{
if(*arszHeaders)
{
// Free header (at most one)
CoTaskMemFree(*arszHeaders);
}
if(arszHeaders[1])
{
CoTaskMemFree(arszHeaders[1]);
}
// Free length one header array
CoTaskMemFree(arszHeaders);
}
if(arBytes)
{
// Free body bytes
CoTaskMemFree(arBytes);
}
// Blank out the output params
*pnHeaderCount = 0;
*parszHeaders = NULL;
*pnBytes = 0;
*parBytes = NULL;
}
}
if(S_OK == hr)
{
// Copy to output parameters
*pnHeaderCount = nHeaderCount;
*parszHeaders = arszHeaders;
*pnBytes = nBytes;
*parBytes = arBytes;
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::GetContent");
return hr;
}
HRESULT HrNewUDNString(CUString & strUUID)
{
UUID uuid;
HRESULT hr = S_OK;
hr = CoCreateGuid(&uuid);
if(SUCCEEDED(hr))
{
hr = HrGUIDToUDNString(uuid, strUUID);
}
TraceHr(ttidError, FAL, hr, FALSE, "HrNewUDNString");
return hr;
}
HRESULT HrGetURLBase(CUString & strURLBase)
{
HRESULT hr = S_OK;
hr = strURLBase.HrAssign(L"http://");
if(SUCCEEDED(hr))
{
hr = strURLBase.HrAppend(c_szReplaceGuid);
if(SUCCEEDED(hr))
{
hr = strURLBase.HrAppend(L":2869/upnphost/");
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGetURLBase");
return hr;
}
HRESULT HrGetContentURL(const UUID & uuid, CUString & strURL)
{
HRESULT hr = S_OK;
hr = strURL.HrAssign(L"udhisapi.dll?content=");
if(SUCCEEDED(hr))
{
CUString strUUID;
hr = HrGUIDToUDNString(uuid, strUUID);
if(SUCCEEDED(hr))
{
hr = strURL.HrAppend(strUUID);
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGetContentURL");
return hr;
}
// Create Virual directory using the Physical Device Identifier and map it to the resource path
HRESULT HrCreatePresentationVirtualDir(const UUID &uuid, const LPWSTR szResourcePath)
{
HRESULT hr = S_OK;
CUString strUUID;
BSTR bstrVirDir;
hr = HrGUIDToUDNString(uuid, strUUID);
if(SUCCEEDED(hr))
{
CUString strTmp;
hr = strTmp.HrAssign(L"/");
if (SUCCEEDED(hr))
{
hr = strTmp.HrAppend(strUUID);
if (SUCCEEDED(hr))
{
hr = strTmp.HrGetBSTR(&bstrVirDir);
if(SUCCEEDED(hr))
{
HrRemoveVroot(bstrVirDir);
hr = HrAddVroot(bstrVirDir,szResourcePath);
SysFreeString(bstrVirDir);
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrCreatePresentationVirtualDir");
return hr;
}
// Remove the virtual directory
HRESULT HrRemovePresentationVirtualDir(const UUID &uuid )
{
HRESULT hr = S_OK;
CUString strUUID;
BSTR bstrVirDir ;
CUString strTmp;
hr = strTmp.HrAssign(L"/");
if(SUCCEEDED(hr))
{
hr = HrGUIDToUDNString(uuid, strUUID);
if(SUCCEEDED(hr))
{
hr = strTmp.HrAppend(strUUID);
}
}
if(SUCCEEDED(hr))
{
hr = strTmp.HrGetBSTR(&bstrVirDir);
if(SUCCEEDED(hr))
{
hr = HrRemoveVroot(bstrVirDir);
SysFreeString(bstrVirDir);
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrRemovePresentationVirtualDir");
return hr;
}
// prepare base URL for the presentation URL
HRESULT HrGetPresentationBaseURL(const UUID &uuid, CUString &strPresentationBaseURL)
{
HRESULT hr = S_OK;
if(SUCCEEDED(hr))
{
CUString strUUID;
hr = strPresentationBaseURL.HrAppend(L"/");
if (SUCCEEDED(hr))
{
hr = HrGUIDToUDNString(uuid, strUUID);
if(SUCCEEDED(hr))
{
hr = strPresentationBaseURL.HrAppend(strUUID);
if(SUCCEEDED(hr))
{
hr = strPresentationBaseURL.HrAppend(L"/");
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGetPresentationBaseURL");
return hr;
}
HRESULT HrGenerateControlAndEventURLs(
IXMLDOMNodePtr & pNodeDevice)
{
HRESULT hr = S_OK;
CUString strControlURLBase;
CUString strEventURLBase;
CUString strUDN;
hr = strControlURLBase.HrAssign(L"udhisapi.dll?control=");
if(SUCCEEDED(hr))
{
hr = strEventURLBase.HrAssign(L"udhisapi.dll?event=");
}
if(SUCCEEDED(hr))
{
// Fetch the UDN
hr = HrSelectNodeText(L"UDN", pNodeDevice, strUDN);
}
// Get all of the services
IXMLDOMNodeListPtr pNodeListServices;
if(SUCCEEDED(hr))
{
hr = HrSelectNodes(L"serviceList/service", pNodeDevice, pNodeListServices);
if(SUCCEEDED(hr))
{
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNodeService;
// Process each service
HRESULT hrTmp = S_OK;
hrTmp = pNodeListServices->nextNode(pNodeService.AddressOf());
if(S_OK != hrTmp)
{
break;
}
CUString strSid;
hr = HrSelectNodeText(L"serviceId", pNodeService, strSid);
if(SUCCEEDED(hr))
{
// Generate the URL suffix
CUString strURL;
hr = strURL.HrAssign(strUDN);
if(SUCCEEDED(hr))
{
hr = strURL.HrAppend(L"+");
if(SUCCEEDED(hr))
{
hr = strURL.HrAppend(strSid);
}
}
CUString strControlURL;
CUString strEventURL;
// Build the real URLs
if(SUCCEEDED(hr))
{
hr = strControlURL.HrAssign(strControlURLBase);
if(SUCCEEDED(hr))
{
hr = strControlURL.HrAppend(strURL);
if(SUCCEEDED(hr))
{
hr = strEventURL.HrAssign(strEventURLBase);
if(SUCCEEDED(hr))
{
hr = strEventURL.HrAppend(strURL);
}
}
}
}
// Now replace them in the document
if(SUCCEEDED(hr))
{
CUString strNode;
hr = strNode.HrAssign(L"/upnphost/");
if (SUCCEEDED(hr))
{
hr = strNode.HrAppend(strControlURL);
if (SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"controlURL",
pNodeService,
strNode);
}
}
}
CUString strOldText;
hr = HrSelectNodeText(L"eventSubURL", pNodeService,
strOldText);
if (SUCCEEDED(hr))
{
CUString strNode;
// Only replace the URL if it doesn't have the remove
// identifier in it. Otherwise, remove the identifier
//
if (lstrcmpi(strOldText, c_szRemoveId))
{
hr = strNode.HrAssign(L"/upnphost/");
if (SUCCEEDED(hr))
{
hr = strNode.HrAppend(strEventURL);
if (SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"eventSubURL",
pNodeService,
strNode);
}
}
}
else
{
CUString strEmpty;
hr = strEmpty.HrAssign(L"");
if (SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"eventSubURL",
pNodeService, strEmpty);
}
}
}
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGenerateControlAndEventURLs");
return hr;
}
HRESULT HrGenDescAndUDNURLForPresentation(
REFGUID guidPhysicalDeviceIdentifier,
IXMLDOMNodePtr & pNodeDevice,
CUString & strDescAndUDNURL)
{
HRESULT hr = S_OK ;
CUString strDesc ;
CUString strUDN ;
hr = HrGetContentURL(guidPhysicalDeviceIdentifier, strDesc);
if(SUCCEEDED(hr))
{
hr = strDescAndUDNURL.HrAssign(L"/upnphost/");
if(SUCCEEDED(hr))
{
hr = strDescAndUDNURL.HrAppend(strDesc);
}
}
if(SUCCEEDED(hr))
{
hr = strDescAndUDNURL.HrAppend(L"+");
if(SUCCEEDED(hr))
{
hr = HrSelectNodeText(L"UDN", pNodeDevice, strUDN);
if(SUCCEEDED(hr))
{
hr = strDescAndUDNURL.HrAppend(strUDN);
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGenDescAndUDNURLForPresentation");
return hr;
}
BOOL IsAbsoluteURL(BSTR bstrPresURL)
{
HRESULT hr = S_OK;
const WCHAR c_szhttp[] = L"http://";
const DWORD c_chhttp = celems(c_szhttp)-1;
// include other conditions for absolute URL like https:// etc.
if(wcsncmp(bstrPresURL,c_szhttp,c_chhttp) == 0 )
return true;
else
return false;
}
HRESULT HrGenPresentationURL(
REFGUID guidPhysicalDeviceIdentifier,
IXMLDOMNodePtr & pNodeDevice,
CUString & strPresFileName,
CUString & strPresentationURL)
{
HRESULT hr = S_OK;
CUString strDescURL ;
hr = HrGetPresentationBaseURL(guidPhysicalDeviceIdentifier,strPresentationURL);
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(strPresFileName);
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(L"?");
if(SUCCEEDED(hr))
{
hr = HrGenDescAndUDNURLForPresentation(guidPhysicalDeviceIdentifier,pNodeDevice,strDescURL);
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(strDescURL);
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGenPresentationURL");
return hr;
}
// Replaces the presentation URL for a device. If presentationURL element has absolute address no change is made.
// File name to the main presentation page is expected, can be without presentation page
HRESULT HrReplacePresentationURL(
REFGUID guidPhysicalDeviceIdentifier,
IXMLDOMNodePtr & pNodeDevice,
BOOL *fIsPresURLTagPresent)
{
HRESULT hr = S_OK;
CUString strPresentationURL;
CUString strPresFileName ;
CUString strUDN;
CUString strUrl;
CUString strDescAndUDNURL;
BSTR bstrPresURL = NULL;
WCHAR chQueryChar = '?' ;
hr = HrSelectNodeText(L"presentationURL", pNodeDevice, strPresFileName);
if(SUCCEEDED(hr))
{
hr = strPresFileName.HrGetBSTR(&bstrPresURL);
if(SUCCEEDED(hr))
{
if(bstrPresURL != NULL && (wcscmp(bstrPresURL,L"") != 0 ) ) { // check if its absolute URL !!!
//if(wcsncmp(bstrPresURL,c_szhttp,c_chhttp) == 0 ) {
if(IsAbsoluteURL(bstrPresURL)) {
if (wcschr(bstrPresURL,chQueryChar) ) {
hr = S_OK;
}
else {
hr = HrGenDescAndUDNURLForPresentation(guidPhysicalDeviceIdentifier,pNodeDevice,strDescAndUDNURL);
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(strPresFileName);
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(L"?");
if(SUCCEEDED(hr))
{
hr = strPresentationURL.HrAppend(strDescAndUDNURL);
if(SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"presentationURL", pNodeDevice, strPresentationURL);
}
}
}
}
}
}
else {
*fIsPresURLTagPresent = true ;
hr = HrGenPresentationURL(guidPhysicalDeviceIdentifier,pNodeDevice,strPresFileName,strPresentationURL);
if(SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"presentationURL", pNodeDevice, strPresentationURL);
}
}
}
else {
hr = S_OK;
}
}
}
else {
// write a function which will test for tag and return S_FALSE if tag is not present
hr = S_OK;
}
SysFreeString(bstrPresURL);
TraceHr(ttidError, FAL, hr, FALSE, "HrReplacePresentationURL");
return hr;
}
HRESULT CDescriptionManager::HrPersistDeviceSettingsToRegistry(
const PhysicalDeviceIdentifier & physicalDeviceIdentifier,
const UDNReplacementTable & udnReplacementTable,
const FileTable & fileTable,
BOOL bPersist)
{
HRESULT hr = S_OK;
// Create / open device host key
HKEY hKeyDescription;
DWORD dwDisposition = 0;
hr = HrCreateOrOpenDescriptionKey(&hKeyDescription);
if(SUCCEEDED(hr))
{
// Generate key name and registry key
CUString strPdi;
HKEY hKeyPdi;
hr = strPdi.HrInitFromGUID(physicalDeviceIdentifier);
if(SUCCEEDED(hr))
{
hr = HrRegCreateKeyEx(hKeyDescription, strPdi, 0, KEY_ALL_ACCESS, NULL, &hKeyPdi, &dwDisposition);
if(SUCCEEDED(hr))
{
// Create UDN mappings
HKEY hKeyMappings;
hr = HrRegCreateKeyEx(hKeyPdi, c_szUDNMappings, 0, KEY_ALL_ACCESS, NULL, &hKeyMappings, &dwDisposition);
if(SUCCEEDED(hr))
{
long nMappings = udnReplacementTable.Keys().GetCount();
for(long n = 0; n < nMappings && SUCCEEDED(hr); ++n)
{
// Create key for mapping
HKEY hKeyMapping;
hr = HrRegCreateKeyEx(hKeyMappings, udnReplacementTable.Keys()[n],
0, KEY_ALL_ACCESS, NULL, &hKeyMapping, &dwDisposition);
if(SUCCEEDED(hr))
{
// Write the value for the mapping
hr = HrRegSetSz(hKeyMapping, L"", udnReplacementTable.Values()[n]);
RegCloseKey(hKeyMapping);
}
}
RegCloseKey(hKeyMappings);
}
// Create file mappings for a fully persistent device
if(bPersist)
{
HKEY hKeyFileMappings;
hr = HrRegCreateKeyEx(hKeyPdi, c_szFiles, 0, KEY_ALL_ACCESS, NULL, &hKeyFileMappings, &dwDisposition);
if(SUCCEEDED(hr))
{
long nMappings = fileTable.Keys().GetCount();
for(long n = 0; n < nMappings && SUCCEEDED(hr); ++n)
{
CUString strFileId;
hr = strFileId.HrInitFromGUID(fileTable.Keys()[n]);
if(SUCCEEDED(hr))
{
// Create key for mapping
HKEY hKeyMapping;
hr = HrRegCreateKeyEx(hKeyFileMappings, strFileId, 0, KEY_ALL_ACCESS, NULL, &hKeyMapping, &dwDisposition);
if(SUCCEEDED(hr))
{
// Save values
hr = HrRegSetSz(hKeyMapping, c_szFilename, fileTable.Values()[n].m_filename);
if(SUCCEEDED(hr))
{
hr = HrRegSetSz(hKeyMapping, c_szMimetype, fileTable.Values()[n].m_mimetype);
}
}
}
}
RegCloseKey(hKeyFileMappings);
}
}
RegCloseKey(hKeyPdi);
}
}
// If anything fails, whack the whole key
if(FAILED(hr))
{
HrRegDeleteKeyTree(hKeyDescription, strPdi);
}
RegCloseKey(hKeyDescription);
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::HrPersistDeviceSettingsToRegistry");
return hr;
}
HRESULT CDescriptionManager::HrLoadDocumentAndRootNode(
const PhysicalDeviceIdentifier & physicalDeviceIdentifier,
IXMLDOMNodePtr & pRootNode)
{
HRESULT hr = S_OK;
// Lookup the id
BSTR * pbstrDocument = m_documentTable.Lookup(physicalDeviceIdentifier);
if(pbstrDocument)
{
// Load the document
IXMLDOMDocumentPtr pDoc;
hr = HrLoadDocument(*pbstrDocument, pDoc);
if(SUCCEEDED(hr))
{
hr = pRootNode.HrAttach(pDoc);
}
}
else
{
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::HrLoadDocumentAndRootNode");
return hr;
}
HRESULT CDescriptionManager::HrPDT_FetchCollections(
BSTR bstrTemplate,
IXMLDOMDocumentPtr & pDoc,
IXMLDOMNodePtr & pRootNode,
CUString & strRootUdnOld,
IXMLDOMNodeListPtr & pNodeListDevices,
IXMLDOMNodeListPtr & pNodeListUDNs,
IXMLDOMNodeListPtr & pNodeListSCPDURLs,
IXMLDOMNodeListPtr & pNodeListIcons)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_FetchCollections");
HRESULT hr = S_OK;
// Load document and fetch needed items
hr = HrLoadDocument(bstrTemplate, pDoc);
if(SUCCEEDED(hr))
{
hr = pRootNode.HrAttach(pDoc);
if(SUCCEEDED(hr))
{
// Get the old root UDN
hr = HrSelectNodeText(L"/root/device/UDN", pRootNode, strRootUdnOld);
if(SUCCEEDED(hr))
{
// Get the lists
hr = HrSelectNodes(L"//device", pRootNode, pNodeListDevices);
if(SUCCEEDED(hr))
{
hr = HrSelectNodes(L"//UDN", pRootNode, pNodeListUDNs);
if(SUCCEEDED(hr))
{
hr = HrSelectNodes(L"//SCPDURL", pRootNode, pNodeListSCPDURLs);
if(SUCCEEDED(hr))
{
hr = HrSelectNodes(L"//icon", pRootNode, pNodeListIcons);
}
}
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_FetchCollections");
return hr;
}
HRESULT CDescriptionManager::HrPDT_DoUDNToUDNMapping(
IXMLDOMNodeListPtr & pNodeListUDNs,
UDNReplacementTable & udnReplacementTable)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_DoUDNToUDNMapping");
HRESULT hr = S_OK;
// Do UDN to UDN mapping
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
// Process each UDN
hrTmp = pNodeListUDNs->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Allocate UDN storage and generate new UDN
CUString strOld;
CUString strNew;
hr = HrNewUDNString(strNew);
if(SUCCEEDED(hr))
{
// Read the old UDN
hr = HrGetNodeText(pNode, strOld);
if(SUCCEEDED(hr))
{
// Do replacement
hr = HrSetNodeText(pNode, strNew);
if(SUCCEEDED(hr))
{
// Add temporary table mapping
hr = udnReplacementTable.HrInsertTransfer(strOld, strNew);
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_DoUDNToUDNMapping");
return hr;
}
HRESULT CDescriptionManager::HrPDT_ReregisterUDNsInDescriptionDocument(
UDNReplacementTable & udnReplacementTable,
IXMLDOMNodeListPtr & pNodeListUDNs)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_ReregisterUDNsInDescriptionDocument");
HRESULT hr = S_OK;
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
// Process each UDN
hrTmp = pNodeListUDNs->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Read the old UDN
CUString strOld;
hr = HrGetNodeText(pNode, strOld);
if(SUCCEEDED(hr))
{
// Lookup in replacement table
CUString * pstrNew = udnReplacementTable.Lookup(strOld);
if(pstrNew)
{
// Do the replacement
hr = HrSetNodeText(pNode, *pstrNew);
}
else
{
TraceTag(ttidDescMan, "HrPDT_ReregisterUDNsInDescriptionDocument: Got invalid UDN in reregister '%S'",
static_cast<const wchar_t *>(strOld));
hr = E_UNEXPECTED;
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_ReregisterUDNsInDescriptionDocument");
return hr;
}
HRESULT CDescriptionManager::HrPDT_FetchPhysicalIdentifier(
UDNReplacementTable & udnReplacementTable,
const CUString & strRootUdnOld,
PhysicalDeviceIdentifier & pdi)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_FetchPhysicalIdentifier");
HRESULT hr = S_OK;
// Fetch identifier of root node
UDN * pUDN = udnReplacementTable.Lookup(strRootUdnOld);
if(!pUDN)
{
TraceTag(ttidError, "CDescriptionManager::ProcessDescriptionTemplate: We can't find the root UDN.");
hr = E_INVALIDARG;
}
if(SUCCEEDED(hr))
{
hr = HrUDNStringToGUID(*pUDN, pdi);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_FetchPhysicalIdentifier");
return hr;
}
BOOL FEventedVariablesPresent(
IXMLDOMNodeListPtr pNodeList)
{
HRESULT hr = S_OK;
HRESULT hrTmp;
BOOL fResult = FALSE;
while (SUCCEEDED(hr) && !fResult)
{
IXMLDOMNodePtr pNode;
// Process each node
hrTmp = pNodeList->nextNode(pNode.AddressOf());
if (S_OK != hrTmp)
{
break;
}
BSTR bstrSendEvents = NULL;
hr = HrGetTextValueFromAttribute(pNode, L"sendEvents", &bstrSendEvents);
if (S_OK == hr)
{
// sendEvents was present so we know there is at least one evented
// variable.. ok to exit now
if (!lstrcmpiW(bstrSendEvents, L"yes"))
{
fResult = TRUE;
}
SysFreeString(bstrSendEvents);
}
else
{
// sendEvents was not present which means we default to evented
// ok to exit now.
fResult = TRUE;
}
}
return fResult;
}
HRESULT HrCheckForEventedVariables(
CUString & strUrl)
{
HRESULT hr = S_OK;
BSTR bstrUrl;
BOOL fEventedVariables = FALSE;
hr = strUrl.HrGetBSTR(&bstrUrl);
if (SUCCEEDED(hr))
{
IXMLDOMDocumentPtr pDoc;
hr = HrLoadDocumentFromFile(bstrUrl, pDoc);
if (SUCCEEDED(hr))
{
IXMLDOMNodePtr pRootNode;
hr = pRootNode.HrAttach(pDoc);
if (SUCCEEDED(hr))
{
IXMLDOMNodeListPtr pNodeList;
hr = HrSelectNodes(L"//stateVariable",
pRootNode, pNodeList);
if (SUCCEEDED(hr))
{
if (FEventedVariablesPresent(pNodeList))
{
fEventedVariables = TRUE;
}
}
}
}
SysFreeString(bstrUrl);
}
if (SUCCEEDED(hr))
{
hr = fEventedVariables ? S_OK : S_FALSE;
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "HrCheckForEventedVariables");
return hr;
}
HRESULT CDescriptionManager::HrPDT_ReplaceSCPDURLs(
IXMLDOMNodeListPtr & pNodeListSCPDURLs,
const wchar_t * szResourcePath,
FileTable & fileTable)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_ReplaceSCPDURLs");
HRESULT hr = S_OK;
// Replace SCPDURLs
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
// Process each SCPDURL
hrTmp = pNodeListSCPDURLs->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Allocate filename storage and generate new URL
CUString strOld;
CUString strNew;
GUID guid;
hr = CoCreateGuid(&guid);
if(SUCCEEDED(hr))
{
// Generate the URL
hr = HrGetContentURL(guid, strNew);
if(SUCCEEDED(hr))
{
// Read the filename
CUString strFilename;
hr = HrGetNodeText(pNode, strFilename);
if(SUCCEEDED(hr))
{
// Make an absolute filename
hr = HrMakeFullPath(szResourcePath, strFilename, strOld);
}
}
if(SUCCEEDED(hr))
{
CUString strNode;
hr = strNode.HrAssign(L"/upnphost/");
if (SUCCEEDED(hr))
{
hr = strNode.HrAppend(strNew);
if (SUCCEEDED(hr))
{
// Do replacement
hr = HrSetNodeText(pNode, strNode);
}
}
}
if (SUCCEEDED(hr))
{
// Determine if the eventSubURL should be replaced later on
//
hr = HrCheckForEventedVariables(strOld);
if (S_FALSE == hr)
{
// No evented variables were found.. mark the eventSubURL
// element to be emptied later on when we process the
// eventing URLs.
//
CUString strRemove;
hr = strRemove.HrAssign(c_szRemoveId);
if (SUCCEEDED(hr))
{
hr = HrSelectAndSetNodeText(L"../eventSubURL", pNode,
strRemove);
}
}
}
if (SUCCEEDED(hr))
{
// Add mapping to data structure
FileInfo fi;
fi.m_filename.Transfer(strOld);
hr = fi.m_mimetype.HrAssign(L"text/xml");
if(SUCCEEDED(hr))
{
hr = fileTable.HrInsertTransfer(guid, fi);
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_ReplaceSCPDURLs");
return hr;
}
HRESULT CDescriptionManager::HrPDT_ReplaceIcons(
IXMLDOMNodeListPtr & pNodeListIcons,
const wchar_t * szResourcePath,
FileTable & fileTable)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_ReplaceIcons");
HRESULT hr = S_OK;
// Replace icons
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
// Process each icon
hrTmp = pNodeListIcons->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Allocate filename storage and generate new URL
CUString strOld;
CUString strNew;
GUID guid;
hr = CoCreateGuid(&guid);
if(SUCCEEDED(hr))
{
// Generate the URL
hr = HrGetContentURL(guid, strNew);
if(SUCCEEDED(hr))
{
// Read the filename
CUString strFilename;
hr = HrSelectNodeText(L"url", pNode, strFilename);
if(SUCCEEDED(hr))
{
// Make an absolute filename
hr = HrMakeFullPath(szResourcePath, strFilename, strOld);
}
}
if(SUCCEEDED(hr))
{
CUString strNode;
hr = strNode.HrAssign(L"/upnphost/");
if (SUCCEEDED(hr))
{
hr = strNode.HrAppend(strNew);
if (SUCCEEDED(hr))
{
// Do replacement
hr = HrSelectAndSetNodeText(L"url", pNode, strNode);
}
}
}
if(SUCCEEDED(hr))
{
// Add mapping to data structure
FileInfo fi;
fi.m_filename.Transfer(strOld);
// Get the mimetype
CUString strMimetype;
hr = HrSelectNodeText(L"mimetype", pNode, strMimetype);
if(SUCCEEDED(hr))
{
fi.m_mimetype.Transfer(strMimetype);
hr = fileTable.HrInsertTransfer(guid, fi);
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_ReplaceIcons");
return hr;
}
HRESULT CDescriptionManager::HrPDT_ReplaceControlAndEventURLs(
IXMLDOMNodeListPtr & pNodeListDevices)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_ReplaceControlAndEventURLs");
HRESULT hr = S_OK;
// Fill in the control and eventing URL for each document
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
// Process each device
hrTmp = pNodeListDevices->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
hr = HrGenerateControlAndEventURLs(pNode);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_ReplaceControlAndEventURLs");
return hr;
}
// Iterates over the devices and fills in the presentation URL for each device
HRESULT CDescriptionManager::HrPDT_ProcessPresentationURLs(
REFGUID guidPhysicalDeviceIdentifier,
IXMLDOMNodeListPtr & pNodeListDevices,
BOOL *fIsPresURLTagPresent)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_ProcessPresentationURLs");
HRESULT hr = S_OK;
// Fill in the presentation URL for each device
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
hrTmp = pNodeListDevices->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
hr = HrReplacePresentationURL(guidPhysicalDeviceIdentifier,pNode,fIsPresURLTagPresent);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_ProcessPresentationURLs");
return hr;
}
HRESULT CDescriptionManager::HrPDT_PersistDescriptionDocument(
const PhysicalDeviceIdentifier & pdi,
IXMLDOMDocumentPtr & pDoc)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPDT_PersistDescriptionDocument");
HRESULT hr = S_OK;
// Write description document to disk
// Get the path to save to
CUString strPath;
hr = HrGetDescriptionDocumentPath(pdi, strPath);
if(SUCCEEDED(hr))
{
BSTR bstr = NULL;
hr = strPath.HrGetBSTR(&bstr);
if(SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = bstr;
hr = pDoc->save(var);
SysFreeString(bstr);
TraceHr(ttidError, FAL, hr, FALSE, "ProcessDescriptionTemplate: IXMLDOMDocument::save failed.");
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPDT_PersistDescriptionDocument");
return hr;
}
STDMETHODIMP CDescriptionManager::ProcessDescriptionTemplate(
/*[in]*/ BSTR bstrTemplate,
/*[in, string]*/ const wchar_t * szResourcePath,
/*[in, out]*/ GUID * pguidPhysicalDeviceIdentifier,
/*[in]*/ BOOL bPersist,
/*[in]*/ BOOL bReregister)
{
CHECK_POINTER(bstrTemplate);
CHECK_POINTER(szResourcePath);
CHECK_POINTER(pguidPhysicalDeviceIdentifier);
CALock lock(*this);
HRESULT hr = S_OK;
// Values to fetch in first phase
IXMLDOMDocumentPtr pDoc;
IXMLDOMNodePtr pRootNode;
CUString strRootUdnOld;
IXMLDOMNodeListPtr pNodeListDevices;
IXMLDOMNodeListPtr pNodeListUDNs;
IXMLDOMNodeListPtr pNodeListSCPDURLs;
IXMLDOMNodeListPtr pNodeListIcons;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if ( SUCCEEDED( hr ) )
{
// Load document and fetch needed items
hr = HrPDT_FetchCollections(bstrTemplate, pDoc, pRootNode, strRootUdnOld, pNodeListDevices,
pNodeListUDNs, pNodeListSCPDURLs, pNodeListIcons);
}
// Temporary data structures to do work in
PhysicalDeviceIdentifier pdi;
UDNReplacementTable udnReplacementTable;
FileTable fileTable;
if(!bReregister)
{
// Do UDN to UDN mapping
if(SUCCEEDED(hr))
{
hr = HrPDT_DoUDNToUDNMapping(pNodeListUDNs, udnReplacementTable);
}
// Fetch identifier of root node
if(SUCCEEDED(hr))
{
hr = HrPDT_FetchPhysicalIdentifier(udnReplacementTable, strRootUdnOld, pdi);
}
}
else
{
if(SUCCEEDED(hr))
{
// Set the physical device identifier
pdi = *pguidPhysicalDeviceIdentifier;
// Open physical device identifier's registry key
HKEY hKeyPdi;
hr = HrOpenPhysicalDeviceDescriptionKey(pdi, &hKeyPdi);
if(SUCCEEDED(hr))
{
// Load the UDNs from registry
hr = HrLD_ReadUDNMappings(hKeyPdi, udnReplacementTable);
if(SUCCEEDED(hr))
{
// Update UDNs in the document
hr = HrPDT_ReregisterUDNsInDescriptionDocument(udnReplacementTable, pNodeListUDNs);
}
RegCloseKey(hKeyPdi);
}
}
}
// Replace SCPDURLs
if(SUCCEEDED(hr))
{
hr = HrPDT_ReplaceSCPDURLs(pNodeListSCPDURLs, szResourcePath, fileTable);
}
// Replace icons
if(SUCCEEDED(hr))
{
hr = HrPDT_ReplaceIcons(pNodeListIcons, szResourcePath, fileTable);
}
// Fill in the control and eventing URL for each document
if(SUCCEEDED(hr))
{
hr = HrPDT_ReplaceControlAndEventURLs(pNodeListDevices);
}
// Fill in the presentation URL for each device
if(SUCCEEDED(hr))
{
BOOL fIsPresURLTagPresent = false ;
hr = pNodeListDevices->reset();
if(SUCCEEDED(hr))
{
hr = HrPDT_ProcessPresentationURLs(pdi,pNodeListDevices,&fIsPresURLTagPresent);
// Create Virtual Directory for the presentation files
if(SUCCEEDED(hr) && fIsPresURLTagPresent )
{
BSTR bstrResourcePath;
bstrResourcePath = SysAllocString(szResourcePath);
hr = HrCreatePresentationVirtualDir(pdi,bstrResourcePath);
SysFreeString(bstrResourcePath);
}
}
}
// Write description document to disk
if(SUCCEEDED(hr) && bPersist)
{
hr = HrPDT_PersistDescriptionDocument(pdi, pDoc);
}
// Commit changes to registry for bPersist
if(SUCCEEDED(hr))
{
hr = HrPersistDeviceSettingsToRegistry(pdi, udnReplacementTable, fileTable, bPersist);
}
// Commit changes to variables
if(SUCCEEDED(hr))
{
// Add entries to the cleanup table
CleanupItem ci;
ci.m_physicalDeviceIdentifier = pdi;
long nCount = fileTable.Keys().GetCount();
for(long n = 0; n < nCount && SUCCEEDED(hr); ++n)
{
ci.m_fileId = fileTable.Keys()[n];
hr = m_cleanupList.HrPushBack(ci);
}
if(SUCCEEDED(hr))
{
{
CLock lockTable(m_critSecReplacementTable);
hr = m_replacementTable.HrInsertTransfer(pdi, udnReplacementTable);
}
if(SUCCEEDED(hr))
{
hr = m_fileTable.HrAppendTableTransfer(fileTable);
}
}
}
// Save description document
if(SUCCEEDED(hr))
{
BSTR bstrDocument = NULL;
hr = pRootNode->get_xml(&bstrDocument);
if(SUCCEEDED(hr))
{
hr = m_documentTable.HrInsert(pdi, bstrDocument);
if(FAILED(hr))
{
SysFreeString(bstrDocument);
}
}
}
// Return identifier
if(SUCCEEDED(hr) && !bReregister)
{
*pguidPhysicalDeviceIdentifier = pdi;
}
if(FAILED(hr))
{
RemoveDescription(pdi, FALSE);
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::ProcessDescriptionTemplate");
return hr;
}
HRESULT HrRegisterService(PSSDP_MESSAGE pSsdpMessage, DWORD dwFlags, HANDLE * pHandle)
{
CHECK_POINTER(pSsdpMessage);
CHECK_POINTER(pHandle);
HRESULT hr = S_OK;
*pHandle = RegisterService(pSsdpMessage, dwFlags);
if(INVALID_HANDLE_VALUE == *pHandle)
{
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "HrRegisterService:(%s) (%s)", pSsdpMessage->szType, pSsdpMessage->szUSN);
return hr;
}
HRESULT CDescriptionManager::HrPD_DoRootNotification(
IXMLDOMNodePtr & pNodeRootDevice,
SSDP_MESSAGE * pMsg,
HandleList * pHandleList)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPD_DoRootNotification");
HRESULT hr = S_OK;
// Do the root node notification
char szaUSN[256];
HANDLE hSvc;
// Get the UDN
CUString strUDN;
hr = HrSelectNodeText(L"UDN", pNodeRootDevice, strUDN);
if(SUCCEEDED(hr))
{
// Format the fields, generate the notificatio, and save the handle
wsprintfA(szaUSN, "%S::upnp:rootdevice", static_cast<const wchar_t*>(strUDN));
pMsg->szUSN = szaUSN;
pMsg->szType = "upnp:rootdevice";
hr = HrRegisterService(pMsg, 0, &hSvc);
if(SUCCEEDED(hr))
{
hr = pHandleList->HrPushBack(hSvc);
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPD_DoRootNotification");
return hr;
}
HRESULT CDescriptionManager::HrPD_DoDevicePublication(
IXMLDOMNodeListPtr & pNodeListDevices,
SSDP_MESSAGE * pMsg,
HandleList * pHandleList)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPD_DoDevicePublication");
HRESULT hr = S_OK;
// Do the device publication
char szaUSN[256];
char szaType[256];
HANDLE hSvc;
// Process each node in the device list
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
hrTmp = pNodeListDevices->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Fetch the UDN
CUString strUDN;
hr = HrSelectNodeText(L"UDN", pNode, strUDN);
if(SUCCEEDED(hr))
{
wsprintfA(szaUSN, "%S", static_cast<const wchar_t*>(strUDN));
pMsg->szUSN = szaUSN;
pMsg->szType = szaUSN;
hr = HrRegisterService(pMsg, 0, &hSvc);
if(SUCCEEDED(hr))
{
hr = pHandleList->HrPushBack(hSvc);
}
}
if(SUCCEEDED(hr))
{
// Fetch the device type
CUString strDeviceType;
hr = HrSelectNodeText(L"deviceType", pNode, strDeviceType);
if(SUCCEEDED(hr))
{
wsprintfA(szaUSN, "%S::%S", static_cast<const wchar_t*>(strUDN), static_cast<const wchar_t*>(strDeviceType));
wsprintfA(szaType, "%S", static_cast<const wchar_t*>(strDeviceType));
pMsg->szUSN = szaUSN;
pMsg->szType = szaType;
hr = HrRegisterService(pMsg, 0, &hSvc);
if(SUCCEEDED(hr))
{
hr = pHandleList->HrPushBack(hSvc);
}
}
}
// Do the services
if(SUCCEEDED(hr))
{
hr = HrPD_DoServicePublication(pNode, strUDN, pMsg, pHandleList);
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPD_DoDevicePublication");
return hr;
}
HRESULT CDescriptionManager::HrPD_DoServicePublication(
IXMLDOMNodePtr & pNodeDevice,
const CUString & strUDN,
SSDP_MESSAGE * pMsg,
HandleList * pHandleList)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrPD_DoServicePublication");
HRESULT hr = S_OK;
// Do the services
char szaUSN[256];
char szaType[256];
HANDLE hSvc;
// Get the services for this device
IXMLDOMNodeListPtr pNodeListServices;
hr = HrSelectNodes(L"serviceList/service", pNodeDevice, pNodeListServices);
if(SUCCEEDED(hr))
{
// Process each service in the list
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNodeService;
hrTmp = pNodeListServices->nextNode(pNodeService.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Fetch the service type
CUString strServiceType;
hr = HrSelectNodeText(L"serviceType", pNodeService, strServiceType);
// We need to only send out one anouncement for each service type.
// Do a selectSingleNode for this type and see if we match.
IXMLDOMNodePtr pNodeTemp;
if(SUCCEEDED(hr))
{
CUString strPattern;
hr = strPattern.HrAssign(L"serviceList/service[./serviceType = '");
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(strServiceType);
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(L"']");
}
}
if(SUCCEEDED(hr))
{
hr = HrSelectNode(strPattern, pNodeDevice, pNodeTemp);
}
}
if(SUCCEEDED(hr) && S_OK == pNodeTemp.HrIsEqual(pNodeService))
{
wsprintfA(szaType, "%S", static_cast<const wchar_t*>(strServiceType));
wsprintfA(szaUSN, "%S::%S", static_cast<const wchar_t*>(strUDN),
static_cast<const wchar_t*>(strServiceType));
pMsg->szUSN = szaUSN;
pMsg->szType = szaType;
hr = HrRegisterService(pMsg, 0, &hSvc);
if(SUCCEEDED(hr))
{
hr = pHandleList->HrPushBack(hSvc);
}
}
// Register with eventing
if(SUCCEEDED(hr))
{
hr = HrRegisterServiceWithEventing(pNodeService, strUDN, TRUE);
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrPD_DoServicePublication");
return hr;
}
STDMETHODIMP CDescriptionManager::PublishDescription(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[in]*/ long nLifeTime)
{
CALock lock(*this);
HRESULT hr = S_OK;
char szaLocHeader[256];
SSDP_MESSAGE msg = {0};
CUString strUrl;
CUString strDesc;
HandleList *pHandleList = NULL;
// Set lifetime and invariants
msg.iLifeTime = nLifeTime;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if ( SUCCEEDED( hr ) )
{
if ( !( pHandleList = new HandleList ) )
{
hr = E_OUTOFMEMORY;
}
}
if ( SUCCEEDED( hr ) )
{
hr = HrGetContentURL(guidPhysicalDeviceIdentifier, strDesc);
}
if(SUCCEEDED(hr))
{
hr = HrGetURLBase(strUrl);
if(SUCCEEDED(hr))
{
hr = strUrl.HrAppend(strDesc);
if(SUCCEEDED(hr))
{
wsprintfA(szaLocHeader, "%S", static_cast<const wchar_t*>(strUrl));
msg.szLocHeader = szaLocHeader;
}
}
}
IXMLDOMNodeListPtr pNodeListDevices;
IXMLDOMNodePtr pNodeRootDevice;
// Get the DOM collections needed
if(SUCCEEDED(hr))
{
IXMLDOMNodePtr pRootNode;
hr = HrLoadDocumentAndRootNode(guidPhysicalDeviceIdentifier, pRootNode);
if(SUCCEEDED(hr))
{
// Fetch the devices
hr = HrSelectNodes(L"//device", pRootNode, pNodeListDevices);
if(SUCCEEDED(hr))
{
hr = HrSelectNode(L"/root/device", pRootNode, pNodeRootDevice);
}
}
}
// Do the root node notification
if(SUCCEEDED(hr))
{
hr = HrPD_DoRootNotification(pNodeRootDevice, &msg, pHandleList);
}
// Do the device publication
if(SUCCEEDED(hr))
{
hr = HrPD_DoDevicePublication(pNodeListDevices, &msg, pHandleList);
}
// If we have succeeded then add handle array to table
if(SUCCEEDED(hr))
{
AssertSz(!m_ssdpRegistrationTable.Lookup(guidPhysicalDeviceIdentifier),
"CDescriptionManager::PublishDescription: Republishing known identifier!");
hr = m_ssdpRegistrationTable.HrInsert(guidPhysicalDeviceIdentifier, pHandleList);
if(SUCCEEDED(hr))
{
// Do this so it doesn't get cleared below
pHandleList = NULL;
}
}
// If handle list gets added to data structure it will be nulled out and this won't be cleaned up
if(pHandleList)
{
long nCount = pHandleList->GetCount();
for(long n = 0; n < nCount; ++n)
{
DeregisterService((*pHandleList)[n], TRUE);
}
delete pHandleList;
}
if(FAILED(hr))
{
HrRD_RemoveFromEventing(guidPhysicalDeviceIdentifier);
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::PublishDescription");
return hr;
}
HRESULT CDescriptionManager::HrLD_ReadUDNMappings(
HKEY hKeyPdi,
UDNReplacementTable & udnReplacementTable)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrLD_ReadUDNMappings");
HRESULT hr = S_OK;
// Read the UDN mappings
HKEY hKeyMappings;
hr = HrRegOpenKeyEx(hKeyPdi, c_szUDNMappings, KEY_ALL_ACCESS, &hKeyMappings);
if(SUCCEEDED(hr))
{
wchar_t szBuf[_MAX_PATH];
DWORD dwSize = _MAX_PATH;
FILETIME ft;
DWORD dwIndex;
for(dwIndex = 0;
SUCCEEDED(hr) && S_OK == HrRegEnumKeyEx(hKeyMappings, dwIndex, szBuf, &dwSize, NULL, NULL, &ft);
dwSize = _MAX_PATH, ++dwIndex)
{
// Open the mapping key
HKEY hKeyMapping;
hr = HrRegOpenKeyEx(hKeyMappings, szBuf, KEY_ALL_ACCESS, &hKeyMapping);
if(SUCCEEDED(hr))
{
CUString strFrom;
CUString strTo;
hr = strFrom.HrAssign(szBuf);
if(SUCCEEDED(hr))
{
hr = HrRegQueryString(hKeyMapping, L"", strTo);
if(SUCCEEDED(hr))
{
hr = udnReplacementTable.HrInsertTransfer(strFrom, strTo);
}
}
RegCloseKey(hKeyMapping);
}
}
RegCloseKey(hKeyMappings);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrLD_ReadUDNMappings");
return hr;
}
HRESULT CDescriptionManager::HrLD_ReadFileMappings(
HKEY hKeyPdi,
FileTable & fileTable)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrLD_ReadFileMappings");
HRESULT hr = S_OK;
HKEY hKeyFileMappings;
hr = HrRegOpenKeyEx(hKeyPdi, c_szFiles, KEY_ALL_ACCESS, &hKeyFileMappings);
if(SUCCEEDED(hr))
{
wchar_t szBuf[_MAX_PATH];
DWORD dwSize = _MAX_PATH;
FILETIME ft;
DWORD dwIndex;
for(dwIndex = 0;
SUCCEEDED(hr) && S_OK == HrRegEnumKeyEx(hKeyFileMappings, dwIndex, szBuf, &dwSize, NULL, NULL, &ft);
dwSize = _MAX_PATH, ++dwIndex)
{
// Open the mapping key
HKEY hKeyMapping;
hr = HrRegOpenKeyEx(hKeyFileMappings, szBuf, KEY_ALL_ACCESS, &hKeyMapping);
if(SUCCEEDED(hr))
{
// Convert the FileId to a guid
GUID guidFileId;
hr = CLSIDFromString(szBuf, &guidFileId);
if(SUCCEEDED(hr))
{
// Read the values
CUString strFilename;
CUString strMimetype;
hr = HrRegQueryString(hKeyMapping, c_szFilename, strFilename);
if(SUCCEEDED(hr))
{
hr = HrRegQueryString(hKeyMapping, c_szMimetype, strMimetype);
if(SUCCEEDED(hr))
{
FileInfo fi;
fi.m_filename.Transfer(strFilename);
fi.m_mimetype.Transfer(strMimetype);
hr = fileTable.HrInsertTransfer(guidFileId, fi);
}
}
}
RegCloseKey(hKeyMapping);
}
}
RegCloseKey(hKeyFileMappings);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrLD_ReadFileMappings");
return hr;
}
HRESULT CDescriptionManager::HrLD_LoadDescriptionDocumentFromDisk(
const PhysicalDeviceIdentifier & pdi,
IXMLDOMDocumentPtr & pDoc)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrLD_LoadDescriptionDocumentFromDisk");
HRESULT hr = S_OK;
// Load the document - use the DOM to at least validate that it is XML
// Get the path to load from
CUString strPath;
hr = HrGetDescriptionDocumentPath(pdi, strPath);
if(SUCCEEDED(hr))
{
BSTR bstr = NULL;
hr = strPath.HrGetBSTR(&bstr);
if(SUCCEEDED(hr))
{
hr = pDoc.HrCreateInstanceInproc(CLSID_DOMDocument30);
if(SUCCEEDED(hr))
{
VARIANT var;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = bstr;
VARIANT_BOOL vb;
hr = pDoc->load(var, &vb);
SysFreeString(bstr);
TraceHr(ttidError, FAL, hr, FALSE, "LoadDescription: IXMLDOMDocument::load failed.");
if(SUCCEEDED(hr) && !vb)
{
hr = E_FAIL;
}
if(FAILED(hr))
{
pDoc.Release();
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrLD_LoadDescriptionDocumentFromDisk");
return hr;
}
HRESULT CDescriptionManager::HrLD_SaveDescriptionDocumentText(
IXMLDOMDocumentPtr & pDoc,
const PhysicalDeviceIdentifier & pdi)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrLD_SaveDescriptionDocumentText");
HRESULT hr = S_OK;
// Save description document
BSTR bstrDocument = NULL;
IXMLDOMNodePtr pRootNode;
hr = pRootNode.HrAttach(pDoc);
if(SUCCEEDED(hr))
{
hr = pRootNode->get_xml(&bstrDocument);
if(SUCCEEDED(hr))
{
hr = m_documentTable.HrInsert(pdi, bstrDocument);
if(FAILED(hr))
{
SysFreeString(bstrDocument);
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrLD_SaveDescriptionDocumentText");
return hr;
}
STDMETHODIMP CDescriptionManager::LoadDescription(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier)
{
CALock lock(*this);
HRESULT hr = S_OK;
UDNReplacementTable udnReplacementTable;
FileTable fileTable;
// Open physical device identifier's registry key
HKEY hKeyPdi;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
hr = HrOpenPhysicalDeviceDescriptionKey(guidPhysicalDeviceIdentifier, &hKeyPdi);
}
if(SUCCEEDED(hr))
{
// Read the UDN mappings
hr = HrLD_ReadUDNMappings(hKeyPdi, udnReplacementTable);
// Read the file mappings
if(SUCCEEDED(hr))
{
hr = HrLD_ReadFileMappings(hKeyPdi, fileTable);
}
RegCloseKey(hKeyPdi);
}
IXMLDOMDocumentPtr pDoc;
// Load the document - use the DOM to at least validate that it is XML
if(SUCCEEDED(hr))
{
hr = HrLD_LoadDescriptionDocumentFromDisk(guidPhysicalDeviceIdentifier, pDoc);
}
// Everything has succeeded to memory so transfer to variables
if(SUCCEEDED(hr))
{
// Add entries to the cleanup table
CleanupItem ci;
ci.m_physicalDeviceIdentifier = guidPhysicalDeviceIdentifier;
long nCount = fileTable.Keys().GetCount();
for(long n = 0; n < nCount && SUCCEEDED(hr); ++n)
{
ci.m_fileId = fileTable.Keys()[n];
hr = m_cleanupList.HrPushBack(ci);
}
if(SUCCEEDED(hr))
{
{
CLock lockTable(m_critSecReplacementTable);
hr = m_replacementTable.HrInsertTransfer(const_cast<UUID&>(guidPhysicalDeviceIdentifier), udnReplacementTable);
}
if(SUCCEEDED(hr))
{
hr = m_fileTable.HrAppendTableTransfer(fileTable);
}
}
}
// Save description document
if(SUCCEEDED(hr))
{
hr = HrLD_SaveDescriptionDocumentText(pDoc, guidPhysicalDeviceIdentifier);
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::LoadDescription");
return hr;
}
HRESULT CDescriptionManager::HrRD_RemoveFromEventing(const PhysicalDeviceIdentifier & pdi)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrRD_RemoveFromEventing");
HRESULT hr = S_OK;
// Remove from eventing
IXMLDOMNodePtr pRootNode;
hr = HrLoadDocumentAndRootNode(pdi, pRootNode);
if(SUCCEEDED(hr))
{
// Fetch the devices
IXMLDOMNodeListPtr pNodeListDevices;
hr = HrSelectNodes(L"//device", pRootNode, pNodeListDevices);
if(SUCCEEDED(hr))
{
// Process each node in the device list
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
hrTmp = pNodeListDevices->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Fetch the UDN
CUString strUDN;
hr = HrSelectNodeText(L"UDN", pNode, strUDN);
// Do the services
if(SUCCEEDED(hr))
{
// Get the services for this device
IXMLDOMNodeListPtr pNodeListServices;
hr = HrSelectNodes(L"serviceList/service", pNode, pNodeListServices);
if(SUCCEEDED(hr))
{
// Process each service in the list
HRESULT hrTmp = S_OK;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNodeService;
hrTmp = pNodeListServices->nextNode(pNodeService.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Deregister with eventing
hr = HrRegisterServiceWithEventing(pNodeService, strUDN, FALSE);
}
}
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrRD_RemoveFromEventing");
return hr;
}
HRESULT CDescriptionManager::HrRD_RemoveFromDataStructures(const PhysicalDeviceIdentifier & pdi)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrRD_RemoveFromDataStructures");
HRESULT hr = S_OK;
// Remove from data structures
// Walk cleanup list
long n = 0;
while(n < m_cleanupList.GetCount())
{
for(n = 0; n < m_cleanupList.GetCount(); ++n)
{
// If we match this cleanup item then remove from fileTable and restart
if(pdi == m_cleanupList[n].m_physicalDeviceIdentifier)
{
m_fileTable.HrErase(m_cleanupList[n].m_fileId);
m_cleanupList.HrErase(n);
break;
}
}
}
// Remove from document table
BSTR * pbstr = m_documentTable.Lookup(pdi);
if(pbstr)
{
SysFreeString(*pbstr);
}
else
{
TraceTag(ttidError, "CDescriptionManager::RemoveDescription: Document not found!");
}
m_documentTable.HrErase(pdi);
// Free the UDN replacement table items
if(SUCCEEDED(hr))
{
CLock lockTable(m_critSecReplacementTable);
hr = m_replacementTable.HrErase(pdi);
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrRD_RemoveFromDataStructures");
return hr;
}
HRESULT CDescriptionManager::HrRD_CleanupPublication(const PhysicalDeviceIdentifier & pdi)
{
TraceTag(ttidDescMan, "CDescriptionManager::HrRD_CleanupPublication");
HRESULT hr = S_OK;
// Cleanup the publication
HandleList ** ppHandleList = NULL;
ppHandleList = m_ssdpRegistrationTable.Lookup(pdi);
if(ppHandleList)
{
long nCount = (*ppHandleList)->GetCount();
for(long n = 0; n < nCount; ++n)
{
DeregisterService((**ppHandleList)[n], TRUE);
}
delete *ppHandleList;
hr = m_ssdpRegistrationTable.HrErase(pdi);
}
else
{
hr = E_INVALIDARG;
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "CDescriptionManager::HrRD_CleanupPublication");
return hr;
}
STDMETHODIMP CDescriptionManager::RemoveDescription(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[in]*/ BOOL bPermanent)
{
CALock lock(*this);
HRESULT hr = S_OK;
// Remove from the registry if present
// Create / open description key
HKEY hKeyDescription;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
hr = HrCreateOrOpenDescriptionKey(&hKeyDescription);
}
if(SUCCEEDED(hr))
{
// Generate key name and registry key
CUString strPdi;
hr = strPdi.HrInitFromGUID(guidPhysicalDeviceIdentifier);
if(SUCCEEDED(hr))
{
if(bPermanent)
{
hr = HrRegDeleteKeyTree(hKeyDescription, strPdi);
}
else
{
// Just delete the file stuff
HKEY hKeyPdi;
hr = HrRegOpenKeyEx(hKeyDescription, strPdi, KEY_ALL_ACCESS, &hKeyPdi);
if(SUCCEEDED(hr))
{
hr = HrRegDeleteKeyTree(hKeyPdi, c_szFiles);
RegCloseKey(hKeyPdi);
}
}
}
RegCloseKey(hKeyDescription);
}
// Ignore registry failures
hr = S_OK;
// Delete the document from disk
CUString strPath;
hr = HrGetDescriptionDocumentPath(guidPhysicalDeviceIdentifier, strPath);
if(SUCCEEDED(hr))
{
DeleteFile(strPath);
}
// Ignore file deletion failures - might not exist
hr = S_OK;
// Remove from eventing
hr = HrRD_RemoveFromEventing(guidPhysicalDeviceIdentifier);
// Remove from data structures
hr = HrRD_RemoveFromDataStructures(guidPhysicalDeviceIdentifier);
// Cleanup the publication
hr = HrRD_CleanupPublication(guidPhysicalDeviceIdentifier);
// Remove Virtual Directory Created for Presentation
// CHECK - Virtual Directory may not be present
hr = HrRemovePresentationVirtualDir(guidPhysicalDeviceIdentifier);
if (FAILED(hr))
hr = S_OK ;
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::RemoveDescription");
return hr;
}
STDMETHODIMP CDescriptionManager::GetDescriptionText(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[out]*/ BSTR * pbstrDescriptionDocument)
{
CHECK_POINTER(pbstrDescriptionDocument);
CALock lock(*this);
HRESULT hr = S_OK;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
// Lookup the id
BSTR * pbstrDocument = m_documentTable.Lookup(guidPhysicalDeviceIdentifier);
if(pbstrDocument)
{
hr = HrSysAllocString(*pbstrDocument, pbstrDescriptionDocument);
}
else
{
hr = E_INVALIDARG;
}
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::GetDescriptionText");
return hr;
}
STDMETHODIMP CDescriptionManager::GetUDNs(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[out]*/ long * pnUDNCount,
/*[out, size_is(,*pnUDNCount,), string]*/
wchar_t *** parszUDNs)
{
CHECK_POINTER(pnUDNCount);
CHECK_POINTER(parszUDNs);
CALock lock(*this);
HRESULT hr = S_OK;
IXMLDOMNodePtr pRootNode;
IXMLDOMNodeListPtr pNodeListUDNs;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
hr = HrLoadDocumentAndRootNode(guidPhysicalDeviceIdentifier, pRootNode);
}
if(SUCCEEDED(hr))
{
// Fetch the UDNs
hr = HrSelectNodes(L"//UDN", pRootNode, pNodeListUDNs);
}
long nLength = 0;
wchar_t ** arszUDNs = NULL;
// Process the UDNs
if(SUCCEEDED(hr))
{
// Get length
hr = pNodeListUDNs->get_length(&nLength);
if(SUCCEEDED(hr))
{
// Allocate array
hr = HrCoTaskMemAllocArray(nLength, &arszUDNs);
if(SUCCEEDED(hr))
{
// Fill with zeros
ZeroMemory(arszUDNs, sizeof(wchar_t*) * nLength);
// Fetch all of the UDNs
long n = 0;
while(SUCCEEDED(hr))
{
IXMLDOMNodePtr pNode;
HRESULT hrTmp = S_OK;
// Fetch a node
hrTmp = pNodeListUDNs->nextNode(pNode.AddressOf());
if(S_OK != hrTmp)
{
break;
}
// Get the text
CUString strText;
hr = HrGetNodeText(pNode, strText);
if(SUCCEEDED(hr))
{
hr = strText.HrGetCOM(arszUDNs+n);
}
++n;
}
}
}
}
if(FAILED(hr))
{
if(arszUDNs)
{
// Free strings
for(long n = 0; n < nLength; ++n)
{
if(arszUDNs[n])
{
CoTaskMemFree(arszUDNs[n]);
}
}
CoTaskMemFree(arszUDNs);
}
arszUDNs = NULL;
nLength = 0;
}
// Copy to output parameters
*pnUDNCount = nLength;
*parszUDNs = arszUDNs;
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::GetUDNs");
return hr;
}
STDMETHODIMP CDescriptionManager::GetUniqueDeviceName(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[in, string]*/ const wchar_t * szTemplateUDN,
/*[out, string]*/ wchar_t ** pszUDN)
{
CHECK_POINTER(szTemplateUDN);
CHECK_POINTER(pszUDN);
HRESULT hr = S_OK;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (FAILED(hr))
{
return hr;
}
// Only lock the replacement table
CLock lock(m_critSecReplacementTable);
*pszUDN = NULL;
CUString strTemplateUDN;
hr = strTemplateUDN.HrAssign(szTemplateUDN);
if(SUCCEEDED(hr))
{
UDNReplacementTable * pudnReplacementTable = m_replacementTable.Lookup(guidPhysicalDeviceIdentifier);
if(pudnReplacementTable)
{
CUString * pstrUDN = pudnReplacementTable->Lookup(strTemplateUDN);
if(pstrUDN)
{
hr = pstrUDN->HrGetCOM(pszUDN);
}
}
}
// If we didn't find it in our tables then fail
if(!*pszUDN && SUCCEEDED(hr))
{
hr = E_INVALIDARG;
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::GetUniqueDeviceName");
return hr;
}
STDMETHODIMP CDescriptionManager::GetSCPDText(
/*[in]*/ REFGUID guidPhysicalDeviceIdentifier,
/*[in, string]*/ const wchar_t * szUDN,
/*[in, string]*/ const wchar_t * szServiceId,
/*[out, string]*/ wchar_t ** pszSCPDText,
/*[out, string]*/ wchar_t ** pszServiceType)
{
CHECK_POINTER(szUDN);
CHECK_POINTER(szServiceId);
CHECK_POINTER(pszSCPDText);
CHECK_POINTER(pszServiceType);
HRESULT hr = S_OK;
IXMLDOMNodePtr pRootNode;
IXMLDOMNodeListPtr pNodeListUDNs;
CUString strSCPDURL;
hr = HrIsAllowedCOMCallLocality((CALL_LOCALITY) CALL_LOCALITY_INPROC);
if (SUCCEEDED(hr))
{
// Get the SCPDURL
hr = HrLoadDocumentAndRootNode(guidPhysicalDeviceIdentifier, pRootNode);
}
if(SUCCEEDED(hr))
{
// Fetch the service node //service/SCPDURL[../serviceId = szServiceId]
CUString strPattern;
hr = strPattern.HrAssign(L"//service/SCPDURL[../serviceId = '");
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(szServiceId);
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(L"']");
if(SUCCEEDED(hr))
{
hr = HrSelectNodeText(strPattern, pRootNode, strSCPDURL);
}
}
}
}
// Get the GUID out of the URL
if(SUCCEEDED(hr))
{
UUID uuid;
hr = HrContentURLToGUID(strSCPDURL, uuid);
if(SUCCEEDED(hr))
{
// Fetch the content
long nHeaderCount = 0;
wchar_t ** arszHeaders = NULL;
long nBytes = 0;
byte * pBytes = NULL;
hr = GetContent(uuid, &nHeaderCount, &arszHeaders, &nBytes, &pBytes);
if(SUCCEEDED(hr))
{
// Content is not NULL terminate so reallocate with another character (yeah its cheesy)
hr = HrCoTaskMemAllocArray(nBytes + 1, pszSCPDText);
if(SUCCEEDED(hr))
{
// Copy text and convert from UTF-8 to unicode
if(!MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<char*>(pBytes), nBytes, *pszSCPDText, nBytes))
{
hr = HrFromLastWin32Error();
}
if(SUCCEEDED(hr))
{
// Null terminate
(*pszSCPDText)[nBytes] = 0;
}
}
// Free everything
CoTaskMemFree(pBytes);
for(long n = 0; n < nHeaderCount; ++n)
{
CoTaskMemFree(arszHeaders[n]);
}
CoTaskMemFree(arszHeaders);
}
}
}
// get the Service Type
if (SUCCEEDED(hr))
{
IXMLDOMNodePtr pServiceTypeNode;
// Fetch the service type //service/SCPDURL[../serviceId = szServiceId]
CUString strPattern;
hr = strPattern.HrAssign(L"//service/serviceType[../serviceId = '");
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(szServiceId);
if(SUCCEEDED(hr))
{
hr = strPattern.HrAppend(L"']");
if(SUCCEEDED(hr))
{
hr = HrSelectNode(strPattern, pRootNode, pServiceTypeNode);
if (SUCCEEDED(hr))
{
BSTR bstr = NULL;
hr = pServiceTypeNode->get_text(&bstr);
if(SUCCEEDED(hr))
{
*pszServiceType = (wchar_t*)CoTaskMemAlloc(CbOfSzAndTerm(bstr));
if (*pszServiceType)
{
lstrcpy(*pszServiceType, bstr);
}
else
{
hr = E_OUTOFMEMORY;
}
SysFreeString(bstr);
}
}
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "CDescriptionManager::GetSCPDText");
return hr;
}
HRESULT HrCreateOrOpenDescriptionKey(
HKEY * phKeyDescription)
{
CHECK_POINTER(phKeyDescription);
HRESULT hr = S_OK;
HKEY hKeyDeviceHost;
hr = HrCreateOrOpenDeviceHostKey(&hKeyDeviceHost);
if(SUCCEEDED(hr))
{
DWORD dwDisposition = 0;
// Create / open description key
hr = HrRegCreateKeyEx(hKeyDeviceHost, c_szDescription, 0, KEY_ALL_ACCESS, NULL, phKeyDescription, &dwDisposition);
RegCloseKey(hKeyDeviceHost);
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOpenDescriptionKey");
return hr;
}
HRESULT HrOpenPhysicalDeviceDescriptionKey(
const UUID & pdi,
HKEY * phKeyPdi)
{
CHECK_POINTER(phKeyPdi);
HRESULT hr = S_OK;
HKEY hKeyDescription;
hr = HrCreateOrOpenDescriptionKey(&hKeyDescription);
if(SUCCEEDED(hr))
{
CUString str;
hr = str.HrInitFromGUID(pdi);
if(SUCCEEDED(hr))
{
hr = HrRegOpenKeyEx(hKeyDescription, str, KEY_ALL_ACCESS, phKeyPdi);
}
RegCloseKey(hKeyDescription);
}
TraceHr(ttidError, FAL, hr, FALSE, "HrOpenPhysicalDeviceDescriptionKey");
return hr;
}
HRESULT HrGetDescriptionDocumentPath(
const UUID & pdi,
CUString & strPath)
{
HRESULT hr = S_OK;
hr = HrGetUPnPHostPath(strPath);
if(SUCCEEDED(hr))
{
hr = HrAddDirectoryToPath(strPath, c_szDescriptionDocuments);
if(SUCCEEDED(hr))
{
CUString strGUID;
hr = strGUID.HrInitFromGUID(pdi);
if(SUCCEEDED(hr))
{
hr = strPath.HrAppend(strGUID);
if(SUCCEEDED(hr))
{
hr = strPath.HrAppend(L".xml");
}
}
}
}
TraceHr(ttidError, FAL, hr, FALSE, "HrGetDescriptionDocumentPath");
return hr;
}
HRESULT HrRegisterServiceWithEventing(
IXMLDOMNodePtr & pNodeService,
const CUString & strUDN,
BOOL bRegister)
{
TraceTag(ttidDescMan, "HrRegisterServiceWithEventing");
HRESULT hr = S_OK;
// Register with eventing
CUString strSid;
hr = HrSelectNodeText(L"serviceId", pNodeService, strSid);
if(SUCCEEDED(hr))
{
// Generate the event identifier
CUString strESID;
hr = strESID.HrAssign(strUDN);
if(SUCCEEDED(hr))
{
hr = strESID.HrAppend(L"+");
if(SUCCEEDED(hr))
{
hr = strESID.HrAppend(strSid);
if(SUCCEEDED(hr))
{
if(bRegister)
{
hr = HrRegisterEventSource(strESID);
}
else
{
hr = HrDeregisterEventSource(strESID);
}
}
}
}
}
TraceHr(ttidDescMan, FAL, hr, FALSE, "HrRegisterServiceWithEventing");
return hr;
}