Mendaftarkan Panggilan Balik

Jika aplikasi memerlukan pemberitahuan ketika nilai variabel status berubah atau instans layanan yang diwakilinya menjadi tidak tersedia, aplikasi harus mendaftarkan fungsi panggilan balik. Untuk mendaftarkan fungsi panggilan balik untuk objek layanan yang akan dipanggil, gunakan metode IUPnPService::AddCallback. Metode ini dapat digunakan untuk mendaftarkan lebih dari satu panggilan balik.

Pengembang tidak boleh membatalkan operasi asinkron di dalam panggilan balik asinkron.

Nota

Menambahkan panggilan balik di Visual Basic berbeda dari metode yang digunakan dalam VBScript. Fungsi GetRef yang digunakan dalam VBScript tidak tersedia di Visual Basic. Oleh karena itu, pengembang harus membuat objekIDispatchyang memiliki fungsi panggilan balik sebagai metode default. Lihat Mendaftarkan Panggilan Balik di Visual Basic.

 

Contoh VBScript

Kode VBScript berikut mendefinisikan fungsi panggilan balik serviceChangeCallback, untuk dipanggil ketika nilai variabel status berubah atau ketika instans layanan menjadi tidak tersedia. Fungsi ini memiliki empat argumen.

Argumen pertama untuk fungsi menentukan alasan panggilan balik dipanggil. Ini dipanggil baik karena variabel status berubah, atau karena instans layanan telah menjadi tidak tersedia.

Argumen kedua adalah objek Layanan di mana callback dieksekusi. Jika panggilan balik dipanggil untuk perubahan variabel status, maka fungsi diteruskan dua argumen tambahan: nama variabel yang berubah, dan nilai barunya.

Dalam contoh ini, panggilan balik hanya menampilkan kotak pesan yang menunjukkan nama variabel yang diubah dan nilai barunya, dan jika panggilan balik dipanggil untuk perubahan variabel status. Jika tidak, ini menampilkan pesan yang menunjukkan instans layanan tidak lagi tersedia.

Bagian terakhir dari fragmen kode menunjukkan cara mendaftarkan fungsi panggilan balik menggunakan metodeAddCallback. Variabel objek layanan, appService dan xportService diasumsikan telah diinisialisasi seperti yang ditunjukkan dalam Mendapatkan Objek Layanan.

'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")

Contoh 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;
}