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

时间:2014-09-08 06:37:11

标签: c++ assembly dos

我写了一个目录信息实用程序,(因为我和我为收集和使用老式硬件而编写的人员)使它兼容DOS和Windows 9x以及Windows XP / Vista / 7/8 64- bit(因为我们也使用那些。)我遇到的问题是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;
}

最后一点是我试图弄清楚出了什么问题。我得到了奇怪的结果,无法弄清楚一个模式。最初,我并不担心清除缓冲区,因为INT调用应该用它自己的值填充它(前2个字节除外,它应该用EDB数据缓冲区大小填充。)显然有这么多随机结果,我在开始的循环中添加了用零填充缓冲区,然后添加缓冲区大小。结果在那一点上停止了随机,它们总是全为零,这意味着INT调用没有填充缓冲区。通过各种测试,我已经确认了他和他正确地为hdi分配缓冲区地址的段和偏移量。我也试过es&amp; di到指针地址而不是缓冲区地址。我不认为它会起作用,因为我读到的所有东西都把它设置为地址而不是指针,但我正在尝试我能想到的一切。在所有情况下,缓冲区都没有充满任何东西。

正如您可能已经知道的那样,这只是一个测试程序,我正在编写以确定将其添加到我的主程序之前的确切过程(除了这个问题之外它工作正常。)FP_行只是宏可以表示为(无符号长)(x&amp; 0xffff0000)&gt;&gt; 16表示段,而(无符号长)(x&amp; 0x0000ffff)表示偏移量。通常你会传递指针(&amp; 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函数,用户无权访问它们,如果他们执行启动命令提示等...

2 个答案:

答案 0 :(得分:1)

哇,用DOS,那个老派!不像使用打卡那样老了,但还是......

显然,FreeDOSFAT 32 support。您可能会尝试将它安装在那些甚至不安装Windows 95的计算机上。

答案 1 :(得分:1)

对于您的老式爱好,您应该使用LBAFAT32规格,Wikipedia: File Allocation Table似乎有良好的联系。

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

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

更好的方式&#34;在所有情况下应该适合您的是使用BIOS调用找出所有基础知识,然后复制算法以计算您自己的代码中的大小等。在旧的DOS时代,没有可用于非Microsoft程序的轻松可重用API。需要做高级事情的程序必须自己知道如何做到这一点。