2012-12-09 32 views
6

Thiết bị này: Belkin Wemo Chuyển
Dev môi trường: MS VC++ 2010 trên Windows7Tôi làm cách nào để truy cập các dịch vụ của thiết bị UPnP?

Tôi đang cố gắng để liệt kê các dịch vụ của một thiết bị UPnP sử dụng C++ từ Windows.

Tôi có con trỏ IUPnPDevice và có thể truy cập một số thuộc tính.
Tôi có con trỏ IUPnPServices và có thể đếm số lượng dịch vụ chính xác (7).
Tôi sử dụng QueryInterface() để có được con trỏ IEnumVARIANT (dường như thành công).
Tuy nhiên, phương pháp Next() luôn không thành công với HRESULT của 0x80040500 - được dịch là Windows error 1280 (0x500) - ERROR_ALREADY_FIBER.
Lỗi này không có ý nghĩa gì đối với tôi.

(Tôi đã thử sử dụng cả hai IEnumVARIANTIEnumUnknown -. Như các tài liệu cho thấy nó có thể là một trong hai, nhưng cả hai đều tạo ra kết quả tương tự)

Tôi đã bao gồm bên dưới file nguồn đầy đủ, cộng với đầu ra nó sản xuất.
[Lưu ý: Mã này được mã hóa cứng để sử dụng udn của thiết bị của riêng tôi]

Tôi rất biết ơn nếu có ai có thể trợ giúp như tôi hiện đang bị kẹt.

Trân trọng,
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: nó tạo ra sau đầu ra:

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:

Sau rất nhiều kết thúc chết, tôi đã quản lý để làm việc này bằng cách thủ công xây dựng các yêu cầu SOAP và gửi các yêu cầu qua TCP bằng cách sử dụng các ổ cắm Windows. Bit khó hiểu đã nhận được cú pháp vừa phải như tôi đã không có kinh nghiệm của SOAP trước đây. [UPnP hữu ích khi xác định địa chỉ IP & số cổng - vì chúng có thể thay đổi]. Khi lên và chạy - nó thực sự đơn giản hơn rất nhiều so với giao diện UPnP. Hãy cho tôi biết nếu bạn quan tâm và tôi có thể đăng mã ... Nó không trực tiếp trả lời câu hỏi tôi đặt ra ở đây, vì vậy sẽ không có ý nghĩa gì khi trả lời câu hỏi của tôi với chi tiết này.

Tuy nhiên, nếu bạn quan tâm, hãy cho tôi biết và tôi có thể đăng mã.

Chúc mừng,
Dave

+0

Lưu ý: Từ trang này [http://www.issackelly.com/blog/2012/07/30/wemo-hacking/] bạn có thể xem danh sách dịch vụ, vì vậy về lý thuyết tôi có thể truy cập dịch vụ trực tiếp sử dụng IUPnPServices :: get_Item() tuy nhiên, tôi không thể tìm ra định dạng đúng cho serviceId (tham số đầu tiên) ... – user390935

+0

Note2: Tôi đã thử sử dụng IUPnPService :: get_Item (L "urn: Belkin: serviceId: basicevent1 ", & serviceId); tuy nhiên HRESULT được trả lại giống như trước (0x80040500) – user390935

+0

Có @ user390935, đăng mã của bạn. Tôi đang tìm kiếm nền tảng máy khách SSDP trung lập. – Vink

Trả lời

2

HRESULT của 0x80040500 không phải là những gì bạn nghĩ, nhưng UPNP_E_INVALID_DOCUMENT. Để giải thích về sự mơ hồ như thế nào, hãy xem my answer in another SO question.

Tôi đoán là thiết bị Belkin của bạn đang cung cấp mô tả thiết bị không tuân thủ hoặc XML mô tả dịch vụ. Không tuân thủ không nhất thiết có nghĩa là định dạng bị hỏng, đặc tả UPnP có rất nhiều yêu cầu phụ. Thử Device Spy từ Công cụ phát triển Intel (liên kết ở dưới cùng của câu trả lời khác), nếu thiết bị bật lên, hãy chạy Device Validator từ cùng một bộ trên đó.

+0

Cảm ơn vì điều này ... Tôi nên biết là Cơ sở là 4. Tôi đoán điều này có nghĩa là Windows không thích phản hồi từ thiết bị. – user390935

+0

Vâng, đó là dự đoán của tôi. HRESULT là một di sản khủng khiếp của 20 năm tuổi tương thích với OS/2. Chỉ có một FACILITY_ITF cho tất cả các "mã do người dùng xác định" là đủ, nhưng Microsoft đang sử dụng cùng một cơ sở cho các API mới của riêng nó, nơi mà nó có thể đã sử dụng một mã không sử dụng khác. –

0

Trải nghiệm của tôi tương tự, trong đó UPnPDeviceFinder chỉ đơn giản là không hoạt động. Nó không bao giờ gửi gói UPnP Search, vì vậy các thiết bị không phản hồi. Cách duy nhất để làm cho nó hoạt động là nếu bạn cũng sử dụng trình phát media windows hoặc menu "Truyền tới thiết bị" (WMP) để bắt đầu tìm kiếm. Vì UPnPDeviceFinder sẽ trả về một số thiết bị, chỉ khi chúng xảy ra khi phát sóng tại thời điểm đó, nhưng thậm chí việc tìm kiếm một XBox (một sản phẩm khác của Microsoft) cũng không hoạt động trong các ví dụ mà không có hoạt động khác đang diễn ra.