通过 WinAPI 套接字连接到蓝牙设备时崩溃(访问冲突读取位置 0x00000004)
我想你是我最后的希望。我这里有一个蓝牙设备(更准确地说是一个传感器),我想连接它并从中读取数据。该设备提供 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();
}
我还做了一些观察:
- 身份验证回调和 BluetoothSendAuthenticationResponseEx 函数工作正常,没有返回错误。
- 如果我没有安装身份验证回调 (BluetoothRegisterForAuthenticationEx),因此必须手动输入 PIN(尝试连接时会自动显示 UI),connect 函数会正确返回,并且一切也都很好。我什至得到了数据(此片段中省略了接收部分)。
- 如果我完全手动搜索和配对(蓝牙托盘图标 -> 添加设备),一切都很好。安装了服务和虚拟串口。数据通过腻子来。
因此,在调用身份验证回调和 connect 函数结束之间的某个地方出现了问题。也许当尝试通过指针获取某个结构数据时,该指针不应该为 NULL,加上偏移量。
或者我做错了什么?是不是少了点什么? 谢谢...
I think you are my last hope. I have got here a Bluetooth device (it is a sensor to be more precisely) which I want to connect to and read data from. The device offers SPP (Serial Port Profile). To avoid the problem of reliable mapping from Bluetooth addresses and virtual serial ports (COM Ports), I am going to use sockets.
Unfortunately the application always crashes before returning from WinAPI function connect(...) with: 0xC0000005: Access violation reading location 0x00000004, so I get no error code.
BUT, and that is weird, when I right-click on the Bluetooth System Tray Icon to to show available devices, my device shows up being authenticated and connected. This list was empty before, of course.
My OS is Windows 7 64 Bit, the IDE is Visual Studio 2010, Microsoft Bluetooth Stack. Code to find and connect to my only device:
#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();
}
I have made some few more observations:
- The authentication callback and the BluetoothSendAuthenticationResponseEx function are working fine, there is no error given back.
- If I do not install the authentication callback (BluetoothRegisterForAuthenticationEx) and therefore have to manually enter the PIN (the UI shows up automatically while trying to connect), connect function returns properly and everything works fine, too. I even got data (the recv part is omitted in this snippet).
- If I search and pair completely manually (Bluetooth Tray Icon -> Add Device), everything is fine, too. A service and a virtual serial port is installed. Data come via putty.
So somewhere between calling the authentication callback and end of the connect function something is going wrong. Maybe when trying to get a certain structure data via a pointer, which should not be NULL, plus offset.
Or am I doing something wrong? Is there something missing?
Thanks...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
问题是您的函数使用了错误的调用约定。 根据MSDN,需要使用
CALLBACK
宏< /a>,如下所示:错误的调用约定将导致返回时堆栈不匹配,这可能会导致 MS 蓝牙代码在找不到其本地变量时发生访问冲突。
或者它可能会导致函数的参数全部混乱。如果
authParams
和pvParam
交换,因为cdecl
调用约定期望参数从右向左推送,而stdcall
推送从左到右,您会在authParams
中得到NULL
,然后authParams->deviceInfo.Address
将尝试读取地址0x04
。编译器应该已经捕获了这一点。编译时打开最大警告 (
/W4
)。您必须忽略有关未知编译指示的警告,这是 我向 Microsoft 报告的标头中的错误(拼写错误#pragma已弃用
)。不幸的是,标题中有第二个错误,更严重的是没有明确指定调用约定,结果是,如果使用
/Gz
,它只能在 x86(32 位代码)上正常工作。哎呀!后续:在 VS2013 附带的 SDK 标头中,这两个问题都已修复。
The problem is that your function is using the wrong calling convention. According to MSDN, you need to use the
CALLBACK
macro, as in:Having the wrong calling convention will result in a stack mismatch on return, which could cause an access violation inside the MS Bluetooth code when it can't find its local variables.
Or it could result in the parameters to your function being all jumbled. If
authParams
andpvParam
are swapped, because thecdecl
calling convention expects args pushed from right to left andstdcall
pushes them left to right, you'd getNULL
inauthParams
, and thenauthParams->deviceInfo.Address
will try to read address0x04
.The compiler should have caught this. Compile with maximum warnings turned on (
/W4
). You'll have to ignore the warnings about unknown pragma, this is a bug in the header which I'm reporting to Microsoft (misspelled#pragma deprecated
).Unfortunately there's a second bug in the header, much more serious, of not specifying the calling convention explicitly, with the result that it will only work correctly on x86 (32-bit code) if
/Gz
is used. Yuck!Followup: In the SDK headers shipped with VS2013, both issues are fixed.
您在某处有空指针访问。 “访问冲突读取位置 0x00000004”表示这一点,因为它距离零仅 4 个字节。
You have a null-pointer access somewhere. "Access violation reading location 0x00000004" indicates that, as it is only 4 bytes away from zero.
我有一些想法要与您分享,但请注意,这些只是预感。尽管我推荐您发布完整的示例,但我还没有编译和调试您的代码。
我认为由于“NULL”指针取消引用,崩溃可能发生在您的身份验证回调函数内。
这些行:
如果您在 32 位 Windows 上运行,并且 '''authParams''' 可能是 '''NULL''' - 在这种情况下,'''deviceInfo''',将导致您描述的消息提供零偏移量(位于 '''BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS''' 的开头),并且 '''.Address''' 确实提供偏移量4 ('''NULL + 4 == 0x00000004'''),因为它遵循 '''DWORD''' 而在 '''BLUETOOTH_DEVICE_INFO''' 布局中没有其他内容。
当你的回调被调用时, '''authParams''' 是否有可能为 NULL?
正如另一位发帖者已经提到的,这可能是由于不正确的调用约定(缺少“CALLBACK”宏)导致正确的参数与编译代码正在读取的位置不一致。
第二个想法是:
可以表示为:
根据标准,这会将“btDeviceInfo”的其他字段清零。
I have a couple of thoughts to share with you, but be advised that these are hunches. I haven't compiled and debugged your code, although I commend you for posting a complete sample.
I think the crash may be within your authentication callback function, due to a '''NULL''' pointer dereference.
These lines:
will cause the message you describe, if you are running on 32-bit Windows, and '''authParams''' may be '''NULL''' -- in that case, '''deviceInfo''' contributes a zero offset (it is at the beginning of the '''BLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS'''), and '''.Address''' does contribute an offset of 4 ('''NULL + 4 == 0x00000004'''), because it follows a '''DWORD''' and nothing else within the '''BLUETOOTH_DEVICE_INFO''' layout.
Is it possible that '''authParams''' is NULL when your callback is called?
As another poster has already mentioned, this could be due to incorrect calling convention (lack of '''CALLBACK''' macro) -- causing otherwise correct parameters to mis-align with the positions the compiled code is reading.
The second thought was:
Can be represented by:
According to the standard, this will zero the other fields of '''btDeviceInfo'''.
或者编写托管代码并使用我的蓝牙库 32feet.NET 超级简单。 http://32feet.codeplex.com/
那么它会崩溃吗——如果是的话,那么你的电脑有问题...
Or write managed code and use my Bluetooth library 32feet.NET Super simple. http://32feet.codeplex.com/
Will it crash then -- if so there's something wrong on your PC...