1

我一直在尝试使用 Winsock API 在 Windows 上进行蓝牙编程,并且遇到了如何确定主机上是否没有蓝牙或扫描集是否为空的问题。

所以程序很简单,启动 Winsock,调用 WSALookupServiceBegin,然后在扫描设备时调用 ServiceNext 和 ServiceEnd。开发机器有一个蓝牙收音机,驱动程序是 Microsoft BT Stack,我可以通过 Windows 使用设备向导找到设备。

问题是在调用 WSALookupServiceBegin 时,在两种情况下会返回 WSASERVICE_NOT_FOUND:

  1. 主机上没有适配器
  2. 范围内没有要扫描的蓝牙设备(即空扫描集)

所以我的问题是:

  1. 这是预期的吗?
  2. 我如何进一步确定发生了哪一个?

提前致谢!

附上代码:

int main(int argc, char **argv)
{
    WSADATA wsd;
    BOOL retVal;

    if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
        printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());
    else
        printf("WSAStartup() is OK!\n");

    scan();

    if (WSACleanup() == 0)
        printf("WSACleanup() is OK!\n");
    else
        printf("WSACleanup() failed with error code %ld\n", WSAGetLastError());

    return 0;
}

和扫描();

void scan()
{
    WSAQUERYSET queryset;

    memset(&queryset, 0, sizeof(WSAQUERYSET));
    queryset.dwSize = sizeof(WSAQUERYSET);
    queryset.dwNameSpace = NS_BTH;

    // begin query
    HANDLE hDeviceLookup;
    if (WSALookupServiceBegin(&queryset, LUP_FLUSHCACHE | LUP_CONTAINERS, &hDeviceLookup)) {
        int last_error = WSAGetLastError();
        wcout << getWinErrorMessage(last_error) << endl;

        return;
    }

    int bufSize = 0x2000;
    void* buf = malloc(bufSize);

    int result = -1;
    while (result == -1) {
        memset(buf, 0, bufSize);

        LPWSAQUERYSET pwsaResults = (LPWSAQUERYSET)buf;
        pwsaResults->dwSize = sizeof(WSAQUERYSET);
        pwsaResults->dwNameSpace = NS_BTH;

        DWORD size = bufSize;

        if (hDeviceLookup == NULL) {
            break;
        }
        if (WSALookupServiceNext(hDeviceLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR | LUP_RETURN_BLOB, &size, pwsaResults)) {
            int last_error = WSAGetLastError();
            switch (last_error) {
            case WSAENOMORE:
            case WSA_E_NO_MORE:
                result = 2;
                break;
            default:
                wcout << getWinErrorMessage(last_error) << endl;
                result = 3;
            }
            WSALookupServiceEnd(hDeviceLookup);
            hDeviceLookup = NULL;

            break;
        }

        BTH_DEVICE_INFO *p_inqRes = (BTH_DEVICE_INFO *)pwsaResults->lpBlob->pBlobData;
        // get device name
        WCHAR name[256];
        BOOL bHaveName = pwsaResults->lpszServiceInstanceName && *(pwsaResults->lpszServiceInstanceName);
        wcout << pwsaResults->lpszServiceInstanceName << endl;
        int deviceClass = p_inqRes->classOfDevice;
        BTH_ADDR deviceAddr;

        deviceAddr = ((SOCKADDR_BTH *)pwsaResults->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr;
    }

    if (buf != NULL) {
        free(buf);
    }

    if (hDeviceLookup != NULL) {
        WSALookupServiceEnd(hDeviceLookup);
        hDeviceLookup = NULL;
    }
}
4

1 回答 1

1

我使用以下代码来确定是否可以使用 Windows 蓝牙堆栈以及是否存在所需的硬件。

CanUseBluetooth() 只是检查是否存在理解蓝牙协议的winsock 提供程序。如果是这种情况,则安装堆栈。

static bool CanUseBluetooth(
   bool throwOnFailure)
{
   static const CAddressTypeBluetooth addressType;

   SOCKET s = ::socket(addressType.Family(), SOCK_STREAM, addressType.Protocol());

   const bool canUseBluetooth = (s != INVALID_SOCKET);

   const DWORD lastError = ::GetLastError();

   ::closesocket(s);

   if (!canUseBluetooth && throwOnFailure)
   {
      throw CWin32Exception(_T("CUsesXPBluetooth::CanUseBluetooth()"), lastError);
   }

   return canUseBluetooth;
}

HarwareActive() 检查我们是否可以绑定到通配符地址,如果我们可以这样做,那么我们有一些使用 Windows 堆栈的活动蓝牙硬件。

static bool HardwareActive(
   bool throwOnFailure)
{
   static const CAddressTypeBluetooth addressType;

   SOCKET s = ::socket(addressType.Family(), SOCK_STREAM, addressType.Protocol());

   if (s == INVALID_SOCKET)
   {
      const DWORD lastError = ::GetLastError();

      ::closesocket(s);

      throw CWin32Exception(_T("CUsesXPBluetooth::HardwareActive() - CanUseBluetooth"), lastError);
   }

   bool hardwareActive = true;

   static const IAddress &address = addressType.WildcardAddress();

   if (SOCKET_ERROR == ::bind(s, &address.AsSockAddr(), address.Size()))
   {
      hardwareActive = false;
   }

   const DWORD lastError = ::GetLastError();

   ::closesocket(s);

   if (!hardwareActive && throwOnFailure)
   {
      throw CWin32Exception(_T("CUsesXPBluetooth::HardwareActive()"), lastError);
   }

   return hardwareActive;
}
于 2013-11-27T11:07:01.647 回答