📄 contentdirectoryservice.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "av_dcp.h"
#include "av_upnp.h"
using namespace av_upnp;
/////////////////////////////////////////////////////////////////////////////
// ContentDirectoryServiceImpl
namespace av_upnp
{
namespace details
{
const DWORD g_nCDMinModeratedEventSleepPeriodms = 2000; // as specified by CDS's spec, the min time between moderated events
}
}
ContentDirectoryServiceImpl::ContentDirectoryServiceImpl()
: m_pContentDirectory(NULL),
ModeratedEventSupport(details::g_nCDMinModeratedEventSleepPeriodms),
m_bSystemUpdateIDChanged(false)
{
InitErrDescrips();
InitToolkitErrs();
InitDISPIDs();
}
ContentDirectoryServiceImpl::~ContentDirectoryServiceImpl()
{
if(m_pContentDirectory)
const DWORD retUnadvise = m_pContentDirectory->Unadvise(this);
// if Unadvise() fails, we can do nothing but ignore.
}
DWORD ContentDirectoryServiceImpl::Init(/* [in] */ IContentDirectory* pIContentDirectory)
{
if(m_pContentDirectory)
return ERROR_AV_ALREADY_INITED;
if(!pIContentDirectory)
return ERROR_AV_POINTER;
m_pContentDirectory = pIContentDirectory;
const DWORD retAdvise = m_pContentDirectory->Advise(this);
if(SUCCESS_AV != retAdvise)
return retAdvise;
return SUCCESS_AV;
}
//
// IEventSink
//
DWORD ContentDirectoryServiceImpl::OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in*/ LPCWSTR pszValue)
{
if(!pszStateVariableName || !pszValue)
return ERROR_AV_POINTER;
DWORD ret = SUCCESS_AV;
ce::gate<ce::critical_section> csEventsLock(m_csEvents);
if(0 == wcscmp(ContentDirectoryState::SystemUpdateID, pszStateVariableName))
{
// This is a moderated event
// Mark that this moderated variable has been updated and store its value for get_ to retrieve later on
if(!m_bSystemUpdateIDChanged)
{
m_bSystemUpdateIDChanged = true;
// no updates -> an update exists, notify TimedEventCaller
AddRefModeratedEvent();
}
}
else if(0 == wcscmp(ContentDirectoryState::ContainerUpdateIDs, pszStateVariableName))
{
// This is a moderated event
// Mark that this moderated variable has been updated and store its value for get_ to retrieve later on
wstring strContainerID, strUpdateID;
wstring::size_type n;
strContainerID = pszValue;
if(wstring::npos == (n = strContainerID.find(L",")))
return ERROR_AV_INVALID_STATEVAR;
strContainerID.resize(n);
strUpdateID = pszValue + n + 1;
if(strContainerID.empty())
return ERROR_AV_INVALID_STATEVAR;
if(strUpdateID.empty())
return ERROR_AV_INVALID_STATEVAR;
if(wstring::npos != strUpdateID.find(L","))
return ERROR_AV_INVALID_STATEVAR;
ContainerUpdateIDsMap::iterator it;
it = m_mapContainerUpdateIDs.find(strContainerID);
if(m_mapContainerUpdateIDs.end() == it)
{
if(m_mapContainerUpdateIDs.end() == m_mapContainerUpdateIDs.insert(strContainerID, strUpdateID))
return ERROR_AV_OOM;
if(1 == m_mapContainerUpdateIDs.size())
// no updates -> an update exists, notify TimedEventCaller
AddRefModeratedEvent();
}
else
it->second = strUpdateID;
}
else
{
if(0 == wcscmp(ContentDirectoryState::TransferIDs, pszStateVariableName))
{
// This is a non-moderated event that CDSImpl implements, store its new value for get_ to retrieve
// (and pass on to IEventSinkSupport like all non-moderated events)
m_strTransferIDs = pszValue;
}
// This is a non-moderated event, pass on to IEventSinkSupport to notify subscriber
ret = IEventSinkSupport::OnStateChanged(pszStateVariableName, pszValue);
}
return ret;
}
DWORD ContentDirectoryServiceImpl::OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in*/ long nValue)
{
if(!pszStateVariableName)
return ERROR_AV_POINTER;
// Convert nValue from a long to a LPCWSTR and pass on to the string version of OnStateChanged()
wstring strValue;
const int nltowLimit = 33;
strValue.reserve(nltowLimit);
_ltow(nValue, strValue.get_buffer(), 10);
return OnStateChanged(pszStateVariableName, strValue);
}
DWORD ContentDirectoryServiceImpl::OnStateChanged(
/*[in]*/ LPCWSTR pszStateVariableName,
/*[in]*/ LPCWSTR pszChannel,
/*[in]*/ long nValue)
{
// This overload of OnStateChanged is only for RenderingControl use
return ERROR_AV_UPNP_ACTION_FAILED;
}
//
// TimedEventCallee
//
void ContentDirectoryServiceImpl::TimedEventCall()
{
// If a state variable has been updated:
// Send update to IEventSinkSupport, reset the updated flag, and remove this var's Ref from TimedEventCaller.
// Ignore return values, we can't do anything in response here.
ce::gate<ce::critical_section> csEventsLock(m_csEvents);
if(m_bSystemUpdateIDChanged)
{
IEventSinkSupport::OnStateChanged(ContentDirectoryState::SystemUpdateID, (LPCWSTR)NULL);
m_bSystemUpdateIDChanged = false;
ReleaseModeratedEvent();
}
if(!m_mapContainerUpdateIDs.empty())
{
IEventSinkSupport::OnStateChanged(ContentDirectoryState::ContainerUpdateIDs, (LPCWSTR)NULL);
m_mapContainerUpdateIDs.clear();
ReleaseModeratedEvent();
}
}
//
// IUPnPService_ContentDirectory1
//
STDMETHODIMP ContentDirectoryServiceImpl::get_TransferIDs(BSTR* pTransferIDs)
{
if(!pTransferIDs)
return E_POINTER;
ce::gate<ce::critical_section> csEventsLock(m_csEvents);
*pTransferIDs = SysAllocString(m_strTransferIDs);
if(!*pTransferIDs)
return m_ErrReport.ReportError(ERROR_AV_OOM);
return S_OK;
}
// get_A_ARG_TYPE_foo() methods are implemented only to satisfy upnp's devicehost, they are not used
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_ObjectID(BSTR* pA_ARG_TYPE_ObjectID)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_Result(BSTR* pA_ARG_TYPE_Result)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_SearchCriteria(BSTR* pA_ARG_TYPE_SearchCriteria)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_BrowseFlag(BSTR* pA_ARG_TYPE_BrowseFlag)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_Filter(BSTR* pA_ARG_TYPE_Filter)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_SortCriteria(BSTR* pA_ARG_TYPE_SortCriteria)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_Index(unsigned long* pA_ARG_TYPE_Index)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_Count(unsigned long* pA_ARG_TYPE_Count)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_UpdateID(unsigned long* pA_ARG_TYPE_UpdateID)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_TransferID(unsigned long* pA_ARG_TYPE_TransferID)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_TransferStatus(BSTR* pA_ARG_TYPE_TransferStatus)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_TransferLength(BSTR* pA_ARG_TYPE_TransferLength)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_TransferTotal(BSTR* pA_ARG_TYPE_TransferTotal)
{
return S_OK;
}
STDMETHODIMP ContentDirectoryServiceImpl::get_A_ARG_TYPE_TagValueList(BSTR* pA_ARG_TYPE_TagValueList)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -