USB及手机平板设备插拔响应解决方案

本文详细介绍了在Windows环境下,通过WM_DEVICECHANGE消息响应USB及手机平板设备的插拔,包括基本原理、VC6中实现步骤、事件类型、参数解析、设备GUID获取、注册设备事件通知的方法,以及在DirectShow中的应用。通过不同方法实现设备插拔的有效判断,确保设备状态的实时响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

USB及手机平板设备插拔响应解决方案

(一)、基本原理:WM_DEVICECHANGE 消息响应

一般WM_DEVICECHANGE只发给顶层窗口。你可以自己创建一个隐藏的顶层窗口来接收这个消息。

(二)、在VC6中,一般要手动添加这个消息的映射代码,分三步,过程如下:

第1步:在窗口类的.h文件中增加:.

        afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);        

第2步:在窗口类的.cpp文件中增加:

     DECLARE_MESSAGE_MAP()

        ON_WM_DEVICECHANGE()

END_MESSAGE_MAP()

第3步:在窗口类的.cpp文件中增加:

BOOL CClassCtrl::OnDeviceChange(UINT nEventType, DWORD dwData)

{

        return (TRUE); // 返回TRUE表示不拒绝此操作

}

(三)在OnDeviceChange的参数中的nEventType,为如下状态定义:

#define DBT_DEVICEARRIVAL               0x8000  // system detected a new device

#define DBT_DEVICEQUERYREMOVE           0x8001  // wants to remove, may fail

#define DBT_DEVICEQUERYREMOVEFAILED     0x8002  // removal aborted

#define DBT_DEVICEREMOVEPENDING         0x8003  // about to remove, still avail.

#define DBT_DEVICEREMOVECOMPLETE        0x8004  // device is gone

#define DBT_DEVICETYPESPECIFIC          0x8005  // type specific event

#if(WINVER >= 0x040A)

#define DBT_CUSTOMEVENT                 0x8006  // user-defined event

#endif /* WINVER >= 0x040A */

(四)在OnDeviceChange的参数中的dwData,一般为如下状态定义:

PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)dwData;

if(pHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)

{

       PDEV_BROADCAST_DEVICEINTERFACE pInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr;       // pInf指向设备相关的信息结构体,参见以下节中的定义

}

(五)由WM_DEVICECHANGE获取设备GUID及设备名(可能含有VID-PID及SN)

typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A {

    DWORD       dbcc_size;

    DWORD       dbcc_devicetype;

    DWORD       dbcc_reserved;

    GUID        dbcc_classguid;

    char        dbcc_name[1];

} DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A;

dbcc_classguid 类似于:{A5DCBF10-6530-11D2-901F-00C04FB951ED}

(六)下面是一些常用的设备的class的GUID举例:

USB Raw Device/USB设备

 {a5dcbf10-6530-11d2-901f-00c04fb951ed} 

Disk Device/磁盘设备

 {53f56307-b6bf-11d0-94f2-00a0c91efb8b} 

Network Card/网卡

 {ad498944-762f-11d0-8dcb-00c04fc3358c} 

Human Interface Device (HID)

人机界面设备

 {4d1e55b2-f16f-11cf-88cb-001111000030} 

Palm/手持设备

 {784126bf-4190-11d4-b5c2-00c04f687a67}

 (七)如何“注册”设备的classGUID

对应的设备事件通知(WINVER 0x0500 方法):

#include <Dbt.h>

DEV_BROADCAST_DEVICEINTERFACE dbi;

ZeroMemory(&dbi,sizeof(dbi));

dbi.dbcc_size       = sizeof(dbi);

dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;

dbi.dbcc_reserved   = 0;

dbi.dbcc_classguid  = hid_guid;

HDEVNOTIFY hDevNotify;

hDevNotify = RegisterDeviceNotification(m_hWnd,

 &dbi, DEVICE_NOTIFY_WINDOW_HANDLE);

if(!hDevNotify)

{

     int Err = GetLastError();

     printf("RegisterDeviceNotification failed: %lx.\n", Err);

     return (FALSE);

}

注意:在程序结束前,一定要记得反注册:

UnregisterDeviceNotification(hDevNotify);

因默认VC6的WINVER宏定义是<0x0500的,故在必要时,在StdAfx.h中添加:

  #if   _MSC_VER   >   1000   

  #pragma   once   

  #endif   //   _MSC_VER   >   1000   

  #define   WINVER   0x0500 

  #define   VC_EXTRALEAN //   Exclude   rarely-used   stuff   from   Windows   headers   

(八)如何“注册”设备的classGUID对应的设备事件通知(动态加载-方法):

// 注册设备通知事件,须与反注册成对儿使用

PVOID RegistCapvNotice(HWND hWnd)

