2012-12-09 2 views
6

장치 : 나는 윈도우에서 C++를 사용하여 UPnP 장치의 서비스를 열거하기 위해 노력하고있어 Windows7의UPnP 장치의 서비스는 어떻게 액세스합니까?

에 MS VC++ 2010 : 벨킨 Wemo는
데브 환경을 전환합니다.

IUPnPDevice 포인터가 있으며 여러 속성에 액세스 할 수 있습니다.
IUPnPServices 포인터가 있고 정확한 수의 서비스를 계산할 수 있습니다 (7).
IEnumVARIANT 포인터를 얻으려면 QueryInterface()을 사용합니다 (성공한 것 같습니다).
그러나 Next() 메서드는 이 0x80040500 인 경우 항상 실패하며 Windows error 1280 (0x500) - ERROR_ALREADY_FIBER으로 변환됩니다.
이 오류는 나에게 이해가되지 않습니다.

은 (둘 다 IEnumVARIANTIEnumUnknown를 사용하여 시도했다 -. 워드 프로세서가 그 중 하나가 될 수 표시로,하지만 모두 같은 결과를)

내가 완전한 소스 파일 아래에 포함 시켰습니다, 플러스 출력이 생산합니다.
[참고 : 내 장치의 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 요청을 수동으로 작성하고 Windows 소켓을 사용하여 TCP를 통해 요청을 보내는 방식으로이 작업을 수행 할 수있었습니다. 이전에 SOAP에 대한 경험이 없었기 때문에 까다로운 비트가 구문을 올바르게 이해하고있었습니다. [UPnP는 IP 주소가 & 인 포트 번호를 식별하는 데 유용했기 때문에 변경 될 수 있습니다. 일단 실행 및 실행 - 실제로는 UPnP 인터페이스보다 훨씬 간단합니다. 관심이 있다면 코드를 게시 할 수 있습니다. 여기에서 제기 한 질문에 직접 대답하지 않으므로이 질문에 대한 답변을 얻지 못할 것입니다.

그러나 관심이 있으시면 알려주세요. 코드를 게시 할 수 있습니다.

건배,
데이브

+0

참고 :이 페이지 [http://www.issackelly.com/blog/2012/07/30/wemo-hacking/]에서 서비스 목록을 볼 수 있으므로 이론적으로 나는 서비스를 직접 IUPnPServices :: get_Item() 사용하여 service.d (첫 번째 매개 변수) 올바른 형식을 알아낼 수 없습니다 ... – user390935

+0

참고 2 : IUPnPService :: get_Item (L "urn : Belkin : serviceId : basicevent1 ", & serviceId); 하지만 반환 된 HRESULT는 이전과 동일합니다 (0x80040500) – user390935

+0

예 @ user390935, 코드를 게시하십시오. 나는 플랫폼 중립적 인 SSDP 클라이언트를 찾고 있었다. – Vink

답변

2
0x80040500의 HRESULT 당신이 생각하지

하지만 UPNP_E_INVALID_DOCUMENT. 그러한 모호성이 가능한 방법에 대한 설명은 my answer in another SO question을 참조하십시오.

내 생각 엔 Belkin 장치가 부적합한 장치 설명 또는 서비스 설명 XML을 제공하고있는 것 같습니다. 부적합은 반드시 포맷이 깨진 것을 의미하지 않으며, UPnP 사양은 부차적 인 요구 사항이 많습니다. 장치가 튀어 나오면 Intel Developer Tools에서 Device Spy (다른 대답의 맨 아래에있는 링크)를 시도한 다음 동일한 장치에서 Device Validator를 실행하십시오.

+0

고마워요 ... 시설이 4 일 때 알려 줬어야했는데.이 말은 Windows가 장치의 응답을 좋아하지 않는다는 것을 의미합니다. – user390935

+0

예, 제 추측입니다. HRESULT는 OS/2와의 20 년 된 호환성의 끔찍한 유산입니다. 자체적으로 충분히 나쁜 모든 "사용자 정의 코드"에 대해 하나의 FACILITY_ITF 만 있지만 Microsoft는 자신의 새 API에 대해 동일한 기능을 사용합니다.이 API는 사용되지 않은 다른 코드를 사용할 수있었습니다. –

0

내 경험은 비슷하지만 UPnPDeviceFinder가 작동하지 않는다는 점에서 비슷합니다. UPnP 검색 패킷을 보내지 않으므로 장치가 응답하지 않습니다. Windows Media Player 또는 WMP 인 "Cast To Device"메뉴를 사용하여 검색을 시작하는 경우에만 작동하도록하는 유일한 방법입니다. UPnPDeviceFinder는 그 순간에 방송되는 경우에만 일부 장치를 반환하지만 다른 활동이없는 예제에서는 XBox (다른 Microsoft 제품)를 찾지 못하는 경우도 있습니다.

관련 문제