WEB开发网
开发学院软件开发汇编语言 实战DeviceIoControl系列之四:获取硬盘的详细信息... 阅读

实战DeviceIoControl系列之四:获取硬盘的详细信息

 2010-01-10 09:37:29 来源:WEB开发网   
核心提示:需要引起注意的是IDINFO第57-58 WORD (CHS可寻址的扇区数),因为不满足32位对齐的要求,实战DeviceIoControl系列之四:获取硬盘的详细信息(2),不可定 义为一个ULONG 字段, Lynn McGuire的程序里正是由于定义为一个ULONG字段,必须有 足够权限// nDrive: 驱动

需要引起注意的是IDINFO第57-58 WORD (CHS可寻址的扇区数),因为不满足32位对齐的要求,不可定 义为一个ULONG 字段。 Lynn McGuire的程序里正是由于定义为一个ULONG字段,导致该结构不可用。 

以下是核心代码:

// 打开设备
// filename: 设备的“文件名 ”
HANDLE OpenDevice(LPCTSTR filename)
{
HANDLE hDevice;
// 打开设 备
hDevice= ::CreateFile(filename,  // 文件名
 GENERIC_READ | GENERIC_WRITE,  // 读写方式
 FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式
 NULL,   // 默 认的安全描述符
 OPEN_EXISTING,  // 创建方式  0,   // 不需设置文件属性
  NULL);   // 不需参照模板文件
return hDevice;
}
// 向驱动发“IDENTIFY DEVICE”命令,获得设备信息
// hDevice: 设备句柄
// pIdInfo: 设备信息结构指 针
BOOL IdentifyDevice(HANDLE hDevice, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP; // 输入数据结构指针
PSENDCMDOUTPARAMS pSCOP; // 输出数据结构指针
DWORD dwOutBytes;  // IOCTL输出数据长度
BOOL bResult;  // IOCTL返回值
// 申请输入/输 出数据结构空间
   pSCIP = (PSENDCMDINPARAMS)::GlobalAlloc(LMEM_ZEROINIT,
sizeof(SENDCMDINPARAMS)-1);
   pSCOP = (PSENDCMDOUTPARAMS)::GlobalAlloc (LMEM_ZEROINIT,
sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1);
// 指定ATA/ATAPI命令 的寄存器值
// pSCIP->irDriveRegs.bFeaturesReg = 0;
// pSCIP- >irDriveRegs.bSectorCountReg = 0;
// pSCIP->irDriveRegs.bSectorNumberReg = 0;
// pSCIP->irDriveRegs.bCylLowReg = 0;
// pSCIP->irDriveRegs.bCylHighReg = 0;
// pSCIP->irDriveRegs.bDriveHeadReg = 0;
pSCIP->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
// 指定输入/输出数据缓冲区大小
pSCIP->cBufferSize = 0;
pSCOP->cBufferSize = sizeof(IDINFO);
// IDENTIFY DEVICE
bResult = ::DeviceIoControl(hDevice, // 设备句柄
 DFP_RECEIVE_DRIVE_DATA,  // 指定IOCTL
 pSCIP, sizeof(SENDCMDINPARAMS) - 1, // 输入数据缓冲区
 pSCOP, sizeof (SENDCMDOUTPARAMS) + sizeof(IDINFO) - 1, // 输出数据缓冲区
 &dwOutBytes,  // 输 出数据长度
 (LPOVERLAPPED)NULL);  // 用同步I/O
// 复制设备参数结构
::memcpy(pIdInfo, pSCOP->bBuffer, sizeof(IDINFO)); // 释放输入/输出数据空间
::GlobalFree(pSCOP);
::GlobalFree(pSCIP);
return bResult;
}
// 向SCSI MINI-PORT 驱动发“IDENTIFY DEVICE”命令,获得设备信息
// hDevice: 设备句柄
// pIdInfo: 设备信息结构指针
BOOL IdentifyDeviceAsScsi(HANDLE hDevice, int nDrive, PIDINFO pIdInfo)
{
PSENDCMDINPARAMS pSCIP; // 输入数据结构指针
PSENDCMDOUTPARAMS pSCOP; // 输出数据结构指针
PSRB_IO_CONTROL pSRBIO; // SCSI输入输 出数据结构指针
DWORD dwOutBytes;  // IOCTL输出数据长度
BOOL bResult;  // IOCTL 返回值
// 申请输入/输出数据结构空间
   pSRBIO = (PSRB_IO_CONTROL)::GlobalAlloc (LMEM_ZEROINIT,
sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1);
   pSCIP = (PSENDCMDINPARAMS)((char *)pSRBIO+sizeof(SRB_IO_CONTROL));
   pSCOP = (PSENDCMDOUTPARAMS)((char *)pSRBIO+sizeof(SRB_IO_CONTROL));
// 填充输入/输出数据
pSRBIO->HeaderLength = sizeof(SRB_IO_CONTROL);
pSRBIO->Timeout = 10000;
pSRBIO->Length = sizeof(SENDCMDOUTPARAMS)+sizeof(IDINFO)-1;
pSRBIO- >ControlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
::strncpy ((char *)pSRBIO- >Signature, SCSIDISK, 8);
// 指定ATA/ATAPI命令的寄存器值
// pSCIP- >irDriveRegs.bFeaturesReg = 0;
// pSCIP->irDriveRegs.bSectorCountReg = 0;
// pSCIP->irDriveRegs.bSectorNumberReg = 0;
// pSCIP->irDriveRegs.bCylLowReg = 0;
// pSCIP->irDriveRegs.bCylHighReg = 0;
// pSCIP- >irDriveRegs.bDriveHeadReg = 0;
pSCIP->irDriveRegs.bCommandReg = IDE_ATA_IDENTIFY;
pSCIP->bDriveNumber = nDrive;
// IDENTIFY DEVICE
bResult = ::DeviceIoControl(hDevice, // 设备句柄
 IOCTL_SCSI_MINIPORT,  // 指定 IOCTL
 pSRBIO, sizeof(SRB_IO_CONTROL) +sizeof(SENDCMDINPARAMS) - 1, // 输入数据缓冲区   pSRBIO, sizeof(SRB_IO_CONTROL) +sizeof(SENDCMDOUTPARAMS) + sizeof(IDINFO) - 1, // 输出
数据缓冲区
 &dwOutBytes, // 输出数据长度
 (LPOVERLAPPED)NULL); // 用 同步I/O
// 复制设备参数结构
::memcpy(pIdInfo, pSCOP->bBuffer, sizeof (IDINFO));
// 释放输入/输出数据空间
::GlobalFree(pSRBIO);
return bResult;
}
// 将串中的字符两两颠倒
// 原因是ATA/ATAPI中的WORD,与Windows采用的字节顺序相 反
// 驱动程序中已经将收到的数据全部反过来,我们来个负负得正
void AdjustString (char* str, int len)
{
char ch;
int i;
// 两两颠倒
for (i=0;i<len;i+=2)
{
 ch = str[i];
 str[i] = str[i+1];
 str[i+1] = ch;
}
// 若是右对齐的,调整为左对齐 (去掉左边的空格)
i=0;
while (i<len && str[i]==' ') i++;
::memmove(str, &str[i], len-i);
// 去掉右边的空格
i = len - 1;
while(i>=0 && str[i]==' ')
{
 str[i] = '';
 i--;
}
} // 读取IDE硬盘的设备信息,必须有 足够权限
// nDrive: 驱动器号(0=第一个硬盘,1=0=第二个硬盘,......)
// pIdInfo: 设 备信息结构指针
BOOL GetPhysicalDriveInfoInNT(int nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;  // 设备句柄
BOOL bResult;  // 返回结果
char szFileName[20]; // 文件名
::sprintf(szFileName,.PhysicalDrive%d, nDrive);
hDevice = ::OpenDevice (szFileName);
if(hDevice == INVALID_HANDLE_VALUE)
{
 return FALSE;
}
// IDENTIFY DEVICE
bResult = ::IdentifyDevice(hDevice, pIdInfo);
if (bResult)
{
 // 调整字符串
 ::AdjustString(pIdInfo->sSerialNumber, 20);
 ::AdjustString(pIdInfo->sModelNumber, 40);
 ::AdjustString(pIdInfo- >sFirmwareRev, 8);
}
::CloseHandle (hDevice);
return bResult;
}
// 用SCSI驱动读取IDE硬盘的设备信息,不受权限制约
// nDrive: 驱动器号(0=Primary Master, 1=Promary Slave, 2=Secondary master, 3=Secondary slave)
// pIdInfo: 设备信息结 构指针
BOOL GetIdeDriveAsScsiInfoInNT(int nDrive, PIDINFO pIdInfo)
{
HANDLE hDevice;  // 设备句柄
BOOL bResult;  // 返回结果
char szFileName[20]; // 文件名
::sprintf(szFileName,.Scsi%d:, nDrive/2); hDevice = ::OpenDevice(szFileName);
if(hDevice == INVALID_HANDLE_VALUE)
{
 return FALSE;
}
// IDENTIFY DEVICE
bResult = ::IdentifyDeviceAsScsi(hDevice, nDrive%2, pIdInfo);
// 检查是不 是空串
if(pIdInfo->sModelNumber[0]=='')
{
 bResult = FALSE;
}
if(bResult)
{
 // 调整字符串
 ::AdjustString(pIdInfo- >sSerialNumber, 20);
 ::AdjustString(pIdInfo->sModelNumber, 40);
 ::AdjustString(pIdInfo->sFirmwareRev, 8);
}
return bResult;
}

Tags:实战 DeviceIoControl 系列

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接