windows下设备的Setup ClassGuid/Device Interface ClassGUID

原创 2016年08月29日 22:18:27

    windows下与设备相关的各种guid名目繁多,MSDN上的解释也写的扑朔迷离,因此想借本文总结一下这些guid应用场景.

    1.最常见的应该是Setup ClassGuid--设备安装类了.当我们打开设备管理器,默认情况下看到的设备列表就是按设备类型----更确切的讲是设备安装类型来排列显示的.比如,windwos将所有的网卡(PCI网卡/无线网卡/外接USB网卡)归到网络适配器一类;将独显集显归到显示适配器一类...windows这样归类的依据是,为同一类设备在驱动安装期间提供相同的安装行为.这种分类方式称为设备安装类(Setup Class).为了唯一的标示各种安装类,MS又用GUID加以区分,因此形成了Setup Class Guid.目前,MS为常见的设备安装类约定了各自的GUID,比如网卡的Setup Class GUID是{4d36e972-e325-11ce-bfc1-08002be10318}.而一些非主流的设备,需要vender自己定义设备安装类,如DDK样例toaster就自立门户的定义了一个设备安装类.除了在设备管理器中可以找到设备安装类GUID,我们可以在注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class找到各种设备类GUID.附带一句,inf文件的[VERSION]节ClassGUID键的值同样也是Setup Class Guid

[version]
Signature   = "$Windows NT$"
Class       = Net ;Realtek PCIe GBE Family Controller网卡的inf文件
ClassGUID   = {4d36e972-e325-11ce-bfc1-08002be10318}
    在代码中访问设备安装类的流程可以参照我前面的blog:整理SetupDixxx函数

    

    2.接着说说Device Interface Class.如果说Setup Class是按设备安装方式而进行分类,那Device Interface Class的功能相对较多:1).可以监听同一类设备是否被注册或者同属一个Device Interface Class中设备的interface被使能;2).用于枚举并打开设备.

    先看第一个功能,注册监听器.在驱动程序中,Fdo程序往往会在AddDevice中注册接口,并在其后IRP_MN_STARTDEVICE中调用IoSetDeviceInterfaceState来使能一个接口供其他系统中其他程序调用;系统中的其他驱动可以通过调用IoRegisterPlugPlayNotification来注册一个回调函数来获取接口使能的事件.MSDN如是注释:

The IoRegisterPlugPlayNotification routine registers a driver callback routine to be called when a PnP event of the specified category occurs. 
NTSTATUS 
  IoRegisterPlugPlayNotification(
    IN IO_NOTIFICATION_EVENT_CATEGORY  EventCategory,
    IN ULONG  EventCategoryFlags,
    IN PVOID  EventCategoryData  OPTIONAL,
    IN PDRIVER_OBJECT  DriverObject,
    IN PDRIVER_NOTIFICATION_CALLBACK_ROUTINE  CallbackRoutine,
    IN PVOID  Context,
    OUT PVOID  *NotificationEntry
    );
EventCategory 
Specifies the category of PnP event for which the callback routine is being registered. EventCategory must be one of the following: 
EventCategoryDeviceInterfaceChange 
PnP events in this category include the arrival (enabling) of a new instance of a device interface class (GUID_DEVICE_INTERFACE_ARRIVAL), 
or the removal (disabling) of an existing device interface instance (GUID_DEVICE_INTERFACE_REMOVAL).

    ReactOS启动过程1调用PoInitSystem初始化电源管理器时,调用IoRegisterPlugPlayNotification监听ACPI Fixed Button接口使能事件:

BOOLEAN
NTAPI
PoInitSystem(IN ULONG BootPhase,
             IN BOOLEAN HaveAcpiTable)
{
    IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
                                       0, /* The registry has not been initialized yet */
                                       (PVOID)&GUID_DEVICE_SYS_BUTTON,
                                       IopRootDeviceNode->
                                       PhysicalDeviceObject->DriverObject,
                                       PopAddRemoveSysCapsCallback,
                                       NULL,
                                       &NotificationEntry);
}
参数5即为回调函数,他要做的就是当接收到事件后,打开使能的接口以便后续处理:

