⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serviceimpl.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 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 "pch.h"
#pragma hdrstop

#include "ssdpapi.h"
#include "upnp.h"
#include "url_verifier.h"
#include "upnp_config.h"

#include "ServiceImpl.h"
#include "SoapRequest.h"
#include "com_macros.h"
#include "HttpRequest.h"

extern url_verifier* g_pURL_Verifier;

// ServiceImpl
ServiceImpl::ServiceImpl(LPCWSTR pwszUniqueDeviceName,
						 LPCWSTR pwszServiceType, 
						 LPCWSTR pwszDescriptionURL,
                         LPCWSTR pwszControlURL, 
                         LPCWSTR pwszEventsURL,
						 UINT    nLifeTime)
    : m_actionQueryStateVar(L"QueryStateVariable", L"urn:schemas-upnp-org:control-1-0"),
      m_statevarVarName(L"", StateVar::string, false),
	  m_dwSubscriptionCookie(0),
	  m_pUPnPService(NULL),
      m_bServiceInstanceDied(false),
      m_bParsedRootElement(false),
      m_hrInitResult(E_UNEXPECTED),
	  m_bSubscribed(false)
{
	// fabricate QueryStateVariable "action"
    Argument arg(L"u:varName", L"", false);
    
    arg.BindStateVar(&m_statevarVarName);

    m_actionQueryStateVar.AddInArgument(arg);
    m_actionQueryStateVar.AddOutArgument(Argument(L"return", L"", true));

	// init data
	m_strUniqueServiceName = pwszUniqueDeviceName;
	m_strUniqueServiceName += L"::";
	m_strUniqueServiceName += pwszServiceType;

	m_strType = pwszServiceType;
    
	ce::WideCharToMultiByte(CP_UTF8, pwszDescriptionURL, -1, &m_strDescriptionURL);
	
	ce::WideCharToMultiByte(CP_UTF8, pwszControlURL, -1, &m_strControlURL);

	ce::WideCharToMultiByte(CP_UTF8, pwszEventsURL, -1, &m_strEventsURL);

	// advise to connection point
	m_hrAdviseResult = g_pConnectionPoint->advise(m_strUniqueServiceName, nLifeTime, this, &m_dwSubscriptionCookie);
}


// ~ServiceImpl
ServiceImpl::~ServiceImpl()
{
	if(m_dwSubscriptionCookie)
		g_pConnectionPoint->unadvise(m_dwSubscriptionCookie);
}


// Init
HRESULT ServiceImpl::Init(const ce::string& strBaseURL)
{
    // convert URLs to absolute
    char    pszAbsoluteURL[INTERNET_MAX_URL_LENGTH];
    DWORD   dw;
    
    InternetCombineUrlA(strBaseURL, m_strDescriptionURL, pszAbsoluteURL, &(dw = sizeof(pszAbsoluteURL)/sizeof(*pszAbsoluteURL)), 0);
    m_strDescriptionURL = pszAbsoluteURL;
    
    if(!g_pURL_Verifier->is_url_ok(m_strDescriptionURL))
	{
	    TraceTag(ttidError, "ServiceImpl::Init: invalid service description URL");
	    return m_hrInitResult = E_FAIL;
	}
    
    InternetCombineUrlA(strBaseURL, m_strControlURL, pszAbsoluteURL, &(dw = sizeof(pszAbsoluteURL)/sizeof(*pszAbsoluteURL)), 0);
    m_strControlURL = pszAbsoluteURL;
    
    if(!g_pURL_Verifier->is_url_ok(m_strControlURL))
	{
	    TraceTag(ttidError, "ServiceImpl::Init: invalid service control URL");
	    return m_hrInitResult = E_FAIL;
	}
    
    InternetCombineUrlA(strBaseURL, m_strEventsURL, pszAbsoluteURL, &(dw = sizeof(pszAbsoluteURL)/sizeof(*pszAbsoluteURL)), 0);
    m_strEventsURL = pszAbsoluteURL;
    
    if(!g_pURL_Verifier->is_url_ok(m_strEventsURL))
	{
	    TraceTag(ttidError, "ServiceImpl::Init: invalid service events URL");
	    return m_hrInitResult = E_FAIL;
	}
    
    // request service description document
    HttpRequest request;

	if(!request.Open("GET", m_strDescriptionURL))
		return request.GetHresult();
	
	if(!request.Send())
		return request.GetHresult();
	
	if(HTTP_STATUS_OK != request.GetStatus())
		return request.GetHresult();
	
    ce::SAXReader                       Reader;
    ce::SequentialStream<HttpRequest>   Stream(request, upnp_config::max_document_size());
    
    // parse service description document
    if(Reader.valid())
    {
        ce::variant v;
        
        Stream.QueryInterface(IID_ISequentialStream, (void**)&v.punkVal);
        v.vt = VT_UNKNOWN;
        
        Reader->putContentHandler(this);

        m_hrInitResult = Reader->parse(v);
        
        if(FAILED(m_hrInitResult))
            TraceTag(ttidError, "SAXXMLReader::parse returned error 0x%08x", m_hrInitResult);
    }
    else
        m_hrInitResult = Reader.Error();

    if(SUCCEEDED(m_hrInitResult) && (m_strSpecVersionMajor != L"1" || m_strSpecVersionMinor != L"0"))
	{
	    TraceTag(ttidError, "ServiceImpl: Invalid document version");
	    m_hrInitResult = E_FAIL;
	}
    
    if(SUCCEEDED(m_hrInitResult))
    {
        // Bind state variables to action arguments
        for(ce::vector<Action>::iterator it = m_Actions.begin(), itEnd = m_Actions.end(); it != itEnd; ++it)
            it->BindArgumentsToStateVars(m_StateVars.begin(), m_StateVars.end());
    }
    
    return m_hrInitResult;
}


