Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Beitrag von zatzen »

Hallo zusammen!

Ich möchte gerne eine scheinbar kleine Aufgabe lösen.

Entweder durch ein TSR oder innerhalb eines Pascal-Programms, in dem ich per "exec"
ein Programm ausführe, möchte ich letzteres z.B. per Tastendruck beenden, da es von
sich aus auf entsprechende Tasten nicht reagiert.
Nach längerer Recherche habe ich einmal gewagt, mit gefährlichem Halbwissen etwas
zu programmieren.
Aber alles was ich bisher weiss ist, dass man ein Programm mit der Funktion 4ch des Interrupts
21h beenden kann, und danach ein RETF folgen sollte, um die CPU wieder zur vorherigen
Leseposition zu bringen.
Ich hatte mir einmal ein Programm geschrieben, das Int 9 auf eine eigene Routine umlenkt,
damit ich z.B. für Spiele beliebig die Tasten abfragen konnte.
Mit meiner Unwissenheit habe ich da einfach mal, wenn der Code 57 (Leertaste) kommt,
die Assembler Befehle "mov ah, 4ch; int21h; retf" eingefügt.
Natürlich war das Ergebnis ein Absturz, auch ohne retf.
Es kann ja gar nicht funktionieren, weil zu der Laufzeit des Programms und dann
noch innerhalb der Interrupt-Routine nur irgendwelche Daten auf dem Stack
liegen, aber nicht die zum Rücksprung hinter den Punkt, wo das "Unterprogramm"
per exec ausgeführt wurde.
Ich könnte weiter probieren, vielleicht künstlich vor dem RETF Daten auf den
Stack legen die ich vorher von der Adresse geholt habe, wo das Programm weiterlaufen
soll, aber das kommt mir auch alles sehr unelegant vor, geschweige denn dass es alles
nur Mutmaßungen sind.
Wie ich kürzlich gelesen habe, ist es auch kritisch, innerhalb Interrupt Routinen
Bios-Funktionen wie die 21h zu nutzen.
Es ist mir ein Rätsel wie man das richtig anstellt und was man da alles beachten muss.
Wenn sich jemand damit auskennt wäre ich dankbar für Hilfe.
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Beitrag von wobo »

Hallo Zatzen,

ich fürchte, das ist kein scheinbar einfaches Problem, sondern ein offensichtlich schier unmögliches. DOS ist ja gerade nicht Multi-Tasking-fähig. Deswegen gibt es unter DOS ja auch keine Möglichkeit, mittels STRG-ALT-Entf ein Programm zu beenden, sondern nur die Möglichkeit, das ganze System neu zu booten.

Es ist das Konzept von DOS, das jedes Programm grundsätzlich auf jede Hardware zugreifen kann, aber dafür im Gegenzug auch zu seiner ordnungsgemäßen Beendigung selbst verpflichtet ist. Wenn es Dir also gelänge, das Programm von außen zu beenden, dann bestünde immer noch die Gefahr, dass andere Systemressourcen noch nicht freigegeben worden sind. Funktion $4C der DOS-Api (Int $21) beendet das Programm, nachdem es seinerseits alles getan hat, um seine Beendigung vorzubereiten.

Das heisst, das Programm muss vor seiner Beendigung selbst dafür sorgen, dass

- es alle seine geöffneten Dateien schließt und zuvor ggf. benötigte Daten speichert,
- es belegte Interrupts wieder freigibt,
- es die Soundausgabe bei Ausgabe via DMA-Autoinit beendet,
- es über das angeforderten Speicher (Funktionen §48-§4A der DOS-API) wieder frei gibt
- es angeforderten EMS-Speicher wieder freigibt,
- es eingeschaltete Grafikmodi wieder schließt,
etc.

All das bleibt ungeschehen, selbst wenn es dir gelänge, die Beendigung von außen herbeizuführen.

Außerdem wärst Du wohl immer noch darauf angewiesen, dass das Programm überhaupt für eine Beendigung über $4C vorgesehen ist. DOS erlaubt auch die Beendigung eines Programms über Int $20, und auch noch über Funktion $00 der DOS-APi. Du hast zwar eine hohe Wahrscheinlichkeit, dass das Programm via Funktion $4C beendet werden will, weil das von MS so empfohlen wurde und auch m.W. meistens so gemacht wurde. Sicher sein kannst Du dir aber da wohl nicht.

Ein Versuch wert sein könnte noch, sich den PSP des Tochterprogramms geben zu lassen und dann zu versuchen, das Programm mittels retf zu beenden, also

mov ah, $62
int $21
mov ax, 0
push bx
push ax
retf


