C++ 在DOS 7.x中获取大型驱动器结构信息

C++ 在DOS 7.x中获取大型驱动器结构信息,c++,assembly,dos,C++,Assembly,Dos,我编写了一个目录信息实用程序(因为我和我为collect&use vintage hardware编写的人)使其与DOS和Windows 9x以及Windows XP/Vista/7/8 64位兼容(因为我们也使用这些)。我遇到的问题是Windows 9x和FAT32驱动器。只要Windows 9x实际加载,我就设法让它工作,但如果我只启动到命令提示符,或在MS-DOS模式下重新启动,我将无法访问允许我获取大驱动器数据的Windows API,它将默认返回到我拥有的DOS例程。这些限制仅限于2G

我编写了一个目录信息实用程序(因为我和我为collect&use vintage hardware编写的人)使其与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或更高版本,我只会运行一个快速组装路由,以获得驱动器结构,并以此方式计算总的可用空间。只是,例程(尽管它没有返回错误)没有用任何东西填充我的缓冲区

代码如下:

#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;
}

那么,我错过了什么?像chkdsk一样,我在调用之前锁定驱动器,在调用之后解锁驱动器(尽管我不确定是否有必要)。如何才能使其正常工作?或者,是否有比使用INT 21h更好的方法获得驱动器结构(集群、每个集群的扇区、每个扇区的字节数)?我在搜索中找到的所有东西都只指向Windows API函数,如果用户执行引导到命令提示符等操作,他们将无法访问这些函数。

哇,使用DOS,这是老生常谈!不像使用打孔卡那样老派,但仍然


很明显,他有。您可以尝试将其安装在那些甚至没有安装Windows 95的机器上。

对于您的传统爱好,您应该为自己配备
LBA
FAT32
规范,这些规范似乎有很好的链接

您可能会发现,这些遗留系统(以及为它们编写的软件)无法正常处理大型磁盘(磁盘大小>2^(32-1))

我认为其他材料也非常重要:

  • 拉尔夫·布朗的中断列表-
  • Flamboux软件的技术帮助!-
  • 彼得·诺顿的诺顿指南-
  • Bochs x86仿真器的BIOS源代码-

在任何情况下,对您都有效的“更好的方法”是使用BIOS调用找出所有的基础知识,然后在您自己的代码中复制用于计算大小等的算法。在旧的DOS时代,没有可用于非Microsoft程序的易于重用的API。需要做高级工作的程序必须知道如何独立完成。

构建老式系统的人倾向于使用当时使用的操作系统。我的小程序可以在DOS 3+上运行(实际上,这是我打算安装和测试的最早版本,可能还要追溯到更远的版本)。它也可以在现代系统上运行(例如,我的Windows 7 64位)。唯一的问题是DOS 7(Windows 9x引导到命令提示符)。这就是我现在正在尝试的工作,DOS 7。仅供参考,当他们发明键盘时,我真的很高兴,穿孔卡片是一个真正的PITA。哇,你绝对应该在CP/M上检查这个!我读错你的代码了吗?看起来,如果成功锁定驱动器,则跳过代码读取数据。否则,可能1)将SI设置为0xF1A6。2) 将dl设置为0x80。3) 使用更大的缓冲区(256?)。事实上,你没有:/我错过了。。。。现在重新编译。。。过了一会儿,唉,是的,我跳过了成功的代码,而不是失败的代码。将jnc操作码更改为jc,并添加了一个新标签(以适当地更改good/bad标志)。好吧,我现在得到了数据,尽管数字似乎不准确。现在我要做更多的测试:)谢谢,我实际上得到了大部分正确的数字。如果使用7303而不是7302,则所有字节值都是正确的。如果我使用7302,那么空闲集群的所有字节值“除外”都是正确的。(自由簇回来了FF FF。)我现在面临的是,由于某种原因,我无法理解,转换为无符号long的数学方法不起作用。在路试中完全正确的5E F5 1F 00(l-h变为0x001FF55E)变为0x0000F65E。我没发现我的数学有什么问题,是吗?好吧,我又犯了一个愚蠢的错误。在printf命令中使用了%u说明符,但没有长时间添加“l”:(啊…问题解决了,很抱歉打扰您。我不想使用7303例程,因为据报道它在CD-ROM上有问题。我将不得不对此进行调查。我不想再编写另一个例程:(我现在正在使用BIOS调用,这就是我遇到问题的原因:(我已经阅读了LBA和FAT32。我在第一次编写这个小实用程序时就做了这些。正如你在上面看到的,我的问题都是我自己创造的。对不起,我不是一个专业程序员,只是一个业余爱好者。我现在已经基本修复了它。一个需要跟踪的小错误(在实际的实用程序代码中,)我和CD-ROM的解决方案应该完成了。
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