📄 upnphost.cpp
字号:
// Format the parameters in the way the AutomationProxy wants them
if (!FormatControlRequest(pSvcCtl, &ucreq))
return FALSE;
memset(&ucresp,0, sizeof(ucresp));
hr = pServiceProxy->m_pap->ExecuteRequest(&ucreq, &ucresp);
if (SUCCEEDED(hr))
{
hr = pServiceProxy->SetControlResponse(pSvcCtl, &ucresp);
if (SUCCEEDED(hr))
{
fRet = TRUE;
}
}
// cleanup
::FreeControlRequest(&ucreq);
::FreeControlResponse(&ucresp);
// if we return false the UPNP service will return a generic fault
// which is fine.
return fRet;
}
//+---------------------------------------------------------------------------
//
// Function: InitCallback
//
// Purpose: Invoked before any other device callbacks,
// when the first subsribe or control request is received.
//
// Arguments:
//
// Returns:
// TRUE if ok, FALSE otherwise
//
BOOL
DeviceProxy::InitCallback()
{
TraceTag(ttidRegistrar, "DeviceProxy::InitRequest\n");
// We need to have a pointer to the implementation object by now
if (!m_pDeviceControl)
{
return FALSE;
}
m_pDeviceControl->Initialize(m_bstrXMLDesc, m_bstrDeviceId, m_bstrInitString);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: ShutdownCallback
//
// Purpose: The UPnP service wants to shutdown the device. This
// is the last callback to be received, so this is where we free
// the DeviceProxy object
//
// Arguments:
//
// Returns:
// returns TRUE
//
BOOL
DeviceProxy::ShutdownCallback()
{
TraceTag(ttidRegistrar, "DeviceProxy::ShutdowndRequest\n");
RemoveDevice();
RemoveFromList();
delete this;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function:
//
// Purpose: Create and publish the UPnP device tree.
//
// Arguments:
// pszXMLDesc [in] XML device description template
//
// Returns:
// HRESULT
//
DeviceProxy::~DeviceProxy()
{
ServiceProxy *pSvc = m_pServices;
while (m_pServices)
{
LONG ref;
pSvc = m_pServices;
m_pServices = pSvc->m_pNext;
pSvc->Shutdown(); // unadvise the event source
ref = pSvc->Release(); // this should delete the service
Assert(ref == 0);
}
SysFreeString(m_bstrDeviceId);
SysFreeString(m_bstrInitString);
SysFreeString(m_bstrResourcePath);
SysFreeString(m_bstrUDN);
SysFreeString(m_bstrXMLDesc);
if (m_pDeviceControl)
{
m_pDeviceControl->Release();
}
}
//
// ServiceProxy implementation
//
//+---------------------------------------------------------------------------
//
// Function:
//
// Purpose: Create and publish the UPnP device tree.
//
// Arguments:
// pszXMLDesc [in] XML device description template
//
// Returns:
// HRESULT
//
HRESULT
ServiceProxy::Initialize(PCWSTR pszUDN, PCWSTR pszSid, PCWSTR pszSCPD, IUnknown *pUPnPServiceObj)
{
HRESULT hr;
m_bstrSid = SysAllocString(pszSid);
if (!m_bstrSid)
return E_OUTOFMEMORY;
m_bstrUDN = SysAllocString(pszUDN);
if (!m_bstrUDN)
return E_OUTOFMEMORY;
hr = CUPnPAutomationProxy::CreateInstance(NULL, IID_IUPnPAutomationProxy, (void **)&m_pap);
if (SUCCEEDED(hr))
{
hr = m_pap->Initialize(pUPnPServiceObj, (PWSTR)pszSCPD);
m_pap->QueryInterface(IID_IUPnPServiceDescriptionInfo, (void **)&m_psdi);
if (SUCCEEDED(hr))
{
// initialize eventing
hr = pUPnPServiceObj->QueryInterface(IID_IUPnPEventSource,(void **)&m_pes);
if (SUCCEEDED(hr))
{
hr = m_pes->Advise((IUPnPEventSink *)this);
if (FAILED(hr))
{
m_pes->Release();
m_pes = NULL;
}
}
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function:
//
// Purpose: release the automation proxy and event source objects.
// Can't put this code in the destructor, because this is where the refcount gets
// decremented; the destructor gets called only when the refcount goes down to zero
//
// Arguments:
//
// Returns:
// nothing
//
void
ServiceProxy::Shutdown()
{
LONG cRef;
if (m_pes)
{
m_pes->Unadvise((IUPnPEventSink *)this);
m_pes->Release();
m_pes = NULL;
}
if (m_pap)
{
if (m_psdi)
{
cRef = m_psdi->Release();
m_psdi = NULL;
}
cRef = m_pap->Release();
Assert(cRef == 0);
m_pap = NULL;
}
}
ServiceProxy::~ServiceProxy()
{
Shutdown(); // won't do anything except perhaps in init error cases
SysFreeString(m_bstrSid);
SysFreeString(m_bstrUDN);
}
//+---------------------------------------------------------------------------
//
// Member: ServiceProxy::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.
// Notes:
//
STDMETHODIMP ServiceProxy::OnStateChanged(DWORD cChanges,
DISPID rgdispidChanges[])
{
return UpdateEventedVariables(TRUE, cChanges, rgdispidChanges); // TRUE -> update and send events
}
// Undocumented UPnP API
BOOL
WINAPI
UpnpUpdateEventedVariables(
PCWSTR pszDeviceName,
PCWSTR pszUDN,
PCWSTR pszServiceId,
DWORD nArgs,
UPNPPARAM *rgArgs);
HRESULT ServiceProxy::UpdateEventedVariables(BOOL bSubmitEvent, DWORD cChanges, DISPID rgdispidChanges[])
{
HRESULT hr = S_OK;
LPWSTR szBody = NULL;
DWORD cVars, ivar;
LPWSTR * rgszNames;
LPWSTR * rgszTypes;
VARIANT * rgvarValues;
AssertSz(m_bstrSid, "What? Did we not get initialized or something?");
AssertSz(m_pap, "Automation proxy not initialized?");
if (!m_pes)
{
hr = E_UNEXPECTED;
}
else if (cChanges && !rgdispidChanges)
{
hr = E_INVALIDARG;
}
else
{
if (!cChanges && !rgdispidChanges)
{
TraceTag(ttidEvents, "Sending all state variables for %S\n", m_bstrSid);
}
hr = m_pap->QueryStateVariablesByDispIds(cChanges, rgdispidChanges,
&cVars, &rgszNames,
&rgvarValues, &rgszTypes);
if (SUCCEEDED(hr))
{
UPNPPARAM *rgParams = new UPNPPARAM[cVars];
if (rgParams)
{
for (ivar = 0; ivar < cVars; ivar++)
{
rgParams[ivar].pszName = rgszNames[ivar];
hr = VariantChangeType(rgvarValues+ivar, rgvarValues+ivar, 0, VT_BSTR);
if (FAILED(hr))
{
TraceError("OnStateChanged:Can't change arg type to BSTR\n", hr);
break;
}
rgParams[ivar].pszValue = V_BSTR(rgvarValues+ivar);
}
if (SUCCEEDED(hr))
{
if (bSubmitEvent)
{
if(!UpnpSubmitPropertyEvent(m_pDevProxy->Name(), m_bstrUDN, m_bstrSid, cVars, rgParams))
{
TraceTag(ttidError,"OnStateChanged: UpnpSubmitPropertyEvent failed error=%d\n", GetLastError());
hr = HrFromLastWin32Error();
}
}
else
{
if(!UpnpUpdateEventedVariables(m_pDevProxy->Name(), m_bstrUDN, m_bstrSid, cVars, rgParams))
{
TraceTag(ttidError,"OnStateChanged: UpnpUpdateEventedVariables failed error=%d\n", GetLastError());
hr = HrFromLastWin32Error();
}
}
}
delete [] rgParams;
}
else
hr = E_OUTOFMEMORY;
for (ivar = 0; ivar < cVars; ivar++)
{
CoTaskMemFree(rgszTypes[ivar]);
CoTaskMemFree(rgszNames[ivar]);
VariantClear(&rgvarValues[ivar]);
}
CoTaskMemFree(rgvarValues);
CoTaskMemFree(rgszTypes);
CoTaskMemFree(rgszNames);
}
}
TraceError("ServiceProxy::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: From Whistler
//
STDMETHODIMP ServiceProxy::OnStateChangedSafe(VARIANT varsadispidChanges)
{
HRESULT hr = S_OK;
SAFEARRAY *psa = V_ARRAY(&varsadispidChanges);
DISPID HUGEP * rgdispids;
// 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);
}
TraceError("CUPnPEventingManager::OnStateChangedSafe", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function:
//
// Purpose: Create and publish the UPnP device tree.
//
// Arguments:
// pszXMLDesc [in] XML device description template
//
// Returns:
// HRESULT
//
HRESULT
ServiceProxy::SetControlResponse(UPNPSERVICECONTROL *pSvcCtl, UPNP_CONTROL_RESPONSE *pucresp)
{
HRESULT hr = S_OK;
if (pucresp->fSucceeded)
{
UPNPPARAM *pParams;
DWORD i, cOutputArgs = 0;
VARIANT *pvar;
BSTR * rgbstrNames = NULL;
BSTR * rgbstrTypes = NULL;
// success response
if (!pucresp->ucrData.Success.cOutputArgs)
return S_OK; // the UPNP service will return a default success response
pParams = new UPNPPARAM [pucresp->ucrData.Success.cOutputArgs];
if (!pParams)
return E_OUTOFMEMORY;
Assert(m_psdi);
if (wcscmp(pSvcCtl->pszAction, L"QueryStateVariable") == 0)
{
pParams[0].pszName = L"return";
pvar = &pucresp->ucrData.Success.rgvarOutputArgs[0];
hr = VariantChangeType(pvar,pvar,0,VT_BSTR);
if (SUCCEEDED(hr))
{
pParams[0].pszValue = V_BSTR(pvar);
cOutputArgs = 1;
}
}
else
{
// one or more output vars need to be specified
// unfortunately we don't have the var names in pucresp (that would be too easy)
// so they need to be determined
hr = m_psdi->GetOutputArgumentNamesAndTypes(
pucresp->bstrActionName,
&cOutputArgs,
&rgbstrNames,
&rgbstrTypes);
if (SUCCEEDED(hr))
{
Assert(cOutputArgs == pucresp->ucrData.Success.cOutputArgs);
for (i=0; i < cOutputArgs; i++)
{
pParams[i].pszName = rgbstrNames[i];
pvar = &pucresp->ucrData.Success.rgvarOutputArgs[i];
hr = VariantChangeType(pvar, pvar, 0, VT_BSTR);
if (FAILED(hr))
{
TraceError("SetControlResponse:Can't change arg type to BSTR\n", hr);
break;
}
pParams[i].pszValue = V_BSTR(pvar);
}
}
}
if (SUCCEEDED(hr))
{
if (!UpnpSetControlResponse(pSvcCtl, cOutputArgs, pParams))
{
TraceTag(ttidError, "UpnpSetControlResponse returned error %d for %S\n",
GetLastError(), pSvcCtl->pszAction);
hr = HrFromLastWin32Error();
}
}
// Clean up.
if (rgbstrNames)
{
for (i = 0; i < cOutputArgs; i++)
{
SysFreeString(rgbstrNames[i]);
rgbstrNames[i] = NULL;
SysFreeString(rgbstrTypes[i]);
rgbstrTypes[i] = NULL;
}
CoTaskMemFree(rgbstrNames);
rgbstrNames = NULL;
CoTaskMemFree(rgbstrTypes);
rgbstrTypes = NULL;
}
delete [] pParams;
}
else
{
int errCode = 501; // Action failed
Assert(pucresp->ucrData.Fault.bstrUPnPErrorCode);
if (pucresp->ucrData.Fault.bstrUPnPErrorCode)
{
errCode = _wtol(pucresp->ucrData.Fault.bstrUPnPErrorCode);
}
// error response
if (!UpnpSetErrorResponse(pSvcCtl, errCode, pucresp->ucrData.Fault.bstrUPnPErrorString))
{
TraceTag(ttidError, "UpnpSetControlResponse returned error %d for %S\n",
GetLastError(), pSvcCtl->pszAction);
hr = HrFromLastWin32Error();
}
}
return hr;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -