註冊回呼
如果應用程式在狀態變數的值變更或它所代表的服務實例變成無法使用時需要通知,應用程式必須註冊回呼函式。 若要註冊要叫用之服務物件的回呼函式,請使用 IUPnPService::AddCallback 方法。 這個方法可用來註冊多個回呼。
開發人員不應該取消非同步回呼內的非同步作業。
注意
在 Visual Basic 中新增回呼與 VBScript 中使用的方法不同。 Visual Basic 中無法使用 VBScript 中使用的 GetRef 函式。 因此,開發人員必須建立 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;
}