65.9K
CodeProject 正在变化。 阅读更多。
Home

查看 UPnP 服务,以及查看 UPnP DLNA 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (4投票s)

2019年7月2日

CPOL

2分钟阅读

viewsIcon

5809

downloadIcon

655

一个用于查看 UPnP 服务和 UPnP DLNA 服务的应用程序

引言

有两个选项卡,一个用于查看 UPnP 服务,另一个用于查看 DLNA 服务。每个选项卡都有一个按钮来获取数据。对于 UPnP,我们以树形结构显示:设备、服务、动作,最后是参数。

右键单击一个动作会显示一个弹出菜单,允许在填充弹出窗口中的参数后执行该动作。动作的输出参数显示在树形结构下方。

单击树形结构中的一个节点会显示该节点的数据。

对于 DNLA,DNLA 数据也以树形结构显示。双击树形结构中的一个节点可以

  • 如果它是一个容器,则可视化其内容
  • 如果它是一个叶子节点,则在控制 Windows Media Player 中显示它(图像、音乐、电影)。

UPNP 部分

微软建议不要在 Windows 消息循环中获取设备、服务、动作和设置。因此,我创建了一个使用事件进行同步的线程。

由于动作的调用必须在与获取相同的执行上下文中完成,因此动作也在线程中调用,该线程将在应用程序活动期间保持活动状态。与动作的参数交换通过两个对象数组(数组中存在不同的类型)完成,一个用于输入,一个用于输出。这对我来说是一个难题。

DLNA UPnP

我没有为这部分使用线程,因为管理起来过于繁琐。因此,获取操作都在消息循环中进行,并带有等待光标的定位。

这部分非常简单,我遇到的唯一问题是 Browse 动作的 Filter 参数,它不是对元素的过滤,而是对每个元素显示的值的过滤。其中,要获得元素的显示 URL,必须放置 * 或放置 "res"。为了测试我的应用程序,我使用了 Synology 和 Windows 10 的 DLNA。这是一个了解 PC 所有多媒体的好方法。

Using the Code

线程代码

Public Class UCUPnPDisplay
    Dim MyThread As Thread = Nothing
    ' Event of end of display of Devices, Services, Actions, Parameters 
    Public Event FinThread(ByVal sender As Object, ByVal e As EventArgs)
    ' Event of end of call action
    Public Event FinInvokeAction(ByVal sender As Object, ByVal e As EventArgsFinInvokeAction)
    ' for calls from thread of the function of the form
    Public Delegate Sub MySubDelegateEventFinThread()
    ' parameters of InvokeAction between form and thread
    Dim MyInvokeMyAction As InvokeMyAction
    ' Synchronization between form and thread for InvokeAction
    ReadOnly MyEvent As New AutoResetEvent(False)
    ' to finish the thread
    Dim NotFini As Boolean = True


    Private Sub RaiseMyEventFinThread()
        RaiseEvent FinThread(Me, New EventArgs)
    End Sub

    Public Sub RaiseEventArgsFinInvokeAction(ByRef vInvokeMyActionElem As InvokeMyAction)
        RaiseEvent FinInvokeAction(Me, New EventArgsFinInvokeAction(vInvokeMyActionElem))
    End Sub
    ' code of the thread
    Public Sub ThreadProc()
        Dim deviceFinder As New UPnPDeviceFinder()
        Dim myupnpDev As UPnPDevice = Nothing
        ' "upnp:rootdevice"
        Dim mediaServerDevices As UPnPDevices = deviceFinder.FindByType("upnp:rootdevice", 0)
        ClTreeNodeUPnP.BuildDevice(mediaServerDevices, MyRacine.Nodes)
        ' Create an instance of the delegate.  
        Dim msd As MySubDelegateEventFinThread = AddressOf RaiseMyEventFinThread
        ' Call the method.  
        Me.Invoke(msd)
        While NotFini
            MyEvent.WaitOne()
            If NotFini Then
                MyInvokeMyAction.InvokeAction()
            End If
        End While
    End Sub

浏览所有设备的的代码。我使用递归来遍历设备/服务的树形结构

    Public Shared Sub BuildDevice(ByRef vDevices As UPnPDevices, _
           ByRef vNodes As TreeNodeCollection)
        For Each upnpDev As UPnPDevice In vDevices
            Dim node As New ClTreeNodeUPnPDevice(upnpDev)
            vNodes.Add(node)
            Try
                If upnpDev.Services.Count > 0 Then
                    For Each service As UPnPService In upnpDev.Services
                        Dim nodeServ As New ClTreeNodeUPnPService(service, node)
                        node.Nodes.Add(nodeServ)
                    Next
                End If
            Catch ex As Exception

            End Try
            If upnpDev.HasChildren Then
                BuildDevice(upnpDev.Children, node.Nodes)
            End If
        Next
    End Sub

现在是显示设备的的代码。节点没有添加到 Treeview(表单的控件),因为我们在线程中,不在相同的执行环境中。

Public Class ClTreeNodeUPnPDevice
        Inherits ClTreeNodeUPnP
        Public MyDevice As UPnPDevice
        Public IconURL As String = ""
        Public localIconFileName As String = ""
        Public descDocURL As String = ""
    Public Sub New(ByRef vUPnPDevice As UPnPDevice)
        MyDevice = vUPnPDevice
        BuildDisplayString()
        Me.ToolTipText = MyDisplayString
        Me.Text = MyDevice.FriendlyName
        IconURL = MyDevice.IconURL("image/png", 48, 48, 24)
        If IconURL IsNot Nothing Then
            localIconFileName = String.Concat_
            (My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData, "\", _
             MyDevice.UniqueDeviceName.Substring(MyDevice.UniqueDeviceName.IndexOf(":") _
             + 1), ".png")
            ClassGetHTTPFile.URLDownLoadToFile(IconURL, localIconFileName)
        End If
        Dim pDescDoc As IUPnPDeviceDocumentAccess
        pDescDoc = vUPnPDevice
        descDocURL = pDescDoc.GetDocumentURL()
        localXmlFileName = String.Concat_
        (My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData, "\", _
         MyDevice.UniqueDeviceName.Substring(MyDevice.UniqueDeviceName.IndexOf(":") _
         + 1), ".xml")
        ClassGetHTTPFile.URLDownLoadToFile(descDocURL, localXmlFileName)
        'création d'une nouvelle instance du membre xmldocument
        XmlDoc = New XmlDocument()
        'création du document
        XmlDoc.Load(localXmlFileName)
    End Sub

现在是显示服务、动作和参数的代码。节点没有添加到 Treeview(表单的控件),因为我们在线程中,不在相同的执行环境中。

