如何访问UPnP设备的服务? [英] How do I access services of UPnP device?

查看:302
本文介绍了如何访问UPnP设备的服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

设备:Belkin Wemo Switch

开发环境:Windows 7上的MS VC ++ 2010



我试图枚举UPnP设备使用Windows中的C ++。



我有IUPnPDevice指针,可以访问几个属性。\\
我有IUPnPServices指针并且可以计算正确的服务数量(7)。
$
我使用QueryInterface()获取IEnumVARIANT指针(看起来成功)。

不过, )方法总是失败,HRESULT为0x80040500 - 这翻译为Windows错误1280(0x500) - ERROR_ALREADY_FIBER。

这个错误对我没有任何意义。



(我试过使用IEnumVARIANT和IEnumUnknown - 因为文档表明它可以是,但两者产生相同的结果。)



包括在完整的源文件下面,加上它产生的输出。

[注:硬编码以使用我自己的设备的udn]





最好的问候,

Dave



代码:

  // UpnpTest1.cpp:定义控制台应用程序的入口点。 
//

#includestdafx.h

#include< windows.h>
#include< upnp.h>

static void DumpComError(const TCHAR * api,HRESULT hr);

int _tmain(int argc,_TCHAR * argv [])
{
int retcode = -1; //假设失败

HRESULT hr = CoInitialize(0);
if(hr == S_OK)
{
IUPnPDeviceFinder * deviceFinder = 0;
hr = CoCreateInstance(CLSID_UPnPDeviceFinder,0,CLSCTX_INPROC_SERVER,IID_IUPnPDeviceFinder,(void **)& deviceFinder);
if(hr == S_OK)
{
IUPnPDevice * device = 0;
hr = deviceFinder-> FindByUDN(Luuid:Socket-1_0-221239K11002F6,&装置);
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-> get_ManufacturerName(& manufacturer);
device-> get_ManufacturerURL(& manufacturerUrl);
device-> get_Description(& description);
device-> get_FriendlyName(& name);
device-> get_ModelURL(& modelUrl);
device-> get_SerialNumber(& serialNumber);
device-> get_UniqueDeviceName(& udn);
device-> get_UPC(& upc);
device-> get_Type(& deviceType);
device-> get_PresentationURL(& presentationUrl);

_tprintf(_T(MANUFACTURER:%s [%s] \\\
),manufacturer,manufacturerUrl);
_tprintf(_T(MODEL:%s [%s] \\\
[%s] \\\
),description,name,modelUrl);
_tprintf(_T(DEVICE:serial =%s\\\
udn =%s\\\
upc =%s\\\
type =%s\\\
),serialNumber,udn,upc,deviceType) ;
_tprintf(_T(URL:%s\\\
),presentationUrl);

IUPnPServices * services = 0;
hr = device-> get_Services(& services);
if(hr == S_OK)
{
if(services)
{
long numberOfServices = 0;
services-> get_Count(& numberOfServices);

if(numberOfServices> 0)
{
IUnknown * unknown = 0;
hr = services-> get__NewEnum(& unknown);
if(hr == S_OK)
{
if(unknown)
{
IEnumVARIANT * enumInterface = 0;
hr = unknown-> QueryInterface(IID_IEnumVARIANT,(void **)& enumInterface);
if(enumInterface)
{
VARIANT var;
unsigned long fetched = 0;
hr = enumInterface->下一步(1,& var,& 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.\\\
);
}
else
DumpComError(_T(IUPnPServices :: get__NewEnum),hr);
}
else
fprintf(stderr,No services available.\\\
);
}
else
fprintf(stderr,无法获取服务集合。\\\
);
}
else
DumpComError(_T(IUPnPDevice :: get_Services),hr);
}
else
fprintf(stderr,Device not found.\\\
);
}
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& i,int max)
{
if(name& ;和名字&&&&& buf&& i> = 0)
i + = _snwprintf_s(& buf [i],max-i,(max- i- * sizeof(TCHAR),_T(%s%s = YES),(i> 0?_T(;):_T
}

static void AddIntToString(const TCHAR * name,int value,TCHAR * buf,int& i,int max)
{
if ;和名字&&&&& buf&& i> = 0)
i + = _snwprintf_s(& buf [i],max-i,(max- i- * sizeof(TCHAR),_T(%s%s =%d),(i> 0?_T(;):_T
}

static void DumpComError(const TCHAR * api,HRESULT hr)
{
bool failure =(hr& 0x80000000?true:false);
bool severe =(hr& 0x40000000?true:false);
bool microsoft =(hr& 0x20000000?false:true);
bool ntStatus =(hr& 0x10000000?true:false);
bool xBit =(hr& 0x08000000?true:false);
int facility =(hr& 0x07FF0000)>> 16;
int code =(hr& 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(\\\
%s()failed,hr = 0x%08x\\\
[%s] \\\
),api,hr,buf);
}

输出:
它产生以下输出:

 制造商:Belkin International Inc. [http://www.belkin.com/] 
型号: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()失败,hr = 0x80040500
[failure = YES; microsoft = YES; facility = 4; code = 1280]

EDIT:

在很多死胡同之后,我已经设法通过手动构建SOAP请求,并通过TCP使用Windows套接字发送请求。 Tricky位正在得到语法正确,因为我没有SOAP的经验。 [UPnP对识别IP地址&端口号 - 因为这些可以改变]。一旦启动并运行 - 它实际上比UPnP接口更简单。让我知道如果你有兴趣,我可以发布代码...它不直接回答我在这里提出的问题,所以它没有意义回答我的问题与这个细节。



但是,如果你有兴趣,请告诉我,我可以发布代码。



干杯, $ b Dave

解决方案

0x80040500的HRESULT不是您的想法,但 UPNP_E_INVALID_DOCUMENT 。有关如何实现这种歧义的说明,请参阅我在另一个SO问题中的答案



我的猜测是,您的Belkin设备提供不符合设备描述或服务描述XML。不一致不一定意味着破坏格式,UPnP规范有大量的次要要求。从英特尔开发人员工具(链接在另一个答案的底部)尝试设备间谍,如果设备弹出,然后从同一套件中运行设备验证器。


The device: Belkin Wemo Switch
Dev environment: MS VC++ 2010 on Windows7

I'm trying to enumerate the services of a UPnP device using C++ from Windows.

I've got the IUPnPDevice pointer and can access several properties.
I've got the IUPnPServices pointer and can count the correct number of services (7).
I use QueryInterface() to get the IEnumVARIANT pointer (which appears to succeed).
However, the Next() method always fails with HRESULT of 0x80040500 - which translates as Windows error 1280 (0x500) - ERROR_ALREADY_FIBER.
This error does not make any sense to me.

(I've tried using both IEnumVARIANT and IEnumUnknown - as the docs indicate it could be either, but both produce the same result.)

I've included below the complete source file, plus the output it produces.
[Note: It's hardcoded to use the udn of my own device]

I'd be very grateful if anyone can help as I'm currently stuck.

Best regards,
Dave

Code:

// UpnpTest1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <windows.h>
#include <upnp.h>

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**)&deviceFinder);
    if (hr==S_OK)
    {
      IUPnPDevice *device=0;
      hr = deviceFinder->FindByUDN(L"uuid:Socket-1_0-221239K11002F6", &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->get_ManufacturerName(&manufacturer);
          device->get_ManufacturerURL(&manufacturerUrl);
          device->get_Description(&description);
          device->get_FriendlyName(&name);
          device->get_ModelURL(&modelUrl);
          device->get_SerialNumber(&serialNumber);
          device->get_UniqueDeviceName(&udn);
          device->get_UPC(&upc);
          device->get_Type(&deviceType);
          device->get_PresentationURL(&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->get_Services(&services);
          if (hr==S_OK)
          {
            if (services)
            {
              long numberOfServices=0;
              services->get_Count(&numberOfServices);

              if (numberOfServices>0)
              {
                IUnknown *unknown=0;
                hr = services->get__NewEnum(&unknown);
                if (hr==S_OK)
                {
                  if (unknown)
                  {
                    IEnumVARIANT *enumInterface=0;
                    hr = unknown->QueryInterface(IID_IEnumVARIANT,(void**)&enumInterface);
                    if (enumInterface)
                    {
                      VARIANT var;
                      unsigned long fetched=0;
                      hr = enumInterface->Next(1, &var, &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 &i, int max)
{
  if (name && *name && value && buf && i>=0)
    i += _snwprintf_s(&buf[i], max-i, (max-i-1)*sizeof(TCHAR), _T("%s%s=YES"), (i>0? _T("; "): _T("")), name);
}

static void AddIntToString(const TCHAR *name, int value, TCHAR *buf, int &i, int max)
{
  if (name && *name && value && buf && i>=0)
    i += _snwprintf_s(&buf[i], max-i, (max-i-1)*sizeof(TCHAR), _T("%s%s=%d"), (i>0? _T("; "): _T("")), name, value);
}

static void DumpComError(const TCHAR *api, HRESULT hr)
{
  bool failure   = (hr&0x80000000? true: false);
  bool severe    = (hr&0x40000000? true: false);
  bool microsoft = (hr&0x20000000? false: true);
  bool ntStatus  = (hr&0x10000000? true: false);
  bool xBit      = (hr&0x08000000? true: false);
  int facility   = (hr&0x07FF0000)>>16;
  int code       = (hr&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);
}

Output: It produces following output:

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]

EDIT:

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 & 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.

However, if you're interested, let me know and I can post the code.

Cheers,
Dave

解决方案

HRESULT of 0x80040500 is not what you think, but UPNP_E_INVALID_DOCUMENT. For explanation of how such ambiguity is possible, see my answer in another SO question.

My guess is that your Belkin device is giving non-conformant device description or service description XML. Non-conformant doesn't necessarily mean broken format, UPnP specification has tons of secondary requirements. Try Device Spy from Intel Developer Tools (link at bottom of the other answer), if the device pops up, then run Device Validator from the same suite on it.

这篇关于如何访问UPnP设备的服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