Windows原生蓝牙编程 第二章 选取设备输入配对码并配对【C++】

蓝牙系列文章目录
第一章 获取本地蓝牙并扫描周围蓝牙信息并输出
第二章 选取设备输入配对码并配对


文章目录

  • 前言
  • 头文件
  • 一、选择想要配对的设备并设置配对码
    • 1.1 设置配对码
    • 1.2 选择设备并配对
  • 二、全部代码
  • 三、测试结果
  • 总结


前言

接着第一章,我们已经把扫描到的蓝牙信息存在了vector数组res中了,接下来我们就要输入配对码进行配对了,为了好理解一点我把res改成devices了=v=


头文件

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4995)

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <stdlib.h>
#include<bluetoothapis.h>
#include <winsock.h>
#include <ws2bth.h>
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "bthprops.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string PassKey;
HANDLE btdi;
vector<BLUETOOTH_DEVICE_INFO> devices;
BLUETOOTH_DEVICE_INFO device;

一、选择想要配对的设备并设置配对码

这里我在第一章的基础上加了个序号,以方便我们选择想要连接的设备,其实也可以通过输入设备名或设备MAC地址来进行连接,做一次匹配找到设备。
这里我偷个懒选择序号来直接访问vector数组=v=,我顺便还把vector数组vector<BLUETOOTH_DEVICE_INFO> devices变成全局数组了,也是偷懒,真正用的时候直接封装到class里的就行了。我还加了个全局变量HANDLE btdi用于保存本地蓝牙句柄信息和BLUETOOTH_DEVICE_INFO device来保存设备。

int i = 0;

while (bfind)
{
	cout << ++i << "\t" << "[Name]:" << wstring2string(btdi.szName);  //远程蓝牙设备的名字
	cout << "\t[Address]:" << getMAC(btdi.Address) << endl;
	res.push_back(btdi);
	bfind = BluetoothFindNextDevice(hbdf, &btdi);//通过BluetoothFindFirstDevice得到的HBLUETOOTH_DEVICE_FIND句柄来枚举搜索下一个远程蓝牙设备,并将远程蓝牙设备的信息储存在btdi中
}
BluetoothFindDeviceClose(hbdf);//使用完后记得关闭HBLUETOOTH_DEVICE_FIND句柄hbdf。

选择好设备后,我们从键盘中输入配对码,设置一个全局string变量PassKey来进行保存配对码。
但注意,如果你使用的单片机这种可以手动设置配对码的设备进行双方通信的话,这个方法是有效的。
但如果你使用其他设备如手机和PC进行连接,那么这个方法是无效的,因为每次PC和手机的配对码都是随机且需要双方同时确认。那么针对PC和手机就需要手动进行连接,连接之后系统会自动保存双方配对码,完成配对,那么就可以可以通过device.fAuthenticated来进行读取当前设备是否已经配对,就不需要设置配对码了。

这里还有个小点是,windowsAPI里配对码是PWSTR类型,我们也需要把输入的string类型的配对码转成PWSTR

1.1 设置配对码

void setPassKey() {
	cout << "请输入配对码:(如果不知道请输入默认0000)";
	cin >> PassKey;
	cout << "您输入的配对码为: " << PassKey << endl;
}

1.2 选择设备并配对

void pairDevice() {
	cout << "输入你想要配对的设备的序号:";
	int index;
	cin >> index;
	//获取设备信息
	BLUETOOTH_DEVICE_INFO device = devices[index - 1];
	//输入配对码
	setPassKey();
	//string转PWSTR
	wstringstream wss;
	for (char c : PassKey) {
		wss << wchar_t(c);
	}
	wstring wstr = wss.str();
	const wchar_t* wcharPtr = wstr.c_str();
	PWSTR AUTHENTICATION_PASSKEY = const_cast<PWSTR>(wcharPtr);
	//开始配对
	wstring ws = device.szName;
	HBLUETOOTH_AUTHENTICATION_REGISTRATION hCallbackHandle = 0;
	DWORD result = -1;
	if (!device.fAuthenticated) {
		result = BluetoothAuthenticateDevice(NULL, btdi, &device, AUTHENTICATION_PASSKEY, (ULONG)wcslen(AUTHENTICATION_PASSKEY));  //配对函数,AUTHENTICATION_PASSKEY是我的蓝牙配对码
		if (result != ERROR_SUCCESS) {
			switch (result)
			{
			case ERROR_CANCELLED:
				cout << "用户取消了身份验证或配对操作" << endl;
				break;
			case ERROR_INVALID_PARAMETER:
				cout << "传递给函数的参数无效" << endl;
				break;
			case ERROR_NO_MORE_ITEMS:
				cout << "没有更多的设备可以配对" << endl;
				break;
			case ERROR_NOT_SUPPORTED:
				cout << "不支持请求的操作" << endl;
				break;
			case ERROR_GEN_FAILURE:
				cout << "通用失败错误" << endl;
				break;
			case ERROR_BUSY:
				cout << "蓝牙堆栈忙" << endl;
				break;
			case ERROR_TIMEOUT:
				cout << "操作超时" << endl;
				break;
			case ERROR_DEVICE_NOT_CONNECTED:
				cout << "蓝牙设备未连接" << endl;
				break;
			case ERROR_DEVICE_NOT_AVAILABLE:
				cout << "设备不可用" << endl;
				break;
			default:
				cout << "校验码出错,请手动进行设备连接" << endl;
				break;
			}
			return;
		}
	}
	cout << "身份验证成功,蓝牙设备已成功配对" << endl;;
	BluetoothUpdateDeviceRecord(&device);
}

