我写了一个目录信息实用程序,并且(因为我和我写这篇文章的人收集和使用老式硬件)使它与 DOS 和 Windows 9x 以及 Windows XP/Vista/7/8 64 位兼容(因为我们也使用它们。)我遇到的问题是 Windows 9x 和 FAT32 驱动器。只要实际加载了 Windows 9x,我就设法让它工作,但是如果我只启动到命令提示符,或者在 MS-DOS 模式下重新启动,我将无法访问允许我获取大驱动器数据的 Windows API,并且它默认回到我拥有的 DOS 例程。这些仅限于 2GB 限制例程。检查 DOS 7.x 程序(主要是 chkdsk)如何处理此问题(因为它们报告正确的驱动器大小没有问题,)似乎它们使用 DOS 中断(主要是 INT 21h)来执行此操作。想想,没问题,我会做一个快速版本检查,如果它是 DOS 7 或更高版本,我将运行一个快速 assembly 路由来获取驱动器结构并计算总空间和可用空间。只是,例程(尽管它没有返回错误)不会用任何东西填充我的缓冲区。
代码如下:
#include <stdio.h>
#include <dos.h>
void main(void) {
unsigned short hes,hdi,sectors,bytes;
unsigned long tclusters,fclusters;
unsigned char far *drivedata;
char test = '\0';
char display[17] = "0123456789ABCDEF";
int count;
drivedata = new unsigned char [63];
for (count = 0; count < 63; count++) drivedata[count] = '\0';
drivedata[0] = '\x3d';
drivedata[1] = '\x00';
hes = FP_SEG(drivedata);
hdi = FP_OFF(drivedata);
asm {
push ax
push es
push di
push ds
push dx
push cx
mov ax,0x440d
mov bx,0x0003
mov cx,0x484a
int 21h
jnc _GOOD
mov ax,0x7302
mov es,[hes]
mov di,[hdi]
mov dx,0x0003
mov cx,0x003f
int 21h
jnc _GOOD
}
test = '\1';
_GOOD:
asm {
mov ax,0x440d
mov bl,0x03
mov cx,0x486a
int 21h
pop cx
pop dx
pop ds
pop di
pop es
pop ax
}
if (test == '\1') {
printf("There was an error.\r\n");
return;
}
tclusters = (unsigned long) drivedata[48];
tclusters = (tclusters * 256) + (unsigned long)drivedata[47];
tclusters = (tclusters * 256) + (unsigned long)drivedata[46];
tclusters = (tclusters * 256) + (unsigned long)drivedata[45];
++tclusters;
fclusters = (unsigned long)drivedata[36];
fclusters = (fclusters * 256) + (unsigned long)drivedata[35];
fclusters = (fclusters * 256) + (unsigned long)drivedata[34];
fclusters = (fclusters * 257) + (unsigned long)drivedata[33];
bytes = (unsigned int)drivedata[5];
bytes = (bytes * 256) + (unsigned int)drivedata[4];
sectors = (unsigned long)drivedata[6];
++sectors;
printf("Drive C has:\r\n");
printf(" Total Clusters: %u\r\n",tclusters);
printf(" Free Clusters: %u\r\n",fclusters);
printf(" Sectors: %u\r\n",sectors);
printf(" Bytes: %u\r\n",bytes);
printf("\r\n");
printf(" | 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n");
printf("---------------------------------------------------------------------");
for (count = 0; count < 63; count++) {
if ((count % 16) == 0) printf("\r\n %c | ",display[(count / 16)]);
printf("%03u ",drivedata[count]);
}
printf("\r\n");
return;
}
最后一点是我试图弄清楚出了什么问题。我得到了奇怪的结果,无法找出模式。最初,我并不担心清除缓冲区,因为 INT 调用应该用它自己的值填充它(前 2 个字节除外,它应该用 EDB 数据缓冲区大小填充。)显然得到这么多之后随机结果,我在循环开始时添加了用零填充缓冲区,然后添加缓冲区大小。结果在那时不再是随机的,它们总是全为零,这意味着 INT 调用没有填充缓冲区。通过各种测试,我已经确认 hes 和 hdi 被正确分配了缓冲区地址的段和偏移量。我也试过 es & di 到指针地址而不是缓冲区地址。我不认为它会像我读到的所有内容所说的那样将其设置为地址而不是指针,但我正在尝试我能想到的一切。在所有情况下,缓冲区都不会被任何东西填满。
您可能会说,这只是我正在编写的一个测试程序,目的是在将其添加到我的主程序之前找出确切的过程(除了这个问题外,它工作得很好。)FP_ 行只是宏对于段可以表示为 (unsigned long)(x & 0xffff0000) >> 16,对于偏移量可以表示为 (unsigned long)(x & 0x0000ffff)。通常你会传递指针 (&drivedata,) 但 drivedata 已经是一个指针。
实际输出:
Drive C has:
Total Clusters: 1
Free Clusters: 0
Sectors: 1
Bytes: 0
| 0 1 2 3 4 5 6 7 8 9 A B C D E F
---------------------------------------------------------------------
0 | 061 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
1 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
2 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
3 | 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000
那么,我错过了什么?像 chkdsk 一样,我在调用之前锁定驱动器并在调用之后解锁它(尽管我不确定是否有必要。)我怎样才能让它正常工作?或者,是否有比使用 INT 21h 更好的方法来获取驱动器结构(簇、每个簇的扇区、每个扇区的字节数)?我在搜索中找到的所有内容都只指向 Windows API 函数,用户将无法访问这些函数,如果他们启动到命令提示符等...
最佳答案
哇,使用 DOS,太老派了!不像使用穿孔卡片那样老派,但仍然...
显然,FreeDOS有FAT 32 support .您可能会尝试在那些甚至没有安装 Windows 95 的机器上安装它。
关于c++ - 在 DOS 7.x 中获取大型驱动器结构信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25718616/