|
Sie können eine ActiveX-EXE-Komponente eine eigene Aufgabe unabhängig von Ihrer eigenen Anwendung und parallel im Hintergrund ausführen lassen - in einem eigenen Thread. Damit jedoch Ihre Anwendung nach dem Aufruf dieser Komponente nicht blockiert ist und wartet, bis diese ihre Aufgabe erledigt hat, müssen Sie den Aufruf entkoppeln (ein so genannter "asynchroner" Aufruf).
In der Komponente halten Sie dazu die eventuell mit dem Start-Aufruf als Parameter übergebenen Daten fest und initiieren zunächst nur einen Mechanismus, der für eine spätere Ausführung der gewünschten Aufgabe mit den übergebenen Daten sorgt. Der Start-Aufruf wäre damit beendet, so dass der diesem Aufruf nachfolgende Code in der Client-Anwendung weiter ausgeführt wird.
Dieser besagte Mechanismus in der Komponente, der sich um die verzögerte Bearbeitung der Aufgabe kümmert, ist ein Timer-Steuerelement. Standardmäßig ist dieser Timer deaktiviert. Die Initiierung des verzögernden Mechanismus besteht nun lediglich darin, diesen Timer zu aktivieren (Enabled = True). Der Interval-Wert des Timers kann beliebig kurz sein, so dass im eigentlichen Sinne gar keine Verzögerung entsteht. Es geht nur darum, dass der Timer sein erstes Ereignis erst auslöst, nachdem die Start-Methode vollständig abgearbeitet worden ist. Wichtig ist nur, dass in diesem Start-Ereignis der Timer sofort wieder deaktiviert wird und das Timer-Ereignis nur ein einzige Mal ausgelöst wird.
Das Form, auf dem der Timer platziert ist, kann unsichtbar bleiben. Es kann aber auch angezeigt werden und beispielsweise eine Fortschrittanzeige enthalten. Von diesem Form muss für die Verbindungsklasse eine eigene Instanz angelegt werden, damit mehrere Client-Anwendungen die Komponente unabhängig voneinander verwenden können und sich nicht die Standard-Instanz des Forms zu teilen brauchen.
Sinnvollerweise sollten Sie auch für eine Abbruchmöglichkeit sorgen, damit entweder der Benutzer der Client-Anwendung die Bearbeitung der Aufgabe vorzeitig abbrechen kann, oder damit deren Bearbeitung automatisch beendet werden kann, wenn die Client-Anwendung selbst beendet wird. Dazu sehen Sie eine Abbruch-Methode in der Verbindungsklasse vor, die in dieser eine Merk-Variable (mCancel) auf True setzt. Diese Merk-Variable ist dann während der Bearbeitung der Aufgabe regelmäßig abzufragen (nicht vergessen, eine DoEvents-Anweisung dort einzufügen, damit das Setzen der Mark-Variablen durchkommt). Ist sie gesetzt, wird die Bearbeitung abgebrochen.
Weiterhin muss ein weiterer Aufruf der Start-Methode während der Bearbeitung der Aufgabe verhindert werden. Auch hierzu wird eine Merk-Variable (mBusy) verwendet und gleich zu Beginn der Start-Methode gesetzt. Beim erneuten Aufruf der Start-Methode wird geprüft, ob mBusy gesetzt ist. Ist dies der Fall, wird erst gar nicht eine erneute Bearbeitung der Aufgabe initiiert, sondern der Aufruf gleich wieder beendet.
Nach Bearbeitung der Aufgabe können Sie ein Ereignis auslösen, das sowohl die Erledigung als das Ergebnis der Bearbeitung an die Client-Anwendung zurückmelden kann.
Das Code-Grundgerüst sieht folgendermaßen aus - zunächst die Verbindungsklasse (z.B. Async.cls):
Public Event Done(Ergebnis As Variant, Cancelled As Boolean)
Private mBusy As Boolean
Private mShowForm As Boolean
Private mForm As frmAsync
Private mCancel As Boolean
Private WithEvents eActionTimer As Timer
Private mData As Variant
Public Function Action(Data As Variant, Optional ShowForm As Boolean) _
As Boolean
If mBusy Then
Action = True
Exit Function
End If
mBusy = True
mCancel = False
mShowForm = ShowForm
mData = Data
Set mForm = New frmAsync
Set eActionTimer = mForm.tmrAction
eActionTimer.Enabled = True
End Function
Public Sub Cancel()
mCancel = True
End Sub
Private Sub eActionTimer_Timer()
Dim nErgebnis As Variant
eActionTimer.Enabled = False
Set eActionTimer = Nothing
If mShowForm Then
mForm.Show
DoEvents
'... Aufgabe bearbeiten, mit Anzeige
DoEvents
'... Aufgabe bearbeiten, mit Anzeige
DoEvents
'... Aufgabe bearbeiten, mit Anzeige
Else
'... Aufgabe bearbeiten, verdeckt
DoEvents
'... Aufgabe bearbeiten, verdeckt
DoEvents
'... Aufgabe bearbeiten, verdeckt
End If
RaiseEvent Done(nrgebnis)
Unload mForm
mBusy = False
End Sub
Private Sub Class_Terminate()
If Not (eActionTimer Is Nothing) Then
eActionTimer.Enabled = False
End If
Set eActionTimer = Nothing
If Not (mForm Is Nothing) Then
Unload mForm
End If
End Sub
Und beispielsweise in der Client-Anwendung:
Private WithEvents eAction As Async
Private Sub cmdStart_Click()
If eAction.Action(10000, CBool(chkShowForm.Value)) Then
MsgBox "Aktion ist bereits aktiv!"
Else
cmdCancel.Enabled = True
End If
End Sub
Private Sub cmdCancel_Click()
eAction.Cancel
End Sub
Private Sub eAction_Done(Ergebnis As Variant, Cancelled As Boolean)
cmdCancel.Enabled = False
MsgBox "Ergebnis: " & Ergebnis
End Sub
Private Sub Form_Load()
Set eAction = New Async
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode _
As Integer)
If Not (eAction Is Nothing) Then
eAction.Cancel
End If
End Sub
|