Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Quick start?
05-02-2013, 07:41 AM (This post was last modified: 05-02-2013 08:39 AM by J4N.)
Post: #1
Quick start?
Hi,

I'm a developer and I need to implement an upnp discovery / register of devices.

Somebody recommend me your lib on stackoverflow, so I'm giving it a try. But for now, it's really complex to me to make me a clear idea, for the following reason:
  • You have not less than 56 DLL, how should I know which one I need? What is those "1" or "2" at the end?
  • I just can't find any small example
  • Why can't I access directly to properties of a CpDevice through a property? Where can I find the exact name of each property?
  • I don't understand the AddRef/RemoveRef? Since we store a reference internaly, we have an active reference and the garbage collector should not be able to recycle this


I started a small test code, but I got an exception:
Code:
public class Tester : IDisposable
    {
        private Dictionary<String, CpDevice> m_devices;
        private CpDeviceListUpnpAll m_list;
        private Timer m_timer;

        public Tester()
        {
            m_list = new CpDeviceListUpnpAll(OnDeviceAdded, OnDeviceRemove);
            m_timer = new Timer(5000);
            m_timer.Elapsed+=AskForRefresh;
            m_search = search;
        }

        private void AskForRefresh(object sender, ElapsedEventArgs e)
        {
            m_list.Refresh();
        }

        private void OnDeviceRemove(CpDeviceList alist, CpDevice adevice)
        {
            if(!m_devices.ContainsKey(adevice.Udn()))
            {
                m_devices[adevice.Udn()] = adevice;
                adevice.AddRef();
                String outAttribute;
                adevice.GetAttribute("Friendly name", out outAttribute);
                Console.WriteLine("Device added :" + outAttribute);
            }
        }

        private void OnDeviceAdded(CpDeviceList alist, CpDevice adevice)
        {
            if (m_devices.ContainsKey(adevice.Udn()))
            {
                m_devices.Remove(adevice.Udn());
                adevice.RemoveRef();
                String outAttribute;
                adevice.GetAttribute("Friendly name", out outAttribute);
                Console.WriteLine("Device removed :" + outAttribute);
            }
        }
        public void Start()
        {
            m_devices = new Dictionary<string, CpDevice>();
            m_timer.Start();
        }

        public void Stop()
        {
            m_timer.Stop();
        }

        public void Dispose()
        {
            Stop();
            m_list.Dispose();
        }
    }

(I know that the code is not yet thread safe)

The exception:
Quote:System.DllNotFoundException was unhandled
Message=Unable to load DLL 'ohNet': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
Source=ohNet.net
TypeName=""
StackTrace:
at OpenHome.Net.ControlPoint.CpDeviceListUpnpAll.CpDeviceListCreateUpnpAll(Callback​Device aAdded, IntPtr aPtrAdded, CallbackDevice aRemoved, IntPtr aPtrRemoved)
at OpenHome.Net.ControlPoint.CpDeviceListUpnpAll..ctor(ChangeHandler aAdded, ChangeHandler aRemoved) in c:\hudson-smarties\workspace\ohNet-Nightly\PLATFORM\Windows-x86\ohNet\OpenHome\Net\Bindings\Cs\ControlPoint\CpDeviceUpnp.cs:line 243
at UPnPTest.Tester..ctor() in E:\Dev\Discovery\XMS_SW_Discovery_B\Solution\UPnPTest\Tester.cs:line 29
at UPnPTest.Program.Main(String[] args) in E:\Dev\Discovery\XMS_SW_Discovery_B\Solution\UPnPTest\Program.cs:line 12
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:

But I'm referencing the main dll "OhNet"

I used http://dependencywalker.com/ to check what is missing, and it's looks like it doesn't load GPSVC.DLL and IESHIMS.DLL ? But I can't add those reference to my project(Not recognized as COM component)
Find all posts by this user
05-02-2013, 09:59 AM
Post: #2
RE: Quick start?
(05-02-2013 07:41 AM)J4N Wrote:  Hi,

I'm a developer and I need to implement an upnp discovery / register of devices.

