Жанр: Учеба

Справочник программиста на IBM PC

сторінка №29

;устанавливаем указатель на начало
MOV AH,42H ;функция установки указателя
MOV BX,HANDLE ;номер файла
INT 21H ;устанавливаем указатель
JC POINTER_ERROR ;проверка на ошибку
;---пишем запись с прямым доступом
MOV AH,40H ;номер функции
MOV BX,HANDLE ;номер файла
MOV CX,30 ;размер записи
LEA DX,REC_BUFFER ;DS:DX указывают на буфер
INT 21H ;пишем запись
JC WRITE_ERROR ;проверка на ошибку

В отличии от метода FCB метод дескриптора файлов не предоставляет
специальной функции для записи блока записей прямого доступа.
Однако Вашей программе необходимо только вычислить количество
байтов, составляющих блок записей, которое должно быть записано.
5.4.6 Чтение из файлов прямого доступа.

Чтение файлов прямого доступа является обратным процессом по
отношению к их записи. MS DOS вычисляет позицию в файле на диске,
затем считывает запись и помещает ее в память. Затем программа
должна разделить запись на поля в точности того же размера, который
был использован при конструировании записи. Не забудьте удалить
символы пробела, добавленные при заподнении полей. Обсуждение
записи данных в файлы прямого доступа [5.4.5] содержит информацию,
которая поможет Вам лучше понять информацию данного раздела.


Высокий уровень.

Для чтения файла прямого доступа необходимо открыть файл и
определить поля записи, как объяснено в разделе, относящемся к
записи в файлы прямого доступа. Затем надо использовать оператор
GET# для чтения определенной записи с диска. GET #1,23 считывает
запись номер #23 из файла, открытого под номером #1. При чтении
записи переменной, именованной в операторе FIELD, автоматически
присваивается соответствующее значение из записи. Например, если
оператор FIELD имеет вид FIELD 1, 20 AS X$, 2 AS Y$, то после
выполнения оператора GET 1,23 переменной X$ будет присвоено значение
первых 20-ти байтов записи 23, а переменной Y$ - следующих
10-ти байтов. Операторы, аналогичные RSET и LSET для выделения
полей данных отсутствуют.
В случае числовых полей, напоминаем, что они должны быть
преобразованы в строковый вид с помощью функций MKI$, MKS$ и
MKD$. Для восстановления их оригинальных значений, с тем чтобы
над ними можно было проводить операции и печатать их, надо преобразовать
эти строки с помощью функций CVI, CVS и CVD. Если Y$
содержит целое число, то для выполнения обратного преобразования
запишите Y% = CVI(Y$), при этом переменная Y% будет содержать
значение, которое имела переменная перед тем как она была специально
обработана для записи в файл прямого доступа. Если Вы
выведете строковое значение переменной, то увидите, что это число
в интервале от 0 до 65535, закодированное в два символа ASCII.
В данном примере открывается файл, созданный в примере пункта
[5.4.5], и выводится содержимое любой из затребованных записей:

100 OPEN "A:NEWDATA" AS #1 LEN = 24 'открываем файл
110 FIELD 1, 18 AS LASTNAME$, 2 AS AGE$, 4 AS WEIGHT$
120 CLS: INPUT "What is the record number";R 'запрос записи
130 IF R*24 " LOF(1) THEN BEEP: PRINT"No such record": GOTO 120
140 GET #1,R 'читаем запись из файла
150 PRINT LASTNAME$, CVI(AGE$), CVS(WEIGHT$) 'выводим ее
160 PRINT: PRINT "Do another (y/n)?" 'будем повторять?
170 C$ = INKEY$: IF C$ = "" THEN 170 'ожидаем ввода
180 IF C$ = "y" OR C$ = "Y" THEN 120 'повторяем, если надо
190 CLOSE 'иначе закрываем файл

Средний уровень.

Метод FCB доступа к файлам имеет две функции для чтения записей
с прямым доступом. С другой стороны, метод дескриптора файлов
использует ту же функцию, что и для чтения последовательных файлов.
Два метода доступа рассматриваются отдельно.
Метод FCB:
Функция 21H прерывания 21H читает одну запись из файла прямого
доступа. Вторая функция, 27H, читает блок последовательных записей.

Создайте управляющий блок файла, как показано в [5.3.5] и
откройте его [5.3.3]. После того как FCB открыт, введите в него
значения полей размера записи (DW по смещению 14) и номера записи
прямого доступа (DD по смещению 33). Если DS:DX указывают на
первый байт FCB, то можно вызывать функцию 21H для чтения записи
и запись будет помещена в паямть, начиная с первого байта DTA.
Если запись успешно прочитана, то в AL будет возвращен 0.
Однако при этом нет гарантии, что чтение прошло без ошибок, поскольку
неверный размер записи может привести к тому, что части
прилегающих записей будут считаны, как будто это одна запись.
Если запрошена запись с номером большим, чем число записей в
файле, то в AL будет возвращено 1 или 3. Если был возвращен код
3, то был считан самый конец файла и была прочитана часть записи
данных. Если был возвращен код 1, то данные вообще не были считаны.

Данный пример считывает одну запись и помещает ее в DTA:

;---в сегменте данных
FCB DB 1,'OLDDATA ', 25 DUP (0)

;---открываем файл и устанавливаем поля FCB
MOV AH,0FH ;номер функции
LEA DX,FCB ;DS:DX указывают на FCB
MOV BX,DX ;копируем смещение FCB
INT 21H ;открываем файл
MOV AX,55 ;размер записи 55 байтов
MOV [BX]+14,AX ;помещаем в поле размера записи
MOV AX,22 ;номер записи для чтения
MOV [BX]+33,AX ;помещаем в поле номера записи
MOV AX,0 ;обнуляем старшее слово этого поля
MOV [BX]+35,AX ;
;---перенос данных из файла в DTA
MOV AH,21H ;номер функции чтения с прямым доступом
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;читаем данные, помещая их в DTA
CMP AL,0 ;проверка на ошибку
JNE READ_ERROR ;
;---позднее, закрываем файл
MOV AH,10 ;номер функции закрытия файла
LEA DX,FCB ;DS:DX указывают на FCB
INT 21H ;закрываем файл

Для чтения блока последовательных записей в память за один
прием надо использовать функцию 27H прерывания 21H. Ее выполнение
подготавливается в точности так же, как и функции 21H, за исключением
того, что вдобавок CX должен содержать число записей которые
надо прочитать за один прием. При возврате CX будет содержать
число реально прочитанных записей. Значения возвращаемые в AL
совпадают с теми, которые возвращаеются функцией 21H. В отличии
от функции 21H поля FCB, в которых хранится информация о положении
записи (поле записи прямого доступа, текущего блока и текущей
записи) автоматически увеличиваются, с тем чтобы они указывали на
следующую несчитанную запись после выполнения функции.
Отметим, что как в случае чтения одной, так и в случае чтения
нескольких записей, поля текущего блока и текущей записи FCB
устанавливаются по значению поля записи прямого доступа. Если Вы
знаете значение текущего блока и текущей записи, а не соответствующий
номер записи прямого доступа, то используйте функцию 24H
прерывания 21H, чтобы она проделала вычисления за Вас. У этой
функции нет входных регистров, надо только, чтобы DS:DX указывали
на открытый FCB. При возврате поле записи прямого доступа будет
заполнено значением, соответствующим установке двух других полей.

Метод дескриптора файлов:
В предыдущем разделе показано, как писать записи прямого доступа
с помощью метода дескриптора файлов. Процедура чтения из
файла с прямым доступом подготавливается совершенно аналогичным
образом, путем вычисления смещения в файле, на которое должен
указывать файловый указатель. DS:DX должны указывать на буфер, в
который будет помещена запись, после чего надо выполнить функцию
3FH прерывания 21H. При входе CX должен содержать размер записи,
а BX - номер файла.

;---в сегменте данных
HANDLE DB ?

FILEPATH DB 'A:OLDDATA',0
REC_BUFFER DB 30 DUP(?)

;---открываем файл
MOV AH,3DH ;номер функции
MOV AL,0 ;код открытия для чтения
LEA DX,FILEPATH ;DS:DX указывают на путь к файлу
INT 21H ;открываем файл
JC OPEN_ERROR ;проверка на ошибку
MOV HANDLE,AX ;запоминаем номер файла
;---вычисляем позицию записи и устанавливаем файловый указатель
MOV AX,30 ;размер записи
MOV CX,54 ;читаем запись #54 (55-ю запись)
MUL CX ;смещение записи в DX:AX
MOV CX,DX ;помещаем старшее слово смещения в DX
MOV DX,AX ;помещаем младшее слово смещения в CX
MOV AL,0 ;устанавливаем указатель на начало файла
MOV AH,42H ;функция установки указателя
MOV BX,HANDLE ;номер файла
INT 21H ;устанавливаем указатель
JC POINTER_ERROR ;обработка ошибки
;---читаем запись с прямым доступом
MOV AH,3FH ;номер функции
MOV BX,HANDLE ;номер файла
MOV CX,30 ;размер записи
LEA DX,REC_BUFFER ;DS:DX указывают на буфер для записи
INT 21H ;читаем запись
JC READ_ERROR ;обработка ошибки