{

    if(!hWnd || !::IsWindow(hWnd)) return (NULL);

    HMODULE hModUser = GetModuleHandle(TEXT("user32.dll"));

    if(!hModUser) return (NULL);

    PRegistDevNotify fnReg = (PRegistDevNotify)GetProcAddress( \

        hModUser, TEXT("RegisterDeviceNotificationA"));

    if(!fnReg) return (NULL);

    

    STDEVINTRF dbci;

    ZeroMemory(&dbci, sizeof(STDEVINTRF));

    dbci.dbcc_size = sizeof(STDEVINTRF);

    dbci.dbcc_devicetype = 0x00000005;

    dbci.dbcc_classguid = AM_KSCATEGORY_CAPTURE;

    

    return (fnReg(hWnd, &dbci, 0x00000000));

}

// 取消注册设备通知(反注册),须与注册成对儿使用

BOOL UnRegistCapvNotice(PVOID hHandle)

{

    if(!hHandle) return (TRUE);

    HMODULE hModUser = GetModuleHandle(TEXT("user32.dll"));

    if(!hModUser) return (FALSE);

    

    PUnRegistDevNotify fnUreg = (PUnRegistDevNotify)GetProcAddress( \

        hModUser, TEXT("UnregisterDeviceNotification"));

    if(!fnUreg) return (FALSE);

    

    return (fnUreg(hHandle));

}

注意:上述在注册的classguid为AM_KSCATEGORY_CAPTURE,视频捕捉设备,可按需更换。

九)在DirectShow里,可以响应EC_DEVICE_LOST事件,来响应视频设备的插拔,它有2参数:lParam1  为(IUnknown*) Pointer,是描述当前设备的过滤器的。lParam2  为0=设备已经移除,1=设备又重新有效了(又上了)由于在移除后,设备过滤器不再有效,所以必须重建graph才行。实现的过滤分以下几步:

1、在类的.h里,增加    IMediaEventEx *m_pEvent;   // 过滤器事件通报

2、然后在创建IGraphBuilder后,获取m_pEvent接口:

    hr = m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pEvent);

3、在设置视频窗口时,把事件的目标窗口设置为所需要的:

    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hVdad, WM_DXGRAPHNOTIFY, 0);    

其中WM_DXGRAPHNOTIFY为窗口自定义消息,可以定义如下:

    #define WM_DXGRAPHNOTIFY     (WM_APP + 110)

4、然后在m_hVdad所在目标窗口类中,增加自定义消息WM_DXGRAPHNOTIFY的响应代码:

   

在.h中增加:

   afx_msg LRESULT OnDshowNotifyForMain(WPARAM wParam, LPARAM lParam);

   DECLARE_MESSAGE_MAP()   

在.cpp中增加:

   ON_MESSAGE(WM_DXGRAPHNOTIFY, OnDshowNotifyForMain)

   END_MESSAGE_MAP()   

   LRESULT CClassCtrl::OnDshowNotifyForMain(WPARAM wParam, LPARAM lParam)

   {

        DoEvt(); return (0); // 增加自定义处理,DoEvt参见下面定义

   }

   

5、DoEvt()里面需要使用m_pEvent接口,故m_pEvent可为全局量,为类中量DoEvt外

用:

   void CClass::DoEvt(void)

   {

      long evCode, param1, param2;

      while(m_pEvent && SUCCEEDED(m_pEvent->GetEvent( \

         &evCode, &param1, &param2, 0))) // 

遍历全部当前事件

      {

         m_pEvent->FreeEventParams(evCode, param1, param2);

         if(evCode == EC_DEVICE_LOST && !param2) Close();

      } 

   }

(十)为了有效地判断视频的插拔,可以采用如下2种方法。

第1种为:只使用WM_DEVICECHANGE消息,注册AM_KSCATEGORY_CAPTURE视频设备通知。    这样可以获取到DEV_BROADCAST_DEVICEINTERFACE结构体,里面有dbcc_name设备名。

    可以创建一个关于此dbcc_name设备的管理列表,响应插拔动作,与dbcc_name检查。

第2种为:对插和拔两个动作,分而治之:    

新到:使用WM_DEVICECHANGE消息来,获取设备插上的消息,打开新到设备。    

移除:再使用EC_DEVICE_LOST消息,来响应对应某个设备的移除。       

这是由于,EC_DEVICE_LOST在没有建立有效的Graph时,新到的设备,它是无法感知的。 EC_DEVICE_LOST只能是graph建立后,感知设备的移除,和它再次插入。所以,EC_DEVICE_LOST感知移除是很有效和针对性的,    再配合WM_DEVICECHANGE来判断新来插入的设备,再创建新的实例。

 

