ABOUT Visual Basic Programmieren Programmierung Download Downloads Tips & Tricks Tipps & Tricks Know-How Praxis VB VBA Visual Basic for Applications VBS VBScript Scripting Windows ActiveX COM OLE API ComputerPC Microsoft Office Microsoft Office 97 Office 2000 Access Word Winword Excel Outlook Addins ASP Active Server Pages COMAddIns ActiveX-Controls OCX UserControl UserDocument Komponenten DLL EXE
Diese Seite wurde zuletzt aktualisiert am 13.04.2000

Diese Seite wurde zuletzt aktualisiert am 13.04.2000
Aktuell im ABOUT Visual Basic-MagazinGrundlagenwissen und TechnologienKnow How, Tipps und Tricks rund um Visual BasicActiveX-Komponenten, Controls, Klassen und mehr...AddIns für die Visual Basic-IDE und die VBA-IDEVBA-Programmierung in MS-Office und anderen AnwendungenScripting-Praxis für IE, Windows Scripting Host und das Scripting-ControlTools, Komponenten und Dienstleistungen des MarktesRessourcen für Programmierer (Bücher, Job-Börse)Dies&Das...

Themen und Stichwörter im ABOUT Visual Basic-Magazin
Code, Beispiele, Komponenten, Tools im Überblick, Shareware, Freeware
Ihre Service-Seite, Termine, Job-Börse
Melden Sie sich an, um in den vollen Genuss des ABOUT Visual Basic-Magazins zu kommen!
Informationen zum ABOUT Visual Basic-Magazin, Kontakt und Impressum

Zurück...

ActiveX-EXE entsorgen

Zurück...


Anzeige

(-hg) mailto:hg_killactivexexe@aboutvb.de

Auch bei noch so sorgfältiger Programmierung kann es doch immer wieder mal passieren, dass eine als Komponente geladene ActiveX-EXE nach dem Beenden einer Client-Anwendung nicht terminiert, sondern einfach weiterläuft. Dafür mag es eine ganze Reihe an Ursachen geben - etwa nicht entladene Forms, zirkuläre Referenzen oder einfach irreguläre Abstürze einer Client-Anwendung.

Soweit die ActiveX-EXE nicht als unsichtbarer Dienst läuft oder ihre App.Title-Eigenschaft nicht auf einen leeren String gesetzt wurde (dann taucht sie unter Windows 9x nicht in der Taskliste auf), könnten Sie solche hängenden ActiveX-EXE-Komponenten vielleicht über den Taskmanager "abschießen". Unter Windows NT/2000 mag das auch noch ohne weitere Auswirkungen auf das Gesamtsystem möglich sein. Unter Windows 9x dagegen kann das das Gesamtsystem ziemlich aus dem Tritt bringen, auch wenn es danach zunächst noch ordentlich weiter zu laufen scheint.

Bei einer im MultiUse-Modus laufenden ActiveX-EXE haben Sie nämlich noch die Chance, zunächst einen Versuch zu starten, die Komponente gewissermaßen "zur Selbstaufgabe" zu bewegen. Sie brauchen nur eine Möglichkeit, ein für diese Aufgabe ausgelegtes Objekt der Komponente zu instanzieren und es in der noch laufenden Komponente aufräumen zu lassen, was immer noch aufzuräumen geht. Da wären etwa noch geladene Forms zu entladen, oder globale Referenzen freizugeben, die von schon nicht mehr existierenden Clients angelegt wurden, und dergleichen mehr. Was im einzelnen zu tun ist, und was noch möglich und erreichbar ist, hängt natürlich von der inneren Architektur der Komponente ab. Aber es steht dem nichts im Wege, zum einen diese Architektur auf eine solche spätere Aufräummöglichkeit hin auszulegen, als auch zum anderen die dafür benötigte "Killer"-Klasse vorzusehen.

Als Beispiel habe ich einmal eine kleine, simple ActiveX-EXE-Komponente angelegt, bei der unschwer zu erkennen ist, dass sie unweigerlich auch nach dem Terminieren des letzten Clients munter weiter laufen wird. Jede einzelne Instanz ihres Application-Objekts lädt nämlich eine Form-Instanz und legt eine Referenz auf diese in einer globalen Collection ab (aus welchem Grund auch immer...).

