通过设备接口寻找设备

设备接口

在WDM驱动中,一般很少用到设备名,也很少用到符号链接,而是用一个设备接口
来指定设备。设备接口其实就是一组全局标识,它是一个128位组成的数字,并能保证在
全世界范围内不会产生冲突。

引入设备接口的主要原因是避免设备名冲突,例如,不同的网卡厂商可能都将自己的
设备名命名为“NetCardDevice",当用户插入两块网卡时,就会引起命名冲突。而引入设
备接口的概念,各个网卡厂商用自己定义的128位数字指定自己的设备,从小概率意义上,
保证了各个设备的设备接口不会一样。

WDM驱动中设置接口

在WDM驱动程序中使用设备接口,首先在创建设备的时候,不能指定设备名,这样
系统会为设备自动创建一个设备名, 该设备名就是一个数字,新设备加入的时候,数字依
次递增。
另外不用IoCreateSymbolicLink创建符号链接,而是用loRegisterDeviceInterface为设备创
建设备接口。应用程序通过设备接口来寻找到设备.

//需要包含此头文件
#include <initguid.h>
//在VS中使用生成GUID  选第二种方式
DEFINE_GUID(MY_WDM_DEVICE, 0xe57c50f, 0xccc, 0x4ad2, 0xa8, 0x95, 0x93, 0xc5, 0xed, 0x11, 0x98, 0x60);

NTSTATUS IoRegisterDeviceInterface(
	IN PDEVICE OBJECT PhysicalDeviceobject,	//物理设备对象 也就是pdo
	IN CONST GUID *InterfaceClassGuid,	//设备接口的指针,这里是GUID类型的指针
	IN PUNICODE STRING ReferenceString OPTIONAL,	//一般设置为NULL
	OUT PUNICODE_STRING SymbolicLinkName	//将GUID输出一串UNICODE字符串
)

创建设备接口

#pragma PAGEDCODE
NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
                           IN PDEVICE_OBJECT PhysicalDeviceObject)
{ 
	//判断代码是否运行在分页内存中
	PAGED_CODE();
	KdPrint(("Enter HelloWDMAddDevice\n"));

	NTSTATUS status;
	PDEVICE_OBJECT fdo;
	status = IoCreateDevice(
		DriverObject,
		sizeof(DEVICE_EXTENSION),
		NULL,//没有指定设备名
		FILE_DEVICE_UNKNOWN,
		0,
		FALSE,
		&fdo);
	if( !NT_SUCCESS(status))
		return status;
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
	pdx->fdo = fdo;
	//附加设备到pdo上
	pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);

	//创建设备接口
	status = IoRegisterDeviceInterface(PhysicalDeviceObject, &MY_WDM_DEVICE, NULL, &pdx->interfaceName);

	if( !NT_SUCCESS(status))
	{
		IoDeleteDevice(fdo);
		return status;
	}
	DbgPrint("SymbolLIinkName=%wZ\n", &pdx->interfaceName);
	//设置接口状态
	IoSetDeviceInterfaceState(&pdx->interfaceName, TRUE);

	if( !NT_SUCCESS(status))
	{
		if( !NT_SUCCESS(status))
		{
			return status;
		}
	}

	fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
	fdo->Flags &= ~DO_DEVICE_INITIALIZING;

	KdPrint(("Leave HelloWDMAddDevice\n"));
	return STATUS_SUCCESS;
}

其实pdx->interfaceName就是暴露给应用程序的符号链接,也就是符号链
接。而这种新符号链接由以下四部分组成:

(1)第一部分是何种总线的设备,如图13-3中的设备就是根总线上的设备,即ROOT。
(2)第二部分是类设备的名称,如图13-3中的设备就是ZHANGFANDEVICE.

(3)第三部分是这种设备的第几个设备,
(4)第四部分是指定的设备接口的GUID。
在后面的讲述中可以看出,应用程序就是通过这组符号链接找到设备的。

应用程序寻找接口

在应用程序中寻找设备,是通过设备接口和设备号决定的。这里的设备号是指如果PC
中安装了两个相同驱动程序的网卡,第一 个网卡就是第0号网卡,而第二个网卡就是第1
号网卡。
在应用程序中主要是通过SetupDiXX系列函数得到设备接口,SetupDiXX用法十分灵
活,具体内容可以查看MSDN的相关资料,下面列出 了寻找接口的程序。

SetupDiGetClassDevs
用来查询与指定参数匹配的所有已安装设备
在这里插入图片描述

#include "stdafx.h"
#include<windows.h>
#include <stdio.h>
#include <InitGuid.h>
#include <SetupAPI.h>
#pragma comment(lib,"SetupAPI.lib")

//使用VS的生成GUID工具,选择第二种方式生成。
DEFINE_GUID(MY_WDM_DEVICE, 0xe57c50f, 0xccc, 0x4ad2, 0xa8, 0x95, 0x93, 0xc5, 0xed, 0x11, 0x98, 0x60);

HANDLE GetDeviceViaInterface(const GUID* pGuid)
{
	//SetupDiGetClassDevs 通过GUID找到对应的设备接口
	HDEVINFO info = SetupDiGetClassDevs(pGuid, 
										NULL,	//总线类型 虚拟设备不用管这个值
										NULL, 	//父窗口
										DIGCF_PRESENT |  //设备在系统中
										DIGCF_INTERFACEDEVICE); //查找的是接口
	if(info==INVALID_HANDLE_VALUE)
	{
		printf("No HDEVINFO available for this GUID\n");
		return NULL;
	}

	// Get interface data for the requested instance
	SP_INTERFACE_DEVICE_DATA IfData;
	ifdata.cbSize = sizeof(IfData);
	//枚举设备接口  一个驱动设备可以创建多个接口 插入一个相同设备就会创建一个设备接口.
	// i 指定了多个设备中的其中一个设备序号 如果没有这个序号就会枚举失败

	for(int i=0;;i++)
	{
		if(!SetupDiEnumDeviceInterfaces(info, NULL, pGuid, i, &IfData))
		{
			if (i==0)
			{
				printf("No SP_INTERFACE_DEVICE_DATA available for this GUID instance\n");
			}
			SetupDiDestroyDeviceInfoList(info);
			return NULL;
		}
			DWORD ReqLen;
		//获取指定接口的详细信息 主要是获得ReqLen
		SetupDiGetDeviceInterfaceDetail(info, &IfData, NULL, 0, &ReqLen, NULL);
		
		//分配符号链接名长度的内存
		PSP_INTERFACE_DEVICE_DETAIL_DATA IfDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA)(new char[ReqLen]);
		if( IfDetail==NULL)
		{
			SetupDiDestroyDeviceInfoList(info);
			return NULL;
		}
	
		// Get symbolic link name
		ifDetail->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
		if( !SetupDiGetDeviceInterfaceDetail(info, &IfData, IfDetail, ReqLen, NULL, NULL))
		{
			SetupDiDestroyDeviceInfoList(info);
			delete ifDetail;
			return NULL;
		}

		printf("Symbolic link is %S\n",ifDetail->DevicePath);
		
	}
	// Open file
	/*HANDLE rv = CreateFile( ifDetail->DevicePath, 
		GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_READ | FILE_SHARE_WRITE,
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if( rv==INVALID_HANDLE_VALUE) rv = NULL;

	delete ifDetail;
	SetupDiDestroyDeviceInfoList(info);*/
	return 0;
}

int main()
{
	GetDeviceViaInterface(&MY_WDM_DEVICE);
	getchar();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值