<think>嗯,用户想了解兼容性测试的应用场景和案例。首先,我需要回忆一下兼容性测试的基本概念。兼容性测试主要是确保软件在不同的硬件、操作系统、浏览器、设备等环境下能够正常工作。根据之前提供的引用,特别是引用[2]和引用[3],里面提到了兼容性测试的不同方面,比如Web应用的设备和浏览器兼容性,消费电子设备的接口兼容性,以及服务器系统的兼容性测试。 首先,用户可能想知道常见的应用场景有哪些。根据引用[2],Web应用测试需要考虑不同的浏览器和设备,比如Chrome、Firefox、Safari,以及不同的移动设备如iOS和Android。然后,消费电子设备的充电接口兼容性测试,如Type-C和Lightning接口,这在引用[3]中有详细说明。还有服务器系统的兼容性,引用[4]提到需要测试不同操作系统和硬件配置的兼容性。 接下来是案例部分。需要具体举例,比如Web应用中的在线文档编辑工具在不同浏览器下的表现,或者移动应用在不同手机型号上的适配问题。例如,引用[2]中的电商平台页面错乱问题,可能就是因为浏览器兼容性导致的。消费电子设备方面,引用[3]提到的Type-C接口插拔问题,以及充电协议的兼容性,比如PD和QC协议。服务器系统方面,引用[4]中的金融系统迁移到新服务器出现性能问题,可能是因为未充分测试系统兼容性。 然后,用户可能还想知道如何实施这些测试。比如,引用[2]提到使用Selenium、BrowserStack等工具进行自动化测试,引用[3]提到的物理接口耐久性测试方法,以及引用[4]中的系统性能分析工具。这些工具和方法可以帮助用户具体实施兼容性测试。 还要注意用户可能的深层需求,比如他们可能在进行软件开发或测试,需要实际案例和解决方案来指导他们的工作。因此,提供具体的测试策略和工具推荐会很有帮助。例如,针对Web应用,使用响应式设计和云测试平台;针对硬件接口,进行插拔测试和协议验证;针对服务器,进行多环境部署测试和性能监控。 最后,要确保回答结构清晰,分点列出场景和案例,并自然地引用提供的资料。同时,按照用户的要求生成相关问题,比如兼容性测试的步骤、工具选择、与功能测试的区别等,这些都能帮助用户进一步了解该主题。</think>### 兼容性测试的常见应用场景与案例 #### 一、兼容性测试的核心目标 兼容性测试旨在验证软件、硬件或系统在不同环境(如操作系统、浏览器、设备、接口等)下的正常运行能力,确保用户体验一致性和功能可靠性[^2][^3][^4]。 --- #### 二、典型应用场景及案例 1. **Web应用跨浏览器/设备兼容性** - **场景**:验证网页在Chrome、Safari、Firefox等不同浏览器,以及手机、平板、PC等设备上的显示和功能一致性。 - **案例**: - 某电商平台在Safari浏览器中出现页面布局错乱,通过CSS前缀兼容性调整解决[^2]。 - 在线教育系统在移动端触屏操作失效,通过响应式设计和触控事件优化修复[^2]。 **测试方法**: ```python # 使用Selenium自动化测试不同浏览器 from selenium import webdriver browsers = [webdriver.Chrome(), webdriver.Firefox()] for driver in browsers: driver.get("https://example.com") assert "首页" in driver.title driver.quit() ``` 2. **消费电子设备接口兼容性** - **场景**:验证Type-C、Lightning等接口与不同充电线、适配器的物理匹配和协议兼容性[^3]。 - **案例**: - 某手机Type-C接口因尺寸偏差导致插拔困难,通过改进模具公差解决。 - 快充协议(如PD/QC)与第三方充电器不兼容,引发充电速度异常,需更新电源管理固件[^3]。 3. **多操作系统/服务器环境兼容性** - **场景**:确保软件在Windows、Linux、macOS等系统或不同服务器配置下稳定运行。 - **案例**: - 金融系统迁移至新Linux服务器后出现内存泄漏,通过内核参数调优和依赖库版本匹配修复。 - 跨平台办公软件在macOS上文件保存失败,因文件路径格式差异导致,需统一路径处理逻辑。 4. **移动端多版本兼容性** - **场景**:适配Android 10~14或iOS 14~17等不同系统版本。 - **案例**: - 某社交App在Android 14上因隐私权限变更导致摄像头调用失败,需更新API调用方式。 - iOS 17新特性导致推送通知延迟,通过调整后台任务调度策略优化。 --- #### 三、关键测试策略 1. **环境优先级划分**:基于用户数据分析(如浏览器使用率、设备市场份额)确定测试重点。 2. **工具组合应用**: - 浏览器兼容性:BrowserStack、Selenium Grid - 移动设备兼容性:AWS Device Farm、itbuilder - 接口协议验证:USB-IF认证工具、ChargerLAB Power-Z 3. **自动化测试集成**:将兼容性测试嵌入CI/CD流程,实现快速反馈。 --- #### 四、常见问题与解决方案 | 问题类型 | 典型案例 | 解决方案 | |----------------|--------------------------|------------------------------| | 渲染差异 | CSS Flex布局在IE11错位 | 添加浏览器前缀或降级方案 | | API兼容性 | Android旧版本缺失新API | 使用兼容库(如AndroidX) | | 协议冲突 | 快充协议握手失败 | 固件支持多协议协商 | | 性能衰减 | 老旧设备运行卡顿 | 代码优化或功能降级策略 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值