Der Code der Application-Klasse (das geladene Form braucht hier keinerlei Code zu enthalten) und eines Standard-Moduls sehen folgendermaßen aus:

' Klasse Application
Private mCounter As Long

Public Property Get Counter() As Long
  mCounter = mCounter + 1
  Counter = mCounter
End Property

Private Sub Class_Initialize()
  Dim nFrmTest As frmTest

  Set nFrmTest = New frmTest
  RegForm nFrmTest
  Load nFrmTest
End Sub

' Standard-Modul modGlobal

Private mForms As Collection

Public Sub RegForm(Form As Form)
  If mForms Is Nothing Then
    Set mForms = New Collection
  End If
  mForms.Add Form
End Sub

Natürlich ist dieses Beispiel ein wenig fadenscheinig. Denn eine ordentliche Programmierung der Klasse enthielte in deren Terminate-Ereignis sicherlich das Gegenstück zur Ablage der Form-Referenz in der globalen Collection. Nur, wie gesagt - Pannen, die im Kern auf einen solchen Fehler zurückzuführen sind, können bei komplexeren Komponenten durchaus vorkommen. Sie sollten dann allerdings vor der Freigabe der endgültig als fertiggestellt anzusehenden Version längst eliminiert sein...

Der Test-Client für diese Komponente ist ebenfalls simpel. Er enthält ein Form mit einem Timer, in dessen Timer-Ereignis der sich bei jedem Aufruf erhöhende Wert der Eigenschaft Counter abgefragt wird. Der Client wird ganz normal beendet - und mit seinem Ende sollte auch die Instanz des Application-Objekts terminieren. Ebenso sollte auch die ganze Komponente enden, wenn sich der letzte Client verabschiedet hat.

Private mApp As Application

Private Sub Form_Load()
  Set mApp = New Application
  lbl.Caption = mApp.Counter
  tmr.Enabled = True
End Sub

Private Sub tmr_Timer()
  lbl.Caption = mApp.Counter
End Sub

Die konkrete Aufgabe für eine "Killer"-Klasse der ActiveX-EXE-Komponente bestünde nun darin, die in der globalen Forms-Collection enthaltenen Forms zu entladen und die Collection aufzulösen. Denn es könnte ja sein, dass in den Unload-Ereignissen der Forms noch einige abschließende Arbeiten zu erledigen wären, etwa irgendeinen Status in die Registrierung zu schreiben, oder einen noch geöffneten Datensatz samt noch geöffneter Datenbank ordentlich zu schließen, oder was auch immer.

Allerdings reicht auch das nicht immer aus, um die Komponente nun endgültig zur Selbstaufgabe zu bringen. In diesem seltenen Fall ist ausnahmsweise (!) einmal die Verwendung der End-Anweisung angebracht und unumgänglich. Ich kann es gar nicht oft genug betonen, dass die End-Anweisung ansonsten nichts, aber auch gar nichts in einer Anwendung zu suchen hat. Bei einer ordentlichen Programmierung und Programm-Architektur ist sie vollkommen überflüssig. Sie sollte lediglich ganz kalkuliert in Ausnahmefällen wie diesem hier mit äußerster Vorsicht eingesetzt werden, nur als allerletzter Notanker, wenn alle Möglichkeiten ausgereizt und alle möglichen Fehlerquellen ausgemerzt sind, eine Anwendung zum Terminieren zu bewegen!

Damit aufgrund des Einsatzes der End-Anweisung der Hilfs-Client, der die "Killer"-Klasse instanziert, nicht davon in Mitleidenschaft gezogen wird, instanziert und lädt die Klasse ein Hilfs-Form mit einem Timer, in dessen Timer-Ereignis die Aufräumarbeiten vorgenommen und schließlich die End-Anweisung ausgeführt werden. Bis zum Aufruf des Timer-Ereignisses ist nämlich der Aufruf des Hilfs-Clients bereits zurückgekehrt und die Arbeit des Hilfs-Clients abgeschlossen. Probieren Sie einmal, den Code zu ändern und rufen Sie die End-Anweisung anstelle der Instanzierung des Hilfs-Forms auf - der Effekt sollte Ihnen deutlich zeigen, was ich Ihnen zu vermitteln versuche.

