Сбой при подключении к устройству Bluetooth через WinAPI Socket (расположение чтения нарушения доступа 0x00000004) - PullRequest
2 голосов
/ 02 июля 2011

Я думаю, ты моя последняя надежда. У меня есть Bluetooth-устройство (точнее, датчик), к которому я хочу подключиться и считывать данные. Устройство предлагает SPP (профиль последовательного порта). Чтобы избежать проблемы надежного сопоставления с адресами Bluetooth и виртуальными последовательными портами (COM-портами), я собираюсь использовать сокеты.

К сожалению, приложение всегда вылетает, прежде чем вернуться из функции WinAPI. connect (...) с: 0xC0000005: Место чтения нарушения доступа 0x00000004 , поэтому я получаю без кода ошибки .

НО, и это странно, когда я щелкаю правой кнопкой мыши на значке в системном трее Bluetooth, чтобы показать доступные устройства, мое устройство обнаруживает аутентификацию и подключение. Этот список, конечно, был пуст до ,

Моя ОС - Windows 7 64-разрядная, IDE - Visual Studio 2010, стек Microsoft Bluetooth. Код для поиска и подключения к моему единственному устройству:

#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>

#define WIN32_LEAN_AND_MEAN

#include <Windows.h>
#include <BluetoothAPIs.h>
#include <Winsock2.h>
#include <Ws2bth.h>



BOOL auth_callback_ex(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS authParams)
{
    BLUETOOTH_AUTHENTICATE_RESPONSE response;
    response.bthAddressRemote = authParams->deviceInfo.Address;
    response.authMethod = authParams->authenticationMethod; // == BLUETOOTH_AUTHENTICATION_METHOD_LEGACY

    UCHAR pin[] = "1234";
    std::copy(pin, pin+sizeof(pin), response.pinInfo.pin);
    response.pinInfo.pinLength = sizeof(pin)-1; //excluding '\0'

    response.negativeResponse = false;


    HRESULT err = BluetoothSendAuthenticationResponseEx(NULL, &response);
    if (err)
    {
        std::cout << "BluetoothSendAuthenticationResponseEx error = " << err << std::endl;
    }

    return true;
}


int main()
{
    BLUETOOTH_DEVICE_SEARCH_PARAMS btSearchParams;

    btSearchParams.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
    btSearchParams.cTimeoutMultiplier = 5;  //5*1.28s search timeout
    btSearchParams.fIssueInquiry = true;    //new inquiry

    //return all known and unknown devices
    btSearchParams.fReturnAuthenticated = true;
    btSearchParams.fReturnConnected = true;
    btSearchParams.fReturnRemembered = true;
    btSearchParams.fReturnUnknown = true;

    btSearchParams.hRadio = NULL;   //search on all local radios



    BLUETOOTH_DEVICE_INFO btDeviceInfo;
    ZeroMemory(&btDeviceInfo, sizeof(BLUETOOTH_DEVICE_INFO));   //"initialize"

    btDeviceInfo.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);

    HBLUETOOTH_DEVICE_FIND btDeviceFindHandle = NULL;

    btDeviceFindHandle = BluetoothFindFirstDevice(&btSearchParams, &btDeviceInfo);
    if(btDeviceFindHandle)
    {

        HBLUETOOTH_AUTHENTICATION_REGISTRATION authCallbackHandle = NULL;

        DWORD err = BluetoothRegisterForAuthenticationEx(&btDeviceInfo, &authCallbackHandle, &auth_callback_ex, NULL);


        if (err != ERROR_SUCCESS)
        {
            DWORD err = GetLastError();
            std::cout << "BluetoothRegisterForAuthentication Error" << err << std::endl; 
        }

        /////////////// Socket
        WSADATA wsaData;
        err = WSAStartup(MAKEWORD(2,2), &wsaData);
        if (err)
        {
            std::cout << "WSAStartup error = " << err << std::endl;
        }


        // create BT socket
        SOCKET s = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
        assert(s != INVALID_SOCKET);    //WSAGetLastError //throw // runtime check release?

        SOCKADDR_BTH btSockAddr;
        btSockAddr.addressFamily = AF_BTH;
        btSockAddr.btAddr = btDeviceInfo.Address.ullLong;
        btSockAddr.serviceClassId = RFCOMM_PROTOCOL_UUID; //SerialPortServiceClass_UUID (no difference)
        btSockAddr.port = BT_PORT_ANY;


        err = connect(s, reinterpret_cast<SOCKADDR*>(&btSockAddr), sizeof(SOCKADDR_BTH));

        /* <--- never got so far --> */

        if (err)
        {
            DWORD wsaErr = WSAGetLastError();
            std::cout << "connect error = " << wsaErr << std::endl;

        }
        else
        {
            //err = shutdown(s, SD_BOTH);

            err = closesocket(s);
            if (err)
            {
                std::cout << "closesocket error = " << err << std::endl;
            }
        }

        WSACleanup();
        ///////////////Socket


        BOOL ok = BluetoothUnregisterAuthentication(authCallbackHandle);
        if (!ok)
        {
            DWORD err = GetLastError();
            std::cout << "BluetoothUnregisterAuthentication Error" << err << std::endl; 
        }



        ok = BluetoothFindDeviceClose(btDeviceFindHandle);
        if (!ok)
        {
            DWORD err = GetLastError();
            std::cout << "BluetoothDeviceClose Error" << err << std::endl; 
        }
    }
    else
    {
        DWORD err = GetLastError();
        std::cout << "BluetoothFindFirstDevice Error" << err << std::endl; 
    }


    std::cin.get();
}

Я сделал еще несколько замечаний:

  • Обратный вызов аутентификации и функция BluetoothSendAuthenticationResponseEx работают нормально, ошибки не возвращаются.
  • Если я не устанавливаю обратный вызов аутентификации ( BluetoothRegisterForAuthenticationEx ) и, следовательно, должен вручную вводить PIN-код (пользовательский интерфейс отображается автоматически при попытке подключения), функция connect возвращается правильно и все тоже отлично работает. Я даже получил данные (часть recv в этом фрагменте опущена).
  • Если я ищу и выполняю сопряжение полностью вручную (иконка в трее Bluetooth -> Добавить устройство), все тоже хорошо. Служба и виртуальный последовательный порт установлены. Данные поступают через замазку.

Итак, где-то между вызовом аутентификации и завершением функции connect что-то идет не так. Может быть, при попытке получить определенную структуру данных через указатель, который не должен быть NULL плюс смещение.

Или я что-то не так делаю? Чего-то не хватает? Спасибо ...

Ответы [ 4 ]

3 голосов
/ 03 июля 2011

Проблема в том, что ваша функция использует неправильное соглашение о вызовах. Согласно MSDN, вам нужно использовать макрос CALLBACK , например:

BOOL CALLBACK auth_callback_ex(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS authParams)

Неправильное соглашение о вызовах приведет к несовпадению стека при возврате, что может привести кнарушение доступа внутри кода MS Bluetooth, когда он не может найти свои локальные переменные.

Или это может привести к путанице в параметрах вашей функции.Если authParams и pvParam поменялись местами, потому что соглашение о вызовах cdecl предполагает, что аргументы сдвинуты справа налево, а stdcall сдвигает их слева направо, вы получите NULL в authParams и затем1015 * попытается прочитать адрес 0x04.

Компилятор должен был это уловить.Компилировать с включенными максимальными предупреждениями (/W4).Вам придется игнорировать предупреждения о неизвестной прагме, это ошибка в заголовке, о которой я сообщаю в Microsoft (неправильно написано #pragma deprecated) .

К сожалению, есть вторая ошибка в заголовке, гораздо более серьезная, в которой не указано явное соглашение о вызовах , в результате чего он будет корректно работать только на x86 (32-битный код), если используется /Gz.Фу!


Продолжение: в заголовках SDK, поставляемых с VS2013, обе проблемы устранены.

0 голосов
/ 03 июля 2011

У меня есть пара мыслей, чтобы поделиться с вами, но имейте в виду, что это догадки.Я не скомпилировал и не отладил ваш код, хотя я рекомендую вам опубликовать полный пример.

Я думаю, что сбой может происходить в вашей функции обратного вызова аутентификации из-за разыменования указателя '' 'NULL' ''.

Эти строки:

response.bthAddressRemote = authParams->deviceInfo.Address;
response.authMethod = authParams->authenticationMethod; // == BLUETOOTH_AUTHENTICATION_METHOD_LEGACY

будутвызвать сообщение, которое вы описываете, если вы работаете в 32-битной Windows, а '' 'authParams' '' может быть '' 'NULL' '' - в этом случае '' 'deviceInfo' '' вносит нулевое смещение(это начало BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS ''), а '.Address' '' имеет смещение 4 ('' 'NULL + 4 == 0x00000004' '), потому что оно следует'' 'DWORD' '' и ничего больше в макете '' 'BLUETOOTH_DEVICE_INFO' ''.

Возможно ли, что '' 'authParams' '' имеет значение NULL при вызове обратного вызова?

Как уже упоминал другой автор, это может быть связано с неправильным соглашением о вызовах (отсутствие макроса '' 'CALLBACK' '') - в противном случае правильные параметры могут не совпадать с позициями, которые читает скомпилированный код.

Вторая мысль была:

BLUETOOTH_DEVICE_INFO btDeviceInfo;
ZeroMemory(&btDeviceInfo, sizeof(BLUETOOTH_DEVICE_INFO));   //"initialize"

btDeviceInfo.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);

Может быть представлен бy:

BLUETOOTH_DEVICE_INFO btDeviceInfo = {sizeof(BLUETOOTH_DEVICE_INFO)};

В соответствии со стандартом это обнулит другие поля '' 'btDeviceInfo' ''.

0 голосов
/ 03 июля 2011

Или напишите управляемый код и используйте мою библиотеку Bluetooth 32feet.NET Super simple.http://32feet.codeplex.com/

Произойдет ли сбой в этом случае - если это так, то на вашем компьютере что-то не так ...

0 голосов
/ 02 июля 2011

У вас есть доступ с нулевым указателем где-то.«Место считывания нарушения доступа 0x00000004 » указывает на это, поскольку это только 4 байта от нуля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...