📄 av_upnp_impl.h
字号:
//
// 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.
//
//
// Implementations of inline functions and templated classes in av_upnp.h
//
#ifndef __AV_UPNP_IMPL_H
#define __AV_UPNP_IMPL_H
#include <variant.h>
namespace av_upnp {
/////////////////////////////////////////////////////////////////////////////
// VirtualServiceSupport
//
// VirtualServiceSupport
//
template <typename T>
VirtualServiceSupport<T>::VirtualServiceSupport(DISPID dispidLastChange, long nFirstInstanceID/* = 0 */)
: ModeratedEventSupport(200),
m_nLastCreatedID(nFirstInstanceID - 1),
m_bGetLastChangeUpdatesOnly(false)
{
assert(nFirstInstanceID >= 0); // the first created ID should be zero or above
m_dispidLastChange[0] = dispidLastChange;
}
//
// ~VirtualServiceSupport
//
template <typename T>
VirtualServiceSupport<T>::~VirtualServiceSupport()
{
assert(m_punkSubscriber == NULL);
// Unregister any remaining service instances
ce::gate<ce::critical_section> csInstancesLock(m_csMapInstances);
while(m_mapInstances.size() > 0)
UnregisterInstance(m_mapInstances.begin()->first);
}
//
// RegisterInstance
//
template <typename T>
DWORD VirtualServiceSupport<T>::RegisterInstance(
/* [in] */ T* pIServiceInstance,
/* [in, out] */ long* pInstanceID)
{
DWORD dw;
ce::gate<ce::critical_section> csInstancesLock(m_csMapInstances);
if(SUCCESS_AV != (dw = CreateUniqueID(pInstanceID)))
return dw;
return RegisterInstance(pIServiceInstance, *pInstanceID);
}
//
// RegisterInstance
//
template <typename T>
DWORD VirtualServiceSupport<T>::RegisterInstance(
/* [in] */ T* pIServiceInstance,
/* [in] */ long InstanceID)
{
DWORD dw;
if(!pIServiceInstance)
return ERROR_AV_POINTER;
if(InstanceID < 0)
return ERROR_AV_INVALID_INSTANCE;
ce::gate<ce::critical_section> gate(m_csMapInstances);
if(m_mapInstances.end() != m_mapInstances.find(InstanceID))
return ERROR_AV_INVALID_INSTANCE;
InstanceMap::iterator it = m_mapInstances.insert(InstanceID, pIServiceInstance);
if(m_mapInstances.end() == it)
return ERROR_AV_OOM;
if(SUCCESS_AV != (dw = pIServiceInstance->Advise(&it->second.virtualEventSink)))
{
m_mapInstances.erase(it);
return dw;
}
AddRefModeratedEvent();
m_nLastCreatedID = InstanceID;
assert(m_nLastCreatedID >= 0);
return SUCCESS_AV;
}
//
// UnregisterInstance
//
template <typename T>
DWORD VirtualServiceSupport<T>::UnregisterInstance(
/* [in] */ long InstanceID)
{
ReleaseModeratedEvent();
ce::gate<ce::critical_section> gate(m_csMapInstances);
const InstanceMap::iterator it = m_mapInstances.find(InstanceID);
if(m_mapInstances.end() == it)
return ERROR_AV_INVALID_INSTANCE;
it->second.pService->Unadvise(&it->second.virtualEventSink);
it->second.pService->Release();
m_mapInstances.erase(it);
return SUCCESS_AV;
}
//
// FindInstance
//
template <typename T>
DWORD VirtualServiceSupport<T>::FindInstance(
/* [in] */ long InstanceID,
/* [out] */ T** ppIServiceInstance)
{
ce::gate<ce::critical_section> gate(m_csMapInstances);
const InstanceMap::iterator it = m_mapInstances.find(InstanceID);
if(m_mapInstances.end() == it)
return ERROR_AV_INVALID_INSTANCE;
if(ppIServiceInstance)
{
*ppIServiceInstance = it->second.pService;
}
return SUCCESS_AV;
}
//
// GetLastChange
//
template <typename T>
DWORD VirtualServiceSupport<T>::GetLastChange(wstring* pLastChange)
{
assert(pLastChange);
assert(pLastChange->empty());
// Start the root <Event> element with appropriate namespace for the service
if(!pLastChange->append(L"<Event xmlns=\"") ||
!pLastChange->append(details::get_event_namespace<T>()) ||
!pLastChange->append(L"\">"))
{
DEBUGMSG(ZONE_AV_ERROR, (AV_TEXT("OOM when creating last change event")));
return ERROR_AV_OOM;
}
m_csMapInstances.assert_locked();
// Loop through each service instance, writing LastChange data for each that has changed, or all if the caller wanted all state variables
for(InstanceMap::iterator it = m_mapInstances.begin(), itEnd = m_mapInstances.end(); itEnd != it; ++it)
{
if(!m_bGetLastChangeUpdatesOnly || it->second.virtualEventSink.HasChanged())
{
wchar_t pszValue[33];
_itow(it->first, pszValue, 10);
// Start <InstanceID> element for this instance
if(!pLastChange->append(L"<InstanceID val=\"") ||
!pLastChange->append(pszValue) ||
!pLastChange->append(L"\">"))
{
return ERROR_AV_OOM;
}
// Have the service instance add its state variables
if(SUCCESS_AV != it->second.virtualEventSink.GetLastChange(m_bGetLastChangeUpdatesOnly, pLastChange))
return ERROR_AV_UPNP_ACTION_FAILED;
// End <InstanceID> element
if(!pLastChange->append(L"</InstanceID>"))
return ERROR_AV_OOM;
}
}
// End <Event> element
if(!pLastChange->append(L"</Event>"))
return ERROR_AV_OOM;
return SUCCESS_AV;
}
//
// CreateUniqueID
// Caller must hold m_csMapInstances
//
template <typename T>
DWORD VirtualServiceSupport<T>::CreateUniqueID(long* pInstanceID)
{
if(!pInstanceID)
return ERROR_AV_POINTER;
assert(m_nLastCreatedID + 1 >= 0);
// used to detect if we've stepped through all instance ids
const long firstID = m_nLastCreatedID;
for(long n = firstID + 1; n != firstID; ++n)
{
if(n < 0)
{
// don't allow for negative IDs
n = 0;
continue;
}
if(m_mapInstances.end() == m_mapInstances.find(n))
{
*pInstanceID = n;
return SUCCESS_AV;
}
}
return ERROR_AV_UPNP_ACTION_FAILED;
}
//
// TimedEventCall
//
template <typename T>
void VirtualServiceSupport<T>::TimedEventCall()
{
ce::gate<ce::critical_section> gateSubscriberLock(m_csPunkSubscriber);
if(!m_punkSubscriber)
return;
ce::gate<ce::critical_section> gateInstancesLock(m_csMapInstances);
// Generate LastChange event if any virtual service instance has unreported changes
for(InstanceMap::iterator it = m_mapInstances.begin(), itEnd = m_mapInstances.end(); itEnd != it; ++it)
{
if(it->second.virtualEventSink.HasChanged())
{
//
// Generate event for LastChange state variable. The even will contain only variables
// that have changed since last event (m_bGetLastChangeUpdatesOnly = true).
// Holding m_csGetLastChange critical section prevents other thread from calling
// GetLastChange until we complete this event.
//
ce::gate<ce::critical_section> gate(m_csGetLastChange);
m_bGetLastChangeUpdatesOnly = true;
//
// OnStateChanged will call back into the service's get_LastChange which in turn calls
// GetLastChange to get value of the LastChange state variable.
//
m_punkSubscriber->OnStateChanged(1, m_dispidLastChange);
m_bGetLastChangeUpdatesOnly = false;
break;
}
}
}
//
// GetLastChange
//
template <typename T>
HRESULT VirtualServiceSupport<T>::GetLastChange(BSTR *pbstrLastChange)
{
// m_csMapInstances critical section is needed by GetLastChange(wstring*)
// and must be entered before entering m_csGetLastChange to avoid deadlock
ce::gate<ce::critical_section> csInstancesLock(m_csMapInstances);
ce::gate<ce::critical_section> gateGetLastChange(m_csGetLastChange);
// static buffer used to build LastChange value (for efficiency)
static details::wstring_buffer LastChangeBuffer;
if(!pbstrLastChange)
return m_ErrReport.ReportError(ERROR_AV_POINTER);
// reset the global buffer so that we can use append to build LastChange value
LastChangeBuffer.ResetBuffer();
// Build LastChange value
const DWORD dw = GetLastChange(&LastChangeBuffer.strBuffer);
if(SUCCESS_AV != dw)
return m_ErrReport.ReportError(dw);
// Allocate BSTR string for LastChange
if(!(*pbstrLastChange = SysAllocString(LastChangeBuffer.strBuffer)))
return m_ErrReport.ReportError(ERROR_AV_OOM);
return S_OK;
}
//
// InvokeVendorAction
//
template <typename T>
DWORD VirtualServiceSupport<T>::InvokeVendorAction(
/* [in] */ LPCWSTR pszActionName,
/* [in] */ DISPPARAMS* pdispparams,
/* [in, out] */ VARIANT* pvarResult)
{
unsigned uArgErr;
ce::variant varInstanceID;
// get first argument (InstanceID)
if(FAILED(DispGetParam(pdispparams, 0, VT_UI4, &varInstanceID, &uArgErr)))
return ERROR_AV_UPNP_ACTION_FAILED;
ce::gate<ce::critical_section> csMapInstances(m_csMapInstances);
// find service instance based on ID
const InstanceMap::iterator it = m_mapInstances.find(varInstanceID.ulVal);
if(it == m_mapInstances.end())
return ERROR_AV_INVALID_INSTANCE;
return it->second.pService->InvokeVendorAction(pszActionName, pdispparams, pvarResult);
}
}
#endif // __AV_UPNP_IMPL_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -