Registrando um retorno de chamada
Se o aplicativo exigir notificação quando o valor de uma variável de estado for alterado ou a instância de serviço que ele representa ficar indisponível, o aplicativo deverá registrar uma função de retorno de chamada. Para registrar uma função de retorno de chamada para o objeto de serviço a ser invocado, use o método IUPnPService::AddCallback . Esse método pode ser usado para registrar mais de um retorno de chamada.
Os desenvolvedores não devem cancelar uma operação assíncrona dentro de um retorno de chamada assíncrono.
Observação
Adicionar um retorno de chamada no Visual Basic é diferente do método usado no VBScript. A função GetRef usada no VBScript não está disponível no Visual Basic. Portanto, um desenvolvedor deve criar um objeto IDispatch que tenha a função de retorno de chamada como o método padrão. Consulte Registrando um retorno de chamada no Visual Basic.
Exemplo de VBScript
O código VBScript a seguir define o serviço de função de retorno de chamadaChangeCallback, a ser invocado quando os valores das variáveis de estado forem alterados ou quando a instância de serviço ficar indisponível. A função tem quatro argumentos.
O primeiro argumento para a função especifica o motivo pelo qual o retorno de chamada é invocado. Ele é invocado porque uma variável de estado foi alterada ou porque a instância de serviço ficou indisponível.
O segundo argumento é o objeto Service para o qual o retorno de chamada é invocado. Se o retorno de chamada for invocado para uma alteração de variável de estado, a função será passada para dois argumentos adicionais: o nome da variável que foi alterada e seu novo valor.
Neste exemplo, o retorno de chamada simplesmente exibe uma caixa de mensagem que mostra o nome da variável alterada e seu novo valor e se o retorno de chamada foi invocado para uma alteração de variável de estado. Caso contrário, ele exibirá uma mensagem que indica que a instância de serviço não está mais disponível.
A última parte do fragmento de código mostra como registrar a função de retorno de chamada usando o método AddCallback . Presume-se que as variáveis de objeto de serviço, appService e xportService foram inicializadas conforme mostrado em Obtendo objetos de serviço.
'State Change Callback Function
'Note: In the sub declaration statement below, VARIABLE_UPDATE
'is one of two possible values for the callbackType argument;
'the other is SERVICE_INSTANCE_DIED
Sub serviceChangeCallback(callbacktype, svcObj, varName, value)
If (callbacktype = "VARIABLE_UPDATE") then
Dim outString
outString = "State Variable Changed:" & vbCrLf
outString = outString & varName & " == " & value
MsgBox(outString, "Service Callback")
Else if (callbacktype = "SERVICE_INSTANCE_DIED") then
MsgBox("Service instance is no longer available",
"Service Callback")
End If
End Sub
' ...
'Add our state change callback to each service
appService.AddCallback GetRef("serviceChangeCallback")
xportService.AddCallback GetRef("serviceChangeCallback")
Exemplo de C++
#include <windows.h>
#include <upnp.h>
#include <stdio.h>
#pragma comment(lib, "oleaut32.lib")
class CUPnPServiceCallback : public IUPnPServiceCallback
{
public:
CUPnPServiceCallback()
{
m_lRefCount = 0;
};
STDMETHODIMP QueryInterface(REFIID iid, LPVOID* ppvObject)
{
HRESULT hr = S_OK;
if(NULL == ppvObject)
{
hr = E_POINTER;
}
else
{
*ppvObject = NULL;
}
if(SUCCEEDED(hr))
{
if(IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IUPnPServiceCallback))
{
*ppvObject = static_cast<IUPnPServiceCallback*>(this);
AddRef();
}
else
{
hr = E_NOINTERFACE;
}
}
return hr;
};
STDMETHODIMP_(ULONG) AddRef()
{
return ::InterlockedIncrement(&m_lRefCount);
};
STDMETHODIMP_(ULONG) Release()
{
LONG lRefCount = ::InterlockedDecrement(&m_lRefCount);
if(0 == lRefCount)
{
delete this;
}
return lRefCount;
};
STDMETHODIMP StateVariableChanged(IUPnPService *pus, LPCWSTR pcwszStateVarName, VARIANT varValue)
{
HRESULT hr = S_OK;
BSTR ServiceId;
hr = pus->get_Id(&ServiceId);
if (SUCCEEDED(hr))
{
VARIANT AlphaVariant;
VariantInit(&AlphaVariant);
hr = VariantChangeType(&AlphaVariant, &varValue, VARIANT_ALPHABOOL, VT_BSTR);
if(SUCCEEDED(hr))
{
printf("StateVariableChanged called for the %S service"
" for %S state variable with the value=%S.\n",
ServiceId, pcwszStateVarName, V_BSTR(&AlphaVariant));
VariantClear(&AlphaVariant);
}
SysFreeString(ServiceId);
}
return hr;
};
STDMETHODIMP ServiceInstanceDied(IUPnPService *pus)
{
HRESULT hr = S_OK;
BSTR ServiceType;
hr = pus->get_ServiceTypeIdentifier(&ServiceType);
if(SUCCEEDED(hr))
{
printf("ServiceInstanceDied called for the %S service!\n", ServiceType);
SysFreeString(ServiceType);
}
return hr;
};
private:
LONG m_lRefCount;
};
HRESULT AddCallbackToService(IUPnPService* pUPnPService)
{
HRESULT hr = S_OK;
IUnknown* pUPnPServiceCallback = new CUPnPServiceCallback;
if(NULL != pUPnPServiceCallback)
{
pUPnPServiceCallback->AddRef();
hr = pUPnPService->AddCallback(pUPnPServiceCallback);
pUPnPServiceCallback->Release();
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}