Newsgroup: it.comp.lang.visual-basic
Titolo: Intercettare la richiesta di download in IE da VB

come da oggetto
Marco Trapanese

 Marco Trapanese

 ha scritto nel messaggio
news:8d8c8b$2ar$1...@news.mclink.it...


 ha scritto nel messaggio
news:8d9oqo$qe8$1...@nslave2.tin.it...


 wrote in message


Beh, si potrebbe anche fare in un modo assurdamente complicato (a me piacciono
le soluzioni assurdamente complicate :), trasformando, con un Winsock, il
proprio programma VB in un proxy server, che filtra le richieste del browser e
ne decide l'esito









 browser Internet Explorer
(ah, per l'applicazione nascosta un paio di suggerimenti: una finestra è
indispensabile, la puoi creare a runtime con CreateWindowEx, però poi devi
mandare in loop il tuo programma, ma senza bloccarlo [usa DoEvents]. Se ti
servono dettagli più precisi o un aiuto su questo punto, dimmelo pure)

 ha scritto nel messaggio
news:AX_K4.158416$pn3.1...@news.infostrada.it...


Ritiro quello che ho detto. Pannello di controllo/Opzioni
Internet/Sicurezza/Internet/Download/Download di file/Disabilita. Piů facile di
cosě!


COME CREARE UN PROGRAMMA VB
COMPOSTO DA UN SOLO MODULO DI CODICE
Innanzitutto raccogliamo il materiale necessario. Lavoreremo parecchio con le
API, ecco quelle che useremo (ometto le Declare - usate il Visualizzatore API):
CreateWindowEx()
[ in un sistema operativo chiamato Windows, l'avrete capito, le finestre sono
essenziali. Mai più senza ]
ShowWindow()
[ le finestre create con l'API precedente sono restie a mostrarsi. Questa
funzione serve a convincerle ]
DefWindowProc()
CallWindowProc()
[ come le gestisce Windows, le finestre, non le gestisce nessun altro... ]
SetWindowLong()
[ ...ma per certe cose dovremo cavarcela da soli ]
RegisterClass()
UnregisterClass()
[ creiamoci la nostra classe personale di finestre ]
PostQuitMessage()
[ altro che End, gente... ]
Indispensabile infine il Type WNDCLASS. Gradite le Const WS_, WS_EX_ e WM_
Ora che abbiamo le Declare che ci servivano, pensiamo a mettere giù un po' di
codice.
Sub Main()
End Sub
[ questa è indispensabile ]
Function WinProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
End Function
[ ecco un esempio di callback. Windows, come vedremo, chiamerà questa funzione
ad ogni evento avvenga sulla finestra che creeremo. La chiamata alla funzione
DefWindowProc rimette il controllo della situazione in mano alle librerie di
Windows. Ad esempio, se il sistema deve ridisegnare la finestra, noi non ci
sporcheremo le mani con un compito così basso e servile, ma lo delegheremo a
Windows ]
Sub Main()
Dim myclass as WNDCLASS
With myclass
.lpfwndproc = Dummy(AddressOf WinProc)
.hInstance = App.hInstance
.lpszClassName = "myclass"
End With
End Sub
Cosa ho fatto? Sto cercando di creare una nuova classe di finestre chiamata
"myclass", e assegno ad una struttura WNDCLASS gli attributi più importanti
della nostra classe: il nome, indispensabile e obbligatoriamente unico, l'handle
dell'istanza dell'applicazione e l'handle della nostra callback, ottenuto
tramite l'operatore AddressOf ed una funzione Dummy, che altro non è se non:
Function Dummy (d As Long) As Long
Dummy = d
End Function
che è un piccolo trucco per salvare un puntatore ricavato con AddressOf in una
variabile
Vediamo se il sistema operativo è pronto ad accogliere la nostra finestra.
retval = RegisterClass(myclass)
Se retval è uguale a 0 al sistema la nostra classe di finestre decisamente non
piace. Non ci resta che arrenderci.
If retval = 0 Then
    End
End If
Proviamo a cambiare nome alla classe, magari usando un nome che nessun serio
programmatore oserebbe usare, del tipo "The Super Duper Window Class". Comunque,
in genere "myclass" va benissimo.
Se il sistema ha gradito, allora procediamo
If retval = 0 Then
    End
Else
    hwnd1 = CreateWindowEx(0, "myclass", "My window", WS_OVERLAPPEDWINDOW _
    , 100, 100, 200, 150, 0, 0, App.hInstance, 0)
End If
Se non funziona, hwnd1 sarà uguale a 0, quindi togliamo il disturbo e
un-registriamo la classe che abbiamo registrato. Se funziona, hwnd1 conterrà
l'handle della finestra creata, quindi, se serve, la mostriamo (nell'IDE
mostratela sempre, o saremo costretti ad usare il pulsante Stop, e il crash sarà
assicurato)
(non vi sto a spiegare tutti gli argomenti di CreateWindowEx, ci sono delle
guide per questo che lo fanno pure meglio di me)
If retval = 0 Then
    End
