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