📄 serviceimpl.cpp
字号:
// argument not found
*puArgErr = position;
return DISP_E_PARAMNOTFOUND;
}
// GetIDsOfNames
HRESULT ServiceImpl::GetIDsOfNames(OLECHAR FAR *FAR *rgszNames,
unsigned int cNames,
DISPID FAR *rgDispId)
{
if(FAILED(m_hrInitResult))
return m_hrInitResult;
if(!cNames)
return S_OK;
CHECK_POINTER(rgszNames);
CHECK_POINTER(rgDispId);
unsigned int i;
// initialize all the names to unknown
for(i = 0; i < cNames; ++i)
rgDispId[i] = DISPID_UNKNOWN;
ce::vector<Action>::iterator it, itEnd;
// first name is method/property name
// actions (methods)
for(it = m_Actions.begin(), itEnd = m_Actions.end(); it != itEnd; ++it)
if(0 == wcscmp(it->GetName(), rgszNames[0]))
{
rgDispId[0] = base_dispid + (it - m_Actions.begin());
break;
}
if(it != itEnd)
{
// if there are more names they are those of method arguments
// check [in] arguments
for(i = 1; i < cNames; ++i)
{
for(int j = 0; j < it->GetInArgumentsCount(); ++j)
if(0 == wcscmp(it->GetInArgument(j).GetName(), rgszNames[i]))
{
Assert(rgDispId[i] == DISPID_UNKNOWN);
rgDispId[i] = j;
break;
}
}
// check [out] arguments
for(i = 1; i < cNames; ++i)
{
for(int j = 0, position = it->GetInArgumentsCount(); j < it->GetOutArgumentsCount(); ++j, ++position)
{
if(it->GetOutArgument(j).IsRetval())
{
// retval doesn't count as argument in IDispatch
--position;
continue;
}
if(0 == wcscmp(it->GetOutArgument(j).GetName(), rgszNames[i]))
{
Assert(rgDispId[i] == DISPID_UNKNOWN);
rgDispId[i] = position;
break;
}
}
}
}
else
{
// state variables (properties)
for(ce::vector<StateVar>::iterator itStateVar = m_StateVars.begin(), itEndStateVar = m_StateVars.end(); itStateVar != itEndStateVar; ++itStateVar)
if(0 == wcscmp(itStateVar->GetName(), rgszNames[0]))
{
rgDispId[0] = base_dispid + (itStateVar - m_StateVars.begin()) + m_Actions.size();
break;
}
}
// check if any names remain unknown
for(i = 0; i < cNames; ++i)
if(rgDispId[i] == DISPID_UNKNOWN)
return DISP_E_UNKNOWNNAME;
return S_OK;
}
// Invoke
HRESULT ServiceImpl::Invoke(DISPID dispIdMember,
WORD wFlags,
DISPPARAMS FAR *pDispParams,
VARIANT FAR *pVarResult,
EXCEPINFO FAR *pExcepInfo,
unsigned int FAR *puArgErr)
{
Action* pAction;
ce::variant var;
HRESULT hr;
int i;
unsigned int position;
if(FAILED(m_hrInitResult))
return m_hrInitResult;
if(wFlags & ~(DISPATCH_PROPERTYGET | DISPATCH_METHOD | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
return E_INVALIDARG;
if(dispIdMember < base_dispid && dispIdMember != query_state_var_dispid)
return DISP_E_MEMBERNOTFOUND;
// propput not supported by UPnP
if((wFlags == DISPATCH_PROPERTYPUT) || (wFlags == DISPATCH_PROPERTYPUTREF))
return DISP_E_MEMBERNOTFOUND;
if(dispIdMember >= base_dispid + m_Actions.size())
{
// from dispid it can only be propget
if(!(wFlags & DISPATCH_PROPERTYGET))
return DISP_E_MEMBERNOTFOUND;
// check if there is a state variable for this dispid
if(dispIdMember - base_dispid - m_Actions.size() >= m_StateVars.size())
return DISP_E_MEMBERNOTFOUND;
return QueryStateVariable(m_StateVars[dispIdMember - base_dispid - m_Actions.size()].GetName(), pVarResult);
}
else
{
// from dispid it can only be a method
if(!(wFlags & DISPATCH_METHOD))
return DISP_E_MEMBERNOTFOUND;
if(dispIdMember == query_state_var_dispid)
pAction = &m_actionQueryStateVar;
else
{
assert(dispIdMember >= base_dispid && dispIdMember < base_dispid + m_Actions.size());
pAction = &m_Actions[dispIdMember - base_dispid];
}
}
if(pDispParams->cArgs != pAction->GetInArgumentsCount() + GetActionOutArgumentsCount(dispIdMember))
return DISP_E_BADPARAMCOUNT;
// init [in] arguments
for(i = 0, position = 0; i < pAction->GetInArgumentsCount(); ++i, ++position)
{
Argument& arg = pAction->GetInArgument(i);
if(FAILED(hr = DispGetParam(pDispParams, position, arg.GetVartype(), &var, puArgErr)))
return hr;
arg.SetValue(var);
}
SoapRequest request;
// Send SOAP request
if(!request.SendMessage(m_strControlURL, pAction->GetSoapActionName(), pAction->CreateSoapMessage()))
{
DWORD dwErr = request.GetError();
if(dwErr == ERROR_SUCCESS)
dwErr = GetLastError();
assert(dwErr != ERROR_SUCCESS);
return HRESULT_FROM_WIN32(dwErr);
}
m_lLastTransportStatus = request.GetStatus();
if(request.GetError() != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(request.GetError());
// Parse SOAP response
if(FAILED(hr = pAction->ParseSoapResponse(request)))
return hr;
if(HTTP_STATUS_OK == m_lLastTransportStatus)
{
// return [out] arguments
for(i = 0, position = pAction->GetInArgumentsCount(); i < pAction->GetOutArgumentsCount(); ++i, ++position)
{
Argument& arg = pAction->GetOutArgument(i);
ce::variant varValue;
if(FAILED(hr = arg.GetValue(&varValue)))
return hr;
if(arg.IsRetval())
{
CHECK_POINTER(pVarResult);
// return [out] argument as result of the Invoke
if(FAILED(hr = VariantCopy(pVarResult, &varValue)))
return hr;
// retval doesn't count as argument in IDispatch
--position;
continue;
}
VARIANTARG* pvarOut;
// get pointer to variant for the [out] argument
if(FAILED(hr = DispGetParamPtr(pDispParams, position, &pvarOut, puArgErr)))
return hr;
// if [out] argument is VT_BYREF | VT_VARIANT then just return value in it
if(pvarOut->vt == (VT_BYREF | VT_VARIANT))
{
if(FAILED(hr = VariantCopy(V_VARIANTREF(pvarOut), &varValue)))
return hr;
continue;
}
// check if [out] parameter is a reference to proper type
if((pvarOut->vt ^ VT_BYREF) != varValue.vt)
{
CHECK_POINTER(puArgErr);
*puArgErr = position;
return DISP_E_TYPEMISMATCH;
}
Assert((pvarOut->vt ^ VT_BYREF) == varValue.vt);
switch(varValue.vt)
{
case VT_UI1: *V_UI1REF(pvarOut) = V_UI1(&varValue);
break;
case VT_UI2: *V_UI2REF(pvarOut) = V_UI2(&varValue);
break;
case VT_UI4: *V_UI4REF(pvarOut) = V_UI4(&varValue);
break;
case VT_I1: *V_I1REF(pvarOut) = V_I1(&varValue);
break;
case VT_I2: *V_I2REF(pvarOut) = V_I2(&varValue);
break;
case VT_I4: *V_I4REF(pvarOut) = V_I4(&varValue);
break;
case VT_R4: *V_R4REF(pvarOut) = V_R4(&varValue);
break;
case VT_R8: *V_R8REF(pvarOut) = V_R8(&varValue);
break;
case VT_CY: *V_CYREF(pvarOut) = V_CY(&varValue);
break;
case VT_BSTR: VariantClear(pvarOut);
*V_BSTRREF(pvarOut) = V_BSTR(&varValue);
break;
case VT_DATE: *V_DATEREF(pvarOut) = V_DATE(&varValue);
break;
case VT_BOOL: *V_BOOLREF(pvarOut) = V_BOOL(&varValue);
break;
case VT_ARRAY | VT_UI1:
VariantClear(pvarOut);
if(FAILED(hr = SafeArrayCopy(V_ARRAY(&varValue), V_ARRAYREF(pvarOut))))
return hr;
break;
default: Assert(0);
break;
}
}
Assert(m_lLastTransportStatus == HTTP_STATUS_OK);
return S_OK;
}
Assert(m_lLastTransportStatus != HTTP_STATUS_OK);
if(m_lLastTransportStatus != HTTP_STATUS_SERVER_ERROR)
return UPNP_E_TRANSPORT_ERROR;
switch(pAction->GetFaultCode())
{
case 0: return UPNP_E_PROTOCOL_ERROR;
case 401: return UPNP_E_INVALID_ACTION;
case 402: return UPNP_E_INVALID_ARGUMENTS;
case 403: return UPNP_E_DEVICE_ERROR; // TO DO: don't we need a specific error for this?
case 404: return UPNP_E_INVALID_VARIABLE;
case 501: return UPNP_E_ACTION_REQUEST_FAILED;
default:
return UPNP_E_ACTION_SPECIFIC_BASE + (pAction->GetFaultCode() - FAULT_ACTION_SPECIFIC_BASE);
}
}
// QueryStateVariable
HRESULT ServiceImpl::QueryStateVariable(LPCWSTR pwszVariableName, VARIANT *pValue)
{
DISPPARAMS DispParams;
ce::variant varStateVar;
unsigned int uArgErr;
if(FAILED(m_hrInitResult))
return m_hrInitResult;
ce::vector<StateVar>::iterator it, itEnd;
for(it = m_StateVars.begin(), itEnd = m_StateVars.end(); it != itEnd; ++it)
if(0 == wcscmp(pwszVariableName, it->GetName()))
break;
if(it == itEnd)
return UPNP_E_INVALID_VARIABLE;
// bind [out] argument to the state variable
m_actionQueryStateVar.GetOutArgument(0).BindStateVar(&*it);
// fabricate a DispParams structure
DispParams.cArgs = 1;
DispParams.cNamedArgs = 0;
DispParams.rgdispidNamedArgs = NULL;
DispParams.rgvarg = &(varStateVar = it->GetName());
return Invoke(query_state_var_dispid, DISPATCH_METHOD, &DispParams, pValue, NULL, &uArgErr);
}
// GetActionOutArgumentsCount
int ServiceImpl::GetActionOutArgumentsCount(DISPID dispidAction)
{
assert(!FAILED(m_hrInitResult));
int nCount = 0;
if(dispidAction >= base_dispid && dispidAction < base_dispid + m_Actions.size())
{
Action* pAction = &m_Actions[dispidAction - base_dispid];
// count not-retval [out] arguments
for(int i = 0; i < pAction->GetOutArgumentsCount(); ++i)
{
if(!pAction->GetOutArgument(i).IsRetval())
++nCount;
}
}
return nCount;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -