Newsgroup: it.comp.lang.visual-basic
Titolo: Classi, Eventi e sincronismo

Ho una perplessità riguardo il flusso effettivo delle operazioni in caso di
oggetti con eventi.
Scenario:
Ho una applicazione che istanzia un oggetto, definito tramite un modulo di
classe:
Private WithEvents myPippo as clsPippo
e la classe pippo ha un metodo, una proprietà ed un evento
Public myProperty as String
Public Event ChangePropertyValue()
Public Sub myMethod
  myProperty = "old"
  RaiseEvent ChangePropertyValue
  Debug.Print myProperty
End Sub
L'applicazione chiama il metodo e quando intercetta l'evento modifica la
porprietà:
Private Sub Test
  Set myPippo = New clsPippo
  myPippo.myMethod
End Sub
Private Sub myPippo_ChangePropertyValue()
  myPippo.myProperty = "new"
End Sub
Quello che mi chiedo è:
Il metodo scatena l'evento e poi stampa la proprietà, che viene modificata
dalla routine di gestione dell'evento.
Quando viene elaborata la routine dell'evento? Per quanto ho potuto
appurare, l'evento è gestito immediatamente, però quello che sapevo è che il
meccanismo è gestito a livello di messaggi di sistema, per cui potrebbe
darsi che il messaggio di evento viene accodato o non trattato subito e
potrebbe capitare nel mio esempio di stampare il vecchio valore della
proprietà.
vostri pareri?
Silv:o)

 Quando viene elaborata la routine dell'evento?
La routine dell'evento entra nella coda degli eventi e viene elaborata in
baso alle priorità dei diversi task, in ordine di ingresso nella coda FIFO.
Però non ti devi preoccupare che nel frattempo il tuo programma dia i
numeri. Siccome l'evento l'hai scatenato tu, il codice si ferma fino a che
il SO non processa l'evento stesso. Un po' come se chiamassi una semplice
SUB.
Il problema ce lo potresti avere se si trattasse di 3 task diversi (due che
scrivano e leggano la proprietà, e il terzo che sia il gestore della
proprietà stessa), ma siccome si svolge tutto all'interno dello stesso task,
vai tranquillo.
Ciao
*Roby*

 se chiamassi una semplice SUB.
Grazie per la delucidazione.
Ho provato a verificare il meccanismo su una dll ActiveX, sia normale che
Exe (che gira su un thread a parte).
Con mia sorpresa il RaiseEvent si è rivelato bloccante, alla stregua di una
normale SUB!
Io credevo che RaiseEvent generasse una chiamata interna ad una
SendMessage/PostMessage, e poi restituisse il controllo. Invece mi accorgo
che anche se l'evento è generato da un'ActiveX exe, il codice che segue il
RaiseEvent viene eseguito solo AL termine del lavoro eseguito dalla routine
di gestione dell'evento dell'applicazione che istanzia la dll.
E io che l'ho sempre considerato un meccanismo sostanzialmente asincrono!
Allora per avere un reale programma asincrono bisogna usare trucchi tipo
l'utilizzo di un Timer (o Api SetTimer)?!
cioè: l'applicazione che riceve l'evento nella routine di gestione
dell'evento fa partire un timer con intervallo minimo e restituisce il
controllo, così che la dll può continuare il suo lavoro.
Supponiamo che la dll debba processare migliaia di dati, e che ogni cento
dati scateni un evento per notificare i progressi fatti. L'applicazione
chiamante allora visualizza il blocco di dati elaborati, e per far questo ci
mette un po' di tempo, durante il quale vorremmo che la dll continuasse il
lavoro in background, non che aspettasse la visualizzazione dei dati già
processati!
Che soluzione suggerireste per questa esigenza?
La mia soluzione è quello che ho dscritto:
ActiveX Exe per il lavoro in backgrund e Timer per restituire immediatamente
il controllo nella routine di gestione dell'evento di notifica.
Ciao, Silv:o)

 l'utilizzo di un Timer (o Api SetTimer)?!
Mhmmm, si, ma il Timer deve stare sull'ActiveX Exe chiamato, altrimenti se
sta sul chiamante è ugualmente bloccante (se era quello che dicevi anche tu
scusa, ma preferisco esagerare con le spiegazioni che essere poco chiaro).
Poniamo che tu chiami dal timer l'evento dell'ActiveX, il codice del timer
resta bloccato fino a che non è finita l'elaborazione dell'ActiveX stesso, e
siccome il timer è stato chiamato da un evento interno alla tua procedura,
anche quella è tragicamente piantata.
Invece dovrebbe essere l'ActiveX Exe che riceve la chiamata dell'evento,
setta il timer che effettuerà l'elaborazione, e ritorna. In questo modo il
chiamante si libera, e il chiamato lavora all'interno del timer (nel quale
si dovrànno gestire i possibili errori dati da eventuali rientranze per
chiamate successive, ovviamente). Il chiamato potrà a sua volta di tanto in
tanto richiamare un metodo del chiamante per informarlo dell'avanzamento.
Anche questo sarà bloccante, ma immagino che i tempi di blocco siano
ininfluenti, dato che il chiamante deve solo mostrare una barra di
avanzamento o roba simile.
Non so se c'è un modo migliore. Probabilmente è possibile evitare di usare
COM e gestire tutto tramite delle semplici SendMessage in broadcast. E' il
sistema che si usava una volta, ma è poco elegante perchè rischi che il tuo
codice di  messaggio venga usato anche da altri.
Ciao
*Roby*

l'utilizzo di un Timer (o Api SetTimer)?!
Temo di si', oppure puoi provare con una PostMessage che manda messaggi
personalizzati.
-- 
ciao, hal


 codice di  messaggio venga usato anche da altri.
Già. Forse il meccanismo del SendMessage/PostMessage è il più semplice, me
lo devo studiare un po' meglio.
...comunque più entro nel dettaglio più vedo i limiti di VB, che l'utilizzo
dell API risolve solo in parte.
E come al solito bisogne studiare e studiare per utilizzarlo al meglio, e
tocca pure subirsi l'ironia degli stolti che quando gli dici che lavori in
VB dicono "ah... VB ...carino, si fanno delle belle interfacce in due
minuti"
--
Ciao, Silv:o