还有一个小点:result = BluetoothAuthenticateDevice(NULL, btdi, &device, AUTHENTICATION_PASSKEY, (ULONG)wcslen(AUTHENTICATION_PASSKEY));中,BluetoothAuthenticateDevice已经不支持使用,被标记为deprecated了,因为我这是老版本上要使用的只能用这个,需要加上#pragma warning(disable : 4995)。

二、全部代码

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 4995)

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <windows.h>
#include <stdlib.h>
#include<bluetoothapis.h>
#include <winsock.h>
#include <ws2bth.h>
#pragma comment(lib, "wsock32.lib")
#pragma comment(lib, "bthprops.lib")
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string PassKey;
HANDLE btdi;
vector<BLUETOOTH_DEVICE_INFO> devices;
BLUETOOTH_DEVICE_INFO device;

string wstring2string(const wstring& ws)
{
	string curLocale = setlocale(LC_ALL, NULL);
	setlocale(LC_ALL, "chs");
	const wchar_t* _Source = ws.c_str();
	size_t _Dsize = 2 * ws.size() + 1;
	char* _Dest = new char[_Dsize];
	memset(_Dest, 0, _Dsize);
	wcstombs(_Dest, _Source, _Dsize);
	string result = _Dest;
	delete[]_Dest;
	setlocale(LC_ALL, curLocale.c_str());
	return result;
}

string getMAC(BLUETOOTH_ADDRESS Daddress)
{
	/*string addr;
	addr = addr.sprintf("%02x:%02x:%02x:%02x:%02x:%02x", Daddress.rgBytes[5], Daddress.rgBytes[4], Daddress.rgBytes[3], Daddress.rgBytes[2], Daddress.rgBytes[1], Daddress.rgBytes[0]);
	return addr;*/
	ostringstream oss;
	oss << hex << setfill('0') << uppercase;
	for (int i = 5; i >= 0; --i) {
		oss << setw(2) << static_cast<int>(Daddress.rgBytes[i]);
		if (i > 0) {
			oss << ":";
		}
	}
	return oss.str();
}

