通过系统接口来获取机器的硬盘信息是编程中常遇见的小问题。
一般情况下,我们常用GetLogicalDrives,GetDriveType这两个API来获取当前系统下,硬盘的逻辑分区信息,以及各个分区的硬件类型。
这次要做的是获取硬盘的系列号信息。
在网上有朋友提供一种以DeviceIoControl函数为核心的办法。通过该函数,发送IOCTL系列的指令,来访问设备的驱动,从而获取指定的信息,或者发送相应的指令。从MSDN上的注释来看,具备访问和控制的综合功能。
但是,这个方法的使用过程中遇见了两个问题。
第一.DeviceIoControl缺乏“自适应性”。
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
我不知道用这个词来概括是否合适——简单地说,原因主要是它必须有程序员来进行错误处理。这个函数的返回值里有一对关于返回数据长度和返回数据指针的参数(即lpOutBuffer和lpBytesReturned),但是这个长度没有任何说服力——经常我们可以用这样的函数进行预读操作,从而获取实际结果需要的空间长度,并由此进行内存分配,但是这个函数没有这个能力。我所能做的就是尽可能的进行估计,然后尽可能的开足够大的空间,显得有点笨拙。
写到这里的时候我觉得其实也可以写个循环,检测范围值是否为122号错误(空间不够),然后再增值空间的写法。这样也许能科学一点。
第二.关于IOCTL的几个码定义
有如下几个定义:
#define DFP_GET_VERSION 0x00074080
#define DFP_SEND_DRIVE_COMMAND 0x0007c084
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088
2号参数DWORD dwIoControlCode可以通过宏进行生成
#define CTL_CODE(DeviceType, Function, Method, Access) (
((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
在CSDN上看到过一个朋友这样的文字:
“通常情况下,我们通过0XEC命令对IDE端口进行监测.获取硬盘信息.
一般情况下,我们就写个VXD或者DRIVER来完成.但是现在,通过MS的S.M.A.R.T.接口,我们可以直接从RING3调用
API DeviceIoControl()来获取硬盘信息.”
后来经过查找,找到了以上定义的原版
SMART_GET_VERSION
SMART_RCV_DRIVER_DATA
SMART_SEND_DRIVE_COMMAND