// AddCallback
HRESULT ServiceImpl::AddCallback(IUPnPService* pUPnPService, IUnknown *punkCallback, DWORD* pdwCookie)
{
	callback c;
	HRESULT  hr;

	if(FAILED(m_hrInitResult))
        return m_hrInitResult;
        
	if(FAILED(m_hrAdviseResult))
		return m_hrAdviseResult;

	Assert(m_dwSubscriptionCookie != 0);
	
	if(!m_bSubscribed)
	{
		if(FAILED(hr = g_pConnectionPoint->subscribe(m_dwSubscriptionCookie, m_strEventsURL)))
			return hr;

		m_bSubscribed = true;
	}

	if(SUCCEEDED(punkCallback->QueryInterface(IID_IUPnPServiceCallback, (void**)&c.m_pUPnPServiceCallback)))
		c.m_type = callback::upnp_service_callback;
	else
		if(SUCCEEDED(punkCallback->QueryInterface(IID_IDispatch, (void**)&c.m_pDispatch)))
			c.m_type = callback::dispatch;
		else
			return E_FAIL;

	Assert(m_pUPnPService == NULL || m_pUPnPService == pUPnPService);
	
	m_pUPnPService = pUPnPService;
	
	ce::gate<ce::critical_section> _gate(m_csListCallback);

	m_listCallback.push_front(c);

	if(pdwCookie)
	{
		// return iterator as cookie
		Assert(sizeof(ce::list<callback>::iterator) == sizeof(*pdwCookie));
		*((ce::list<callback>::iterator*)pdwCookie) = m_listCallback.begin();
	}
	
	return S_OK;
}


// RemoveCallback
HRESULT ServiceImpl::RemoveCallback(DWORD dwCookie)
{
	HRESULT hr = E_INVALIDARG;
	
	if(FAILED(m_hrInitResult))
        return m_hrInitResult;
	
	Assert(sizeof(ce::list<callback>::iterator) == sizeof(dwCookie));
	ce::list<callback>::iterator itCallback = *((ce::list<callback>::iterator*)&dwCookie);

	ce::gate<ce::critical_section> _gate(m_csListCallback);

	// can't assume that dwCookie is a valid iterator so I look for it in the list
	for(ce::list<callback>::iterator it = m_listCallback.begin(), itEnd = m_listCallback.end(); it != itEnd; ++it)
		if(it == itCallback)
		{
			m_listCallback.erase(it);
			
			hr = S_OK;
			break;
		}

	return hr;
}


