W ostatniej części cyklu omówione zostaną dalsze wywołania systemowe oraz krótki program ilustrujący sposób wywołania programu z innego programu.
Funkcja 25h - umożliwia ustawienie wartości wektorów przerwań. W AL należy podać numer przerwania (00h do FFh), a w DS:DX - wartość wektora, czyli adres procedury obsługującej dane przerwanie. Wartość wektora można oczywiście wpisać bezpośrednio pod jeden z adresów od 0000:0000h do 0000:03FC. Nie jest to jednak zalecane, gdyż w przyszłych wersjach systemu (wielozadaniowych) bezpośrednia zmiana wartości wektorów w pamięci albo zostanie zablokowana przez mechanizmy systemu, albo zmodyfikowana bez wiedzy systemu mogłaby mieć fatalne skutki.
Funkcja 2Ah - pozwala odczytać datę. Po jej wykonaniu otrzymuje się :
- w AL - dzień tygodnia (0 = niedziela, ... , 6 = sobota)
- w DL - dzień miesiąca (1 ... 31)
- w DH - miesiąc (1 ...12)
- w CX - rok (1980 ... 2099)
Funkcja 2Bh - służy do ustawienia daty. Data zakodowana jest identycznie, jak przy funkcji 2Ah, tym razem jednak składniki daty są parametrami wejściowymi. Jeśli po powrocie z wywołania AL = 0, to podane parametry były prawidłowe, jeśli AL = FFh - nieprawidłowe.
Funkcja 2Ch - pozwala odczytać czas. Po jej wywołaniu otrzymuje się :
- w CH - godziny (0 ... 23)
- w CL - minuty (0 ... 59)
- w DH - sekundy (0 ... 59)
- w DL - setne sekundy (0 ... 99)
Mimo podawania przez procedurę setnych części sekundy, odczyt nie może być zrealizowany z dokładnością większą niż 1/20 sekundy - wynika to ze sposobu obsługi tej funkcji przez BIOS.
Funckcja 2Dh - służy do ustawienia czasu. Parametry wejściowe odpowiadają parametrom wyjściowym funkcji 2Ch, prawidłowość danych sygnalizowana jest identycznie jak przy funkcji 2Bh.
Funkcja 2Eh - ustawia lub zeruje wskaźnik weryfikacji zapisu na dysku. Normalnie wskaźnik ten jest wyzerowany, gdyż zapis na dysku jest stosunkowo niezawodny. Można jednak ustawić ten wskaźnik, wówczas po każdym zapisie na dysk następuje odczyt i sprawdzenie wartości kodu CRC (dane nie są porównywane). AL = 01h powoduje ustawienie wskaźnika weryfikacji, zaś AL = 00h - jego wyzerowanie.
Funkcja 30h - podaje numer wersji systemu operacyjnego. Po jej wywołaniu w AL przekazywany jest numer główny (2 dla wersji 2.X, 3 dla 3.X, 0 dla wersji wcześniejszych od 1.28), w AH - numer występujący po kropce (np. 08h dla MS-DOS 2.08).
Funkcja 33h - podaje albo zmienia sposób reakcji na naciśnięcie klawiszy CTRL-C. MS-DOS oferuje możliwość przerywania programu przez wciśnięcie CTRL-C. Normalnie reakcja na takie przerwanie możliwa jest tylko w czasie wykonywania funkcji o numerach 01h ... 0Ch. Funkcja 33h daje możliwość przerwania programu w czasie wykonywania każdej z funkcji systemowych, dla której nie jest to z założenia wykluczone. Jeśli chcemy użyć funkcji 06h lub 07h do odczytania znaku ASCII odpowiadającego CTRL-C, trzeba wpierw za pomocą funcji 33h wyłączyć reakcję na to przerwanie. Parametry wejściowe :
- AL = 00h - pobranie chwilowego sposobu reakcji na CTRL-C
- AL = 01h - zmiana sposobu reakcji na CTRL-C
Dla AL = 01h :
- DL = 00h - wyłączenie reakcji na CTRL-C
- DL = 01h - włączenie reakcji na CTRL-C
Parametry wyjściowe :
- AL = FFh - zły kod w AL przy wywoływaniu funkcji
- DL = 00h - reakcja na CTRL-C wyłączona
- DL = 01h - reakcja na CTRL-C włączona
Funkcja 35h - podaje w ES:BX wartość wektora przerwania adres. Przed wywołanie w AL należy podać numer badanego przerwania.
Funkcja 36h - dostarcza informacji o organizacji dysku. W DL należy podać numer napędu (0 - aktualnie wybrany, 1 - A: itd.). W wyniku podaje :
- w AX - liczba sektorów przypadających na jednostkę alokacji - klaster lub FFFFh - jeśli w DL podano zły numer napędu,
- w BX - liczbę dostępnych klastrów,
- w CX - liczbę bajtów w sektorze,
- w DX - całkowitą liczbę klastrów na dysku.
Funkcja 38h - podaje lub ustala sposób przedstawiania takich informacji, jak: data i czas, symbol waluty, separator części dziesiętnej liczby, separator liczby tysięcy. Sposób przedstawiania zależy od kraju, w którym używa się komputera. Np. w Europie datę zapisuje się w postaci dd.mm.rr, a w USA - mm/dd/rr.
Po załadowaniu systemu MS-DOS sposób przedstawiania informacji wybrany jest zgodnie z wierszem COUNTRY kod znajdującym się w zbiorze CONFIG.SYS, przy czym kod ten jest trzycyfrowym międzynarodowym telefonicznym numerem kierunkowym danego kraju. Uwaga: podanie numeru kierunkowego Polski (48) nie przynosi oczekiwanych rezultatów. Niestety, nie wszystkie kraje są rozpoznawane przez DOS. Za pomocą funkcji 38h można sprawdzić, do jakiego kraju system jest w danej chwili dopasowany i na czym to dopasowanie polega.
Przy dopasowywaniu systemu do jakiegoś kraju w rejestrze DX trzeba umieścić FFFFh, a w rejestrze AL, kod tego kraju. Jeśli kod kraju jest większy od 254, to w AL należy umieścić FFh, a w BX 6-bitowy kod kraju. Jeśli po powrocie z wywołania funkcji ustawiony jest wskaźnik przeniesienia, to świadczy, że źle podano kod kraju (w AX znajduje się wówczas kod błędu).
Jeśli chcemy sprawdzić, do jakiego kraju system jest w danej chwili dopasowany, musimy w AL umieścić 00h, a w DS:DX adres 32-bajtowego bufora na informacje przekazywane zwrotnie przez system. Po powrocie z wywołania, jeśli wskaźnik przeniesienia jest zerem (brak błędu), to w rejestrze BX pojawi się kod kraju, a w 32-bajtowym buforze informacja o krajowym zapisu (tabela 1, albo tabela 2).
Tabela 1. Informacja opisująca sposób zapisu w danym kraju, zwracana przez funkcję 38h dla wersji MS-DOS3.0 i późniejszych.
| Przemieszczenie względem DS:DX | Zawartość |
| 00h ... 01h |
Format daty:
|
| 02h ... 06h | Symbol waluty - ciąg ASCIIZ |
| 07h ... 08h | Separator tysięcy - ciąg ASCIIZ |
| 09h ... 0Ah | Separator części dziesiętnej - ciąg ASCIIZ |
| 0Bh ... 0Ch | Separator w dacie - ciąg ASCIIZ |
| 0Dh ... 0Eh | Separator w czasie - ciąg ASCIIZ |
| 0Fh |
Bajt opisujący sposób zapisu sum pieniężnych
|
| 10h | liczba znaczących cyfr dziesiętnych w sumach pieniężnych |
| 11h |
Bajt opisujący postać czasu :
|
| 12h ... 15h | Adres (przemieszczenie, segment) procedury, która na podstawie kodu małej litery występującej w danym języku (80h ... FFh) podaje kod odpowiadającej jej dużej litery. Kod małej litery trzeba podać w AL, kod dużej litery zwracany jest też w AL. |
| 16h ... 17h | Separator pozycji na liście - ciąg ASCIIZ |
| 18h ... 1Fh | Zarezerwowane |
Tabela 2. Informacja opisująca sposób zapisu w danym kraju, zwracana przez funkcję 38h, dla wersji MS-DOS wcześniejszych od 3.0
| Przemieszczenie względem DS:DX | Zawartość |
| 00h ... 01h | Format daty |
| 02h ... 03h | Symbol waluty - ciąg ASCIIZ |
| 04h ... 05h | Separator tysięcy - ciąg ASCIIZ |
| 06h ... 07h | Separator części dziesiętnej - ciąg ASCIIZ |
| 08h ... 1Fh | Nieużywane |
Począwszy od wersji MS-DOS 3.0 można też sprawdzić, na czym polega sposób dopasowania systemu do jakiegoś kraju, bez zmieniania aktualnego dopasowania. W tym celu w AL należy umieścić kod tego kraju (lub w AL liczbę 255, zaś 16-bitowy kod kraju w BX). Podobnie jak poprzednio, adres bufora na informacje zwrotne trzeba podać w DS:DX, zaś zwracane w tym buforze informacje o sposobie zapisu są zgodne z tabelą 2.
Uwaga : wersje MS-DOS wcześniejsze od 3.0 nie pozwalają sprawdzić sposobu dopasowania do dowolnego kraju (przy sprawdzaniu dopasowania AL musi być równe 0), a ponadto możliwe jest dopasowanie się tylko do kilku krajów. Informacje o sposobie zapisu dla wcześniejszych od 3.0 są przedstawiane inaczej (tabela 1) niż dla wersji 3.0 i późniejszych (tabela 2). Wersja 3.0 i późniejsze dopuszczają istnienie symbolu waluty składającego się z jednego do 4 znaków.
Opisana funkcja umożliwia konstruowanie programów wyprowadzających wyniki w postaci uzależnionej od kraju, w którym pracuje komputer.
Funkcja 57h - podaje lub ustawia datę i czas ostatniego zapisu do już istniejącego pliku. Przy wywołaniu funkcji w AL należy umieścić 00h w odczytywaniu lub 01h w ustawianiu daty i czasu, w BX - nr kanału logicznego przyporządkowanego plikowi (handle). Jeśli data i czas są ustawiane (AL = 01h), w CX trzeba podać czas, a w DX - datę (w postaci zakodowanej, opisanej wcześniej, z tym, że w przypadku rejestrów bajty są zamienione, to znaczy DH zawiera mniej znaczącą część daty itd.). W przypadku odpytywania (AL = 0) po powrocie z procedury, w podobny sposób w rejestrze DX zakodowana jest data, a w CX - czas.
Uruchomienie programu z innego programu typu COM
Przyjrzyjmy się bliżej funkcji 4Bh. Umożliwia ona załadowanie z dysku do pamięci i uruchomienie programu. W szczególności programem tym może być standardowy interpreter poleceń - COMMAND.COM. Podając mu jako parametr ciąg znaków ASCII będących poleceniem, można spowodować wykonanie dowolnego polecenia wewnętrznego (np. DIR) lub zewnętrznego (np. DSKCHK), bądź poleceń znajdujących się w pliku typu .BAT. Przykład programu ładującego do pamięci dodatkową kopię interpretera poleceń pokazano na wydruku 1. Najpierw wywoływana jest funkcja 4Ah, zmieniająca rezerwację pamięci dla programu.
MS-DOS musi zawsze wiedzieć, jakie obszary pamięci przydzielone są programowi (w związku z tym system nie ma prawa w nich nic zapisywać) oraz jakie obszary są pozostawione do dyspozycji systemu (w związku z tym program nie ma prawa w nich nic zapisywać). Po załadowaniu i uruchomieniu programu cała dostępna pamięć (niezależnie od długości programu) jest przydzielona programowi. System nie może więc załadować żadnego innego programu. Najpierw trzeba zwolnić część pamięci. Służy do tego funkcja 4Ah, dla której w ES należy podać adres segmentowy bloku pamięci, w którym zaczyna się pierwszy program, a w BX - liczbę bloków, jaką należy pierwszemu programowi przyporządkować. Przyporządkowując pierwszemu programowi liczbę bloków, którą rzeczywiście wykorzystuje, zwalniamy pozostałą część pamięci. Dopiero po takiej operacji można żądać załadowania innego programu.
W opisywanym programie zmieniono sposób reakcji na wciśnięcie klawiszy CTRL+C. Normalnie po ich wciśnięciu nastąpiłoby przerwanie programu i powrót do systemu operacyjnego. Tutaj zastosowano zmianę wartości wektora odpowiadającego wciśnięciu CTRL+C. Nowa wartość jest adresem procedury, która porządkuje stos i wraca do głównej pętli programowej. Po wciśnięciu CTRL+C zamiast powrotu do systemu operacyjnego następuje więc powrót do wyświetlania menu. Do systemu operacyjnego można wrócić (poprzez jego powtórne załadowanie) po wybraniu z menu pozycji 2.
Wydruk 1.
NAME INVOKE
; Program ten najpierw wyświetla menu, z którego użytkownik może wybrać 3
; opcje. Pierwsza opcja umożliwia załadowanie standardowego interpretera
; poleceń i wykonanie polecenia wewnętrznego DIR; druga opcja powoduje
; załadowanie tego samego interpretera i wykonanie polecenia zewnętrznego
; CHKDSK; trzecia opcja powoduje wykonanie sekwencji instrukcji
; powodujących restart systemu operacyjnego
;
; napęd systemowy (zawierający COMMAND.COM) powinien być napędem C: jeśli
; tak nie jest, to w ciągu znaków zdefiniowanych za etykietą PROGRAM
; należy odpowiednio zmienić literę dysku. Tekst źródłowy należy wpisać do
; zbioru invoke.asm
;
; Assemblacja : masm invoke
; Konsolidacja : link invoke
; Utworzenie zbioru .com : exe2com invoke invoke.com
; Wykonanie : invoke
CODE SEGMENT WORD 'CODE'
ASSUME CS:CODE, DS:CODE, ES:CODE, SS:CODE
BUFFERED_INPUT EQU 0Ah ; DOS: odczyt wiersza wprowadz. z klaw.
CHECK_KEY EQU 0Bh ; DOS: sprawdzenie bufora klawiatury
CONSOL_INPUT EQU 00h ; kanał wprowadzania z klawiatury
CONSOL_OUTPUT EQU 0ah ; kanał wyprowadzania na klawiaturę
CTRL_C_INT EQU 23h ; nr. wektora przerwania CTRL-C
CR EQU 0Dh ; znak ASCII: powrót karetki
DOS EQU 21h ; przerwanie obsługujące funkcje DOS
EXECUTE EQU 4Bh ; DOS: załad. i wykonanie programu z dysku
FLUSH_BUFFER EQU 0Ch ; DOS: zerowanie bufora klawiatury
LF EQU 0Ah ; znak ASCII: nowy wiersz
SET_BLOCK EQU 4Ah ; DOS: zmiana wielk. pamięci programu
SET_VECTOR EQU 25h ; DOS: zmiana wektora przerwania
TERMINATE EQU 4Ch ; DOS: powrót do systemu operacyjnego
WRITE EQU 40h ; DOS: wyprow. do zbioru lub urządz.
; KOD ****************************************************************
ORG 100h
INVOKE_MOD:
MOV SP, OFFSET STACK_END ; przesunięcie stosu z końca
; segmentu na koniec programu
MOV AX, CS ; wpisanie adresu segmentowego
MOV PARAMETER[4], AX ; w odpowiednie miejsca bloku
MOV PARAMETER[8], AX ; parametrów dla funkcji 4Bh
MOV PARAMETER[12], AX
MOV BX, OFFSET STACK_END
MOV CX, 4 ; obliczenie liczby kompletnych
SHR BX, CL ; 16-najtowych bloków w programie
INC BX ; wzgl. ostatn niepełnego bloku
MOV AH, SET_BLOCK ; DOS: zmiana rezerwacji w pamię.
INT DOS
JNC OUTPUT_MENU ; jeśli błąd, to go obsłuż
JMP ERROR
OUTPUT_MENU:
MOV AH, SET_VECTOR ; DOS: zał. wektora obsł. przerw
MOV AL, CTRL_C_INT
MOV DX, OFFSET CTRL_C_SERVICE ; zał. nowego adr. wektorowego
INT DOS
MOV AH, WRITE ; DOS: wyprow. ciągu zn. na kons.
MOV BX, CONSOL_OUTPUT ; standard. kanał wypr. na kons.
INT DOS
JC ERROR
FLUSH_AGAIN:
MOV AH,FLUSH_BUFFER ; zerow. bufora wprowadz. z kons.
MOV AL, FFh ; i nic więcej
INT DOS
CMP AL, 0
JNZ FLUSH_AGAIN ; prób. znowu gdy buf. nie pusty
WAIT_LOOP:
MOV AH, CHECK_KEY ; DOS: czekaj na wciś. dow. klaw.
INT DOS
CMP AL, 0 ; czy wciśnięto znak?
JZ WAIT_LOOP ; jeśli nie, to pętla oczek.
RET
WAIT ENDP
; Poniższa procedura jest wykonywana po wciśnięciu CTRL_C; ustawia ona
; wskaźnik stosu na wartość, jaką posiadał po zainicjowaniu programu i
; wymusza skok do etykiety OUTPUT_MENUCTRL_C_SERVICE
MOV SP, OFFSET STACK_END
JMP OUTPUT_MENU
; DANE *****************************************************************
FCB1 DB 12 DUP(0) ; wymagany, lecz nieużywany FCB
FCB2 DB 12 DUP(0) ; wymagany, lecz nieużywany FCB
INPUT_BUFFER DB 128 DUP(0) ; bufor używany przez funkcję 0Ah
STORE_SP DW ? ; bufor przech. wart. wsk. stosu
; tabl. skoków do procedur odpowiadających poz. menu
JUMP_TABLE DW DIR_OUTPUT, CHECK_DISK, REBOOT
; Text menu wyświetlanego na ekranie
MENU_TEXT DB 'Masz do wyboru następujące opcje:'
DB CR,LF,LF
DB '1 Wyświetlenie aktualnego katalogu',CR,LF
DB '2 Test aktualnie wybranego dysku',CR,LF
DB '3 Zakończenie tego programu',CR,LF,LF
DB 'Twój wybór:'
MENU_END DB 0
; Deklaracje opisujące blok parametrów dla funkcji 4Bh
PARAMETER DW 0 ; 0 oznacza, że otoczenie
; (ENVIRONMENT) nie ulega zmianie
DW ?.? ; adr. (offset, segment) do ciągu
; ASCIIZ opisuj. ładowany program
DW OFFSET FCB1,? ; adres FCB1 (nieużywanego)
DW OFFSET FCB2,? ; adres FCB2 (nieużywanego)
PROGRAM DB 'C:COMMAND.COM',0 ; nazwa ładowanego programu
; Wiersze poleceń przekazywanych wywoływanemu programowi.
; Zawierają: liczbę znaków (bez CR), ciąg znaków, CR
PROG_1_COMMAND DB OFFSET PROG_2_COMMAND - $ -2,' /C DIR', CR
PROG_2_COMMAND DB OFFSET END_COMMAND - $ - 2,' /C CHKDSK/F',CR
END_COMMAND DB 0
REBOOT_ADDRESS DW 0000h,FFFFh ; wektor inicj. procesora 8086/8088
WAIT_TEXT DB CR,LF,LF,'Dalej dowolny klawisz',CR,LF
WAIT_END DB 0
; STOS ************************************************************
DB 40 DUP(?)
STACKEND:
CODE ENDS
END INVOKE MOD
MOV CX, OFFSET MENU_END - OFFSET MENU_TEXT ; dł. wypr. tekstu
MOV DX, OFFSET MENU_TEXT ; adres ciągu znaków
INT DOS
JC ERROR ; jeśli był błąd, to go obsłuż
MOV AH, FLUSH_BUFFER ; DOS: zerow bufora wyprow. kons.
MOV AL, BUFFERED_INPUT ; DOS: buf. czytanie z konsoli
MOV DX, OFFSET INPUT_BUFFER ; ustalenie adresu bufora kons.
MOV BYTE PTR INPUT_BUFFER, 2 ; odczyt 2 zn (znak wyboru + CR)
INT DOS
MOV AL, [INPUT_BUFFER+1]
XOR AH, AH
CMP AX, 1 ; Czy wprow. dokł. jeden znak ?
JNZ OUTPUT_MENU ; jeśli nie, to ponownie
MOV BL, [INPUT_BUFFER+2] ;
XOR BH, BH ;
CMP BX, '3' ; Czy wprow. znaki 1, 2 albo 3 ?
JG OUTPUT_MENU ; nie, znak o zbyt dużym kodzie
CMP BX, '1'
JL OUTPUT_MENU ; nie, znak o zbyt małym kodzie
opr. Zbigniew Pojmański.
Mikrolkan Marzec 1988r.