实战 DeviceIoControl 系列 之二:获取软盘/硬盘/光盘的参数
2011-03-30 14:14
337 查看
Q 在 MSDN的那个 demo 中,将设备名换成“A:”取 A 盘参数,先用资源管理
器读一下盘,再运行这个程序可以成功,但换一张盘后就失败;换成“CDROM0”
取 CDROM参数,无论如何都不行。这个问题如何解决呢?
A 取软盘参数是从软盘上读取格式化后的信息,也就是必须执行读操作,这一
点与硬盘不同。将CreateFile中的访问方式改为 GENERIC_READ 就行了。
IOCTL_DISK_GET_DRIVE_GEOMETRY这个 I/O 控制码,对软盘和硬盘有效,但
对一些可移动媒介如 CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数,
还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问
题。
Q 使用这些 I/O 控制码,需要什么样的输入输出数据格式呢?
A DeviceIoControl使用这两个控制码时,都不需要输入数据。
IOCTL_DISK_GET_DRIVE_GEOMETRY直接输出一个 DISK_GEOMETRY结构:
Q 调用方法我了解了,请用 VC举个例子来实现我所期待已久的功能吧?
A 好,现在就演示一下如何取软盘/硬盘/光盘的参数。测试时,记得要有软盘/
光盘插在驱动器里喔!
首先,用 MFC AppWizard 生成一个单文档的应用程序,取名为DiskGeometry,让它的 View基于 CEditView。
然后,添加以下的.h 和.cpp 文件。
DiskGeometryView.cpp,包含头文件 GetDiskGeometry.h。
在 OnGetDiskGeometry 中,添加以下代码
最后,最后干什么呢?编译,运行......
器读一下盘,再运行这个程序可以成功,但换一张盘后就失败;换成“CDROM0”
取 CDROM参数,无论如何都不行。这个问题如何解决呢?
A 取软盘参数是从软盘上读取格式化后的信息,也就是必须执行读操作,这一
点与硬盘不同。将CreateFile中的访问方式改为 GENERIC_READ 就行了。
IOCTL_DISK_GET_DRIVE_GEOMETRY这个 I/O 控制码,对软盘和硬盘有效,但
对一些可移动媒介如 CD/DVD-ROM、TAPE等就不管用了。要取CDROM参数,
还得另辟蹊径。IOCTL_STORAGE_GET_MEDIA_TYPES_EX能够帮我们解决问
题。
Q 使用这些 I/O 控制码,需要什么样的输入输出数据格式呢?
A 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 需要紧接此结构的另外的空间。
Q 调用方法我了解了,请用 VC举个例子来实现我所期待已久的功能吧?
A 好,现在就演示一下如何取软盘/硬盘/光盘的参数。测试时,记得要有软盘/
光盘插在驱动器里喔!
首先,用 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("rn%s result = %srn", szDevName[i], bResult ? "success" : "failure"); strMsg+=strTmp; if (!bResult) continue; strTmp.Format(" Media Type = %drn", dg.MediaType); strMsg+=strTmp; strTmp.Format(" Cylinders = %I64drn", dg.Cylinders); strMsg+=strTmp; strTmp.Format(" Tracks per cylinder = %ldrn", (ULONG) dg.TracksPerCylinder); strMsg+=strTmp; strTmp.Format(" Sectors per track = %ldrn", (ULONG) dg.SectorsPerTrack); strMsg+=strTmp; strTmp.Format(" Bytes per sector = %ldrn", (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)rn", DiskSize, DiskSize / (1024 * 1024)); strMsg+=strTmp; } CEdit& Edit = GetEditCtrl(); Edit.SetWindowText(strMsg);
最后,最后干什么呢?编译,运行......
相关文章推荐
- 实战 DeviceIoControl 系列 之二:获取软盘/硬盘/光盘的参数
- 实战 DeviceIoControl 系列 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数 分类: windows驱动程序WDM 2013-09-25 14:46 401人阅读 评论(0) 收藏
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数(学习)
- 实战DeviceIoControl 之二:获取软盘/硬盘/光盘的参数