在上面那个例子中,将设备名换成“A:”取A盘参数,先用资源管理器读一下盘,再运行这个程序可以成功,但换一张盘后就失败;换成“CDROM0”取CDROM参数,无论如何都不行。这个问题如何解决呢?
取软盘参数是从软盘上读取格式化后的信息,也就是必须执行读操作,这一点与硬盘不同。将CreateFile中的访问方式改为GENERIC_READ就行了。IOCTL_DISK_GET_DRIVE_GEOMETRY这个I/O控制码,对软盘和硬盘有效,但对一些可移动媒介如CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数,还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问题。
DeviceIoControl使用这两个控制码时,都不需要输入数据。IOCTL_DISK_GET_DRIVE_GEOMETRY直接输出一个DISK_GEOMETRY结构:
typedef struct _DISK_GEOMETRY {
LARGE_INTEGER Cylinders; // 柱面数
MEDIA_TYPE MediaType; // 介质类型
DWORD TracksPerCylinder; // 每柱面的磁道数
DWORD SectorsPerTrack; // 每磁道的扇区数
DWORD BytesPerSector; // 每扇区的字节数
} DISK_GEOMETRY;
IOCTL_STORAGE_GET_MEDIA_TYPES_EX输出一个GET_MEDIA_TYPES结构:
typedef struct _GET_MEDIA_TYPES {
DWORD DeviceType; // 设备类型
DWORD MediaInfoCount; // 介质信息条数
DEVICE_MEDIA_INFO MediaInfo[1]; // 介质信息
} GET_MEDIA_TYPES;
让我们来看一下DEVICE_MEDIA_INFO结构的定义:
typedef struct _DEVICE_MEDIA_INFO {
union {
struct {
LARGE_INTEGER Cylinders; // 柱面数
STORAGE_MEDIA_TYPE MediaType; // 介质类型
DWORD TracksPerCylinder; // 每柱面的磁道数
DWORD SectorsPerTrack; // 每磁道的扇区数
DWORD BytesPerSector; // 每扇区的字节数
DWORD NumberMediaSides; // 介质面数
DWORD MediaCharacteristics; // 介质特性
} DiskInfo; // 硬盘信息
struct {
LARGE_INTEGER Cylinders; // 柱面数
STORAGE_MEDIA_TYPE MediaType; // 介质类型
DWORD TracksPerCylinder; // 每柱面的磁道数
DWORD SectorsPerTrack; // 每磁道的扇区数
DWORD BytesPerSector; // 每扇区的字节数
DWORD NumberMediaSides; // 介质面数
DWORD MediaCharacteristics; // 介质特性
} RemovableDiskInfo; // “可移动盘”信息
struct {
STORAGE_MEDIA_TYPE MediaType; // 介质类型
DWORD MediaCharacteristics; // 介质特性
DWORD CurrentBlockSize; // 块的大小
} TapeInfo; // 磁带信息
} DeviceSpecific;
} DEVICE_MEDIA_INFO;
其中CD-ROM属于“可移动盘”的范围。请注意,GET_MEDIA_TYPES结构本身只定义了一条DEVICE_MEDIA_INFO,额外的DEVICE_MEDIA_INFO需要紧接此结构的另外的空间。
现在就演示一下如何取软盘/硬盘/光盘的参数。测试时,记得要有软盘/光盘插在驱动器里喔!
首先,用MFC AppWizard生成一个单文档的应用程序,取名为DiskGeometry,让它的View基于CEditView。
然后,添加以下的.h和.cpp文件。
//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.h
//////////////////////////////////////////////////////////////////////////////
#if !defined(GET_DISK_GEOMETRY_H__)
#define GET_DISK_GEOMETRY_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <winioctl.h>
BOOL GetDriveGeometry(const char* filename, DISK_GEOMETRY *pdg);
#endif // !defined(GET_DISK_GEOMETRY_H__)
//////////////////////////////////////////////////////////////////////////////
// GetDiskGeometry.cpp
//////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "GetDiskGeometry.h"
// IOCTL_STORAGE_GET_MEDIA_TYPES_EX可能返回不止一条DEVICE_MEDIA_INFO,故定义足够的空间
#define MEDIA_INFO_SIZE sizeof(GET_MEDIA_TYPES)+15*sizeof(DEVICE_MEDIA_INFO)
// filename -- 用于设备的文件名
// pdg -- 参数缓冲区指针
BOOL GetDriveGeometry(const char* filename, DISK_GEOMETRY *pdg)
{
HANDLE hDevice; // 设备句柄
BOOL bResult; // DeviceIoControl的返回结果
GET_MEDIA_TYPES *pmt; // 内部用的输出缓冲区
DWORD dwOutBytes; // 输出数据长度
// 打开设备
hDevice = ::CreateFile(filename, // 文件名
GENERIC_READ, // 软驱需要读盘
FILE_SHARE_READ | FILE_SHARE_WRITE, // 共享方式
NULL, // 默认的安全描述符
OPEN_EXISTING, // 创建方式
0, // 不需设置文件属性
NULL); // 不需参照模板文件
if(hDevice == INVALID_HANDLE_VALUE)
{
// 设备无法打开...
return FALSE;
}
// 用IOCTL_DISK_GET_DRIVE_GEOMETRY取磁盘参数
bResult = ::DeviceIoControl(hDevice, // 设备句柄
IOCTL_DISK_GET_DRIVE_GEOMETRY, // 取磁盘参数
NULL, 0, // 不需要输入数据
pdg, sizeof(DISK_GEOMETRY), // 输出数据缓冲区
&dwOutBytes, // 输出数据长度
(LPOVERLAPPED)NULL); // 用同步I/O
// 如果失败,再用IOCTL_STORAGE_GET_MEDIA_TYPES_EX取介质类型参数
if(!bResult)
{
pmt = (GET_MEDIA_TYPES *)new BYTE[MEDIA_INFO_SIZE];
bResult = ::DeviceIoControl(hDevice, // 设备句柄
IOCTL_STORAGE_GET_MEDIA_TYPES_EX, // 取介质类型参数
NULL, 0, // 不需要输入数据
pmt, MEDIA_INFO_SIZE, // 输出数据缓冲区
&dwOutBytes, // 输出数据长度
(LPOVERLAPPED)NULL); // 用同步I/O
if(bResult)
{
// 注意到结构DEVICE_MEDIA_INFO是在结构DISK_GEOMETRY的基础上扩充的
// 为简化程序,用memcpy代替如下多条赋值语句:
// pdg->MediaType = (MEDIA_TYPE)pmt->MediaInfo[0].DeviceSpecific.DiskInfo.MediaType;
// pdg->Cylinders = pmt->MediaInfo[0].DeviceSpecific.DiskInfo.Cylinders;
// pdg->TracksPerCylinder = pmt->MediaInfo[0].DeviceSpecific.DiskInfo.TracksPerCylinder;
// ... ...
::memcpy(pdg, pmt->MediaInfo, sizeof(DISK_GEOMETRY));
}
delete pmt;
}
// 关闭设备句柄
::CloseHandle(hDevice);
return (bResult);
}
然后,在Toolbar的IDR_MAINFRAME上添加一个按钮,ID为ID_GET_DISK_GEOMETRY。打开ClassWizard,在DiskGeometryView中
添加ID_GET_DISK_GEOMETRY的映射函数OnGetDiskGeometry。打开DiskGeometryView.cpp,包含头文件GetDiskGeometry.h。
在OnGetDiskGeometry中,添加以下代码
const char *szDevName[]=
{
"\\\\.\\A:",
"\\\\.\\B:",
"\\\\.\\PhysicalDrive0",
"\\\\.\\PhysicalDrive1",
"\\\\.\\PhysicalDrive2",
"\\\\.\\PhysicalDrive3",
"\\\\.\\Cdrom0",
"\\\\.\\Cdrom1",
};
DISK_GEOMETRY dg;
ULONGLONG DiskSize;
BOOL bResult;
CString strMsg;
CString strTmp;
for(int i=0; i<sizeof(szDevName)/sizeof(char*); i++)
{
bResult = GetDriveGeometry(szDevName[i], &dg);
strTmp.Format("\r\n%s result = %s\r\n", szDevName[i], bResult ? "success" : "failure");
strMsg+=strTmp;
if(!bResult) continue;
strTmp.Format(" Media Type = %d\r\n", dg.MediaType);
strMsg+=strTmp;
strTmp.Format(" Cylinders = %I64d\r\n", dg.Cylinders);
strMsg+=strTmp;
strTmp.Format(" Tracks per cylinder = %ld\r\n", (ULONG) dg.TracksPerCylinder);
strMsg+=strTmp;
strTmp.Format(" Sectors per track = %ld\r\n", (ULONG) dg.SectorsPerTrack);
strMsg+=strTmp;
strTmp.Format(" Bytes per sector = %ld\r\n", (ULONG) dg.BytesPerSector);
strMsg+=strTmp;
DiskSize = dg.Cylinders.QuadPart * (ULONG)dg.TracksPerCylinder *
(ULONG)dg.SectorsPerTrack * (ULONG)dg.BytesPerSector;
strTmp.Format(" Disk size = %I64d (Bytes) = %I64d (Mb)\r\n", DiskSize, DiskSize / (1024 *1024));
strMsg+=strTmp;
}
CEdit& Edit = GetEditCtrl();
Edit.SetWindowText(strMsg);
最后,最后干什么呢?编译,运行......
分享到:
相关推荐
在Windows下,可以通过`CreateFile`打开`\\.\PhysicalDriveX`(X为硬盘编号),然后使用`DeviceIoControl`函数传递`IOCTL_STORAGE_QUERY_PROPERTY`控制代码来获取硬盘属性,包括序列号。在Linux中,可以读取`/dev/...
本主题主要关注如何使用易语言来通过DeviceIoControl函数获取硬盘的序列号。 硬盘序列号是每个硬盘的唯一标识符,通常用于识别和追踪硬盘。在Windows操作系统中,我们可以利用设备I/O控制(DeviceIoControl)函数来...
在Windows API中,获取硬盘序列号的常用函数是 `DeviceIoControl`,它允许应用程序向设备发送控制代码。要使用这个函数,我们需要定义以下几点: 1. **设备句柄**:通过 `CreateFile` 函数获得,该函数接收设备名...
易语言DeviceIoControl取硬盘序列号源码,DeviceIoControl取硬盘序列号,倒序排列,DeviceIoControl,CreateFileA,CloseHandle,GetLastError,LocalAlloc,LocalFree
DeviceIoControl取硬盘序列号.rar
功能:结合WMI和DeviceIoControl获取网卡原生MAC地址和当前MAC地址 入口参数: iQueryType:需要获取的网卡类型 0:包括USB网卡 1:不包括USB网卡 pMacAddress:存储网卡MAC地址 uSize:可存储的最大网卡...
3. `DeviceIoControl`函数:这个函数允许你向设备发送控制代码,从而获取更深入的设备信息,如硬盘的型号、容量、分区信息等。通过指定不同的控制代码(IOCTLs),可以获取不同的设备属性。 除了上述API,可能还会...
"VB6.0获取硬盘序列号的代码" VB6.0 获取硬盘序列号的代码是使用 Visual Basic 6.0 编程语言开发的一种获取硬盘序列号的方法。本文将对该代码进行详细的解释和分析。 代码结构 该代码主要由四部分组成: 1. 常量...
本文将详细讲解如何使用C语言在Linux和Windows操作系统下获取CPU序列号、硬盘序列号以及网卡的相关信息,如网卡名称、IP地址、MAC地址和网络连接状态。 首先,让我们关注CPU序列号的获取。在Windows系统中,可以...
在这个“易语言DeviceIoControl取硬盘序列号源码”教程中,我们将深入探讨如何利用易语言来获取硬盘的序列号,这是一个进阶的编程实践,涉及到系统底层的I/O控制。 首先,`DeviceIoControl`是一个Windows API函数,...
在VC++编程环境中,获取硬盘序列号是一项常见的需求,特别是在软件授权、系统识别或数据安全等领域。硬盘序列号是每个硬盘制造商在生产过程中赋予的独特标识,通常存储在硬盘的固件区域。本篇将深入探讨如何使用VC++...
4. **解析结果**:根据DeviceIoControl的返回值,我们可以获取到硬盘的分区信息,包括每个分区的起始位置、结束位置等。结合这些信息,我们可以确定每个分区的盘符。 5. **处理分区信息**:最后,将每个分区的盘符...
在Delphi中,可以通过访问SMART数据来获取硬盘温度,这通常需要调用特定的硬盘驱动程序接口,如`CreateFile`函数打开硬盘设备,然后使用`DeviceIoControl`进行控制操作。 此外,内存温度的获取相对复杂,因为没有...
使用DeviceIoControl APi 获取 IOCTL_STORAGE_PREDICT_FAILURE 产品信息中的 VendorSpecific 也可以使用 命名空间root/wmi下MSStorageDriver_ATAPISmartData类的子集VendorSpecific内存放了硬盘内部芯片存储的所有...
接着,分配内存并再次调用`DeviceIoControl`来获取硬盘的存储标识符,其中包括序列号。最后,从返回的缓冲区中提取序列号字符串。 需要注意的是,硬盘序列号通常包含非打印字符,因此在处理时应确保正确解码和显示...
在C++中,我们可以利用`#include <windows.h>`头文件,然后调用`CreateFile`函数打开硬盘设备,再通过`DeviceIoControl`函数发送控制代码IOCTL_STORAGE_QUERY_PROPERTY来获取硬盘属性,其中包含序列号信息。...
在IT领域,获取硬盘的SMART(Self-Monitoring, Analysis, and Reporting Technology)信息是一项重要的任务,这有助于预测硬盘可能出现的故障,及时采取备份措施。SMART技术是硬盘自我监测、分析和报告的一种机制,...
例如,可以调用`DeviceIoControl`函数配合`IOCTL_STORAGE_QUERY_PROPERTY`控制代码来获取硬盘信息。这需要定义一些结构体,如STORAGE_PROPERTY_QUERY和STORAGE_DEVICE_DESCRIPTOR,然后解析返回的设备描述符,从中...
在Windows操作系统中,DeviceIoControl是一个非常重要的API,它提供了应用程序与设备驱动程序之间通信的桥梁。本实战教程将深入探讨如何使用DeviceIoControl来直接操控设备,从而实现对硬件的高级控制。以下是对这个...