Else
    hwnd1 = CreateWindowEx(...)
    If hwnd1 = 0 Then
        UnregisterClass "myclass", App.hInstance
        End
    Else
        ShowWindow hwnd1, 1
    End If
End If
Bene. Per ottenere la residenza in memoria, facciamo semplicemente:
Do
DoEvents 'se non ci fosse bisognerebbe inventarlo
If dead Then Exit Do
'dead è una variabile Boolean da definire nelle dichiarazioni del modulo
Loop
--
Function WinProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Select Case uMsg
    Case WM_DESTROY
        'notifichiamo la distruzione della finestra alla Sub Main
        dead = true
        'Lasciamo che Windows distrugga la finestra
        WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
    Case Else
        'In tutti gli altri casi lasciamo che se ne occupi Windows
        WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
End Select
End Function
Questo significa che quando la finestra viene chiusa, il programma esce dal
Loop, dopodichè:
Do
DoEvents 'se non ci fosse bisognerebbe inventarlo
If dead Then Exit Do
'dead è una variabile Boolean da definire nelle dichiarazioni del modulo
Loop
'De-registriamo la nostra classe
UnregisterClass "myclass", App.hInstance
'Il thread chiede al sistema di ucciderlo e ritornare 0 come valore
PostQuitMessage 0
--
Questo programma ha una sola finestra, nuda. L'ideale se vi serve semplicemente
intercettare messaggi o monitorare il sistema. Se vi serve aggiungere pulsanti o
controlli di sorta, basta chiederlo e continuerò questo "tutorial"

 controlli di sorta, basta chiederlo e continuerò questo "tutorial".
Evvaiii!...
Continua, ti prego: fossero anche tutte balle... e' cosi' piacevole da
leggere! :)))
--
Ciao.
Maurizio


[...]

 API, ecco quelle che useremo (ometto le Declare - usate il Visualizzatore API):
Hyperion, se non ci fossi bisognerebbe inventarti.
Con quale consumata perizia vai overlappando qua e là.
Gentile e leggiadro, come le API sui fiori.
Il brano scorre leggero leggero.
Quali ricordi evoca, poi.
Mi sovviene, anni fa:
la mia prima finestra tra le "finestre" !
(e poi crash - sigh)
Grazie.
Ho fatto bene a trascinarmi dietro il portatile.
La Pasqua sarà migliore.

 essenziali. Mai più senza ]
MI-TI-CO !
Keep Message. Non tanto (beh, non solo) per l'argomento, quanto per lo stile.
Buona Pasqua, G.

A GRANDE RICHIESTA CONTINUA
IL TUTORIAL SUL SUBCLASSING
(NOTA: il subclassing, checchè se ne dica, è facilissimo)
 - piatto del giorno: messagebox alla pressione di un pulsante -