vector<BLUETOOTH_DEVICE_INFO> scanDevices()
{
	HBLUETOOTH_RADIO_FIND hbf = NULL;
	HANDLE hbr = NULL;
	HBLUETOOTH_DEVICE_FIND hbdf = NULL;
	BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) }; //调用BluetoothFindFirstDevice搜索本机蓝牙收发器所需要的搜索参数对象
	BLUETOOTH_RADIO_INFO bri = { sizeof(BLUETOOTH_RADIO_INFO) }; //初始化一个储存蓝牙收发器信息(BLUETOOTH_RADIO_INFO)的对象bri
	BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS) };//调用BluetoothFindFirstDevice搜索本所需要的搜索参数对象
	BLUETOOTH_DEVICE_INFO btdi = { sizeof(BLUETOOTH_DEVICE_INFO) };  //初始化一个远程蓝牙设备信息(BLUETOOTH_DEVICE_INFO)对象btdi,以储存搜索到的蓝牙设备信息
	hbf = BluetoothFindFirstRadio(&btfrp, &hbr); //得到第一个被枚举的蓝牙收发器的句柄hbf可用于BluetoothFindNextRadio,hbr可用于BluetoothFindFirstDevice。若没有找到本机的蓝牙收发器,则得到的句柄hbf=NULL

	vector<BLUETOOTH_DEVICE_INFO> res;

	bool brfind = hbf != NULL;
	while (brfind)
	{
		if (BluetoothGetRadioInfo(hbr, &bri) == ERROR_SUCCESS)//获取蓝牙收发器的信息,储存在bri中
		{
			cout << "[Local Device Name]:" << wstring2string(bri.szName) << "\t";   //蓝牙收发器的名字
			cout << "[Local Device Address]: " << getMAC(bri.address) << endl;
			cout << "------------------------蓝牙扫描结果如下----------------------------" << endl;

			btsp.hRadio = hbr;  //设置执行搜索设备所在的句柄,应设为执行BluetoothFindFirstRadio函数所得到的句柄
			btsp.fReturnAuthenticated = TRUE;//是否搜索已配对的设备
			btsp.fReturnConnected = FALSE;//是否搜索已连接的设备
			btsp.fReturnRemembered = TRUE;//是否搜索已记忆的设备
			btsp.fReturnUnknown = TRUE;//是否搜索未知设备
			btsp.fIssueInquiry = TRUE;//是否重新搜索,True的时候会执行新的搜索,时间较长,FALSE的时候会直接返回上次的搜索结果。
			btsp.cTimeoutMultiplier = 30;//指示查询超时的值,以1.28秒为增量。 例如,12.8秒的查询的cTimeoutMultiplier值为10.此成员的最大值为48.当使用大于48的值时,调用函数立即失败并返回
			hbdf = BluetoothFindFirstDevice(&btsp, &btdi);//通过找到第一个设备得到的HBLUETOOTH_DEVICE_FIND句柄hbdf来枚举远程蓝牙设备,搜到的第一个远程蓝牙设备的信息储存在btdi对象中。若没有远程蓝牙设备,hdbf=NULL。
			bool bfind = hbdf != NULL;
			int i = 0;

			while (bfind)
			{
				cout << ++i << " " << "[Name]:" << wstring2string(btdi.szName);  //远程蓝牙设备的名字
				cout << "\t[Address]:" << getMAC(btdi.Address) << endl;
				res.push_back(btdi);
				bfind = BluetoothFindNextDevice(hbdf, &btdi);//通过BluetoothFindFirstDevice得到的HBLUETOOTH_DEVICE_FIND句柄来枚举搜索下一个远程蓝牙设备,并将远程蓝牙设备的信息储存在btdi中
			}
			BluetoothFindDeviceClose(hbdf);//使用完后记得关闭HBLUETOOTH_DEVICE_FIND句柄hbdf。
		}
		CloseHandle(hbr);
		brfind = BluetoothFindNextRadio(hbf, &hbr);//通过BluetoothFindFirstRadio得到的HBLUETOOTH_RADIO_FIND句柄hbf来枚举搜索下一个本地蓝牙收发器,得到可用于BluetoothFindFirstDevice的句柄hbr。
	}
	return res;
}

void setPassKey() {
	cout << "请输入配对码:(如果不知道请输入默认0000):";
	cin >> PassKey;
	cout << "您输入的配对码为: " << PassKey << endl;
}

void pairDevice() {
	cout << "输入你想要配对的设备的序号:";
	int index;
	cin >> index;
	//获取设备信息
	device = devices[index - 1];
	//输入配对码
	setPassKey();
	//string转PWSTR
	wstringstream wss;
	for (char c : PassKey) {
		wss << wchar_t(c);
	}
	wstring wstr = wss.str();
	const wchar_t* wcharPtr = wstr.c_str();
	PWSTR AUTHENTICATION_PASSKEY = const_cast<PWSTR>(wcharPtr);
	//开始配对
	wstring ws = device.szName;
	HBLUETOOTH_AUTHENTICATION_REGISTRATION hCallbackHandle = 0;
	DWORD result = -1;
	if (!device.fAuthenticated) {
		result = BluetoothAuthenticateDevice(NULL, btdi, &device, AUTHENTICATION_PASSKEY, (ULONG)wcslen(AUTHENTICATION_PASSKEY));  //配对函数,AUTHENTICATION_PASSKEY是我的蓝牙配对码
		if (result != ERROR_SUCCESS) {
			switch (result)
			{
			case ERROR_CANCELLED:
				cout << "用户取消了身份验证或配对操作" << endl;
				break;
			case ERROR_INVALID_PARAMETER:
				cout << "传递给函数的参数无效" << endl;
				break;
			case ERROR_NO_MORE_ITEMS:
				cout << "没有更多的设备可以配对" << endl;
				break;
			case ERROR_NOT_SUPPORTED:
				cout << "不支持请求的操作" << endl;
				break;
			case ERROR_GEN_FAILURE:
				cout << "通用失败错误" << endl;
				break;
			case ERROR_BUSY:
				cout << "蓝牙堆栈忙" << endl;
				break;
			case ERROR_TIMEOUT:
				cout << "操作超时" << endl;
				break;
			case ERROR_DEVICE_NOT_CONNECTED:
				cout << "蓝牙设备未连接" << endl;
				break;
			case ERROR_DEVICE_NOT_AVAILABLE:
				cout << "设备不可用" << endl;
				break;
			default:
				cout << "校验码出错,请手动进行设备连接" << endl;
				break;
			}
			return;
		}
	}
	cout << "身份验证成功,蓝牙设备已成功配对" << endl;;
	BluetoothUpdateDeviceRecord(&device);
}

void main() {
	devices = scanDevices();
	pairDevice();
	return;
}

三、测试结果

我的手机和电脑已经提前配对好了,原因我已经在本文的第一点里已经说过了。
在这里插入图片描述
编译运行一下,老规矩MAC地址打码=v=
在这里插入图片描述
输入我要连接我的手机,输入序号5
输入配对码,已经我已经和电脑配对过了,但我也不知道配对码是多少没输入0000
结果如下
在这里插入图片描述
用系统保存过的信息配对,完美配对。

总结

如果您觉得有用请点赞评论收藏一波,下一章我们开始通信!=v=

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/109785.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode 43. 字符串相乘 中等

题目 - 点击直达 1. 43. 字符串相乘 中等1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 思路一 做加法1. 思路分析2. 时间复杂度3. 代码实现 3. 思路二 做乘法1. 思路分析2. 时间复杂度3. 代码实现 1. 43. 字符串相乘 中等 1. 题目详情 给定两个以字符串形式表示的非负整…

Acrobat Pro DC 2023 PDF编辑器 for Mac

Acrobat Pro DC是一款由Adobe开发的专业级PDF编辑和管理软件。作为PDF行业的标准工具&#xff0c;它提供了广泛的功能和工具&#xff0c;适用于个人用户、企业和专业人士。 Acrobat Pro DC具备丰富的编辑功能&#xff0c;可以对PDF文件进行文本编辑、图像编辑和页面重排等操作。…

订水商城H5实战教程-05权限控制

目录 1 判断用户是否登录2 创建事件流3 获取不到Userid的问题4 权限控制整体效果 我们上一篇讲解了用户注册的功能&#xff0c;当用户注册完毕的时候再次打开小程序的时候就需要验证权限。权限分为两类&#xff0c;第一类是判断用户是否注册&#xff0c;第二类是当前用户具备什…

Linux启动之uboot分析

Linux启动之uboot分析 uboot是什么&#xff1f;一、补充存储器概念1.存储器种类1.norflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;2.nandflash - 是非易失性存储器&#xff08;也就是掉电保存&#xff09;3.SRAM - 静态随机访问存储器 - Static Random Acc…

什么是鉴权?一篇文章带你了解postman的多种方式

一、什么是鉴权&#xff1f; 鉴权也就是身份认证&#xff0c;就是验证您是否有权限从服务器访问或操作相关数据。发送请求时&#xff0c;通常必须包含相应的检验参数以确保请求具有访问权限并返回所需数据。通俗的讲就是一个门禁&#xff0c;您想要进入室内&#xff0c;必须通…

MySQL(3):基本的 SELECT 语句

SQL 语言 SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是使用关系模型的数据库应用语言&#xff0c; 与数据直接打交道 。 SQL 有两个重要的标准&#xff0c;分别是 SQL92 和 SQL99&#xff0c;它们分别代表了 92 年和 99 年颁布的 SQL 标…

一体化模型图像去雨+图像去噪+图像去模糊(图像处理-图像复原-代码+部署运行教程)

本文主要讲述了一体化模型进行去噪、去雨、去模糊&#xff0c;也就是说&#xff0c;一个模型就可以完成上述三个任务。实现了良好的图像复原功能&#xff01; 先来看一下美女复原.jpg 具体的&#xff1a; 在图像恢复任务中&#xff0c;需要在恢复图像的过程中保持空间细节…

windows应用软件扫描报告 不告谱 要钱

chatGPT开路&#xff0c;帮找。 当你想要查找Windows软件的漏洞而不涉及查看源代码时&#xff0c;你可以使用一些专门设计用于扫描漏洞的工具。这些工具通常会检查已安装的软件和操作系统的漏洞&#xff0c;并提供建议或修补程序。以下是一些可以用于查找Windows软件漏洞的工具…