// StateVariableChanged
void ServiceImpl::StateVariableChanged(LPCWSTR pwszName, LPCWSTR pwszValue)
{
	ce::variant						varValue;
	ce::vector<StateVar>::iterator	itStateVar, itEndStateVar;

	// find the state variable
	for(itStateVar = m_StateVars.begin(), itEndStateVar = m_StateVars.end(); itStateVar != itEndStateVar; ++itStateVar)
		if(0 == wcscmp(itStateVar->GetName(), pwszName))
		{
			itStateVar->Decode(pwszValue, &varValue);
			break;
		}
	
	if(itStateVar != itEndStateVar)
	{
		ce::gate<ce::critical_section> _gate(m_csListCallback);

        for(ce::list<callback>::iterator it = m_listCallback.begin(), itEnd = m_listCallback.end(); it != itEnd; ++it)
			if(it->m_type == callback::upnp_service_callback)
			{
                // IUPnPServiceCallback callback
				it->m_pUPnPServiceCallback->StateVariableChanged(m_pUPnPService, pwszName, varValue);
			}
			else
			{
				// IDispatch callback
				Assert(it->m_type == callback::dispatch);

				DISPPARAMS  DispParams = {0};
				VARIANT     rgvarg[4];
				UINT        uArgErr;
				
				DispParams.cArgs = 4;
				DispParams.rgvarg = rgvarg;

				rgvarg[3].vt = VT_BSTR;
                rgvarg[3].bstrVal = SysAllocString(L"VARIABLE_UPDATE");
				
				// don't AddRef m_pUPnPService
                rgvarg[2].vt = VT_DISPATCH;
				rgvarg[2].pdispVal = m_pUPnPService;
				
				rgvarg[1].vt = VT_BSTR;
                rgvarg[1].bstrVal = SysAllocString(pwszName);

				VariantInit(&rgvarg[0]);
                
                if(SUCCEEDED(VariantCopy(&rgvarg[0], &varValue)))
                {
				    it->m_pDispatch->Invoke(DISPID_VALUE, IID_NULL, 0, DISPATCH_METHOD, &DispParams, NULL, NULL, &uArgErr);

                    VariantClear(&rgvarg[0]);
                }

                VariantClear(&rgvarg[1]);
                // don't clear rgvarg[2]
                VariantClear(&rgvarg[3]);
			}
	}
}


// AliveNotification
void ServiceImpl::AliveNotification(LPCWSTR pszUSN, LPCWSTR pszLocation, LPCWSTR pszAL, DWORD dwLifeTime)
{
}


// ServiceInstanceDied
void ServiceImpl::ServiceInstanceDied(LPCWSTR pszUSN)
{
	if(!m_bServiceInstanceDied)
    {
        ce::gate<ce::critical_section> _gate(m_csListCallback);

        m_bServiceInstanceDied = true;
        
        for(ce::list<callback>::iterator it = m_listCallback.begin(), itEnd = m_listCallback.end(); it != itEnd; ++it)
		    if(it->m_type == callback::upnp_service_callback)
		    {
                // IUPnPServiceCallback callback
			    it->m_pUPnPServiceCallback->ServiceInstanceDied(m_pUPnPService);
		    }
		    else
		    {
			    // IDispatch callback
			    Assert(it->m_type == callback::dispatch);

			    DISPPARAMS  DispParams = {0};
			    VARIANT     rgvarg[2];
			    UINT        uArgErr;
			    
			    DispParams.cArgs = 2;
			    DispParams.rgvarg = rgvarg;

			    rgvarg[1].vt = VT_BSTR;
                rgvarg[1].bstrVal = SysAllocString(L"SERVICE_INSTANCE_DIED");
			    
			    // don't AddRef m_pUPnPService
                rgvarg[0].vt = VT_DISPATCH;
			    rgvarg[0].pdispVal = m_pUPnPService;

			    it->m_pDispatch->Invoke(DISPID_VALUE, IID_NULL, 0, DISPATCH_METHOD, &DispParams, NULL, NULL, &uArgErr);

                VariantClear(&rgvarg[1]);
                // don't clear rgvarg[0]
		    }
    }
}


// DispGetParamPtr
HRESULT DispGetParamPtr(DISPPARAMS FAR *pDispParams, unsigned int position, VARIANTARG** ppVar, unsigned int FAR *puArgErr)
{
    unsigned int cPositionArgs = pDispParams->cArgs - pDispParams->cNamedArgs;

    // check if the argument is among positional arguments
    if(position < cPositionArgs)
    {
        *ppVar = &pDispParams->rgvarg[pDispParams->cArgs - position - 1];
        return S_OK;
    }

    // look for the argument among named arguments
    for(unsigned int i = 0; i < pDispParams->cNamedArgs; ++i)
        if(static_cast<DISPID>(position) == pDispParams->rgdispidNamedArgs[i])
        {
            *ppVar = &pDispParams->rgvarg[i];
            return S_OK;
        }
    
    CHECK_POINTER(puArgErr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -