Newsgroup: it.comp.lang.visual-basic
Titolo: [?] Ancora subclassing

Ho creato un controllo che effettua il subclassing dei messaggi di win, ma
con la SetWindowLong() posso legarmi solo ad un oggetto alla volta.
E' possibile intercettare _TUTTI_ i messaggi dell'applicazione?
Devo installare un hook con WH_CALLWNDPROC anzichč usare la SetWindowLong()?
E poi come accidenti funziona l'hook WH_CALLWNDPROC?
Ciao e grazie.

Gli hook funzionano bene in VB, ma chiaramente è una pizza quando sei in
debug, ma con qualche #if ci se la cava.
----------------------------------------------------------------------
Stefano Minardi
Zetesis: 
zet...@mclink.it
----------------------------------------------------------------------

debug, ma con qualche #if ci se la cava.
E' proprio per questo che mi sto facendo un ocx: per poter debuggare con
facilità senza rischiare continui crash.
Ciao

...

Provato, ma sembra che la WH_CALLWNDPROC non regga molto (va in crash
sistematicamente all'uscita della mia funz. callback).
Inoltre mi sembra che SDK si contraddica, ma forse non capisco bene:
CallWndProc() <che č la MIA funz. di callback>
nCode
Specifies whether the hook procedure must process the message. If nCode is
HC_ACTION, the hook procedure must process the message. If nCode is less
than zero, the hook procedure must pass the message to the CallNextHookEx
function without further processing and should return the value returned by
CallNextHookEx.
credo si traduca cosě:
if nCode >= 0 then
    [... process the message ...]
else
    CallNextHookEx(...)
end if
Ma passa sempre dall'else e poi va in crash... boh
Ciao

Ho paura che troverai delle difficoltà. Mentre fare un ocx per il
subclassamento è facile e sensato - è orientato ad un hwnd, quindi l'ocx è
indipendente dall'ospite - un hook ti intercetta tutti gli eventi del
thread, quindi anche quelli dell'ocx. Ne risulta che hai le stesse
difficoltà (o quasi) sia che tu scriva un ocx sia che tu implementi l'hook
direttamente nel codice (l'ocx gira nel thread dell'ospite).


Se ho capito quello che vuoi fare, forse dovresti chiamare SetWindowsHookEx
non con WH_CALLWNDPROC ma con WH_GETMESSAGE. In questo modo infatti
intercetti tutti i messaggi diretti alle window di un thread (WH_CALLWNDPROC
è un caso particolare e riguarda solo i messaggi spediti via SendMessage).
In questo caso, nella tua callback avresti:
if nCode = HC_ACTION then    'dove HC_ACTION=0
    [... process the message ...]
else
    GetMsgProc=CallNextHookEx(...)
end if
"[... process the message ...]" dovrebbe poi copiare in una struttura MSG la
struttura puntata da lParam. In questo modo ottieni varie informazioni, fra
le quali l'handle della window cui è diretto il messaggio e il codice del
messaggio stesso. A questo punto dipende da cosa vuoi farne: il messaggio
può essere semplicemente segnalato (quindi chiami
GetMsgProc=CallNextHookEx(...) senza colpo ferire - anche in questo caso),
'mangiato' ovvero  modificato, rediretto ad un'altra window (
p.es
. per
implementare un KeyPreview che funzioni sul serio - in questo caso può
essere necessario intervenire sul messaggio con
TranslateMessage/DispatchMessage).
Ricordati comunque che la tua funzione di callback (GetMsgProc o CallWndProc
che sia) deve ritornare il ritorno di CallNextHookEx, che non devi
modificare nCode, lParam o wParam, che la tua callback ritorna
esplicitamente 0 solo nel caso in cui la tua callbackabbia processato il
messaggio nel modo appropriato.

...

Wow!
Così sì che funziona perfettamente! Grazie.
Ma perchè dici che la KeyPreview standard non funziona?
Fammi provare con il mio sistema...
Ciao

> Ma perchè dici che la KeyPreview standard non funziona?
Alcuni oggetti intercettano i messaggi prima della form.


Aspè, aspè, fatemi capire... come funziona la storia degli OCX e dei loro
thread? Io credevo si trattasse di thread quasi completamente separati