Somebody recommend me your lib on stackoverflow, so I'm giving it a try. But for now, it's really complex to me to make me a clear idea, for the following reason:
  • You have not less than 56 DLL, how should I know which one I need? What is those "1" or "2" at the end?

You need two of the DLLs, the rest are optional. The mandatory ones are ohNet.dll (the core UPnP stack, implemented in unmanaged C++) and ohNet.net.dll (.NET bindings to all the stack's APIs).

For information, the other DLLs are control point or device stack helpers for individual UPnP services. The form of the names is [Stack][Domain][Service][Version] where
  • Stack is Cp or Dv and signifies whether the class is relevant for control point or device stack
  • Domain is the domain (e.g. upnp.org, openhome.org) of the publisher of the service. (This is needed to guarantee uniqueness of class names in auto-generated code.)
  • Service is the name of the UPnP service
  • Version is the version number of the service. (The "1" or "2" at the end)

You are free to use any of these DLLs if you wish. You can also ignore them or place their source into your own DLL.

(05-02-2013 07:41 AM)J4N Wrote:  
  • I just can't find any small example

  • The TestProxy test app is the best example of a control point app. See OpenHome/Net/Bindings/Cs/ControlPoint/Tests/TestProxy.cs for the source. You can build it using make TestProxyCs

    See TestDvDevice - source at OpenHome/Net/Bindings/Cs/Device/Tests/TestDvDevice.cs, build with make TestDvDeviceCs for a device stack example.

    (05-02-2013 07:41 AM)J4N Wrote:  
  • Why can't I access directly to properties of a CpDevice through a property? Where can I find the exact name of each property?

  • Sorry, I'm not sure what you mean. Can you provide some examples of the types of properties you want to access?

    (05-02-2013 07:41 AM)J4N Wrote:  
  • I don't understand the AddRef/RemoveRef? Since we store a reference internaly, we have an active reference and the garbage collector should not be able to recycle this

  • Your use of AddRef and RemoveRef in the code you posted is good. You're probably correct that we could have found a way to avoid exposing these APIs in .NET but this would have caused some other difficulties. The library must be disposed before exit and all device references need to have been released when the library is closed so we couldn't wait for GC to free references. We'd also have needed a lot of extra documentation; at present all language bindings follow the same patterns so a single set of overview docs cover things.

    (05-02-2013 07:41 AM)J4N Wrote:  I started a small test code, but I got an exception:

    I'd guess the exception is saying that the .NET bindings in ohNet.net.dll failed to load the underlying stack in ohNet.dll. On Windows, you need to have these two DLLs in the same directory; on Linux you may need to set LD_LIBRARY_PATH to point towards the unmanaged DLL.

    Once you get this sorted, you'll probably get a runtime exception. Your device list handling code is good but you need to initialise the library first. TestProxy contains an example of this:

    Code:
    Core.InitParams initParams = new Core.InitParams();
    using (Core.Library lib = Core.Library.Create(initParams))
    {
        Core.SubnetList subnetList = new Core.SubnetList();
        Core.NetworkAdapter nif = subnetList.SubnetAt(0);
        uint subnet = nif.Subnet();
        Console.WriteLine("Using adapter: {0}", nif.Name());
        subnetList.Dispose();
        lib.StartCp(subnet);
        // your code goes here.  block until your code completes
    }

    One other thing to consider, calling Refresh() on a device list under a timer may not be necessary. The device list starts by sending out a MSEARCH and reporting the responses to that via its Added delegate. It also listens for devices multicast ALIVE and BYEBYE notifications and will report these at any time via the Added and Remove delegates. There's no harm in also calling Refresh() periodically but the only thing it'll do is spot removal of devices which don't send a BYEBYE earlier and guard against the multicast messages being missed by your control point (unlikely on a wired connection; pretty common on iOS on a wireless connection).
    Find all posts by this user
    05-02-2013, 10:07 AM (This post was last modified: 05-02-2013 10:18 AM by J4N.)
    Post: #3
    RE: Quick start?
    (05-02-2013 09:59 AM)simonc Wrote:  
    (05-02-2013 07:41 AM)J4N Wrote:  [*]Why can't I access directly to properties of a CpDevice through a property? Where can I find the exact name of each property?

    Sorry, I'm not sure what you mean. Can you provide some examples of the types of properties you want to access?
    I mean by example the "FriendlyName", why can't I access with device.FriendlyName ?

    (05-02-2013 09:59 AM)simonc Wrote:  
    (05-02-2013 07:41 AM)J4N Wrote:  I started a small test code, but I got an exception:

    I'd guess the exception is saying that the .NET bindings in ohNet.net.dll failed to load the underlying stack in ohNet.dll. On Windows, you need to have these two DLLs in the same directory; on Linux you may need to set LD_LIBRARY_PATH to point towards the unmanaged DLL.

    Once you get this sorted, you'll probably get a runtime exception. Your device list handling code is good but you need to initialise the library first. TestProxy contains an example of this:

    Code:
    Core.InitParams initParams = new Core.InitParams();
    using (Core.Library lib = Core.Library.Create(initParams))
    {
        Core.SubnetList subnetList = new Core.SubnetList();
        Core.NetworkAdapter nif = subnetList.SubnetAt(0);
        uint subnet = nif.Subnet();
        Console.WriteLine("Using adapter: {0}", nif.Name());
        subnetList.Dispose();
        lib.StartCp(subnet);
        // your code goes here.  block until your code completes
    }
    First: I will always have multiple adapter, so I can't use any subnet to start the list
    Secondly: Seems that in the http://www.openhome.org/releases/artifac...ase.tar.gz archive(found on http://www.openhome.org/releases/artifacts/ohNet/ ), there is no ohNet.dll, only a ohNet.net.dll. Where should I get it?
    EDIT
    I saw the Bundle, which contains the library. Now I don't have the previous exception, but this one, when I instantiate the CpDeviceListUpnpAll:
    Quote:System.AccessViolationException was unhandled
    Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
    Source=ohNet.net
    StackTrace:
    at OpenHome.Net.ControlPoint.CpDeviceListUpnpAll.CpDeviceListCreateUpnpAll(Callback​Device aAdded, IntPtr aPtrAdded, CallbackDevice aRemoved, IntPtr aPtrRemoved)
    at OpenHome.Net.ControlPoint.CpDeviceListUpnpAll..ctor(ChangeHandler aAdded, ChangeHandler aRemoved)
    at UPnPTest.Tester..ctor() in E:\Dev\Discovery\XMS_SW_Discovery_B\Solution\UPnPTest\Tester.cs:line 29
    at UPnPTest.Program.Main(String[] args) in E:\Dev\Discovery\XMS_SW_Discovery_B\Solution\UPnPTest\Program.cs:line 12
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    at System.Threading.ThreadHelper.ThreadStart()
    InnerException:
    Find all posts by this user
    05-02-2013, 10:32 AM
    Post: #4
    RE: Quick start?
    (05-02-2013 10:07 AM)J4N Wrote:  I mean by example the "FriendlyName", why can't I access with device.FriendlyName ?

    No particular reason. We chose to use similar patterns for all language bindings but could always add additional functions to also allow device properties to be accessed via .NET properties.

    To answer your earlier question, the following device properties can be accessed using GetAttribute:
    • "Upnp.FriendlyName"
    • "Upnp.Location"
    • "Upnp.DeviceXml"
    • "Upnp.Root"
    • "Upnp.PresentationUrl"
    • "Upnp.Service.[name]"

    (05-02-2013 10:07 AM)J4N Wrote:  First: I will always have multiple adapter, so I can't use any subnet to start the list

    The control point stack can only operate on a single subnet at a time. If you have multiple adapters which operate on the same subnet (e.g. a laptop with wired and wireless adapters), it will automatically prefer the wired adapter then switch to wireless if the wired adapter goes down. If your adapters will be on different subnets, you'll need to choose which one to operate on.

    In both cases, the InitParams class allows you to register delegates which will run when the list of available subnets change.

    (05-02-2013 10:07 AM)J4N Wrote:  Secondly: Seems that in the http://www.openhome.org/releases/artifac...ase.tar.gz archive(found on http://www.openhome.org/releases/artifacts/ohNet/ ), there is no ohNet.dll, only a ohNet.net.dll. Where should I get it?
    EDIT
    I saw the Bundle, which contains the library. Now I don't have the previous exception, but this one, when I instantiate the CpDeviceListUpnpAll:

    Have you initialised the stack? My previous answer includes code you can use for this.
    Find all posts by this user
    05-02-2013, 10:42 AM (This post was last modified: 05-02-2013 11:32 AM by J4N.)
    Post: #5
    RE: Quick start?
    Here is how I modified my code with your response(and get the error):

    Code:
    public class Tester : IDisposable
        {
            private Dictionary<String, CpDevice> m_devices;
            private CpDeviceListUpnpAll m_list;
            private Library m_lib;
            private Timer m_timer;

            public Tester()
            {
                InitParams initParams = new InitParams();
                m_list = new CpDeviceListUpnpAll(OnDeviceAdded, OnDeviceRemove);
                m_lib = Library.Create(initParams);
                m_timer = new Timer(5000);
                m_timer.Elapsed += AskForRefresh;
            }

            private void AskForRefresh(object sender, ElapsedEventArgs e)
            {
                m_list.Refresh();
            }

            private void OnDeviceRemove(CpDeviceList alist, CpDevice adevice)
            {
                lock (m_list)
                {
                    if (!m_devices.ContainsKey(adevice.Udn()))
                    {
                        m_devices[adevice.Udn()] = adevice;
                        adevice.AddRef();
                        String outAttribute;
                        adevice.GetAttribute("Friendly name", out outAttribute);
                        Console.WriteLine("Device added :" + outAttribute);
                    }
                }
            }

            private void OnDeviceAdded(CpDeviceList alist, CpDevice adevice)
            {
                lock (m_list)
                {
                    if (m_devices.ContainsKey(adevice.Udn()))
                    {
                        m_devices.Remove(adevice.Udn());
                        adevice.RemoveRef();
                        String outAttribute;
                        adevice.GetAttribute("Friendly name", out outAttribute);
                        Console.WriteLine("Device removed :" + outAttribute);
                    }
                }
            }

            public void Start()
            {
                SubnetList subnetList = new SubnetList();
                NetworkAdapter nif = subnetList.SubnetAt(0);
                uint subnet = nif.Subnet();
                Console.WriteLine("Using adapter: {0}", nif.Name());
                subnetList.Dispose();
                m_lib.StartCp(subnet);
                m_timer.Start();
                m_devices = new Dictionary<string, CpDevice>();
            }

            public void Stop()
            {
                m_timer.Stop();
            }

            public void Dispose()
            {
                Stop();
                m_lib.Dispose();
                m_list.Dispose();
            }
        }

    It's two ethernet cable, which goes in different section of the enterprise, we have absolutely to detect devices on both entities(it's mostly because of this that we decided to not use the intel library anymore, because it wasn't managing well the multi-adapter configurations.

    EDIT
    I just saw that the Library.Create was called just after the initialization of the List, seems to work now. But I still have to figure out how to make it work with several adapter

    EDIT2
    I saw that I've less devices added than when I'm using the MangedUPnP library, any idea why? Here all printers, ... are not detected
    And for the device host, is there a sample of code in c#?
    Find all posts by this user
    05-02-2013, 11:37 AM
    Post: #6
    RE: Quick start?
    (05-02-2013 10:42 AM)J4N Wrote:  EDIT
    I just saw that the Library.Create was called just after the initialization of the List, seems to work now. But I still have to figure out how to make it work with several adapter

    Are these adapters on different subnets? If they are, I'm afraid ohNet won't be suitable for you. There is no way to persuade the control point stack to run on multiple subnets.

    Running multiple Library instances is nearly possible but would require some changes to various APIs.

    (05-02-2013 10:42 AM)J4N Wrote:  EDIT2
    I saw that I've less devices added than when I'm using the MangedUPnP library, any idea why? Here all printers, ... are not detected

    I've never had any report of ohNet missing devices during discovery... There are a couple of things you could try.

    If you have a lot of UPnP devices on your network, shorter MSEARCH times may lead to device responses being lost due to the msearching socket's recv buffer overflowing. ohNet defaults to requesting that MSEARCH responses are spread over 3 seconds. You could try increasing this to 5 seconds by changing InitParams.MsearchTimeSecs.

    If that doesn't help, see whether Intel Device Spy agrees with ManagedUpnp about the contents of your network (to check that ManagedUpnp isn't returning devices that respond to a MSEARCH but don't deliver device xml).
    Find all posts by this user
    05-02-2013, 11:42 AM (This post was last modified: 05-02-2013 11:46 AM by J4N.)
    Post: #7
    RE: Quick start?
    Hi,

    Intel Device Spy agrees with ManagedUpnp. Now I think that maybe it's because we are only listening one of the two network cards(they have the same name, I don't know which is which.

    I'm sad that this library doesn't fit my needs, it was looking promising :/. One last question, when we use Device Host, will it be announced on all subnet of all network cards? If this is the case, maybe I can use it for the device host(and not for the Client Control part)
    And do you have one c# example for device host?
    Find all posts by this user
    05-02-2013, 11:48 AM
    Post: #8
    RE: Quick start?
    (05-02-2013 11:42 AM)J4N Wrote:  Intel Device Spy agrees with ManagedUpnp. Now I think that maybe it's because we are only listening one of the two network cards(they have the same name, I don't know which is which.

    Ok, that'd make sense.

    (05-02-2013 11:42 AM)J4N Wrote:  I'm sad that this library doesn't fit my needs, it was looking promising :/. One last question, when we use Device Host, will it be announced on all subnet of all network cards? If this is the case, maybe I can use it for the device host(and not for the Client Control part)

    Yes, the device stack operates on all available subnets by default. So long as you avoid calling Library.SetCurrentSubnet, devices are advertised and respond on all active adapters. The stack will detect if the list of available adapters changes and will also advertise devices on any adapters that appear at runtime.
    Find all posts by this user
    05-02-2013, 12:11 PM
    Post: #9
    RE: Quick start?
    I currently have the following code to add a device:

    Code:
                InitParams initParams = new InitParams();
                m_lib = Library.Create(initParams);
                m_lib.StartDv();
                m_server = new DvServerUpnp();
                DvDeviceStandard dvDeviceStandard = new DvDeviceStandard(Guid.NewGuid().ToString());
                dvDeviceStandard.SetAttribute("Upnp.FriendlyName", "Test device");

                dvDeviceStandard.SetAttribute("Upnp.Domain", "av.openhome.org");
                dvDeviceStandard.SetAttribute("Upnp.Type", "XmsHostService");
                dvDeviceStandard.SetAttribute("Upnp.Version", "1");
                dvDeviceStandard.SetAttribute("Upnp.Manufacturer", "Meggitt SA");
                dvDeviceStandard.SetAttribute("Upnp.ManufacturerUrl", "http://www.meggitt.com");
                dvDeviceStandard.SetAttribute("Upnp.ModelDescription", "VibroSight Host Service UPnP Device");
                dvDeviceStandard.SetAttribute("Upnp.ModelName", "VibroSight Host Service Device");
                dvDeviceStandard.SetAttribute("Upnp.ModelNumber", "1");
                dvDeviceStandard.SetAttribute("Upnp.ModelUrl", "");
                dvDeviceStandard.SetAttribute("Upnp.SerialNumber", "");
                dvDeviceStandard.SetAttribute("Upnp.Upc", "");
                m_server.AddDevice(dvDeviceStandard);
                dvDeviceStandard.SetEnabled();

    But how do we add a service on this device?
    Find all posts by this user
    05-02-2013, 12:15 PM
    Post: #10
    RE: Quick start?
    (05-02-2013 12:11 PM)J4N Wrote:  I currently have the following code to add a device:

    [snip]

    But how do we add a service on this device?

    Short answer, have you seen the Device Stack overview doc at http://www.openhome.org/wiki/OhNet ?

    I'll post a longer answer later if this isn't enough info.
    Find all posts by this user


    Forum Jump: