Windows下用VS2019编译libusb,手把手打造你的专属ADB调试工具(C语言实战)
Windows平台实战:用VS2019编译libusb打造ADB控制工具
在嵌入式开发和移动设备调试领域,USB通信一直是核心技术痛点。许多开发者习惯使用现成的ADB工具,却对底层通信机制知之甚少。本文将带你从零开始,在Windows平台上用VS2019编译libusb库,并开发一个能直接控制Android设备屏幕的实用工具。不同于常规教程只讲理论,我们会深入每个配置细节,解决实际开发中90%的坑点。
1. 环境准备与libusb编译
1.1 工具链安装
开发USB通信程序需要准备以下环境组件:
- Visual Studio 2019:建议安装"使用C++的桌面开发"工作负载
- Git for Windows:用于获取libusb源码
- CMake 3.20+:跨平台构建工具
- Windows Driver Kit (WDK):可选,用于驱动签名
注意:确保安装时勾选"MSVC v142 - VS2019 C++ x64/x86构建工具"和"Windows 10 SDK"
1.2 获取libusb源码
打开Git Bash执行以下命令克隆最新源码:
git clone https://github.com/libusb/libusb.git cd libusb git checkout v1.0.24 # 使用稳定版本1.3 编译libusb静态库
在libusb目录创建build文件夹,使用CMake配置工程:
mkdir build && cd build cmake .. -G "Visual Studio 16 2019" -A Win32 -DCMAKE_BUILD_TYPE=Release关键CMake参数说明:
| 参数 | 作用 | 推荐值 |
|---|---|---|
-G | 指定生成器 | VS2019对应"Visual Studio 16 2019" |
-A | 平台架构 | Win32或x64 |
-DBUILD_SHARED_LIBS | 生成动态库 | OFF(建议静态链接) |
用VS2019打开生成的libusb.sln,编译ALL_BUILD项目。成功后在build目录的lib/Release下会生成:
libusb-1.0.lib:静态库文件libusb-1.0.dll:动态链接库
2. VS2019项目配置实战
2.1 创建控制台项目
新建Win32控制台项目,配置关键属性:
- C/C++ → 常规 → 附加包含目录:添加libusb源码目录的
libusb文件夹 - 链接器 → 输入 → 附加依赖项:添加
libusb-1.0.lib - C/C++ → 预处理器 → 预处理器定义:添加
LIBUSB_STATIC
2.2 解决常见编译错误
错误1:无法打开包括文件: "config.h"
解决方案:从libusb源码的msvc目录复制config.h到项目包含路径
错误2:LNK2019: 无法解析的外部符号 __imp_libusb_init
解决方案:检查是否正确定义了LIBUSB_STATIC宏
2.3 部署运行时文件
将以下文件复制到exe输出目录:
libusb-1.0.dlllibusb-1.0.pdb(调试用)
3. ADB通信协议深度解析
3.1 ADB协议帧结构
ADB使用二进制协议帧,核心结构如下:
#pragma pack(push, 1) typedef struct { uint32_t command; // 命令标识(如A_SYNC, A_CNXN) uint32_t arg0; // 参数1 uint32_t arg1; // 参数2 uint32_t data_length; // 数据长度 uint32_t data_crc32; // 数据校验 uint32_t magic; // 固定为0xFFFFFFFF ^ command } amessage; typedef struct { amessage msg; uint8_t payload[1024]; // 实际数据 } apacket; #pragma pack(pop)3.2 USB端点识别
Android设备的ADB接口有特定标识:
#define ADB_VENDOR_ID 0x18D1 // Google VID #define ADB_CLASS 0xFF #define ADB_SUBCLASS 0x42 #define ADB_PROTOCOL 0x01设备枚举代码示例:
libusb_device** devs; ssize_t cnt = libusb_get_device_list(NULL, &devs); for(int i=0; devs[i]; i++){ libusb_device_descriptor desc; libusb_get_device_descriptor(devs[i], &desc); if(desc.idVendor == ADB_VENDOR_ID){ // 检查接口描述符 libusb_config_descriptor* config; libusb_get_config_descriptor(devs[i], 0, &config); for(int j=0; j<config->bNumInterfaces; j++){ const libusb_interface* inter = &config->interface[j]; // ...检查接口类/子类/协议 } } }4. 实现屏幕控制功能
4.1 建立ADB连接流程
完整的ADB连接需要以下步骤:
- 初始化libusb上下文
- 查找并匹配ADB接口
- 申请接口控制权
- 发送认证密钥
- 建立CNXN会话
- 发送命令
关键认证代码:
int authenticate(libusb_device_handle* dev_handle){ apacket pkt; memset(&pkt, 0, sizeof(pkt)); // 发送AUTH请求 pkt.msg.command = A_AUTH; pkt.msg.arg0 = ADB_AUTH_TOKEN; send_packet(dev_handle, &pkt); // 等待设备响应 while(1){ if(receive_packet(dev_handle, &pkt) < 0) return -1; if(pkt.msg.command == A_CNXN){ printf("认证成功!\n"); return 0; } } }4.2 屏幕控制命令实现
Android通过input子系统控制设备,常用命令:
| 命令 | 功能 | KeyEvent值 |
|---|---|---|
| 亮屏 | 唤醒设备 | 224 |
| 熄屏 | 关闭屏幕 | 26 |
| 电源键 | 开关屏幕 | 26 |
| 主页键 | 返回主页 | 3 |
实现熄屏的完整代码:
void turn_off_screen(libusb_device_handle* dev_handle){ apacket pkt; char cmd[] = "shell:input keyevent 26"; pkt.msg.command = A_OPEN; pkt.msg.arg0 = 0; pkt.msg.arg1 = 0; pkt.msg.data_length = strlen(cmd); memcpy(pkt.payload, cmd, pkt.msg.data_length); send_packet(dev_handle, &pkt); // 等待命令执行结果 while(receive_packet(dev_handle, &pkt) == 0){ if(pkt.msg.command == A_OKAY){ printf("屏幕已关闭\n"); break; } } }4.3 调试技巧与排错
常见问题1:LIBUSB_ERROR_ACCESS(权限不足)
解决方案:
- 确保设备已开启USB调试
- 使用Zadig工具替换驱动为libusb-win32
- 以管理员身份运行程序
常见问题2:设备连接后立即断开
检查点:
- USB线缆质量
- 主机USB端口供电能力
- 尝试不同的USB传输模式
实用调试命令:
# 查看USB设备列表 libusb_print_devices() # 启用详细日志 libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_DEBUG);5. 工程化进阶技巧
5.1 多线程处理
USB通信建议采用生产者-消费者模式:
void* read_thread(void* arg){ while(!exit_flag){ apacket pkt; if(receive_packet(dev_handle, &pkt) == 0){ pthread_mutex_lock(&queue_mutex); enqueue(packet_queue, &pkt); pthread_mutex_unlock(&queue_mutex); } } return NULL; }5.2 性能优化
提升传输效率的关键参数:
// 设置USB传输超时(毫秒) libusb_bulk_transfer(dev_handle, endpoint, data, length, &transferred, 5000); // 调整缓冲区大小 #define MAX_PACKET_SIZE 512 // 全速USB #define MAX_PACKET_SIZE 1024 // 高速USB5.3 跨平台兼容
通过条件编译实现多平台支持:
#ifdef _WIN32 #include <windows.h> #define SLEEP_MS(ms) Sleep(ms) #else #include <unistd.h> #define SLEEP_MS(ms) usleep((ms)*1000) #endif在实际项目中,我发现最稳定的通信方式是采用同步传输+超时重试机制。当处理大批量数据时,适当增大USB传输缓冲区可以减少系统调用开销。对于需要频繁发送小命令的场景(如屏幕控制),建议维护一个命令队列统一处理。
