CFloppyDisk 2.0






4.91/5 (27投票s)
一个用于直接读取和写入软盘扇区的类 [Win 95/98/ME/NT/2K/XP]
这个类有什么用?
CFloppyDisk
是一个允许您直接读取和写入物理软盘扇区的类。该类提供了用于重置软盘控制器、读取物理扇区和写入物理扇区的静态成员函数。我使用“物理扇区”这个术语是为了避免与绝对扇区混淆。
老实说,这三个函数也可以放在一个头文件中,并作为一种源代码库分发。但我将其做成了一个类,以便人们更容易使用它。如今,人们倾向于将一切都做成类。
为什么要做这个类?
在 Windows NT/2000 中,我们可以使用 CreateFile
API 调用直接读写软盘。您可以简单地打开 \\.\A:
不幸的是,这种技术在 Windows 95、98 和 ME 下不起作用。这可能表明,在 GUI 之下,ME 比人们普遍认为的更接近 98,而不是 2000。现在,这个缺点已经解决了。我希望这个类能为您提供良好的服务。
一个类 - 任何操作系统
正如我刚才提到的,NT/2K 系列操作系统和 Windows 9x/ME 系列操作系统在直接访问软盘的技术上存在巨大差异。使用这个类,您无需担心您的程序将在哪个版本的 Windows 上运行。类内部有独立的函数集,但用户可以简单地调用通用函数。类会进行必要的操作系统版本检查,并在内部调用相应的函数。
要求
- 您必须运行 Windows 95/98/ME/NT/2K/XP 其中之一
使用该类。
有三个静态函数供您使用。因此,您不应该实例化该类。只需包含头文件并直接调用静态函数即可。
ResetDisk
static void ResetDisk()
ResetDisk
重置软盘控制器和驱动器。它不会对软盘做任何事情。但是软盘驱动器的读/写磁头将被重新校准。通常,您可能希望在进行一系列读写操作之前先进行一次控制器复位。但在遇到错误时,您也必须使用它。如果在发生错误后不复位控制器,那么磁盘控制器将随机且不可预测地运行。
ReadFloppyDisk
static int ReadFloppyDisk(BYTE *buffer, WORD cylinder, WORD sector, WORD head)
ReadFloppyDisk
用于将单个物理扇区读入缓冲区。对于大多数标准软盘,软盘扇区为 512 字节。因此,缓冲区至少应分配 512 字节。您可能想找出您的软盘驱动器支持的每扇区字节数。其他参数是圆柱体 (cylinder)、扇区 (sector) 和磁头 (head),它们是指定要从中读取扇区的物理参数。此函数成功时返回 0,失败时返回非零值,请务必检查返回值。
WriteFloppyDisk
static int WriteFloppyDisk(BYTE *buffer, WORD cylinder, WORD sector, WORD head)
WriteFloppyDisk
是 ReadFloppyDisk
的类似函数,但功能相反。它将缓冲区中的字节写入由圆柱体、扇区和磁头指定的物理扇区。此函数成功时返回 0,失败时返回非零值,请务必检查返回值。
一些需要注意的事项
软盘驱动器的电机可能需要一些时间才能跟上我们的函数调用。这些函数不会等待这个过程完成。因此,您必须小心,在确认数据已成功读入或写出特定扇区之前,不要对同一个扇区进行连续的读写操作。您经常会发现函数返回失败。这是因为现在大多数软盘驱动器都已长时间未使用或过度使用,并且常常处于非常糟糕的状态。软盘的质量也大不如前。解决方法是将所有调用循环三次。
例如,如果您正在执行读取或写入操作,请调用函数,如果失败,请再次调用。重复此操作三次。我发现三次是一个相当不错的数字,可以获得合理的成功率。另外,在长时间操作后调用 reset 函数会有所帮助。请记住,软盘驱动器是您计算机中工作最慢的部分,请记住这一点。这意味着,不要试图催促它。如果您正在将关键信息写入扇区,例如用于复制保护,那么最好在它们之间使用 Sleep
。
Example usage
void CCFloppyDiskTestDlg::OnButton1() { unsigned char buff[512]; strcpy((char*)buff,"This is kinda cool"); CFloppyDisk::ResetDisk(); if(CFloppyDisk::WriteFloppyDisk(buff,3,1,0)==NISH_ERROR) MessageBox("write failed"); if(CFloppyDisk::ReadFloppyDisk(buff,3,1,0)==NISH_ERROR) MessageBox("read failed"); MessageBox((char*)buff); }
如何循环调用以提高成功率。
int m_return_code; int count=0; while(m_return_code=CFloppyDisk::ReadFloppyDisk(buff,3,1,0)) { count++; if(count==3) break; } if(m_return_code) { MessageBox("After three attempts, we still failed. Destroy the floppy"); }
关于 ResetDisk 的技术说明
在 Windows NT/2K 中,我们无法直接调用中断 13h。对于 Windows 9x/ME 系列操作系统,该类调用中断 13h 功能 0h 来重置软盘控制器。为了在 Windows NT/2K 系列操作系统中实现相同的效果,我采用了不同的方法。
起初,我错误地认为 Windows NT/2K 不会有重置问题,但事实证明我错了。然后,我遇到了重置 NT/2K 在直接打开软盘时维护的内部缓冲区和错误标志的问题。这时我才发现,我所要做的就是打开软盘然后立即关闭它。我用坏软盘进行了尝试。我的成功率从很低的 20% 提高到将近 95% [仍然偶尔会出错]。但这可以通过使用我上面提到的三倍循环方法提高到 99.999%。我认为发生的情况是,当我们关闭文件句柄时,NT/2K 会刷新其内部缓冲区。这可能在内部导致软盘驱动器的重置。我不确定这一点,但这个推断似乎非常可能。
版本历史
- 2.0 版本 - 现在支持 Windows 95/98/ME/NT/2K/XP
- 1.0 版本 - 只支持 Windows 95/98/ME
致谢
Todd C. Wilson - 是 Todd 建议我写一个支持两类操作系统的组合类。2.0 版本归功于 Todd。
Michael Dunn & Tim Smith - 正如您通过查看源代码可能观察到的那样,该类的所有功能都是通过静态函数实现的。而我非常需要通过调用静态函数来对某些静态成员进行某种形式的静态构造。没有 Tim 和 Mike 的帮助,我可能仍然会坐在这里困惑地咒骂微软。