windows下设备的Setup ClassGuid/Device Interface ClassGUID
2016-08-29 22:18
429 查看
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
2.接着说说Device Interface Class.如果说Setup Class是按设备安装方式而进行分类,那Device Interface Class的功能相对较多:1).可以监听同一类设备是否被注册或者同属一个Device Interface Class中设备的interface被使能;2).用于枚举并打开设备.
先看第一个功能,注册监听器.在驱动程序中,Fdo程序往往会在AddDevice中注册接口,并在其后IRP_MN_STARTDEVICE中调用IoSetDeviceInterfaceState来使能一个接口供其他系统中其他程序调用;系统中的其他驱动可以通过调用IoRegisterPlugPlayNotification来注册一个回调函数来获取接口使能的事件.MSDN如是注释:
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插入事件.
说完Device Interface Class的监听功能,再来说说它枚举和打开设备接口的功能.前面也说过,Fdo会在创建设备后为设备创建一个Interface,供上层应用程序访问,引入设备接口的原因是避免设备名冲突,不能保证自己为设备取的SymbolicLink不会和系统中其他设备的SymbolicLink重名,而引入设备接口后,通过128bit的数字指定设备名,就减少了重名的可能.
以toaster驱动为例,他创建了一个接口.从winobj输出来看,其接口名是InstanceID+InterfaceGuid形式,这样大大减小了重名的概率.当然这也增加了程序访问设备的难度,这里我简单列出toaster中enum.exe枚举Device Interface ClassGUID然后打开Interface的代码以供参考:
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 Class @ Windows Programming @setupapi
- Analysis of undocumented Windows function NhGetInterfaceNameFromDeviceGuid
- Device Interface GUID
- 程序实现启用/禁用设备(驱动)enable/disable device with windows api
- device_create device_destroy 使用==mknod及通过class_create自动创建设备节点
- The Windows Driver Model Simplifies Management of Device Driver I/O Requests(WDM对设备驱动I/O请求管理的简化)
- 介绍一个梅举设备信息的DDK函数:SetupDiGetClassDevs
- Human Interface Device (HID) Class Decoder
- class_create(),class_device_create()或device_create()自动创建设备文件结点
- IoEnumerateDeviceObjectList 枚举驱动的所有设备 文件过滤驱动 windows内核开发
- class_create(),device_create自动创建设备文件结点
- class_create(),device_create自动创建设备文件结点
- class_create(),device_create自动创建设备文件结点
- Graphics Device Interface:图形设备接口
- 驱动中使用class_device_create()报错的原因,自动创建设备节点
- SetupDiGetDeviceInterfaceDetail 函数
- 用SetupDiGetClassDevs枚举设备
- windows server 2008 r2通过Windows Mobile Device Center无法找到设备
- class_create(),class_device_create()或device_create()自动创建设备文件结点
- SetupDiEnumDeviceInfo-使用SetupDi系列函数进行设备信息的管理(二)