我认为你是我最后的希望。我有一个蓝牙设备(它更准确地说是一个传感器),我想连接到它并从中读取数据。该设备提供SPP(串行端口配置文件)。为了避免从蓝牙地址和虚拟串行端口(COM端口)可靠映射的问题,我将使用套接字。
不幸的是,在从WinAPI函数 connect (...)返回之前,应用程序总是崩溃: 0xC0000005:访问冲突读取位置0x00000004 ,所以我得到否错误代码。
但是,这很奇怪,当我右键单击蓝牙系统托盘图标以显示可用设备时,我的设备显示已经过身份验证和连接。此列表之前是空的,课程。
我的操作系统是Windows 7 64位,IDE是Visual Studio 2010,Microsoft蓝牙堆栈。找到并连接到我唯一设备的代码:
#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();
}
我做了一些更多的观察:
因此,在调用身份验证回调和连接函数结束之间出现问题。也许当试图通过指针获取某个结构数据时,该指针不应该是NULL,加上偏移量。
或者我做错了什么?有什么遗失的吗? 谢谢......
答案 0 :(得分:3)
问题是你的函数使用了错误的调用约定。 According to MSDN, you need to use the CALLBACK
macro,如:
BOOL CALLBACK auth_callback_ex(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS authParams)
具有错误的调用约定将导致返回时堆栈不匹配,这可能导致MS蓝牙代码内无法找到其本地变量时发生访问冲突。
或者它可能导致您的函数的参数全部混乱。如果authParams
和pvParam
被交换,因为cdecl
调用约定期望args从右向左推,而stdcall
从左向右推,所以{{1}在NULL
中,然后authParams
会尝试读取地址authParams->deviceInfo.Address
。
编译器应该抓住这个。在启用最大警告(0x04
)时进行编译。您将不得不忽略有关未知编译指示的警告,这是bug in the header which I'm reporting to Microsoft (misspelled #pragma deprecated
)。
不幸的是有a second bug in the header, much more serious, of not specifying the calling convention explicitly,结果是只有在使用/W4
时它才能在x86(32位代码)上正常工作。呸!
跟进:在VS2013附带的SDK标头中,两个问题都已修复。
答案 1 :(得分:0)
您在某处有空指针访问权限。 “访问冲突读取位置 0x00000004 ”表示,因为距离零只有4个字节。
答案 2 :(得分:0)
我有几点想与你分享,但请注意,这些都是预感。我没有编译和调试你的代码,虽然我赞扬你发布了一个完整的样本。
我认为崩溃可能在您的身份验证回调函数中,因为''''NULL'''指针取消引用。
这些行:
response.bthAddressRemote = authParams->deviceInfo.Address;
response.authMethod = authParams->authenticationMethod; // == BLUETOOTH_AUTHENTICATION_METHOD_LEGACY
将导致您描述的消息,如果您在32位Windows上运行,并且'''authParams'''可能'''NULL''' - 在这种情况下,'''deviceInfo'''贡献一个零偏移量(它位于''''BLUETOOTENTICATION_CALLBACK_PARAMS'''的开头),'''。地址'''的偏移量为4('''NULL + 4 == 0x00000004''') ,因为它遵循'''DWORD'''并且在'''BLUETOOTH_DEVICE_INFO'''布局中没有其他内容。
调用回调时'''authParams'''是否可能为NULL?
正如另一张海报已经提到的,这可能是由于错误的调用约定(缺少'''CALLBACK'''宏) - 导致其他正确的参数与编译代码正在读取的位置不一致。 / p>
第二个想法是:
BLUETOOTH_DEVICE_INFO btDeviceInfo;
ZeroMemory(&btDeviceInfo, sizeof(BLUETOOTH_DEVICE_INFO)); //"initialize"
btDeviceInfo.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
可以表示:
BLUETOOTH_DEVICE_INFO btDeviceInfo = {sizeof(BLUETOOTH_DEVICE_INFO)};
根据标准,这将使'''btDeviceInfo'''的其他字段为零。
答案 3 :(得分:-1)
或者编写托管代码并使用我的蓝牙库32feet.NET超级简单。 http://32feet.codeplex.com/
它会崩溃吗 - 如果是这样,你的电脑就出现了问题......