NTSTATUS
NTAPI
PopAddRemoveSysCapsCallback(
	IN PVOID NotificationStructure,
	IN PVOID Context)
{
	Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationStructure;

	if (Notification->Size != sizeof(DEVICE_INTERFACE_CHANGE_NOTIFICATION))
		return STATUS_INVALID_PARAMETER;
	if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID) == sizeof(GUID)))
		Arrival = TRUE;
	else if (RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID) == sizeof(GUID)))
		Arrival = FALSE;
	else
		return STATUS_INVALID_PARAMETER;


		InitializeObjectAttributes(
			&ObjectAttributes,
			Notification->SymbolicLinkName, //获得符号链接名
			OBJ_KERNEL_HANDLE,
			NULL,
			NULL);
		//打开设备
		Status = ZwOpenFile(
			&FileHandle,
			FILE_READ_DATA,
			&ObjectAttributes,
			&IoStatusBlock,
			FILE_SHARE_READ | FILE_SHARE_WRITE,
			0);

		Status = ObReferenceObjectByHandle(
			FileHandle,
			FILE_READ_DATA,
			IoFileObjectType,
			ExGetPreviousMode(),
			(PVOID*)&FileObject,
			NULL);

		DeviceObject = IoGetRelatedDeviceObject(FileObject);
		ObDereferenceObject(FileObject);

		KeInitializeEvent(&Event, NotificationEvent, FALSE);
		Irp = IoBuildDeviceIoControlRequest(
			IOCTL_GET_SYS_BUTTON_CAPS,
			DeviceObject,
			NULL,
			0,
			&Caps,
			sizeof(Caps),
			FALSE,
			&Event,
		//应该是向底层ACPI.sys发送IRP,然后由BIOS完成相应的处理
		Status = IoCallDriver(DeviceObject, Irp);

    同样应用程序可以通过调用RegisterDeviceNotification得到类似的效果,如winddk/src/usb/usbview程序中,usbview.c调用RegisterDeviceNotification获得usb插入事件.

    broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;

    memcpy( &(broadcastInterface.dbcc_classguid),
            &(GUID_CLASS_USB_DEVICE),
            sizeof(struct _GUID));

    gNotifyDevHandle = RegisterDeviceNotification(hWnd,
                                                  &broadcastInterface,
                                                  DEVICE_NOTIFY_WINDOW_HANDLE);

    // Now register for Hub notifications.
    memcpy( &(broadcastInterface.dbcc_classguid),
            &(GUID_CLASS_USBHUB),
            sizeof(struct _GUID));

    gNotifyHubHandle = RegisterDeviceNotification(hWnd,
                                                  &broadcastInterface,
                                                  DEVICE_NOTIFY_WINDOW_HANDLE);
    不过RegisterDeviceNotification注册的事件发生后,貌似是用win32消息发送给制定窗口,由窗口进行事件处理.

    说完Device Interface Class的监听功能,再来说说它枚举和打开设备接口的功能.前面也说过,Fdo会在创建设备后为设备创建一个Interface,供上层应用程序访问,引入设备接口的原因是避免设备名冲突,不能保证自己为设备取的SymbolicLink不会和系统中其他设备的SymbolicLink重名,而引入设备接口后,通过128bit的数字指定设备名,就减少了重名的可能.

    

   以toaster驱动为例,他创建了一个接口.从winobj输出来看,其接口名是InstanceID+InterfaceGuid形式,这样大大减小了重名的概率.当然这也增加了程序访问设备的难度,这里我简单列出toaster中enum.exe枚举Device Interface ClassGUID然后打开Interface的代码以供参考:

//这段是驱动中注册接口
DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER,
        0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);
//  {D35F7840-6A0C-11d2-B841-00C04FAD5171}

NTSTATUS
Bus_AddDevice(
    PDRIVER_OBJECT DriverObject,
    PDEVICE_OBJECT PhysicalDeviceObject
    )
{
    ...

    status = IoCreateDevice (
                    DriverObject,               // our driver object
                    sizeof (FDO_DEVICE_DATA),   // device object extension size
                    NULL,                       // FDOs do not have names
                    FILE_DEVICE_BUS_EXTENDER,   // We are a bus
                    FILE_DEVICE_SECURE_OPEN,    //
                    TRUE,                       // our FDO is exclusive
                    &deviceObject);   
    ...
    status = IoRegisterDeviceInterface (
                PhysicalDeviceObject,
                (LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER,
                NULL,
                &deviceData->InterfaceName);
} 

NTSTATUS
Bus_StartFdo (
    PFDO_DEVICE_DATA            FdoData,
    PIRP   Irp )
{
    ...
    status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE);
    ...
}