Problem ist hier u.a., dass DOS nicht reentrant ist, also ein Absturz verursacht werden kann, wenn das Tochterprogramm gerade selbst die DOS-API in Anspruch nimmt. Ich glaube aber, dass es ohne enormen Aufwand (eigenen v86-Monitor?) nicht möglich sein wird.

Edit: Die Idee von Dosferatu aus dem anderen Thread - Simulierung der jeweiligen Beendigungstaste durch Eintragen in den BIOS-Puffer - gefällt mir eigentlich am Besten, da du dann ja dem Tochterprogramm die eigene Beendigung mit allem Pipapo (Dateien schließen etc.) überlässt. Setzt halt voraus, dass das Programm die Beendigung auch so zulässt, und nicht selbst Port $60 pollt (wie Dosferatu alles geschrieben hat).
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Beitrag von zatzen »

Hallo wobo!

Ersteinmal vielen Dank für Deine ausführliche Erklärung!

Die Aussichten sind also nicht so gut, aber ich kann das mit dem PSP
ja einmal versuchen.

Es ist so, dass sich das ganze in DosBox abspielen soll, und nach dem
Beenden nur noch ein "exit" folgen, also die Box geschlossen werden
soll. Demnach wäre es vielleicht egal, wenn das Programm nicht
ordnungsgemäß beendet wird und somit das System in einem
labilen Zustand zurücklässt.

Oh, ich lese gerade Deine Bearbeitung.
Ich habe das mit dem Tastaturpuffer vorher schon in Erwägung gezogen.
Letztlich dachte ich mir, es wäre vielleicht möglich, Strg+F9 zu simulieren,
was die Tastenkombinatiom ist, um DosBox mit sofortiger Wirkung zu
beenden. Ich hatte da bisher aber keinen Erfolg. Zum einen ist fraglich,
ob DosBox die Hotkeys auf Meta-Ebene, also nicht aus dem emulierten
Dos-Programm bezieht, zum anderen wird die Abfrage wohl nicht über
den Tastaturpuffer laufen, sondern über Port 60h.
Aber vielleicht geht es ja doch über den Puffer. Die Sache ist nur,
das laufende Programm interessiert sich ja erst dann für den Inhalt,
wenn es eine Abfrage tätigt.
Ich muss das einfach mal mit meinem ZSMPLAY probieren,
ich glaube das "saugt" die ganze Zeit am Tastaturpuffer...
mov ax, 13h
int 10h

while vorne_frei do vor;
wobo
DOS-Guru
Beiträge: 613
Registriert: So 17. Okt 2010, 14:40

Re: Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Beitrag von wobo »

Ich fürchte, unter Dosbox wird das ganze erst recht nicht funktionieren. Ich würde wetten, dass der Dosbox-Steuercode Strg-F9 vorher abgefangen wird, also Dosbox diesen gar nicht in den simulierten Tastaturpuffer hineinschreibt. So ist jedenfalls meine Erinnerung, dass nämlich die Steuerbefehle von Dosbox wir Strg-F9 gar nicht in den Tastaturpuffer gelangen.

Auch wenn DosBox die Steuerbefehle weiterleiten würde, würde das wohl nicht helfen. DosBox dürfte es ziemlich egal sein, was in den simulierten Tastaturpuffer gelangt, da es sich die Steuerbefehle vom jeweiligen Betriebssystem (Windows, Linux) geben lässt. Wenn Dein Programm unter Dos einen Steuerbefehl in den simulierten Tastaturpuffer schreibt, dann ist das für DosBox einfach kein echter Steuerbefehl, weil er nicht von "außen" kommt.

Hast Du mal probiert, einen Warmstart durchzuführen (Int $19)? Dann ist das Programm auch weg. Wie verhält sich Dosbox dann?
Benutzeravatar
zatzen
DOS-Guru
Beiträge: 518
Registriert: Di 17. Apr 2012, 05:10
Wohnort: bei Köln
Kontaktdaten:

Re: Programm durch TSR oder "übergeordnetes" Programm mit Interrupt-Routinen beenden

Beitrag von zatzen »

Ja, ist leider wohl so dass sich Dosbox nur von aussen kommandieren lässt, aber dass lag ja auch nahe.

Auf die Sache mit Int 19h bin ich noch gar nicht gekommen.

Habs ausprobiert: Es erscheint für ca. 1 Sekunde in dicker Schrift "Reboot requested. Exiting now."
und dann geht die Box zu. Als Notlösung schonmal nicht übel. Danke :)

Perfekt wäre, wenn's direkt zuginge. Ob man das noch rauskriegt...
mov ax, 13h
int 10h

while vorne_frei do vor;
Antworten