When starting with UPnP development, some test projects, I initially started of with the Microsoft stack, as its already included in most Windows versions. But the documentation on the microsoft UPnP stack is so sparse, all examples I could find, were in C and then still only controlpoints, no devices. Hence I started using the Developer tools for UPnP (formerly by Intel). They contain a fully functional C# UPnP stack, and a code generator that generates a C stack. Just compile the C# stack and the resulting dll can be used from any (including VB) .NET language. Besides that the toolset contains a number of very usefull UPnP utilities.
The tools where initially available as the Intel UPnP tools, and after having disappeared from the Intel website for some time they have been relaunched as open source. Currently the stack is being maintained by Ylian Saint-Hilaire (Intel), and he does a good job at it (several bugfixes and improvements I submitted landed in the code quickly). Its a pitty that there isn’t a public forum for the UPnP tools.
This post is mostly about my experiences getting things up-and-running using the C# stack, which has its peculiarities, so here is what I learned;
Getting the stack in Visual Studio 2008
To get that working I took the following steps; In the source package, open the UPnP project (C#), its located in the GLOBAL directory (The solution file was VS2010, so I opened the Project file, which opened just fine in VS2008). Once opened, build the project to generate the DLL. For these steps there is no C# knowledge required, whatsoever.
IntelliSense comments are available, not very detailed, but together with the sample applications its enough to get you going. IntelliSense is not readily available though, the XML generation has been switched off (probably because it generates warnings when building the C# stack). To fix it, all you have to do is open the project properties and tick the checkbox for XML documentation generation.
Concepts of the method calls
Whenever you add a UPnP method, you provide an object to handle it. The C# stack uses reflection to find the named method on that object and execute it. So if you have a UPnP method called “SetTarget”, then your object must also have a method called “SetTarget” (and obviously the method must be a public member of the object). The same applies for the parameters the method takes, the names must match exactly. Because of this setup, the values that should be returned from a method call, are always passed back through the parameters of the method, they are never functions with return values (see also the ‘Coding with VB’ section below).
The beauty of it is that, once the object has been set up, the UPnP stack only behaves as a very transparent translation layer between the programmatic object and the UPnP communications with the outside world.
Order of creating things
1) create a Device object
2) create a Service object
3) create the methods for the service object
4) create a Statevariable
5) create the relationship between a statevariable (created in step 4) and the related method(s) (created in step 3)
6) add the statevariable to the service object, and if you need more statevariables, go back to step 4
8) add the service to the device, and if you need more services, go back to step 2
If you start your device, but it doesn’t show up on the network (the DeviceSpy utility is great for this), you probably missed something here. In this respect its the same as with the types, the stack is very picky, doesn’t always throw an exception, but just doesn’t work in these cases.
The stack is very picky about types
The types defined for methods and parameters must match and the stack is very picky about it! The method/statevariable definitions must match the types used in .NET. Consider this;
Dim x as Byte = 10
‘ y is a StateVariable, of type Byte
MyUPnPService.SetStateVariable("y", x * 10)
Will not work and will not throw an exception. x is a Byte type, but the result of x * 10 is considered an Integer, so there is a type mismatch. The stack will not throw an exception, but will report it in its internal debugging log. Check the code of the sample apps, at startup it will check for a ‘/DEBUG’ commandline option, if set it will show the debug window. Whenever you see inexplicable things happen (or not happen), use this internal debug log to check for additional exceptions. If you don’t these bugs will be very hard to track.
Coding in Visual Basic
In C# a function/method, can use the ‘out’ keyword to indicate that the value of a parameter is passed by reference (and any changes to the value will be passed back to the calling code), similar to the ‘ByRef’ keyword in Visual Basic. But unfortunately its not that simple, because of the difference between C# and Visual Basic an additional interop attribute must be specified to make it work. The attribute must be specified for each parameter of a method call that should pass its contents back to the calling code.
public void GetStatus(out bool ResultStatus)
ResultStatus = lightState;
Equivalent in VB;
Public Sub GetStatus(<System.Runtime.InteropServices.Out()> ByRef ResultStatus As Boolean)
ResultStatus = lightState
(Unfortunately in the code sample the ‘<’ and ‘>’ characters only show as ‘<’ and ‘>’. Have to fix that on the blog someday..)
If all else fails
I try to just use the generated UPnP.dll in my projects, but when I really can’t figure out what/why it doesn’t work, I just add the source project to the solution and step through the UPnP stack to find the nasty bug I’m hunting.