title: How do I access services of UPnP device?
body: <p>The device: Belkin Wemo Switch<br/>
  Dev environment: MS VC++ 2010 on Windows7</p>
  
  <p>I'm trying to enumerate the services of a UPnP device using C++ from Windows.</p>
  
  <p>I've got the <code>IUPnPDevice</code> pointer and can access several properties.<br/>
  I've got the <code>IUPnPServices</code> pointer and can count the correct number of services (7).<br/>
  I use <code>QueryInterface()</code> to get the <code>IEnumVARIANT</code> pointer (which appears to succeed).<br/>
  However, the <code>Next()</code> method always fails with <code>HRESULT</code> of <code>0x80040500</code> - which translates as <code>Windows error 1280 (0x500) - ERROR_ALREADY_FIBER</code>.<br/>
  This error does not make any sense to me.</p>
  
  <p>(I've tried using both <code>IEnumVARIANT</code> and <code>IEnumUnknown</code> - as the docs indicate it could be either, but both produce the same result.)</p>
  
  <p>I've included below the complete source file, plus the output it produces.<br/>
  [Note: It's hardcoded to use the udn of my own device]</p>
  
  <p>I'd be very grateful if anyone can help as I'm currently stuck.</p>
  
  <p>Best regards,<br/>
  Dave</p>
  
  <p>Code:</p>
  
  <pre><code>// UpnpTest1.cpp : Defines the entry point for the console application.
  //
  
  #include "stdafx.h"
  
  #include &lt;windows.h&gt;
  #include &lt;upnp.h&gt;
  
  static void DumpComError(const TCHAR *api, HRESULT hr);
  
  int _tmain(int argc, _TCHAR* argv[])
  {
    int retcode=-1; // assume failure
  
    HRESULT hr = CoInitialize(0);
    if (hr==S_OK)
    {
      IUPnPDeviceFinder *deviceFinder=0;
      hr = CoCreateInstance(CLSID_UPnPDeviceFinder, 0, CLSCTX_INPROC_SERVER, IID_IUPnPDeviceFinder, (void**)&amp;deviceFinder);
      if (hr==S_OK)
      {
        IUPnPDevice *device=0;
        hr = deviceFinder-&gt;FindByUDN(L"uuid:Socket-1_0-221239K11002F6", &amp;device);
        if (hr==S_OK)
        {
          if (device)
          {
            TCHAR *manufacturer=0, *manufacturerUrl=0;
            TCHAR *description=0, *name=0, *modelUrl=0;
            TCHAR *serialNumber=0, *udn=0, *upc=0, *deviceType=0;
            TCHAR *presentationUrl=0;
  
            device-&gt;get_ManufacturerName(&amp;manufacturer);
            device-&gt;get_ManufacturerURL(&amp;manufacturerUrl);
            device-&gt;get_Description(&amp;description);
            device-&gt;get_FriendlyName(&amp;name);
            device-&gt;get_ModelURL(&amp;modelUrl);
            device-&gt;get_SerialNumber(&amp;serialNumber);
            device-&gt;get_UniqueDeviceName(&amp;udn);
            device-&gt;get_UPC(&amp;upc);
            device-&gt;get_Type(&amp;deviceType);
            device-&gt;get_PresentationURL(&amp;presentationUrl);
  
            _tprintf(_T("MANUFACTURER: %s [%s]\n"), manufacturer, manufacturerUrl);
            _tprintf(_T("MODEL:        %s [%s]\n              [%s]\n"), description, name, modelUrl);
            _tprintf(_T("DEVICE:       serial=%s\n              udn=%s\n              upc=%s\n              type=%s\n"), serialNumber, udn, upc, deviceType);
            _tprintf(_T("URL:          %s\n"), presentationUrl);
  
            IUPnPServices *services=0;
            hr = device-&gt;get_Services(&amp;services);
            if (hr==S_OK)
            {
              if (services)
              {
                long numberOfServices=0;
                services-&gt;get_Count(&amp;numberOfServices);
  
                if (numberOfServices&gt;0)
                {
                  IUnknown *unknown=0;
                  hr = services-&gt;get__NewEnum(&amp;unknown);
                  if (hr==S_OK)
                  {
                    if (unknown)
                    {
                      IEnumVARIANT *enumInterface=0;
                      hr = unknown-&gt;QueryInterface(IID_IEnumVARIANT,(void**)&amp;enumInterface);
                      if (enumInterface)
                      {
                        VARIANT var;
                        unsigned long fetched=0;
                        hr = enumInterface-&gt;Next(1, &amp;var, &amp;fetched);
  
                        if (hr==S_OK)
                        {
  
                        }
                        else
                          DumpComError(_T("IEnumVARIANT::Next"), hr);
                      }
                      else
                        DumpComError(_T("IUnknown::QueryInterface"), hr);
                    }
                    else
                      fprintf(stderr, "Failed to get enumeration interface.\n");
                  }
                  else
                    DumpComError(_T("IUPnPServices::get__NewEnum"), hr);
                }
                else
                  fprintf(stderr, "No services available.\n");
              }
              else
                fprintf(stderr, "Failed to get services collection.\n");
            }
            else
              DumpComError(_T("IUPnPDevice::get_Services"), hr);
          }
          else
            fprintf(stderr, "Device not found.\n");
        }
        else
          DumpComError(_T("IUPnPDeviceFinder::FindByUDN"), hr);
      }
      else
        DumpComError(_T("CoCreateIndex"), hr);
    }
    else
      DumpComError(_T("CoInitialize"), hr);
  
    return retcode;
  }
  
  static void AddBoolToString(const TCHAR *name, bool value, TCHAR *buf, int &amp;i, int max)
  {
    if (name &amp;&amp; *name &amp;&amp; value &amp;&amp; buf &amp;&amp; i&gt;=0)
      i += _snwprintf_s(&amp;buf[i], max-i, (max-i-1)*sizeof(TCHAR), _T("%s%s=YES"), (i&gt;0? _T("; "): _T("")), name);
  }
  
  static void AddIntToString(const TCHAR *name, int value, TCHAR *buf, int &amp;i, int max)
  {
    if (name &amp;&amp; *name &amp;&amp; value &amp;&amp; buf &amp;&amp; i&gt;=0)
      i += _snwprintf_s(&amp;buf[i], max-i, (max-i-1)*sizeof(TCHAR), _T("%s%s=%d"), (i&gt;0? _T("; "): _T("")), name, value);
  }
  
  static void DumpComError(const TCHAR *api, HRESULT hr)
  {
    bool failure   = (hr&amp;0x80000000? true: false);
    bool severe    = (hr&amp;0x40000000? true: false);
    bool microsoft = (hr&amp;0x20000000? false: true);
    bool ntStatus  = (hr&amp;0x10000000? true: false);
    bool xBit      = (hr&amp;0x08000000? true: false);
    int facility   = (hr&amp;0x07FF0000)&gt;&gt;16;
    int code       = (hr&amp;0x0000FFFF);
  
    TCHAR buf[1024]={0};
    int bufsize = sizeof(buf)/sizeof(TCHAR);
    int i=0;
  
    AddBoolToString(_T("failure"), failure, buf, i, bufsize);
    AddBoolToString(_T("severe"), severe, buf, i, bufsize);
    AddBoolToString(_T("microsoft"), microsoft, buf, i, bufsize);
    AddBoolToString(_T("ntStatus"), ntStatus, buf, i, bufsize);
    AddBoolToString(_T("xBit"), xBit, buf, i, bufsize);
    AddIntToString(_T("facility"), facility, buf, i, bufsize);
    AddIntToString(_T("code"), code, buf, i, bufsize);
  
    _ftprintf(stderr, _T("\n%s() failed, hr=0x%08x\n[%s]\n"), api, hr, buf);
  }
  </code></pre>
  
  <p>Output:
  It produces following output:</p>
  
  <pre><code>MANUFACTURER: Belkin International Inc. [http://www.belkin.com/]
  MODEL:        Belkin Plugin Socket 1.0 [WeMo Switch]
                [http://www.belkin.com/plugin/]
  DEVICE:       serial=221239K11002F6
                udn=uuid:Socket-1_0-221239K11002F6
                upc=123456789
                type=urn:Belkin:device:controllee:1
  URL:          http://192.168.1.16:49153/pluginpres.html
  
  IEnumVARIANT::Next() failed, hr=0x80040500
  [failure=YES; microsoft=YES; facility=4; code=1280]
  </code></pre>
  
  <p><strong>EDIT:</strong></p>
  
  <p>After a lot of dead-ends, I have managed to get this working by manually building the SOAP requests, and sending the requests via TCP using Windows sockets. Tricky bit was getting the syntax just right as I had no experience of SOAP before. [UPnP was useful to identify the IP address &amp; port number - as these can change]. Once up and running - it's actually a lot simpler than the UPnP interface. Let me know if you're interested and I can post the code... It doesn't directly answer the question I posed here, so it wouldn't make sense to answer my question with this detail.</p>
  
  <p>However, if you're interested, let me know and I can post the code.</p>
  
  <p>Cheers,<br/>
  Dave</p>