Я написал справочную информацию утилиты и (потому что я, и люди, которых я написал это для сбора & использовать устаревшее аппаратное обеспечение), сделав его совместимым с DOS и Windows 9x, а также с 64-битной Windows XP / Vista / 7/8 (потому что мы их также используем). Проблема, с которой я столкнулся, была с дисками Windows 9x и FAT32. Мне удалось заставить его работать до тех пор, пока Windows 9x была фактически загружена, но если я загружаюсь только из командной строки или перезагружаюсь в режиме MS-DOS, я теряю доступ к API Windows, что позволило мне получить большие данные с диска и его по умолчанию вернулось к программе DOS, которую я имею. Они ограничены процедурами ограничения 2 ГБ. Изучая, как программы 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 правильно назначается сегмент и смещение адреса буфера. Я тоже пробовал & di к адресу указателя вместо адреса буфера. Я не думал, что это сработает, потому что все, что я прочитал, говорит, чтобы установить его по адресу, а не по указателю, но я пробовал все, что мог придумать. Во всех случаях буфер не заполняется чем-либо.
Как вы, вероятно, можете сказать, это всего лишь тестовая программа, которую я пишу, чтобы выяснить точную процедуру перед ее добавлением в мою основную программу (которая прекрасно работает, за исключением этой проблемы). Строки FP_ — это просто макросы, которые могут быть указано как (без знака долго) (х & 0xffff0000) >> 16 для сегмента и (без знака 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. Вы можете попытаться установить его на тех компьютерах, на которых даже не установлена Windows 95.
Для вашего винтажного хобби вы должны вооружиться LBA
а также FAT32
технические характеристики, Википедия: Таблица размещения файлов кажется, есть хорошие ссылки.
Вы можете узнать одну вещь: эти устаревшие системы (и программное обеспечение, написанное для них) не могли обрабатывать большие диски (размер диска> 2 ^(32-1)Изящно
Другие материалы, я думаю, также были бы очень важны:
«Лучший способ», который должен работать для вас во всех случаях, состоит в том, чтобы использовать вызовы BIOS, чтобы выяснить все основы, а затем воспроизвести алгоритмы для расчета размеров и т. Д. В вашем собственном коде. В старые времена DOS не было легко повторно используемого API, доступного для программ не от Microsoft. Программы, которые должны были делать продвинутые вещи, должны были знать, как сделать это самостоятельно.