Bene, le Declare sono tutte quelle dell'ultima volta. Ne aggiungiamo giusto due
o tre perchè stavolta faremo qualcosa di più.
LoadLibrary()
[ da maneggiare con molta cautela, ma da' grandi soddisfazioni se domata ]
FreeLibrary()
[ perchè dobbiamo lasciare la stanza nelle stesse condizioni in cui era ]
CallWindowProc()
[ chiama una funzione di cui è noto il puntatore, quindi dinamite pura per il
VB. Preparatevi a salvare spesso, e resettare ancora di più ]
Le Const sono le stesse della lezione scorsa, a cui si aggiunge la GWL_WNDPROC.
SetWindowLong() ve l'avevo fatta mettere l'ultima volta, e non l'avevamo usata.
Stavolta ci sarà indispensabile, perchè lavoreremo con giocattoli non nostri, e
in qualche modo ce ne dovremo impossessare.
Vi direi anche di aggiungere la Sub InitCommonControls(), perchè faremmo
veramente scintille (in pratica vi insegnerei come fare a meno di molti OCX), ma
purtroppo il database del mio API Viewer è obsoletuccio, e questa mi manca.
Inoltre aggiungete queste Const, che nei testi non si trovano ma che se dovete
creare finestre molto complesse, contenenti decine e decine di controlli
alleggeriranno molto il carico del compilatore:
Const WC_BUTTON = "BUTTON"
Const WC_COMBOBOX = "COMBOBOX"
Const WC_EDIT = "EDIT"
Const WC_LISTBOX = "LISTBOX"
Const WC_MDICLIENT = "MDICLIENT"
Const WC_SCROLLBAR = "SCROLLBAR"
Const WC_STATIC = "STATIC"
Questo modo di programmare vi costringe ad una precisa visione d'insieme, ossia
un'attenta pianificazione a tavolino dell'aspetto e del comportamento del vostro
programma. Come forse già sapete, la struttura del linguaggio e le limitazioni
intrinseche non ci permetteranno di creare funzioni o thread (questo poi, mai e
poi mai) a runtime, al massimo potrete farvi un bel modulo di classe per
semplificare alcune operazioni, ma del resto è proprio così che funzionano i
_veri_ ActiveX (almeno dovrebbero).
Il nostro primo obiettivo non sarà comunque molto ambizioso: ci limiteremo ad
aggiungere un pulsante alla nostra finestra, e a mostrare un messaggio quando
questo verrà cliccato.
Nella sezione Dichiarazioni aggiungerei:
Dim hwnd2 As Long
Dim proc2 As Long
Dim old_proc2 As Long
(d'ora in poi, se vedete un 2 in fondo ad una variabile, significa che è
riferita al pulsante - che ancora non abbiamo creato)
Modificate la WinProc in questo modo:
Function WinProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Select Case hwnd
Case hwnd1
    Select Case uMsg
        Case WM_DESTROY
            'notifichiamo la distruzione della finestra alla Sub Main
            dead = true
            'Lasciamo che Windows distrugga la finestra
            WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
        Case Else
            'In tutti gli altri casi lasciamo che se ne occupi Windows
            WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
    End Select
Case hwnd2
        Select Case uMsg
            Case Else
                WinProc = CallWindowProc(old_proc2, hwnd2, uMsg, wParam, lParam)
End Select
End Function
In pratica la nostra WinProc è così versatile (generica) che con i giusti
accorgimenti può andar bene per tutte le finestre del nostro thread. Gli
accorgimenti altro non sono che una distinzione dell'handle della finestra,
ossia una distinzione della finestra (gli handle sono univoci), e una chiamata
alle funzioni standard delle finestre, giusto per non doverci riscrivere tutte
le librerie.
Avrete notato una cosa, se avete prestato particolare attenzione al codice. E
cioè che CallWindowProc() ha un parametro in più di DefWindowProc(). Posso
spiegare tutto, lo giuro. Ma per ora cerchiamo almeno di mostrare il pulsante.
La Sub Main va modificata, innanzitutto:
If retval = 0 Then
    End
Else
    hwnd1 = CreateWindowEx(...)
    If hwnd1 = 0 Then
        UnregisterClass "myclass", App.hInstance
        End
    Else
        ShowWindow hwnd1, 1
        hwnd2 = CreateWindowEx(0, WC_BUTTON, "Click me!", WS_VISIBLE, _
        10, 10, 200, 200, hwnd1, 0, App.hInstance, ByVal 0&)
    End If
End If
Qui sto cercando di creare un pulsante. L'ho definito "figlio" della finestra
creata in precedenza, almeno spero - ricontrollate il codice, magari, perchè
sono sicuro di essermi lasciato dietro almeno un parametro.
(NOTA: WS_VISIBLE è un trucco per evitare di dover usare ShowWindow())
Se avviate il codice così com'è... beh, vi aspetta una piccola sorpresa, diciamo
un piccolo scherzo che ho voluto farvi perchè ha un effetto davvero curioso e
molto divertente (provatelo). Se vogliamo fare le cose sul serio, facciamo così,
piuttosto:
...
hwnd2 = CreateWindowEx(0, WC_BUTTON, "Click me!", _
WS_VISIBLE Or WS_CHILD, 10, 10, 200, 200, hwnd1, _
0, App.hInstance, ByVal 0&)
...
Oooh, il pulsante adesso è lì dove dovrebbero stare tutti gli onesti pulsanti di
questo mondo, perfetto. Diamogli un po' di vita, adesso. Impadroniamocene.
hwnd2 = CreateWindowEx(...)
proc2 = Dummy(AddressOf WinProc)
old_proc2 = SetWindowLong(hwnd2, GWL_WNDPROC, proc2)
Ok! Ora il pulsante è in mano nostra. Tutti i messaggi diretti al pulsante
arriveranno alla nostra callback. Ma noi non ci accontentiamo di gioire, noi ne
approfittiamo per conseguire il nostro scopo:
Function WinProc(ByVal hwnd As Long, _
ByVal uMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Select Case hwnd
Case hwnd1
    Select Case uMsg
        Case WM_DESTROY
            'notifichiamo la distruzione della finestra alla Sub Main
            dead = true
            'Lasciamo che Windows distrugga la finestra
            WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
        Case Else
            'In tutti gli altri casi lasciamo che se ne occupi Windows
            WinProc = DefWindowProc(hwnd, uMsg, wParam, lParam)
    End Select
Case hwnd2
        Select Case uMsg
            Case 533
                MsgBox "Il pulsante è stato cliccato!!!"
                WinProc = CallWindowProc(old_proc2, hwnd2, uMsg, wParam, lParam)
            Case Else
                WinProc = CallWindowProc(old_proc2, hwnd2, uMsg, wParam, lParam)
End Select
End Function
Provate pure, dovrebbe funzionare alla perfezione. Il parametro extra di
CallWindowProc() è il puntatore alla funzione originale. Nel caso di una
finestra generica, DefWindowProc() va più che bene. Ma per una finestra già
discretamente evoluta, come un Button, dobbiamo fare uso di una funzione più
specifica.
E LoadLibrary()? Anche stavolta vi ho fatto mettere una funzione inutile?
Giammai. Se anzichè quello che abbiamo fatto, avessimo fatto questo:
(dichiarazioni)
Dim richedlb As Long
(Sub Main)
If retval = 0 Then
    End
Else
    hwnd1 = CreateWindowEx(...)
    If hwnd1 = 0 Then
        UnregisterClass "myclass", App.hInstance
        End
    Else
        ShowWindow hwnd1, 1
        richedlb = LoadLibrary("RICHED32.DLL")
        hwnd2 = CreateWindowEx(0, "RichEdit", "Click me!", _
        WS_VISIBLE Or WS_CHILD, 10, 10, 200, 200, _
        hwnd1, 0, App.hInstance, ByVal 0&)
    End If
End If
Anzichè un misero Button abbiamo creato nientepopodimenoche una Rich Text Box!!!
Perchè la classe "RichEdit" viene registrata automaticamente dalla libreria
RICHED32.DLL, ma la libreria in questione concede i suoi servigi ad un thread
alla volta (mi ricorda qualcuno...), quindi ogni thread che intende usare una
Rich Text Box la deve caricare con LoadLibrary() (VB è strettamente
mono-threading, quindi non ci sarà mai bisogno di chiamarla più di una volta per
libreria in ogni programma).
Certo, una Rich Text Box va proprio subclassata di brutto, perchè non è un
semplice coso simil-3D che si limita ad andare su e giù quando viene cliccato
con il mouse. Però, cavolo, non male, che ve ne pare?
In ogni caso, ad ogni utilizzo della LoadLibrary dovrà corrispondere una
chiamata alla funzione FreeLibrary(). Nel nostro caso, appena prima di
PostQuitMessage(), aggiungiamo:
FreeLibrary richedlb
e così facciamo un po' di pulizia in memoria.
Se sapessi la Declare di InitCommonControls() vi insegnerei persino come fare a
meno dell'OCX dei Common Controls, pensate un po'. Magari la prossima volta.
Anzi, la prossima volta vi spiego tutti i controlli più comuni, come le caselle
di testo, le combobox, eccetera
--
In ogni caso, per maggiori dettagli, consultate la Win32 Programmers' Reference
della Borland, dove ho imparato tutto quello che so sul subclassing, e molto
altro. Il libro in questione viene distribuito gratuitamente sotto forma di un
file HLP delle dimensioni approssimative di 17 MegaByte (è davvero
dettagliatissima), e si può trovare in FTP, in circa 10-20 archivi pubblici di
università o organizzazioni senza scopo di lucro. Un tempo avevo tutti questi
indirizzi, ma tra un casino e l'altro li ho persi tutti. Ma se non sbaglio Pal
ne ha conservato almeno uno.
--
Se avete altri dubbi, chiedete pure. Sarò ben felice di arricchire questo
tutorial di nuove lezioni. Magari (azzardo) lo si potrebbe pubblicare anche sul
Sito Comune, una volta completo.
Un'idea che mi viene così su due piedi è insegnarvi come si condividono dati tra
due istanze del vostro programma usando RegisterWindowMessage() e SendMessage(),
appena imparerò a farlo io :). Alla prossima, in ogni caso. Che ho scritto
davvero tanto, e sono un po' stanco.

IL TUTORIAL SUL SUBCLASSING
[Mega Ultra Clip]
Complimenti per il lavorone!
Perché non lo "impacchetti" tutto in HTML, prepari un articoletto e lo invii al Sito Comune? Puoi
prendere spunto da quelli già presenti, sia come impostazione che come layout (sarebbe bello che
fosse in linea con quello del SC); Tra l'altro tempo fa avevo scritto un articoletto sulle
nozionistiche di base del subclassing: magari il tuo potrebbe essere la sua logica continuazione....
Ciao,
Moreno
#sirri#@
morenosoft.com
(togliete "#" dall'indirizzo)
Moreno Sirri VB Site - 
http://www.morenosoft.com/MSVBSite/
---------------------------------------------------------------------------
Le risposte alle tue domande le trovi sul Sito Comune di questo NewsGroup:
 
http://www.murialdo.it/it_lang_vb
---------------------------------------------------------------------------