//这段摘自应用层enum.cpp 枚举Interface guid并打开设备
hardwareDeviceInfo = SetupDiGetClassDevs (
                       (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER,
                       NULL, // Define no enumerator (global)
                       NULL, // Define no
                       (DIGCF_PRESENT | // Only Devices present
                       DIGCF_DEVICEINTERFACE)); // Function class devices.

    deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);

    if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo,
                                 0, // No care about specific PDOs
                                 (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER,
                                 0, //
                                 &deviceInterfaceData)) {

    SetupDiGetDeviceInterfaceDetail (
            HardwareDeviceInfo,
            DeviceInterfaceData,
            NULL, // probing so no output buffer yet
            0, // probing so output buffer length of zero
            &requiredLength,
            NULL); // not interested in the specific dev-node

    predictedLength = requiredLength;

    deviceInterfaceDetailData = malloc (predictedLength);

    if(deviceInterfaceDetailData)
        deviceInterfaceDetailData->cbSize =
                      sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);


    if (! SetupDiGetDeviceInterfaceDetail (
               HardwareDeviceInfo,
               DeviceInterfaceData,
               deviceInterfaceDetailData,
               predictedLength,
               &requiredLength,
               NULL)) {
        printf("Error in SetupDiGetDeviceInterfaceDetail\n");
        free (deviceInterfaceDetailData);
        return FALSE;
    }

    file = CreateFile ( deviceInterfaceDetailData->DevicePath,
                        GENERIC_READ, // Only read access
                        0, // FILE_SHARE_READ | FILE_SHARE_WRITE
                        NULL, // no SECURITY_ATTRIBUTES structure
                        OPEN_EXISTING, // No special create flags
                        0, // No special attributes
                        NULL); // No template file




版权声明:本文为博主原创文章,未经博主允许不得转载。

常见设备的GUID

用SetupDi*类函数可以进行设备管理,其中就要用到设备类的GUID。    全球唯一标识符 (GUID) 是一个字母数字标识符,用于指示产品的唯一性安装。在许多流行软件应用程序(例如 Web 浏览...
  • eric422113
  • eric422113
  • 2011年07月14日 21:55
  • 7037

Windows下设备GUID常识

原文地址 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class :是设备安装类GUID,在devguid.h中。 HKEY...
  • HeathLedger1990
  • HeathLedger1990
  • 2016年07月20日 15:22
  • 2698

VC自动侦测USB参考

关于USB设备的自动侦测,该如何解决 http://m.myexception.cn/vc-mfc/114413.html 关于USB设备的自动侦测 不知道为什么,U盘能侦测到插入和移除, US...
  • phenixyf
  • phenixyf
  • 2015年09月28日 12:59
  • 1875

怎么侦测USB端口上有设备插拔?

WM_DEVICECHANGLE消息,nEventType为DBT_DEVICEARRIVAL且dwData  = 7时就是U盘连接事件(没弄错的话)我想RegisterDeviceNotificat...
  • lanmanck
  • lanmanck
  • 2009年01月23日 09:22
  • 5390

Device Interface GUID

MSDN中的内容位置: DEVICE I/O下的 Device ManagementMSDN的Windows Multimedia#include       #include       #in...
  • tomorrowsprogress
  • tomorrowsprogress
  • 2009年06月24日 15:38
  • 2162

设备接口列举(备忘)常用手法

一般列举设备驱动都是安装程序需要完成的工作 HDEVINFO SetupDiCreateDeviceInfoList(     IN LPGUID ClassGuid, OPTIONAL    ...
  • rocispeng
  • rocispeng
  • 2012年11月06日 18:38
  • 738

INF文件详解(32位64位兼容INF)

INF文件格式要求 一个INF文件是以段组织的简单的文本文件。一些段油系统定义(System-Defined)的名称,而另一些段由INF文件的编写者命名。每个段包含特定的条目和命名,这些命名用于引用I...
  • whatday
  • whatday
  • 2013年08月30日 15:55
  • 16234

关于 设备安装类GUID、设备接口类GUID

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class :是设备安装类GUID HKEY_LOCAL_MACHINE\SYSTEM\Cur...
  • xiliang_pan
  • xiliang_pan
  • 2012年10月12日 15:34
  • 9515

常用设备接口类GUID

注意:在VC中使用这些常量名称时,除了包含相应的头文件外,还需要预先包含initguid.h头文件。即: [cpp] view plain copy #in...
  • hanghang121
  • hanghang121
  • 2016年06月13日 10:57
  • 1194

Device Interface Classes WDM

ms-help://MS.WDK.v10.7600.091201/DevInst_d/hh/DevInst_d/setup-cls_701b0efb-d581-4b55-84cc-a46816ddde...
  • kelsel
  • kelsel
  • 2016年10月08日 17:13
  • 86
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:windows下设备的Setup ClassGuid/Device Interface ClassGUID
举报原因:
原因补充:

(最多只允许输入30个字)