簡體   English   中英

如何使用 WSASetService 在 Windows 設備上使用 WSAQUERYSET 結構來宣傳藍牙服務

[英]How to use WSASetService to advertise bluetooth service using WSAQUERYSET structure on Windows devices

我從https://docs.microsoft.com/en-us/windows/win32/bluetooth/bluetooth-and-wsasetservice讀到有兩種方法可以向本地 SDP 服務器提交服務:

  • 應用程序可以讓系統公布一個簡單的藍牙 SDP 服務記錄,該記錄由 WSAQUERYSET 結構中的標准成員構建。

  • 應用程序可以讓系統通過在 WSAQUERYSET 結構的 lpBlob 成員中傳遞 BTH_SET_SERVICE 結構來通告他們自己的藍牙 SDP 記錄。 這是一種更復雜的方法。

對我來說,第一個是首選,但我現在可以找到的所有代碼示例都使用第二個。 我認為這可能涉及到設置有關服務的信息,例如 WSAQUERYSET 成員中的地址、端口、服務 uuid:

    //Service Information
    int port = 4;
    BTH_ADDR address = xxx;
    GUID serviceUuid = {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx};
    char* serviceName = "xxx";
    //....

    //Putting service information into WSAQUERYSET
    WSAQUERYSET Service;
    memset( &Service, 0, sizeof( Service ) );
    Service.dwSize      = sizeof( Service );
    //Service.xxx         = xxx
    //...
    Service.dwNameSpace = NS_BTH;
    if ( WSASetService( &Service, RNRSERVICE_REGISTER, 0 ) == SOCKET_ERROR ) {
        return WSAGetLastError();
    }
    else {
        return 0;
    }

目前,我在猜測如何設置這些屬性,但不知何故,我無法成功宣傳可以檢測到的服務。 我真的希望有一些可行的代碼示例。

一開始你不需要硬編碼port = 4; 但使用bind獲取動態空閑端口,使用getsockname獲取端口號。 例如(沒有錯誤檢查)

SOCKADDR_BTH asi = { AF_BTH, 0, {}, BT_PORT_ANY };
SOCKET s = WSASocket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM, 
    0, 0, WSA_FLAG_NO_HANDLE_INHERIT|WSA_FLAG_OVERLAPPED);
bind(s, (PSOCKADDR)&asi, sizeof(asi));
int len = sizeof(asi);
getsockname(s, (PSOCKADDR)&asi, &len);

那么您需要調用 WSASetService,如Bluetooth 和 WSAQUERYSET for Set Service中所述。 這里描述了WSAQUERYSET中使用的所有參數。 只有一個例外 - lpszServiceInstanceName描述為

可選,但推薦。

但如果不使用它 - 我們得到了一個無效的參數被提供 所以這是強制參數。

ULONG BthRegisterService(LPCGUID lpServiceClassId, PCWSTR ServiceName, PSOCKADDR_BTH asi)
{
    CSADDR_INFO csa = { 
        { (PSOCKADDR)asi, sizeof(SOCKADDR_BTH) }, {}, SOCK_STREAM, BTHPROTO_RFCOMM 
    };

    WSAQUERYSET wqs = { sizeof(wqs) };
    wqs.lpszServiceInstanceName = const_cast<PWSTR>(ServiceName);
    wqs.lpServiceClassId = const_cast<PGUID>(lpServiceClassId);
    wqs.dwNameSpace = NS_BTH;
    wqs.dwNumberOfCsAddrs = 1;
    wqs.lpcsaBuffer = &csa;

    return WSASetService(&wqs, RNRSERVICE_REGISTER, 0) ? WSAGetLastError() : NOERROR;
}

這種方式的缺點 - 我們無法取回我們注冊的記錄的HANDLE ,對於帶有RNRSERVICE_DELETE的后期調用WSASetService - 為此需要使用指向BTH_SET_SERVICEBLOB 為此,我們需要通過自己的原始 SDP 記錄 stream 進行格式化。

所以調用BthRegisterService我們可以這樣:

struct __declspec(uuid("00112233-4455-6677-8899-aabbccddeeff")) MyServiceClass;
BthRegisterService(&__uuidof(MyServiceClass), L"*", &asi);

但是,如果我們可以格式化 SDP 記錄,我們也可以直接使用IOCTL_BTH_SDP_SUBMIT_RECORD進行注冊,然后使用IOCTL_BTH_SDP_REMOVE_RECORD進行注銷

對於打開的藍牙設備,需要使用帶有CM_Get_Device_Interface_ListWGUID_BTHPORT_DEVICE_INTERFACE

由 NspSetService 格式化的 SDP 記錄看起來像

UCHAR SdpRecordTmplt[] = {
    // [//////////////////////////////////////////////////////////////////////////////////////////////////////////
    0x35, 0x33,                                                                                                 //
    //
    // UINT16:SDP_ATTRIB_CLASS_ID_LIST                                                                          //
    0x09, 0x00, 0x01,                                                                                           //
    //      [/////////////////////////////////////////////////////////////////////////////////////////////////  //
    0x35, 0x11,                                                                                             //  //
    // UUID128:{guid}                                                                                       //  //
    0x1c, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,   //  //
    //      ]/////////////////////////////////////////////////////////////////////////////////////////////////  //
    //
    // UINT16:SDP_ATTRIB_PROTOCOL_DESCRIPTOR_LIST                                                               //
    0x09, 0x00, 0x04,                                                                                           //
    //      [/////////////////////////////////                                                                  //
    0x35, 0x0f,                             //                                                                  //
    // (L2CAP, PSM=PSM_RFCOMM)              //                                                                  //
    //          [/////////////////////////  //                                                                  //
    0x35, 0x06,                         //  //                                                                  //
    // UUID16:L2CAP_PROTOCOL_UUID16     //  //                                                                  //
    0x19, 0x01, 0x00,                   //  //                                                                  //
    // UINT16:PSM_RFCOMM                //  //                                                                  //
    0x09, 0x00, 0x03,                   //  //                                                                  //
    //          ]/////////////////////////  //                                                                  //
    // (RFCOMM, CN=Port)                    //                                                                  //
    //          [/////////////////////////  //                                                                  //
    0x35, 0x05,                         //  //                                                                  //
    // UUID16:RFCOMM_PROTOCOL_UUID16    //  //                                                                  //
    0x19, 0x00, 0x03,                   //  //                                                                  //
    // UINT8:CN                         //  //                                                                  //
    0x08, 0x**,                         //  //                                                                  //
    //          ]/////////////////////////  //                                                                  //
    //      ]/////////////////////////////////                                                                  //
    //
    // UINT16:SDP_ATTRIB_SERVICE_NAME                                                                           //
    0x09, 0x01, 0x00,                                                                                           //
    // STR:4 "ABCD"                                                                                             //
    0x25, 0x04, 0x41, 0x42, 0x43, 0x44                                                                          //
    // ]//////////////////////////////////////////////////////////////////////////////////////////////////////////
};

這里只有 UUID128 ( ServiceClassId ),rfcomm 端口號和名稱被更改

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM