WPFxUPnP 2 その3

WPFxUPnP 2 その3

久しぶりに、UPnPのデバイスについて・・・。

まずは、UPnPのライトのデバイスクラスを作成します。

public class UPnPLightDevice : INotifyPropertyChanged
{
    public UPnPDevice Device { get; set; }
    public UPnPService SwitchPowerService { get; set; }

    public UPnPLightDevice(UPnPDevice pDevice)
    {
        try
        {
            Device = (UPnPDevice)Marshal.GetUniqueObjectForIUnknown(Marshal.GetIUnknownForObject(pDevice));

            SwitchPowerService = Device.Services["urn:upnp-org:serviceId:SwitchPower:1"];
            SwitchPowerService.AddCallback(this);
        }
        catch (Exception)
        {
            if (SwitchPowerService != null)
            {
                Marshal.ReleaseComObject(SwitchPowerService);
            }
            if (Device != null)
            {
                Marshal.ReleaseComObject(Device);
            }
            throw;
        }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    bool _Status = false;
    public bool Status
    {
        get { return _Status; }
        set
        {
            _Status = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Status"));
            }
        }
    }

コンストラクタで、DeviceFinderで見つけたUPnPDeviceを残し、そこから、urn:upnp-org:serviceId:SwitchPower:1サービスを取得します。
後は、ライトの値をプロパティとして、出して、値が変わるとINotifyPropertyChangedを用いて、WPFへ変更通知を送るようにしています。

そして、urn:upnp-org:serviceId:SwitchPower:1のアクションをそれぞれ定義します。

    public void SetTarget(bool status)
    {
        object[] inarg = new object[1] { (status ? 1 : 0) };
        object[] outarg = new object[1];
        SwitchPowerService.InvokeAction("SetTarget", inarg, outarg);
    }

    public bool GetTarget()
    {
        object[] inarg = new object[1];
        object outarg = new object();
        SwitchPowerService.InvokeAction("GetTarget", inarg, ref outarg);
        return (bool)(((object[])outarg)[0]);
    }

    public bool GetStatus()
    {
        object[] inarg = new object[1];
        object outarg = new object();
        SwitchPowerService.InvokeAction("GetStatus", inarg, ref outarg);
        return (bool)(((object[])outarg)[0]);
    }

あと、SwitchPowerService.AddCallback(this);で、urn:upnp-org:serviceId:SwitchPower:1サービスの状態変更通知を貰えるように、設定します。
AddCallbackで指定するには、IUPnPServiceCallbackインターフェースを継承する必要があります。
よって、クラス定義が次のようになります。

public class UPnPLightDevice : IUPnPServiceCallback, INotifyPropertyChanged
{
・・・(省略)・・・
    #region IUPnPServiceCallback
    public void ServiceInstanceDied(UPnPService pus)
    {
        Marshal.ReleaseComObject(pus);
    }

    public void StateVariableChanged(UPnPService pus, string pcwszStateVarName, object vaValue)
    {
        try
        {
            if (pcwszStateVarName == "Status")
            {
                Status = ((bool)vaValue);
            }
        }
        catch (Exception) { }
        finally
        {
            Marshal.ReleaseComObject(pus);
        }
    }
    #endregion
}