' Klasse KillInstance

Private mFrmKillInstance As frmKillInstance

Public Sub Kill()
  Set mFrmKillInstance = New frmKillInstance
  mFrmKillInstance.tmr.Enabled = True
End Sub

' Hilfs-Form frmKillInstance

Private Sub tmr_Timer()
  ReleaseForms
  End
End Sub

' zusätzliche Aufräum-Prozedur im Standard-Modul modGlobal

Public Sub ReleaseForms()
  If Not (mForms Is Nothing) Then
    Do While mForms.Count
      Unload mForms(1)
      mForms.Remove 1
    Loop
    Set mForms = Nothing
  End If
End Sub

Der Hilfs-Client, der die Komponente zur Selbstaufgabe bewegen soll, besteht nur aus einem Standard-Modul mit einer kurzen Sub Main-Prozedur:

Public Sub Main()
  Dim nKill As KillInstance
  
  Set nKill = New KillInstance
  nKill.Kill
End Sub

Sie sehen, dass Sie mit recht geringem Aufwand noch retten können, was zu retten ist, ehe Sie zur rigiden Maßnahme eines Abschusses durch den Taskmanager greifen müssen. Dieses Verfahren hat sogar den Vorteil, dass Sie damit auch auf einfache Weise auf einem entfernten Server laufende, hängengebliebene Komponenten entsorgen können. Denn das Verfahren bedient sich ganz regulärer COM-Technik und ist vollkommen transparent in Bezug auf den Ausführungsort der Komponente. Und wenn es sein muss, können Sie auf diesem Wege auch kaskadierende Entrümpelungsaktionen anstoßen: Hat die Komponenten wiederum andere Komponenten instanziert, und sind die Referenzen auf diese für die Killer-Klasse noch greifbar, brauchen auch diese weiteren Komponenten lediglich auf ähnliche Weise aufräumbar vorbereitet zu sein...

Sie können den Code der Test-Komponente, des Test-Clients und des "Killer"-Clients einschließlich kompilierter EXE-Dateien für die Visual Basic-Versionen 5 und 6 separat herunterladen - allerdings ohne Runtime-Dateien. Starten Sie die EXE-Datei im jeweiligen Verzeichnis ActiveXExe einmal kurz, um die Komponente zu registrieren. Starten Sie dann einmal ein paar Instanzen des Clients und beenden diese wieder in willkürlicher Reihenfolge. Sie sollten dann im Taskmanager auch nach dem Beenden des letzten Clients immer noch die Komponente sehen können. Starten Sie nun einmal den Killer-Client - und das Problem sollte sich wie vorgesehen erledigt haben.


Code und Beispiel-Projekte (VB 5 - ohne Runtime!) (killactivexexe5.zip - ca. 18 KB)
Code und Beispiel-Projekte (VB 6 - ohne Runtime!) (killactivexexe6.zip - ca. 17 KB)


Artikel
Zum Download-Bereich dieses Artikel
Mail an den Autor dieses Artikels

KnowHow
Zur KnowHow-Übersicht

KnowHow-Themen
Themen - Allgemeines
Themen - Entwicklungsumgebung (VB-IDE)
Themen - Forms
Themen - Steuerelemente (Controls)
Themen - Grafik
Themen - Dateien
Themen - UserControls
Themen - Einsteiger-Tipps
Themen - Wussten Sie...?

Übersicht nach Titeln in alphabetischer Reihenfolge
Übersicht nach Erscheinungsdatum

Schnellsuche



Zum Seitenanfang

Copyright © 1999 - 2017 Harald M. Genauck, ip-pro gmbh  /  Impressum

Zum Seitenanfang

Zurück...

Zurück...

Download Internet Explorer