Регистрация обратного вызова
Если приложению требуется уведомление о том, что значение переменной состояния изменяется или экземпляр службы, который оно представляет, становится недоступным, приложение должно зарегистрировать функцию обратного вызова. Чтобы зарегистрировать функцию обратного вызова для вызываемого объекта службы, используйте метод IUPnPService::AddCallback . Этот метод можно использовать для регистрации нескольких обратных вызовов.
Разработчики не должны отменять асинхронную операцию внутри асинхронного обратного вызова.
Примечание
Добавление обратного вызова в Visual Basic отличается от метода, используемого в VBScript. Функция GetRef , используемая в VBScript, недоступна в Visual Basic. Поэтому разработчик должен создать объект IDispatch с функцией обратного вызова в качестве метода по умолчанию. См . раздел Регистрация обратного вызова в Visual Basic.
Пример VBScript
Следующий код VBScript определяет функцию обратного вызова serviceChangeCallback, вызываемую при изменении значений переменных состояния или когда экземпляр службы становится недоступным. Функция имеет четыре аргумента.
Первый аргумент функции указывает причину вызова обратного вызова. Он вызывается либо из-за изменения переменной состояния, либо из-за недоступности экземпляра службы.
Второй аргумент — объект Service, для которого вызывается обратный вызов. Если обратный вызов вызывается для изменения переменной состояния, то функции передаются два дополнительных аргумента: имя измененной переменной и ее новое значение.
В этом примере обратный вызов просто отображает окно сообщения, в котором отображается имя измененной переменной и ее новое значение, а также значение , если обратный вызов был вызван для изменения переменной состояния. В противном случае отображается сообщение о том, что экземпляр службы больше недоступен.
В последней части фрагмента кода показано, как зарегистрировать функцию обратного вызова с помощью метода AddCallback . Предполагается, что переменные объекта службы, appService и xportService были инициализированы, как показано в разделе Получение объектов службы.
'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")
Пример 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;
}