Public Class ClTreeNodeUPnPService
    Inherits ClTreeNodeUPnP

    Public MyService As UPnPService
    Public Sub New(ByRef vService As UPnPService, vNServ As ClTreeNodeUPnPDevice)
        MyService = vService
        BuildDisplayString()
        Me.ToolTipText = MyDisplayString
        Me.Text = MyService.ServiceTypeIdentifier
        Dim nt As XmlNode = RechercherNoeudValeurArbre_
        (vNServ.XmlDoc.ChildNodes, "UDN", vNServ.MyDevice.UniqueDeviceName).ParentNode
        Dim racineUrl As String = vNServ.descDocURL
        Dim index As Integer
        For i As Integer = 0 To 2
            index = racineUrl.IndexOf("/", index + 1)
        Next
        racineUrl = racineUrl.Substring(0, index)
        nt = RechercherNoeudValeurArbre(nt.ChildNodes, "serviceID", vService.Id).ParentNode
        Dim UrlXml As String = RechercherValeurNoeud(nt.ChildNodes, "SCPDURL")
        localXmlFileName = String.Concat_
        (My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData, _
        "\", MyService.Id.Replace(":", "_"), ".xml")
        ClassGetHTTPFile.URLDownLoadToFile_
        (String.Concat(racineUrl, UrlXml), localXmlFileName)
        'création d'une nouvelle instance du membre xmldocument
        XmlDoc = New XmlDocument()
        'création du document
        XmlDoc.Load(localXmlFileName)
        '
        ' traitement des actions
        '
        Dim xmlNodeListAction = RechercherNoeudArbre(XmlDoc.ChildNodes, "actionList")
        Dim xmlNodeDescParam = RechercherNoeudArbre(XmlDoc.ChildNodes, "serviceStateTable")
        For Each xmlNodeAction As XmlNode In xmlNodeListAction.ChildNodes
            Dim nodeAction As New ClTreeNodeUPnPServiceAction With {
             .Text = RechercherValeurNoeud(xmlNodeAction.ChildNodes, "name")}
            Me.Nodes.Add(nodeAction)
            Dim xmlNodeListParametre = _
            RechercherNoeud(xmlNodeAction.ChildNodes, "argumentList")
            If xmlNodeListParametre IsNot Nothing Then
                For Each xmlNodeParametre As XmlNode In xmlNodeListParametre.ChildNodes
                    Dim nodeParametre As New ClTreeNodeUPnPServiceActionParametre
                    nodeAction.Nodes.Add(nodeParametre)
                    nodeParametre.Text = RechercherValeurNoeud_
                                         (xmlNodeParametre.ChildNodes, "name")
                    nodeParametre.SiDirectionIn = String.Compare_
                    (RechercherValeurNoeud(xmlNodeParametre.ChildNodes, "direction"), _
                    "in", True) = 0
                    Dim str As String = RechercherValeurNoeud_
                    (xmlNodeParametre.ChildNodes, "relatedStateVariable")
                    Dim xmlNodeCarPar As XmlNode = _
                    RechercherNoeudValeurArbre(xmlNodeDescParam.ChildNodes, _
                    "name", str).ParentNode
                    nodeParametre.DataType = RechercherValeurNoeud_
                    (xmlNodeCarPar.ChildNodes, "dataType")
                    Dim xmlNodeValueList As XmlNode = RechercherNoeud_
                    (xmlNodeCarPar.ChildNodes, "allowedValueList")
                    If xmlNodeValueList IsNot Nothing Then
                        For Each xmlNodeValue As XmlNode In xmlNodeValueList
                            nodeParametre.AllowedValue.Add(xmlNodeValue.InnerText)
                        Next
                    End If
                    Dim xmlNodeDefaultValue As XmlNode = _
                    RechercherNoeud(xmlNodeCarPar.ChildNodes, "defaultValue")
                    If xmlNodeDefaultValue IsNot Nothing Then
                        nodeParametre.DefaultValue = xmlNodeDefaultValue.InnerText
                        nodeParametre.IfDefauktValue = True
                    End If
                    Dim xmlNodeValueRange As XmlNode = _
                    RechercherNoeud(xmlNodeCarPar.ChildNodes, "allowedValueRange")
                    If xmlNodeValueRange IsNot Nothing Then
                        Dim xmlNodeMinmum As XmlNode = _
                        RechercherNoeud(xmlNodeValueRange.ChildNodes, "minimum")
                        If xmlNodeMinmum IsNot Nothing Then
                            nodeParametre.Minimum = xmlNodeMinmum.InnerText
                        End If
                        Dim xmlNodeMaximum As XmlNode = _
                        RechercherNoeud(xmlNodeValueRange.ChildNodes, "maximum")
                        If xmlNodeMaximum IsNot Nothing Then
                            nodeParametre.Maximum = xmlNodeMaximum.InnerText
                        End If
                        nodeParametre.IfMinMax = True
                    End If
                Next
            End If
        Next
  End Sub

调用带有参数的动作的代码如下所示

   Private Sub ExécuterLactionToolStripMenuItem_Click(sender As Object, e As EventArgs) _
        Handles ExécuterLactionToolStripMenuItem.Click 'AppelerLactionToolStripMenuItem
        If TypeOf TvwUPnP.SelectedNode Is ClTreeNodeUPnPServiceAction Then
            Dim dlg As New FrmGetInParameter
            Dim objectOut As New Object
            dlg.NodeAction = TvwUPnP.SelectedNode
            If dlg.ShowDialog() = DialogResult.OK Then
                MyInvokeMyAction = New InvokeMyAction_
                (CType(dlg.NodeAction.Parent, ClTreeNodeUPnPService).MyService, _
                dlg.NodeAction.Text, dlg.TabParametre, Me, dlg.NodeAction)
                MyEvent.Set()
            End If
        Else
            MessageBox.Show(My.Resources.YouMustSelectAnActionNode)
        End If
    End Sub

历史

  • 2019年7月2日:初始版本
© . All rights reserved.