Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

View UPnP Services and also View UPnP DLNA Services

4.91/5 (4 votes)
11 Jan 2024CPOL2 min read 5.5K   609  
An application to view UPnP services and also to view UPnP DLNA services
Allows you to view UPnP and DNLA links which allows you to connect to DNLA servers to view photos, listen to music and watch movies.

Introduction

There are two tabs, one to view UPnP services and another to view DLNA services. Each tab has a button to acquire the data. For the UPnP, we display in the form of a tree: the Devices, Services, Actions and finally, the Parameters.

Right-clicking on an action displays a pop-up menu that allows after populating the parameters in a pop'up to perform the action. The output parameters of the action are displayed under the tree.

Clicking on a tree node displays the data for that node.

For the DNLA, the DNLA data is displayed as a tree, too. A double-click on the node of the tree allows:

  • If it's a container to visualize its contents
  • If it's a leaf, show it in the control Window Media Player (image, music, movie)

The UPNP Part

Microsoft suggests that you do not acquire Devices, Services, Actions, and Settings in the Windows message loop. So I created a thread with synchronization by event.

Since the call of the actions must be done in the same execution context as the acquisition, the Actions are also called in the thread, which will remain active while the application is active. The exchanges of parameters with the actions are done with two arrays of objects (there are disparate types in the array), one in input and one in output. It was a puzzle for me.

DLNA UPnP

I did not use a thread for this part as being too cumbersome to manage. The acquisitions are therefore in the message loop with the positioning of the waiting cursor.

This part is quite simple, the only problem I had was the Filter parameter of the Browse action which is a filter not on the elements, but on the values that are displayed for each element. Among other things, to have the display URL of the element, you must either put * or put "res". To test my application, I had DLNA of Synology and Windows 10. It is a good method to know all the multimedia of the PC.

Using the Code

Code of thread:

VB
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

The code to browse all Devices. I use recursivity for the path of the tree of devices / services:

VB
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

Now the code to display Devices. The nodes are not added to the Treeview, which is a control of the form because we are in the thread, so not in the same execution environment.

VB
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

Now the code to display Services, Actions and Parameters. The nodes are not added to the Treeview, which is a control of the form because we are in the thread, so not in the same execution environment.

VB
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

The code to call an Action with the parameters is as given below:

VB
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

History

  • 2nd July, 2019: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)