2.1驱动程序开发原理
在无操作系统的裸机中,或者类似如DOS这样操作系统中,应用程序和硬件的交互是非常简单的。如同牛郎织女,本来就睡在同一张床上,想怎么说悄悄话都行。可是现在情况有变,他们被天河分开了。要想见面聊几句,也要麻烦喜鹊来搭桥。在WINDOWS操作系统中,应用程序与硬件间的交互与此极其类似。如果没有操作系统,我们访问硬件空间可能只需一条指令就行,甚至可以访问任意的内存空间或者IO空间。因此应用程序和硬件就成了牛郎织女,被操作系统这个天河硬生生的隔开了。当应用程序要访问某个硬件或者内存空间时,就必须借助于喜鹊(驱动程序)了。至于为什么要把硬件层和应用程序隔开,答案是——安全。允许应用程序随意访问硬件是一件很危险的事情,除了可能会造成蓝屏死机之类的问题,还会发生密码的安全性问题。从这一点来说,上面的比喻还真是不够贴切,牛郎织女分开好像不是安全原因,无论比喻贴不贴切,还是往下继续吧。
应用程序访问驱动程序,要指定驱动程序的符号链接名,然后把要发送的信息发送出去。操作系统找到相关驱动程序,驱动程序把信息发动给指定硬件。如写信一样,驱动程序像邮差。
2.2应用程序寻找设备接口的方法——SetupDixx系列函数
2.2.1SetupDiGetClassDevs
函数定义
HDEVINFO
SetupDiGetClassDevs(
constGUID*ClassGuid,
PCTSTR Enumerator,
HWND hwndParent,
DWORD Flags
);
SetupDiGetClassDevs 获取一个指定类别或全部类别的所有已安装设备的信息
参数说明:
输入参数:
PGUID ClassGuid
在创建设备列表的时候提供一个指向GUID的指针。如果设定了标志DIGCF_ALLCLASSES,则这个参数可以忽略,且列表结果中包括所有已经安装的设备类别。
PCTSTR Enumerator
提供包含设备实例的枚举注册表分支下的键名,可以通过它获取设备信息。如果这个参数没有指定,则要从整个枚举树中获取所有设备实例的设备信息。
HWND hwndParent
提供顶级窗口的句柄,所有用户接口可以使用它来与成员联系。
DWORD Flags
提供在设备信息结构中使用的控制选项。可以是以下数值:
DIGCF_PRESENT - 只返回当前存在的设备。
DIGCF_ALLCLASSES - 返回所有已安装的设备。如果这个标志设置了,ClassGuid参数将被忽略。
DIGCF_PROFILE - 只返回当前硬件配置文件中的设备。
返回值:
HDEVINFO
如果函数运行成功,返回设备信息结构的句柄,该结构包含与指定参数匹配的所有已安装设备。如果失败,则返回INVALID_HANDLE_VALUE。调用GetLastError可以获得更多错误信息。
说明使用此函数,需要包含头文件setupapi.h。
此外,在project setting中的link页面需要添加setupapi.lib。
在setuapi.h中有如下定义:
typedef PVOID HDEVINFO;
即HDEVINFO是个无类型指针
2.1.2 SetupDiEnumDeviceInfo(SetupDiEnumDeviceInterface同样有memberindex 可以视情况定)
函数定义
BOOLEAN
SetupDiEnumDeviceInfo(
IN HDEVINFO DeviceInfoSet,
IN DWORD MemberIndex,
OUT PSP_DEVINFO_DATA DeviceInfoData
);
SetupDiEnumDeviceInfo 枚举指定设备信息集合的成员,并将数据放在PSP_DEVINFO_DATA中
参数说明:
DeviceInfoSet
提供一个设备信息集合的句柄
MemberIndex
指定一个要取得的设备信息成员序号,从0开始
DeviceInfoData
指向SP_DEVINFO_DATA结构的指针,关于指定成员的返回信息就放在该结构中
Return ValueThe
成功返回True,否则返回False)
如果要枚举全部设备信息成员,装载者首先应该将MemberIndex设为0调用SetupDiEnumDeviceInfo,然后递增MemberIndex(使用一个for循环),调用SetupDiEnumDeviceInfo,直至所有成员全部遍历(此时函数返回False,并且GetLastError返回ERROR_NO_MORE_ITEMS)
2.1.3SetupDiGetDeviceInterfaceDetail
函数定义
WINSETUPAPI BOOL WINAPI
SetupDiGetDeviceInterfaceDetail(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
OUT PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, OPTIONAL
IN DWORD DeviceInterfaceDetailDataSize,
OUT PDWORD RequiredSize, OPTIONAL
OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
);
SetupDiGetDeviceInterfaceDetail這個API主要在取得該裝置的路徑, 而路徑會放到你所給的參數DeviceDetailData裏面, 然而因為每一個裝置的路徑名稱不一樣, 所以該結構的大小不一定, 故OS希望程式設計者"呼叫兩次", 第一次你必須給一個DWORD變數的位置於參數5:
DWORD RequiredSize = 0;
於第一次呼叫時DeviceDetailData為NULL, 而OS會將該結構所須的大小放到 RequiredSize裏面, 這樣你才可以用來呼叫malloc去分配空間給DeviceDetailData; 再一次的呼叫, OS就會將"裝置路徑"放到DeviceDetailData裏面了.
你說你predictedLength 及requiredLength的除錯值皆為83, 我想你的除錯 點放錯位罝了, 你是否將斷點放到第二次呼叫之後了呢? 不然你的程式到下
面這一行時:
predictedLength = requiredLength;
怎麼看都是0, 因為在上面的程式除了宣告外, 根本沒用到.
2.1.4
SetupDiDestroyDeviceInfoList
BOOLEAN
SetupDiDestroyDeviceInfoList(
IN HDEVINFO DeviceInfoSet
);
SetupDiDestroyDeviceInfoList destroys a device information set and frees all associated memory.
(销毁一个设备信息集合,并且释放所有关联的内存)
Parameters
DeviceInfoSet
Supplies a handle to the device information set to destroy. (要释放的设备信息句柄)
Return ValueThe function returns TRUE if it is successful. Otherwise it returns FALSE and the logged error can be retrieved with a call to GetLastError. (成功返回True,否则返回False)
IoSetDeviceInterfaceState函数可用来enable或者disable一个设备,它接受IoRegisterDeviceInterface返回的symbolic link name。
有三种方法来注册一个device interface class:
1、一些内核模式组件,例如许多驱动,可以调用I/O管理器例程。
2、用户模式应用程序可以调用SetupDiXxx函数。
3、INF文件里设置INF DDInstall.Interfaces域。
SetupDi 设备接口函数:
SetupDiCreateDeviceInterface
为一个设备注册设备功能(Registers device functionality(a device interface) for a device)。SetupDiOpenDeviceInterface
重新获得一个已经存在的设备接口的信息,并且把它添加到指定的device information set中。SetupDiGetDeviceInterfaceAlias
返回指定设备接口的别名SetupDiGetClassDevs
返回一个设备信息集合,这个集合包含了指定class的设备的信息。SetupDiGetClassDevsEx
返回一个设备信息集合,这个集合包含了指定本地的或者远程计算机的class设备的信息。SetupDiEnumDeviceInterfaces
返回device information集合一个设备接口元素的一个内容结构。每次调用都返回一个设备接口的信息。SetupDiGetDeviceInterfaceDetail
返回一个特定设备接口的详细信息
SetupDiCreateDeviceInterfaceRegKey
创建一个注册表子键来存储一些关于一个设备接口实例的信息,并且返回这个键的句柄。SetupDiOpenDeviceInterfaceRegKey
指定一个设备接口实例,然后返回其注册表子键的句柄。SetupDiDeleteDeviceInterfaceRegKey
删除一个指定设备接口实例的注册表子键。SetupDiInstallDeviceInterfaces
这是DIF_INSTALLINTERFACES请求的默认处理函数。他安装INF文件DDInstall.Interfaces域列出的那些设备接口。SetupDiRemoveDeviceInterface
从系统中删除一个注册了的设备接口。SetupDiDeleteDeviceInterfaceData
从一个设备信息集合里面伤处一个设备接口。SetupDiSetDeviceInterfaceDefault
为一个device calss设置一个指定的设备接口为默认接口。SetupDiInstallClassEx
安装一个class installer或者一个借口class。SetupDiOpenClassRegKeyEx
打开设备安装class注册表键,设备接口class注册表键,或者一个指定的class子键。这个函数能打开本地机器或者远程机器里的指定注册表键。
SetupDi设备属性函数(windwos vista和后续版本):
SetupDIGetClassProperty
重新获得一个device setup class或者一个device interface class的设备属性。SetupDiGetClassPropertyEx
可用于本地或远程计算机SetupDIGetClassPropertyKeys
获得一列设备property keys,这些keys代表了一个device setup class或者一个device interface class的设备属性。SetupDiGetClassPropertyKeysEx
可用于本地或远程计算机。SetupDiGetDeviceInterfaceProperty
获得一个设备接口的设备属性。SetupDiGetDeviceINterfacePropertyKeys
获得一列设备属性keys,这些keys代表一个设备接口的属性。SetupDiGetDeviceProperty
获得一个设备实例属性
SetupDiGetDevicePropertyKeys
………………SetupDISetClassProperty
为一个设备安装class或一个设备接口class设置class属性SetupDiSetClassPropertyEx
本地远程计算机SetupDiSetDeviceInterfaceProperty
为一个设备接口设置设备属性SetupDiSetDeviceProperty
为一个设备实例设置设备属性
驱动安装函数:
DiInstallDevice
安装一个指定的驱动,这个驱动之前在driver store里已经安装过。而且一个PnP设备目前在系统里面(vista和以后版本系统)DiInstallDriver
在driver store里预安装一个驱动,和在匹配一个PnP设备的时候安装这个驱动。DiRollbackDriver
回滚一个已经安装在一个指定设备的驱动到为这个设备设置的后备驱动DiShowUpdateDevice
显示一个指定设备的硬件升级向导(vista和后续版本)InstallSelectedDriver
在一个选定的设备上安装一个指定的驱动UpdateDriverForPlugAndPlayDevices
更新已经安装的功能驱动,这个功能驱动用来匹配系统中的PnP设备。
SetupDi设备信息函数:
SetupDiCreateDeviceInfoList
创建一个空的device information set。这个集合可以被用来联系一个class GUID。SetupDiCreateDeviceInfoListEx
本地远程计算机SetupDiCreateDeviceInfo
创建一个新的设备信息元素,并把它加入到一个指定的设备信息集合中。SetupDiOpenDeviceInfo
获取一个设备实例的信息,并把它加入到指定的设备信息集合中。SetupDiEnumDeviceInfo
返回一个设备信息集合里面的信息元素。SetupDiGetDeviceInstanceId
获取设备实例ID,这个ID与一个设备信息元素联合着。SetupDiGetDeviceInfoListClass
获取一个class GUID的设备信息集合。SetupDiGetDeviceInfoListDetail
Retrieves information associated with a device information set including the class GUID, remote machine handle, and remote machine name.获取设备信息集合,里面包括了class GUID 远程机器handle,和远程机器名字SetupDiGetClassDevPropertySheets
获取一个指定的设备信息元素的属性单句柄,或者指定设备信息集合的设备安装class的属性单句柄SetupDiGetClassDevs
获取一个包含有指定的class的所有设备信息集合SetupDiGetClassDevsEx
本地或者远程机器SetupDiSetSelectedDevice
设置一个指定的设备信息元素成为一个设备信息集合的选定成员。这个函数一般在安装向导使用SetupDiGetSelectedDevice
获取指定设备信息集合里目前选择的设备SetupDiRegisterDeviceInfo
与PnP管理器注册一个信息设备实例SetupDiDeleteDeviceInfo
从一个指定的设备信息集合中删除一个元素。这个函数不删除真正的设备SetupDiDestroyDeviceInfoList
删除一个设备信息集合并清理所有内存
SetupDI驱动信息函数
SetupDiBuildDriverInfoList
建立一列与制定设备实例有联系的驱动,或者设备信息集合的全局class驱动列表SetupDiEnumDriverInfo
枚举一个驱动信息列表中的成员SetupDiGetDriverInfoDetail
获取一个是定的驱动信息元素的详细信息SetuoDiSetSelectedDriver
设置一个指定的驱动列表成员成为当前选定的驱动。这个函数可以用来冲洗设置驱动列表以至于没有当前选定驱动SetupDiGetSelectedDriver
获取驱动列表中已经被选中的驱动SetupDiCancelDriverInfoSearch
取消一个驱动列表查询,这个查询目前不在同一个线程中运行SetupDiDestroyDriverInfoList
消灭一个驱动信息列表
SetupDi驱动选择函数
SetupDiAskForOEMDisk
显示一个对话框,来让用户选择一个OEM安装磁盘的路径SetupDiSelectOEMDrv
用用户提供的一个OEM路径来为一个设备选择一个驱动SetupDiSelectDevice
为一个DIF_SELECTDEVICE请求的默认句柄
另附msdn setupdi***系列函数说明 http://msdn.microsoft.com/en-us/library/ff551120(v=vs.85).aspx
若有提示SetupDi****无法解析的外部符号则要加setupapi.h setupapi.lib 这些可以在下面的链接下载。http://download.csdn.net/detail/gaofeidongdong/4157679