Как получить доступ к услугам устройства UPnP?

Устройство: Belkin Wemo Switch
Среда разработки: MS VC ++ 2010 на Windows7

Я пытаюсь перечислить службы устройства UPnP, используя C ++ из Windows.

У меня есть IUPnPDevice указатель и может получить доступ к нескольким свойствам.
У меня есть IUPnPServices указатель и может рассчитывать правильное количество услуг (7).
я использую QueryInterface() чтобы получить IEnumVARIANT указатель (который, кажется, успешно).
Тем не менее Next() метод всегда терпит неудачу с HRESULT из 0x80040500 — что переводится как Windows error 1280 (0x500) - ERROR_ALREADY_FIBER,
Эта ошибка не имеет никакого смысла для меня.

(Я пытался использовать оба IEnumVARIANT а также IEnumUnknown — как показывают документы, это может быть и так, но оба результата дают одинаковый результат.)

Я включил ниже полный исходный файл, а также вывод, который он производит.
[Примечание: жестко запрограммировано использование UDN моего собственного устройства]

Буду очень признателен, если кто-нибудь сможет помочь, так как я застрял.

С наилучшими пожеланиями,
Дейв

Код:

// 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);
}

Выход:
Он производит следующий вывод:

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]

РЕДАКТИРОВАТЬ:

После многих тупиков мне удалось заставить это работать, вручную создавая запросы SOAP и отправляя запросы через TCP с использованием сокетов Windows. Сложно было правильно понять синтаксис, так как раньше у меня не было опыта работы с SOAP. [UPnP было полезно для определения IP-адреса & номер порта — как они могут измениться. После запуска — на самом деле все намного проще, чем интерфейс UPnP. Дайте мне знать, если вам интересно, и я могу опубликовать код … Он не дает прямого ответа на вопрос, который я здесь поставил, поэтому не имеет смысла отвечать на мой вопрос с такими подробностями.

Однако, если вам интересно, дайте мне знать, и я могу опубликовать код.

Ура,
Дейв

6

Решение

HRESULT 0x80040500 это не то, что вы думаете, но UPNP_E_INVALID_DOCUMENT. Для объяснения того, как такая двусмысленность возможна, см. мой ответ в другом вопросе ТАК.

Я предполагаю, что ваше устройство Belkin выдает описание устройства или описание службы в формате XML. Несоответствие не обязательно означает неправильный формат, спецификация UPnP имеет множество вторичных требований. Попробуйте Device Spy из Intel Developer Tools (ссылка внизу другого ответа), если устройство всплывает, а затем запустите Device Validator из того же набора на нем.

2

Другие решения

Мой опыт похож, в том, что UPnPDeviceFinder просто не работает. Он никогда не отправляет пакет поиска UPnP, поэтому устройства не отвечают. Единственный способ заставить его работать, если вы также используете Windows Media Player или меню «Cast To Device» (которое является WMP), чтобы начать поиск. Так как это UPnPDeviceFinder вернет некоторые устройства, только если они будут транслироваться в этот момент, но даже поиск XBox (другого продукта Microsoft) в примерах не работает без какой-либо другой активности.

0

По вопросам рекламы [email protected]