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:
Public Class UCUPnPDisplay
Dim MyThread As Thread = Nothing
Public Event FinThread(ByVal sender As Object, ByVal e As EventArgs)
Public Event FinInvokeAction(ByVal sender As Object, ByVal e As EventArgsFinInvokeAction)
Public Delegate Sub MySubDelegateEventFinThread()
Dim MyInvokeMyAction As InvokeMyAction
ReadOnly MyEvent As New AutoResetEvent(False)
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
Public Sub ThreadProc()
Dim deviceFinder As New UPnPDeviceFinder()
Dim myupnpDev As UPnPDevice = Nothing
Dim mediaServerDevices As UPnPDevices = deviceFinder.FindByType("upnp:rootdevice", 0)
ClTreeNodeUPnP.BuildDevice(mediaServerDevices, MyRacine.Nodes)
Dim msd As MySubDelegateEventFinThread = AddressOf RaiseMyEventFinThread
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:
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.
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)
XmlDoc = New XmlDocument()
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.
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)
XmlDoc = New XmlDocument()
XmlDoc.Load(localXmlFileName)
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:
Private Sub ExécuterLactionToolStripMenuItem_Click(sender As Object, e As EventArgs) _
Handles ExécuterLactionToolStripMenuItem.Click
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