Un OCX č un ActiveX in-process, quindi gira nel thread di chi lo utilizza
(infatti se dichiari una globale in un OCX o in qualsiasi dll in-process,
questa č vista, oltre che dal programma ospite, anche da tutte le istanze
che questo crea dell'OCX).
Dimostrazione: quando il codice di un OCX (scritto in VB) č in esecuzione,
si ha il fenomeno del blocco del thread - non puoi eseguire due sezioni di
codice VB nello stesso processo contemporaneamente. Se fossero thread
separati - 
p.es
. un programma e una o piů copie di un ActiveX Exe
(out-of-process) questo non accadrebbe.
(Ovviamente la sospirata versione 7 sembra consentire la creazione di thread
da VB.)


Ok, colgo l'occasione per fare qualche domanda in piů sui thread, in particolare
sul multithreading in VB. Al momento attuale (sul mio computer, versione 5 di VB
Enterprise) che risultati si possono ottenere con il multithreading? Io al
massimo ho crashato due o tre volte l'IDE e poco piů

Io mi accontentavo anche solo di chiamare funzioni API in asincrono, non
pretendo poi molto... o forse sě? Illuminatemi!

 wrote in message
papG4.72799$pn3.8...@news.infostrada.it...


 sincrone).
Devo semplicemente chiamare una Void (si chiamano cosě le Sub in C, vero?) che
altro non fa che emettere un beep dall'altoparlante interno. La funzione non
ritorna un valore, non fa niente che giustifichi un'esecuzione "modale" ("finchč
non ho finito io tu non ti muovi")... forse sarebbe meglio se fosse la DLL ad
essere multithread, piuttosto che il mio povero programma

 essere multithread, piuttosto che il mio povero programma
Non mi è chiara una cosa: la funzione non mi pare bloccante - svolge un
compito per il quale bastano sì e no 5 istruzioni assembler - quindi non
capisco perché non chiamarla sincronicamente.
Normalmente si ha la necessità di fare chiamate asincrone quando il compito
è (verosimilmente) molto lungo e nel frattempo si vuole fare altro -
tipicamente consentire all'utente di fare qualcos'altro. In questi casi si
chiama una funzione specifica che ritorna immediatamente ma che innesca un
meccanismo di esecuzione in background che dev'essere interrogato
periodicamente ed eventualmente interrotto. Nel tuo caso, invece, il compito
è breve e la funzione - immagino - non prevede il rilascio immediato proprio
per questo. Diversamente dovrebbe essere la funzione ad essere strutturata
in questo modo - cioè: dovrebbe creare un thread e tornare immediatamente e
il thread dovrebbe essere interrogabile tramite una funzione apposita e/o
eseguire delle callback al chiamante, infine dovrebbe avere una funzione
apposita per la chiusura anticipata del thread. Quindi dovrebbe essere la
dll responsabile della creazione di un thread che giri parallelamente a
quello che l'ha generata (cioè il tuo in VB).
Se devi realizzare una cosa del genere *in* VB (cioè non chiamare una
funzione così *da* VB, che sarebbe normale (questo si fa normalmente con i
db) ma scrivere la dll in VB) allora sono amari, perché se fai una dll che
gira in-process, appena torni al chiamente addio codice della dll - a meno
che tu non usi qualche controllo che continua a lavorare, come 
p.es
. un
timer. Alternativamente potresti creare un ActiveX-Exe che torna
immediatamente al chiamante, ma che continua a far girare il proprio codice
perché è in un thread diverso. (Ma non mi pare che questo sia il tuo caso.)
Se invece hai un problema come questo: il programma chiama questa funzione n
volte e tutte le esecuzioni devono avvenire in multithreading, allora non
puoi farlo in un unico prg VB se la dll non ti rilascia subito il
controllo - cioè se non crea un thread in proprio. Puoi ottenere questo solo
facendo un ActiveX-Exe e creandone n istanze (pesantissimo) dal tuo prg:
ciascuna istanza esegue la chiamata alla dll ma siccome la chiamata è
sincrona devi farlo in questo modo:
(a) il tuo prg crea un'istanza dell'ActiveX
(b) l'ActiveX ha una funzione Beep che fa quanto segue:
    (b1) imposta un timer a intervallo minimo (o qualsiasi altro oggetto) in
grado di scatenare un evento asincrono
    (b2) torna al chiamante immediatamente
    (b3) al momento dell'evento esegue la chiamata alla dll
(c) il tuo prg crea un'istanza dell'ActiveX
[...] etc.
(e ovviamente devi distruggere tutte le istanze!)
Gli eventi (b3) e (c)-ss. non sono sincroni.
(Spero di averci dato almeno in qualcosa)