;---позднее, закрываем файл
MOV BX,HANDLE ;номер файла
MOV AH,3EH ;функция закрытия файла
INT 21H ;закрываем файл
JC CLOSE_ERROR ;проверка на ошибку
5.4.7 Проверка данных после операций чтения/записи.

MS DOS может проверять правильность производимого обмена с
диском прямо во время обмена. Ошибки происходят настолько редко,
что средства проверки обычно не используются, чтобы не замедлять
обмен с диском. Однако, если это необходимо, то имеется два способа
проверки. Один состоит во включении команды VERIFY = ON в
файл CONFIG.SYS, который автоматически читается при загрузке
операционной системы. Впоследствии, все дисковые операции будут
проверяться. Это единственный способ проверки доступный в Бейсике.
Второй метод состоит использовании специальной функции DOS
для верификации только критических дисковых операций. Если процедура
верификации обнаруживает ошибку, то она сообщает об условии
критической ошибки, как описано в [7.2.5].

Средний уровень.

Функция 2EH прерывания 21H включает и выключает проверку.
Поместите в AL 1 - для включения верификации и 0 - для выключения.
DL также должно быть равно 0. Затем надо выполнить прерывание.
У этой функции нет выходных регистров.

;---включение верификации
MOV AL,1 ;номер кода
MOV DL,0 ;необходимый входной регистр
MOV AH,2EH ;номер функции
INT 21H ;включаем проверку

Для определения текущего режима верификации надо вызвать функцию
54H прерывания 21H. У нее нет входных регистров. При возврате
AL = 1, если проверка включена и AL = 0, если выключена.
5.4.8 Определение дисковых ошибок и восстановление после них.

Дисковые операции настолько сложны, что имеется большое количество
возможных ошибок. Большинство дисковых ошибок обсуждаются
вместе с операциями, при которых они могут происходить. В данном
разделе они собраны вместе, чтобы помочь Вам при разработке процедуры
общего назначения для восстановления после дисковых ошибок.

Дисковые ошибки бывают двух типов, которые мы будем называть
мягкими (soft) и жесткими (hard). Мягкие ошибки возникают из-за
неправильного запроса на доступ к файлу: запрошенный файл может
отсутствовать или дисковое пространство может кончиться прежде,
чем будет записан весь файл. С другой стороны, жесткие ошибки
возникают при неверных последовательностях или временных несоответствий
при дисковых операциях, которые могут быть следствием
неверного выравнивания или проблем с накопителем. В этом случае,
лучше всего произвести сброс диска перед обработкой.


Высокий уровень.

В [7.2.5] объяснено как подготовить процедуру обработки ошибок.
Оператор ON ERROR GOSUB заставляет программу перейти на
процедуру обработки ошибки при возникновении критической ошибки.
Процедура прежде всего определяет кодовый номер ошибки в Бейсике,
который для дисковых ошибок может быть одним из следующих:

52 Bad file number. (Неверный номер файла.) Файл не отк-
рыт под тем номером, к которому идет обращение (#1,
#2 и т.д.)
53 File not found. (Файл не найден.) Используется при
выполнении операторов LOAD, KILL, NAME, FILES и OPEN.
54 Bad file mode. (Неверный режим доступа.) Попытка дос-
тупа к файлу другим образом, по сравнению с тем, для
чего он был открыт, например, попытка записи в после-
довательный файл, открытый для чтения.
55 File already open. (Файл уже открыт.) Попытка открыть
файл, который уже открыт, или уничтожить (KILL) файл,
который еще не закрыт.
58 File already exists. (Файл уже существует.) Попытка
переименовать файл (с помощью NAME) на имя, которое
уже есть в каталоге.
61 Disk full. (Диск полон.) См. специальное обсуждение в
[5.1.4], относящееся к этой ошибке.
62 Input past end. (Чтение за концом файла.) Попытка
прочитать из последовательного файла больше перемен-
ных, чем он содержит. Чтобы избежать этой ошибки ис-
пользуйте функцию EOF, как объяснено в [5.4.4].
63 Bad record number. (Неверный номер записи.) Попытка
прочитать или записать запись с номером большим, чем
число записей в файле.
64 Bad file name. (Неверное имя файла.) Используется
операторами KILL, NAME и FILES.
67 Too many files. (Слишком много файлов.) В каталоге
больше нет места для записи информации о файлах. Дру-
гой возможный вариант состоит в том, что открытие еще
одного файла приведет к тому, что будет превышено
максимально допустимое число одновременно открытых
файлов.
70 Disk is write-protected. (Диск защищен от записи.)
71 Disk is not ready. (Диск не готов.) Наиболее вероятно,
не закрыт дисковод с дискетой.
72 Disk media error. (Диск поврежден.) Как правило, это
сообщение выдается при повреждении дискеты, однако
иногда оно появляется при сбоях оборудования.
74 Specified wrong disk in RENAME operation. (Указан
неверный диск в операции RENAME.)
75 Path/file access error. (Ошибка доступа к файлу.)
Попытка открыть подкаталог или метку тома, как файл.
Или попытка писать в файл, который защищен от записи.
Эта ошибка чаще всего выдается при попытке удалить
текущий каталог. Появляется при операциях OPEN, NAME,
MKDIR, CHDIR и RMDIR.
76 Path not found. (Путь не найден.) Неправильно указан
путь или его не существует. Появляется при операциях
OPEN, MKDIR, CHDIR и RMDIR.

После того как процедура распознала ошибку, необходимо информировать
об ошибке пользователя. Когда пользователь сообщит, что
причина ошибки устранена, то оператор RESUME посылает программу
назад на ту строку, где произошла ошибка. Оператор RESUME может
сопровождаться номером строки, поэтому программа может вернуться
к началу всей последовательности дисковых операций, независимо от
того, в какой строке произошла ошибка (отметим, что файлы не
закрываются при возникновении ошибки). В следующем примере программа
позволяет восстановить ситуацию после ошибок, связанных с
переполнением диска и защитой от записи:

100 ON ERROR GOSUB 5000 '
600 '''
5000 '''
5010 IF ERR = 61 PRINT "Disk full": GOTO 5100
5020 IF ERR = 70 PRINT "Disk is write protected": GOTO 5100
5100 PRINT "Correct the problem, then strike any key"
5110 C$ = INKEY$: IF C$ = "" THEN 5110
5120 RESUME 600

Средний уровень.

Функция 1 прерывания 13H возвращает в AL байт, дающий статус
дискового накопителя. Значение его битов следующее:
биты 0-1 01 = неверная команда, или, если бит 3 = 1, то
попытка обмена данными за границей 64K
10 = адресная метка не найдена
11 = попытка записи на защищенный от записи диск
2 1 = указанный сектор не найден
3 1 = переполнение DMA (потеря данных при обмене),
или, если бит 0 = 1, то попытка обмена дан-
ными за границей 64K
4 1 = данные прочитаны неверно, надо повторить
5 1 = ошибка контроллера
6 1 = ошибка операции поиска
7 1 = нет ответа от накопителя (тайм-аут)
Каждая из функций обращения к диску MS DOS использует только
некоторые из возможных кодов ошибок, а некоторые функции не сообщают
об ошибке. Однако во всех случаях при возникновении ошибки
устанавливается флаг переноса. Если произошла ошибка, то номер
кода этой ошибки возвращается в AX. Вот коды, относящиеся к дисковым
операциям:

1 Неверный номер функции
2 Файл не найден
3 Путь не найден
4 Уже открыто максимально допустимое число файлов
5 Отрицание доступа (ошибка оборудования)
6 Неверный номер файла
15 Указан неверный накопитель
16 Попытка удалить текущий каталог
17 Не то же устройство
18 Больше нет файлов (при поиске в каталоге с использова-
нием джокеров)

Восстановление после этих "мягких" ошибок несложно. Некоторые
предупреждают Вас о программных ошибках. Другие возникают из-за
ошибочных действий пользователя. Если же не отвечает сам накопитель,
то произошла критическая ошибка. В разделе [7.2.5] показано
как написать процедуру обработки критических ошибок.
В MS DOS 3.0 введены расширенные коды ошибок. Они могут быть
получены с помощью функции 59H прерывания 21H, когда флаг переноса
индицирует возникновение ошибки. Обсуждение этого вопроса см.
в [7.2.5].

Глава 6. Принтер.


Раздел 1. Управление работой принтера.


MS DOS может работать с тремя параллельными устройствами (LPT1
- LPT3) и в этой главе показано как управлять ими. Последовательные
принтеры управляются в точности так же, как и параллельные,
за исключением способа, которым данные посылаются на принтер; эта
информация приведена в разделе 1 главы 7. Каждое параллельное
устройство имеет свой адаптер. Адаптер управляется тремя регистрами
ввода/вывода и адреса портов этих регистров различны для
каждого адаптера. Область данных BIOS содержит базовые адреса для
каждого адаптера. Базовый адрес соответствует младшему адресу
группы из трех адресов портов. Базовый адрес для LPT1 -
0040:0008, для LPT2 - 0040:000A и т.д. Какой адаптер назначен
какому номеру LPT - не определено , как видно из нижеприведенной
таблицы. По этой причине программа, котрая прямо адресуется в
параллельный порт, должна выискивать адреса, которые он использует.
Отметим, что при инициализации базовому адресу присваивается
значение 0, когда соответствующий адаптер не установлен.

Адаптер Выходных данных Статуса Управления

Монохромная карта (PC/XT/AT) 3BCH 3BDH 3BEH

Адаптер принтера PC/XT
Адаптер принтера PCJr 378H 379H 37AH
Последовательная/параллельная
карта AT (установленная как LPT1)

Последовательная/параллельная 278H 279H 27AH
карта AT (установленная как LPT2)

Регистр выходных данных - это тот адрес порта, через который
проходит каждый байт данных, посылаемый в принтер. Регистр статуса
сообщает различную информацию о принтере; процессор может
постоянно опрашивать его, чтобы распознать момент, когда все в
порядке и можно посылать данные. Регистр статуса сообщает также,
что произошла ошибка на принтере. Регистр управления инициализирует
адаптер и управляет выводом данных. Он может также подготавливать
параллельный порт для операций прерывания, с тем чтобы
принтер посылал прерывание к процессору, когда он готов к приему
очередного символа, оставляя процессор свободным для других дел.
Вот значение битов регистров статуса и управления:

Регистр управления
бит 0 0 = нормальная установка, 1 = вызывает вывод байта
данных
1 0 = нормальная установка, 1 = автоматический перевод
строки после возврата каретки
2 0 = инициализировать порт принтера, 1 = нормальная
установка
3 0 = отмена выбора принтера, 1 = нормальная установка
4 0 = прерывание принтера запрещено, 1 = разрешено
5-7 не используются
Регистр статуса
бит 0-2 не используются
3 0 = ошибка принтера, 1 = нет ошибки
4 0 = принтер off-line, 1 = принтер on-line
5 0 = бумага вставлена, 1 = нет бумаги
6 0 = принтер подтверждает прием символа, 1 = нормаль-
ная установка
7 0 = принтер занят, 1 = принтер свободен

Не имеется никаких оснований, чтобы любая программа не имела
процедуру восстановления при ошибках, возникающих при работе с
принтером. Хорошо написанная программа должна начинать с проверки
того, что принтер связан с машиной (on line). Если присоединен не
один принтер, то программа должна позволять пользователю выбрать
с каким из них он будет работать. Кроме того, эта процедура должна
восстанавливать ситуацию при любых ошибках принтера, при этом
хотелось бы, чтобы не было необходимости снова печатать весь
документ.
6.1.1 Инициализация порта принтера/повторная инициализация
принтера.

Программы должны инициализировать порт каждого принтера (LPT1
- LPT3) перед первым использованием принтера. Порты принтера
должны также повторно инициализироваться после устранения причин
ошибки принтера. Не путайте инициализацию порта принтера с инициализацией
самого принтера. Инициализация принтера это внутреннее
дело принтера. Она происходит автоматически при его включении
и в большинстве случаев принтер не может быть повторно инициализирован
без его выключения и повторного включения. Но программа
может повторно инициализировать принтер, в том смысле, что
могут быть восстановлены начальные параметры, которые принтер
использует для печати, отменяя все специальные шрифты, остановы
табуляции и т.д. Считается правилом хорошего тона производить
такой сброс принтера, когда программа завершает работу с ним.
Языки высокого уровня инициализируют порт принтера автоматически,
но программы на языке ассемблера требуют для этой цели
короткую процедуру. С другой стороны, восстановление начальных
параметров печати требуется во всех программах. Некоторые принтеры,
такие как новые Эпсоновские принтеры, имеют "главный код
сброса", который приводит к полному сбросу принтера. Но поскольку
не все принтеры имеют такой код, то программа должна предусматривать
в своей завершающей части восстановление всех измененных
параметров. Например, она может подать коды выключения курсива,
выключения плотной печати и т.д. Не забудьте включить вызов этой
процедуры в процедуру выхода по Ctrl-Break.
Имейте в виду, что на многих принтерах символы не печатаются
до тех пор, пока не получен код возврата каретки, завершающий
строку (или до тех пор пока не введена целая строка данных).
Символы могут спокойно ожидать в буфере принтера, даже после
того, как породившая их программа завершилась. Когда начинается
новая передача данных на принтер, то эти символы будут напечатаны.
Чтобы избежать этой проблемы, не забывайте почистить буфер
перед началом печати; а в качестве правил хорошего тона, чистите
буфер также при завершении программы. Это делается посылкой на
принтер кода ASCII 24 (при этом параметры печати не меняются).


Средний уровень.

Функция 1 прерывания 17H BIOS инициализирует порт принтера и
возвращает байт, дающий статус порта. Поместите в DX номер порта
- число от 0 до 2 для LPT1 - LPT3, после чего вызовите прерывание.
Байт статуса принтера (идентичный обсуждаемому в [6.1.2])
возвращается в AH.

;---инициализация LPT1
MOV AH,1 ;функция инициализации принтера
MOV DX,0 ;LPT1
INT 17H ;проводим инициализацию

Низкий уровень.

Ренистр управления выводом каждого адаптера принтера имеет
бит, который вызывает инициализацию адаптера. Этот регистр имеет
адрес порта на 2 больше, чем базовый адрес адаптера. Напоминаем,
что базовый адрес для LPT1 хранится в ячейке 0040:0008, для LPT2
- в 0040:000A и т.д. Имеют значение только младшие 5 битов регистра
управления выводом. Бит 2 - бит инициализации принтера и
обычно он устанавливается в 1. Для инициализации адаптера надо
сбросить этот бит в 0 на тысячу тактов пустого цикла (3000 для AT
или на 1/20 секунды, используя счетчик времени суток BIOS
[2.1.5]). В этот момент нужно, чтобы был установлен только бит 3
(принтер выбран). Поэтому пошлите в порт значение 12, сделайте
задержку, а затем пошлите в порт обычное (без прерываний) неинициализонное
значение, которое равно 8.
В данном примере инициализируется LPT1:

;---инициализируем LPT1
MOV DX,ES:[8] ;считываем базовый адрес в DX
INC DX ;прибавляем 2 к базовому адресу
INC DX ;
MOV AL,12 ;значение для инициализации
OUT DX,AL ;начинаем инициализацию
DELAY: MOV AX,1000 ;начало пустого цикла
DEC AX ;уменьшаем счетчик
JNZ DELAY ;повторяем 1000 раз
MOV AL,8 ;обычное значение для регистра
OUT DX,AL ;конец инициализации
6.1.2 Проверка того, что принтер связан с машиной.

Программа всегда должна проверить, что принтер связан с машиной,
перед тем, как послать на него вывод. Легко установить, что
принтер не готов, так как бит 3 регистра статуса принтера устанавливается
в 1 в этом случае. Но намного сложнее точно определить
почему принтер не готов: выключен ли он, отменен выбор принтера
или в нем нет бумаги. Это происходит из-за того, что принтеры
разных производителей посылают разные наборы битов в регистр
статуса принтера, даже когда они находятся в идентичном состоянии.
Хотя регистр статуса имеет биты, которые должны показывать
эти три состояния принтера, но в реальности значения битов могут
не соответствовать этим условиям (бит

Список сторінок

Поділитися у соцмережах

☏ Замовлення реклами: +3805044-68-872

© Асоціація електронних бібліотек України

☝ Усі матеріали сайту (зокрема статті, зображення, рекламні оголошення тощо) призначені лише для попереднього ознайомлення. Усі права на публікації, представлені на сайті, належать їхнім законним власникам. Просимо Вас не зберігати копії інформації.