Libreria EmiNBC - Classe NoBlockingCall
Utilizzo della classe
Vediamo come si esegue una chiamata a dei metodi in modalità di No Bloching
aiutandoci con il seguente codice autocommentato:
Option Explicit
' Se un oggetto deve utilizzare delle chiamate che ritornino il più velocemente
' possibile indipendentemente da ciò che la chiamata debba fare a monte,
' è necessario utilizzare delle chiamate non bloccanti che poi
' eseguano in background le chiamate alle funzioni effettivamente da chiamare.
' La libreria EmiNBC gestisce appunto tale problematica.
' Affichè un oggetto posso utilizzare la classe NoBlockingCall è necessario che
' l'oggetto implementi l'interfaccia INoBlockingCall che, tramite il suo metodo
'
' Private Sub INoBlockingCall_MethodCalled(ByVal NBCObj As EmiNBC.NoBlockingCall)
'
' gestisce una chiamata di callback che viene utilizzata per la chiamata della
' funzione effettiva da chiamare.
Implements INoBlockingCall
' E' poi necessario definire, a livello di modulo un oggetto di tipo NoBlockingCall.
' E' possibile gestire piu' oggetti di tale tipo ma e' conveniente generare una
' array di tali oggetti per ogni chiamata NB (No Blocking) che si desidera gestire
' BNC(0) gestirà la chiamata NB alla funzione Test1
' BNC(1) gestirà la chiamata NB alla funzione Test2
Dim BNC(0 To 1) As NoBlockingCall
' Chiamiamo la sub Test1 in modalità NB
Private Sub Command1_Click()
' Impostiamo a Nothing l'oggetto NB delegato
' a gestire la chiamata alla funzione
' Test1. Questa cosa è utile qualora avessimo
' chiamato command1_click velocemente
' (molto velocemente :) una seconda volta mentre
' la prima chiamata NB ancora
' non ha chiamato la Test1. BNC(0) infatti NON
' muore finche non ha fatto il suo dovere
' chiamando la Test1. Siamo così sicuri che,
' una volta superata questa riga, la
' precedente chiamata a BNC(0) ha compiuto
' completamente il suo lavoro, ossia ha
' già inoltrato al client la volonta di chiamare Test1
Set BNC(0) = Nothing
' Inizializzo l'oggetto di NB
Set BNC(0) = New NoBlockingCall
With BNC(0)
' Imposto la funzione da chiamare in modalità NB.
' La funzione da chiamare è "Test1"
.MethodNameToCall = "Test1"
' Associo una chiave univoca di tipo Long a questo oggetto e, guarda caso,
' scelgo l'indice dell'array a cui l'oggetto appartiene. Questo sarà
' utile nella chiamata di callback per distruggere l'oggetto
.Index = 0
' Gli associo me stesso per usufruire della chiamata di callback tramite
' l'interfaccia da me implementata INoBlockingCall
Set .Parent = Me
' Lancio il metodo in modalità NB
.CallMethod
' Esco. Qui il metodo "Test1" NON è stato ancora eseguito. E' questo il bello
' delle chiamate NB: Test1 può anche essere una chiamata che durerà un tempo molto
' lungo per essere eseguita ma intanto il flusso del programma è gia uscito
' dal metodo Command1_Click
End With
End Sub
Private Sub Command2_Click()
Dim i&
' Chiamiamo il metodo Test2 in modalità NB e, per giunta, chiamiamolo dieci volte
' di fila di modo da verificare che non ci siano problemi qualora cercassimo di
' terminare un oggetto che non ha ancora eseguito la chiamata di callback.
' In sostanza, vogliamo verificare che Test2 venga lanciato dieci volte e non
' magari una volta sola e che non ci siano buchi nella libreria che potrebbero
' causare errori di runtime
' En-passan, Test2 ha bisogno di due parametri da passare. vedremo
' così come si faccia questo.
For i& = 1 To 10
CallTest2WithNoBlockingMethod i&, "Pippo"
Next
End Sub
Private Sub CallTest2WithNoBlockingMethod(ByVal FirstArgument As Long, _
ByVal SecondArgument As String)
' Qui ora è veramente utile impostare a
' Nothing BNC(1). La seconda chiamata a questa
' funzione avviene sicuramente prima che BNC(1)
' chiamata in precedenza abbia utilizzato
' l'interfaccia di callback
' INoBlockingCall_MethodCalled(ByVal NBCObj As EmiNBC.NoBlockingCall)
' per notificarmi che è stato espresso il
' desiderio di lanciare la funzione "Test2"
' Se si commenta tale riga si ottiene o un errore
' di runtime o si esegue l'esecuzione
' di "Test2" UNA SOLA VOLTA alla decima chiamata,
' quando finalmente le acque si calmano.
' Così facendo, questa riga non ritorna finchè BNC(1)
' non ha compiuto tutto il suo lavoro.
' Come effetto si ha però che, con questa libreria di
' NB non è possibile eseguire una funzione
' più di una volta ogni 10-20 millisecondi.
' E' uno svantaggio tanto grosso ? :)
Set BNC(1) = Nothing
Set BNC(1) = New NoBlockingCall
With BNC(1)
.MethodNameToCall = "Test2"
' Aggiungiamo qui i valori da passare alla funzione Test2.
' Test2 ha bisogno di due parametri
'
' Private Sub Test2(ByVal Index As Long, ByVal Key As String)
'
' Passiamo i valori corrispondenti stando attenti a inserirli nell'ordine
' in cui vengono richiesti da Test2. Prima il primo e poi il secondo
.AddParameter FirstArgument
.AddParameter SecondArgument
.Index = 1
Set .Parent = Me
.CallMethod
End With
End Sub
Private Sub Test1()
' Viene eseguita la funzione Test1
Debug.Print "Test1 Sub Called"
End Sub
Private Sub Test2(ByVal Index As Long, ByVal Key As String)
' Viene eseguita la funzione Test2
Debug.Print "Test2 Sub Called with arg1=" & Index & " and arg2=" & Key
End Sub
Private Sub INoBlockingCall_MethodCalled(ByVal NBCObj As EmiNBC.NoBlockingCall)
' Definisco una variabile array di tipo variant
' qualora la chiamata alla funzione NB
' necessiti di parametri aggiuntivi che saranno
' stati passati in precedenza
Dim C() As Variant
With NBCObj
' A seconda del metodo da chiamare eseguo una funzione differente
Select Case .MethodNameToCall
Case "Test1"
' Se il metodo e' Test1 lo eseguo
Call Test1
Case "Test2"
' Se il metodo è Test2, che ha bisogno di due parametri, allora estraggo
' i due parametri e poi eseguo il metodo passandogli i due parametri
C = .ParametersArray
Call Test2(C(0), C(1))
End Select
' Grazie al fatto che la proprieta Index dell'oggetto NB corrisponde proprio
' all'indice dell'array a cui appartiene NBC posso distruggere semplicemente
' l'oggetto relativo a questa chiamata di callback
Set BNC(.Index) = Nothing
End With
End Sub
|