SQL优化(慢查询优化方法)正确使用数据库索引

文章目录 (一) 建立索引的正确姿势1 &#xff09;索引不要包含选择性过低字段2&#xff09; 选择性高的字段前置或者单独建立索引3&#xff09;尽量使用覆盖索引 (二) 使用索引的正确姿势1&#xff09; 最左匹配截断2&#xff09; 隐式转换3&#xff09; in order by 导致排序失…

R2R 的一些小tip

批次间控制器(Run-to-run Controller)&#xff0c;以应对高混合生产的挑战。将最优配方参数与各种工业特征相关联的模型是根据历史数据离线训练的。预测的最优配方参数在线用于调整工艺条件。 批次控制(R2R control)是一种先进的工艺控制技术&#xff0c;可在运行(如批次或晶圆…

Matlab | 基于二次谱提取地震数据的地震子波

本文通过地震数据二次谱求取地震子波谱&#xff0c;具体方法如下&#xff1a; MATLAB代码实现如下&#xff1a; function w SndSpecExtWavelet(x, M) % 功能&#xff1a;基于二次谱提取输入地震数据data的地震子波wavelet % Extracting Wavelet from Input Seismic Dat…

Flutter 使用 GetX 中遇到的问题

创建了控制器&#xff0c;但是在别的页面中&#xff0c;无法引用控制器里面的某些变量 如下图&#xff1a;后来发现&#xff0c;是命名的问题&#xff0c; 如果是以 _ 下划线开头的变量&#xff0c;那么就无法被引用

测开(性能测试---LoadRunner)

目录 一、LoadRunner的安装 二、Loadrunner的基本概念 三、开发测试脚本——VUG 3.1 脚本录制 3.2 脚本加强 四、设计场景——Controller LoadRunner是一款开源桌面应用软件&#xff0c;可用来模拟用户负载完成性能测试工作&#xff0c;LoadRunner的功能在版本不断升级的…

SDP协议分析

目录 SDP的结构SDP语法必需字段可选字段字段顺序子字段 3.SDP例子 1. SDP的结构 SDP&#xff08;Session Description Protocol&#xff09;完全是⼀种会话描述格式&#xff0c;它不属于传输协议&#xff0c;它只使⽤于适当的传输协议&#xff0c;包括会话通知协议&#xf…

ERROR: There can be only one Game target per project.

UATHelper: Packaging (Windows (64-bit)): ERROR: There can be only one Game target per project. D:\dock\Intermediate\Source 把旧的文件删去 一般会出现在更改项目名称后 感谢 There can be only one Game target per project - Development Discussion / Content C…

关于Spring和SpringBoot中对配置文件的读取

Spring读取xml文件 具体流程见网址Spring源码分析2 — spring XML配置文件的解析流程 - 知乎 (zhihu.com) 我这里只做一下总结和自己的理解&#xff1a; &#xff08;1&#xff09;通过getConfigLocations方法, 从web.xml文件中读取配置文件地址&#xff0c;如果web.xml中读取…

使用 jdbc 技术升级水果库存系统(后端最终版本,不包含前端)

1、配置依赖 <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><dependency><groupId>junit</groupId><…

智能工厂解决方案

智能工厂解决方案&#xff1a;生产工单 智能工厂解决方案&#xff1a;物流中转 样品单-4.2寸 工单任务卡-4.2寸 工单流转卡-4.2寸 生产配送卡-4.2寸 工序参数卡-7.5寸 生产拣配单-7.5寸 仓库24代-参数 接收路由器发送的数据信息并解析&#xff0c;做出相应的指示&#…

图片去除水印文字怎么去除?这几个方法快来收藏

图片怎么去除水印文字&#xff1f;现在嘛&#xff0c;图片已经成了我们生活和工作里必不可少的一部分&#xff0c;可是有时候看图的时候&#xff0c;总会碰到一些带水印的图片&#xff0c;这些水印总是搞得图片看起来不那么爽&#xff0c;所以很多人都想知道图片怎么去除水印文…

如何改善设备综合效率(OEE)并提高工厂的生产力

在现代制造业中&#xff0c;提高设备综合效率&#xff08;Overall Equipment Efficiency&#xff0c;OEE&#xff09;是企业追求高效生产和优化生产能力的重要目标之一。OEE是一个关键的绩效指标&#xff0c;可以帮助企业评估设备的利用效率、生产效率和质量水平。本文将从三个…