February 10, 2013

Using Universal Plug And Play (UPnP) with Delphi



UPnP is a set of networking protocols that allows discovery of networked devices supporting UPnP. For example, you can easily discover printers, Wi-Fi access points, internet gateways, Streaming servers and many other types of devices.

Microsoft Windows provides an API to use UPnP. This API is located in a DLL which basically exposes a COM interface. You’ll find the documentation on Microsoft MSDN website http://msdn.microsoft.com/en-us/library/windows/desktop/aa382303(v=vs.85).aspx.

UPnP API is not complex to use but, of course, is not written the “Delphi way”. This is why I wrote a Delphi layer above the API to ease its use.

I created an object TNetworkDeviceFinder which implement the call back functions that Microsoft API requires to discover UPnP devices connected on the network and expose the result as a set of properties and a single event.

To get an abstraction level, I had the choice to write a component or an interface. I selected to implement it as an interface. Basically you may use my TNetworkDeviceFinder object as a simple Delphi object or as an interface. The later is easier.

I wrote a complete demo application available from my website at http://www.overbyte.be/eng/blog_source_code.html. You can download full source code so I will only show here some significant portions. The demo application is interesting not only for his UPnP usage, but also as a model for a real application. It has those features:
  • Search for a UPnP device on the network using many criteria
  • List all UPnP devices on the network
  • Have his data persistent
  • Have if form position and size persistent
  • Store the INI file in Local/AppData folder (Win7 friendly)

The demo application in action looks like this:



On this screen dump, you see the result of the search for “WD TV Live” on the network. As you can see in the result, this is a Western Digital streaming media player. The search has been done by model name. The combobox allows you to search by all other datas.

Once you have discovered the device, you have at hand a lot of informations. For example, you have the PresentationURL which you can use to manage the device. You get the IP which can be used to access the streaming function.

Another example: Here I searched for “Sagem” in manufacturer name. The result is related to my internet router. You can use the resulting PresentationURL to have the IP address and later use it to open a port for NAT traversal.



There are countless applications…

All this is very easy using the TNetworkDeviceFinder object Id designed. Here are the stepas:

  1. Add UPnPFinder unit in the uses clause
  2. Declare a variable in the protected section:
FNetworkDeviceFinder : INetworkDeviceFinder;


  1. Initialize the variable, for example in the FormCreate event:
FNetworkDeviceFinder := TNetworkDeviceFinder.Create;


  1. Assign the event handler which is called when a device is found:
FNetworkDeviceFinder.OnSearchResult := SearchResultHandler;


  1. Write the handler for the event:
procedure TUPnPFinderDemoForm.SearchResultHandler(
Sender : TObject;
State : TSearchResultState;
var CancelFlag : Boolean);
begin
if State = srsNotFound then
Memo1.Lines.Add(FNetworkDeviceFinder?PresentationURL);
end;


  1. Start the search, for example from a ButtonClick event:
FNetworkDeviceFinder.StartSearchAsync(ndfwModelName, 'Sagem');


  1. When you don’t need the feature anymore, for example in the FormDestroy, cancel any pending search and free the interface:
if Assigned(FNetworkDeviceFinder) then begin
FNetworkDeviceFinder.CancelSearchAsync;
FNetworkDeviceFinder := nil;
end;

That’s it! You will find complete source code for the demo and the object at my website: http://www.overbyte.be/frame_index.html?redirTo=/blog_source_code.html
This article is located at:
http://francois-piette.blogspot.be/2013/02/using-universal-plug-and-play-upnp-with.html

If you like this article, please share it!
Follow me on Twitter



3 comments:

Christophe Ravaut said...

Nice, I approched my Philips Streamium (WaC7500) with Delphi and the upnp.dll. I also use the TIdUDPClient.

Unknown said...

Your link to the MSN site has an ')' at the end which causes it to not load.

Mark said...

Thanks for posting this code. Unfortunately it does not find all the devices that other tools find. It does not appear to be an error in your implementation of the Windows interface. I am not sure what is the problem. I have searched and I see nothing that would prevent all the devices from being found.