Home | Chi sono | Contattami
 

Progr. lineare

Delphi
 
Componenti
  Database
 
Miei articoli

Windows

Miei articoli 

 

Creare un Explorer Monitor


In questo articolo viene descritta la realizzazione di un programma per intercettare tutte le navigazioni della shell di Windows e di Internet Explorer. Delphi contiene un componente (TWebBrowser) che ci consente di avere un browser integrato all' interno delle nostre applicazioni. Tale componente è il risultato dell' importazione della type library relativa a shdocvw.dll. La prima cosa che andiamo a fare è disinstallare tale componente e successivamente importare la type library relativa a shdocvw.dll.

Apriamo Delphi, menù Component --> Install Packages , andiamo sulla voce Internet Explorer Components , click su Remove e quindi Yes : abbiamo eliminato il package che contiene i componenti Internet presenti dentro Delphi (il componente TWebBrowser tanto per intenderci). Questo perché andremo a sostituire tali componenti con le versioni che ci creeremo personalmente importando la Type Library corrispondente. Per importare la Type Library basta andare sul menù Project --> Import Type Library e selezionare la voce Microsoft Internet Controls come nella figura che segue.



 

Tuttavia voglio effettuare l’ operazione con uno strumento terzo che è più evoluto e oltretutto è correlato di codice sorgente (scritto guardacaso proprio in Delphi). Un salto all’ indirizzo

http://www.techvanguards.com

e scarichiamo il programma EventSinkImp alla pagina

http://www.techvanguards.com/products/eventsinkimp/

Ok installiamo il programma e avremo in Start --> Programs --> EventSinkImp l’ eseguibile che fa al caso nostro. Lanciamolo e selezioniamo sempre la voce Microsoft Internet Controls



 

La casella di testo Output Folder indica la cartella in cui verranno create le unit di Import della Type Library in questione: si può impostare una cartella diversa da quella di default (che è la cartella di installazione di Delphi) come nella figura sopra. Click su Import e vengono create due Unit: SHDocVw_TLB.pas e SHDocVwEvents.pas. A questo punto ci creiamo un nuovo package e vi aggiungiamo le due Unit in questione. Ora non resta altro che compilare ed installare il package. Una piccola nota: se apriamo le due Unit e guardiamo la procedura Register vediamo che i componenti vengono installati nella paletta ActiveX: se non li vogliamo installare li sopra, dobbiamo semplicemente dare il nome della paletta in cui vogliamo che vengano installati. Una volta terminata l’ installazione avremo i seguenti componenti:

TSHDocVWDWebBrowserEvents2 TSHDocVWDWebBrowserEvents TSHDocVWDShellwindowsEvents TSHDocVWDShellNameSpaceEvents TSHDocVWDsearchAssistantEvents TwebBrowser_V1

Ora apriamo un nuovo progetto e cominciamo a creare il programma: utilizzeremo 2 dei 6 componenti e più precisamente i componenti

TSHDocVWDWebBrowserEvents2 TSHDocVWDShellwindowsEvents

TSHDocVWDWebBrowserEvents2 ci consente di intercettare gli eventi a livello di singola finestra della Shell di Windows: ad esempio apro “Risorse del computer”, se entro in una delle unità di disco, tale navigazione viene rilevata. Idem per la classica navigazione con Internet Explorer. E’ importante sottolineare come Internet Explorer e le varie finestre della Shell di Windows (Risorse del Computer, Panello di controllo, etc…) siano trattate in maniera identica. Basta dare un’ occhiata agli eventi (autoesplicativi) per capire l’ utilità di questo componente: BeforeNavigate2, DownloadBegin, FileDownload, NavigateComplete2, etc..

TSHDocVWDShellwindowsEvents ci consente di intercettare gli eventi a livello di tutta la Shell di Windows; gli eventi in questione sono 2: creazione di una nuova finestra (WindowRegistered), chiusura di una finestra (WindowRevoked)

L’ interface principale è IShellWindows che, come dice il nome, ci consente di accedere alle finestre della Shell di Windows. In particolare la proprietà Count restituisce il numero di finestre della Shell aperte, mentre la proprietà Item restituisce un riferimento ad ogni finestra. Ad esempio se vogliamo enumerare le finestre della Shell con relativi indirizzi

Var ShellWin: IShellWindows; ShellWin := CoShellWindows.Create ... ... For i := 0 to ShellWin.Count - 1 do Begin With ShellWin.Item[i] as IWebBrowser2 do ShowMessage(LocationUrl); End;

Per consentire il rilevamento degli eventi di creazione e chiusura di finestre della Shell, usiamo TSHDocVWDShellwindowsEvents nel seguente modo

Var ShellWin: IShellWindows; ShellWinEvents: TSHDocVWDShellwindowsEvents; ... ... ShellWin := CoShellWindows.Create ShellWinEvents.Connect(ShellWin);

in questo modo vengono rilevati gli eventi di creazione e chiusura di una finestra che potranno essere gestiti tramite l' implementazione degli eventi WindowRegistered e WindowRevoked. Per consentire la rilevazione di eventi a livello di singola finestra della Shell di Windows, usiamo TSHDocVWDWebBrowserEvents2 nel seguente modo:

Var ShellWin: IShellWindows; WBEvents: TSHDocVWDWebBrowserEvents2; ... ... ShellWin := CoShellWindows.Create WBEvents.Connect(ShellWin.Item(2) as IWebBrowser2);

in questo modo vengono rilevati gli eventi che interessano la finestra della Shell di Windows di indice 2 che potranno essere gestiti tramite implementazione dei vari eventi di TSHDocVWDWebBrowserEvents2 tra i quali è degno di nota BeforeNavigate2. Nel nostro caso vogliamo intercettare gli eventi su tutte le finestre e non su una sola (come nell’ esempio qui sopra). Il tutto può essere raggiunto tramite la seguente procedura generalizzata per la connessione di una interface per la gestione di eventi (Sink) ad un’ altra interface dalla quale scaturiscano gli eventi (Source).

procedure InterfaceConnect(const Source: IUnknown; const IID: TIID; const Sink: IUnknown; var Connection: Longint); var CPC: IConnectionPointContainer; CP: IConnectionPoint; begin Connection := 0; if Succeeded(Source.QueryInterface(IConnectionPointContainer, CPC)) then if Succeeded(CPC.FindConnectionPoint(IID, CP)) then CP.Advise(Sink, Connection); end;

IID rappresenta il tipo della Sink interface, mentre Connection è un intero che viene restituito dalla procedura come identificativo del collegamento effettuato e quindi nel nostro caso per ogni finestra scriveremo:

InterfaceConnect(ShellWin.Item(i) as IWebbrowser2, DwebbrowserEvents2, WBevents, Connection);

dove i è una variabile compresa tra 0 e ShellWin.Count – 1: ShellWin.Item(i) as IWebbrowser2 rappresenta appunto la finestra della Shell di indice i, WBEvents è l’ interface che consente l’ intercettazione degli eventi sulla finestra (e che quindi andiamo a collegare alla finestra in questione). All’ avvio del programma (evento OnCreate della Form) dobbiamo enumerare le finestre della Shell aperte e per ognuna di esse chiamare InterfaceConnect per consentirne il monitoraggio. Stessa cosa deve essere fatta in caso di creazione di una nuova finestra (evento WindowRegistered di TSHDocVWDShellwindowsEvents). Ok ora cominciamo a scrivere il codice

type TForm1 = class(TForm) WBEvents: TSHDocVwDWebBrowserEvents2; ShellWinEvents: TSHDocVwDShellWindowsEvents; private { Private declarations } public { Public declarations } end; var Form1: TForm1;

Nell’ evento OnCreate della Form ci andiamo a collegare a tutte le finestre della Shell di Windows (incluse quelle di Internet Explorer) eventualmente già aperte e lo facciamo con il codice seguente

implementation {$R *.DFM} var ShellWin: ShDocVw_Tlb.IshellWindows; Connection: Integer; procedure InterfaceConnect(const Source: IUnknown; const IID: TIID; const Sink: IUnknown; var Connection: Longint); var CPC: IConnectionPointContainer; CP: IConnectionPoint; begin Connection := 0; if Succeeded(Source.QueryInterface(IConnectionPointContainer, CPC)) then if Succeeded(CPC.FindConnectionPoint(IID, CP)) then CP.Advise(Sink, Connection); end; procedure TForm1.FormCreate(Sender: TObject); var X: Integer; begin ShellWin := CoShellWindows.Create; ShellWinEvents.Connect(ShellWin); for x := 0 to ShellWin.Count - 1 do InterfaceConnect(ShellWin.Item(x) as IWebbrowser2, DwebbrowserEvents2, WBevents, Connection); end;

Bene ora passiamo ad intercettare le varie navigazioni: il componente WBEvents: TSHDocVwDWebBrowserEvents2 ha i seguenti eventi ed i 2 selezionati sono quelli che ci servono per intercettare le navigazioni

L' implementazione è la seguente:

procedure TForm1.WBEventsBeforeNavigate2(Sender: TObject; const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); Begin ShowMessage(URL); end;

URL è l’ indirizzo verso il quale si sta navigando: deve essere decodificato per avere la stringa che, inserita manualmente nel browser o in una finestra qualsiasi della shell di windows, ci restituisce la pagina di destinazione. Se non voglio procedere alla navigazione basta che scrivo Cancel := True. E' importante osservare che pDisp è un riferimento alla finestra in cui si è verificato l' evento: al posto del parametro URL potremmo usare (pDisp as IWebBrowser2).LocationUrl.

procedure TForm1.WBEventsDownloadBegin(Sender: TObject); begin with (ShellWin.Item(ShellWin.Count - 1) as IWebbrowser2) do begin ShowMessage(LocationUrl); end; end;

Se apriamo la unit di import SHDocVw_TLP.Pas vediamo che l’ interface IwebBrowser2 ha la seguente gerarchia di derivazione: IWebBrowser --> IWebBrowserApp --> IWebBrowser2. Tra le proprietà di IWebBrowser c’ è appunto LocationUrl che indica l’ indirizzo della pagina di cui stiamo iniziando il browsing. Inoltre l’ interface IWebBrowserApp fornisce il metodo Quit che consente l’ abort del download: quindi se non volessi consentire la navigazione verso la pagina in questione basterebbe scriver semplicemente Quit.
Passiamo ora all’ altro componente: il componente ShellWinEvents: TSHDocVwDShellWindowsEvents ha i seguenti 2 eventi e quello selezionato è quello che ci serve per rilevare l’ apertura di una nuova finestra:

L'implementazione è la seguente

procedure TForm1.ShellWinEventsWindowRegistered(Sender: TObject; lCookie: Integer); begin with (ShellWin.Item(ShellWin.Count - 1) as IWebbrowser2) do begin ShowMessage(LocationURL); end; InterfaceConnect(ShellWin.Item(ShellWin.Count - 1) as IWebbrowser2, DwebbrowserEvents2, WBevents, Connection); end;

Le considerazioni sono analoghe a quelle relative all’ evento OnDownloadBegin del componente
WBEvents: TSHDocVwDWebBrowserEvents2. Per quanto riguarda la decodifica dell’ url si può usare la seguente procedura implementata nella unit seguente che ho trovato su internet grazie a Alexander Dzyubenko

unit DzURL; { By Alexander Dzyubenko alexander@dzsoft.com http://www.dzsoft.com } interface uses SysUtils, Dialogs; function UrlEncode(const DecodedStr: String; Pluses: Boolean): String; // Encodes standard string into URL data format. // Example: http://www.dzsoft.com -> http%3A%2F%2Fwww.dzsoft.com%2F // Pluses parameter specifies whether spaces will be // encoded as '+' or as '%20' function UrlDecode(const EncodedStr: String): String; // Decodes URL data into a readable string. // Example: http%3A%2F%2Fwww.dzsoft.com%2F -> http://www.dzsoft.com function HexToInt(HexStr: String): Int64; // Taken from http://www.delphi3000.com/article.asp?id=1412 implementation function UrlEncode(const DecodedStr: String; Pluses: Boolean): String; var I: Integer; begin Result := ''; if Length(DecodedStr) > 0 then for I := 1 to Length(DecodedStr) do begin if not (DecodedStr[I] in ['0'..'9', 'a'..'z', 'A'..'Z', ' ']) then Result := Result + '%' + IntToHex(Ord(DecodedStr[I]), 2) else if not (DecodedStr[I] = ' ') then Result := Result + DecodedStr[I] else begin if not Pluses then Result := Result + '%20' else Result := Result + '+'; end; end; end; function UrlDecode(const EncodedStr: String): String; var I: Integer; begin //showmessage(encodedstr); Result := ''; if Length(EncodedStr) > 0 then begin I := 1; while I <= Length(EncodedStr) do begin if EncodedStr[I] = '%' then begin Result := Result + Chr(HexToInt(EncodedStr[I+1] + EncodedStr[I+2])); I := Succ(Succ(I)); end else if EncodedStr[I] = '+' then Result := Result + ' ' else Result := Result + EncodedStr[I]; //showmessage(Result); I := Succ(I); end; end; end; function HexToInt(HexStr: String): Int64; var RetVar : Int64; i : byte; begin HexStr := UpperCase(HexStr); if HexStr[length(HexStr)] = 'H' then Delete(HexStr,length(HexStr),1); RetVar := 0; for i := 1 to length(HexStr) do begin RetVar := RetVar shl 4; if HexStr[i] in ['0'..'9'] then RetVar := RetVar + (byte(HexStr[i]) - 48) else if HexStr[i] in ['A'..'F'] then RetVar := RetVar + (byte(HexStr[i]) - 55) else begin Retvar := 0; break; end; end; Result := RetVar; end; end.

In allegato ho inserito anche un demo che qui vediamo in azione

Come si può notare vengono rilevate sia navigazioni nella Shell sia navigazioni in Internet Explorer. Degne di nota sono le ultime 3 righe: ho aperto il "Pannello di Controllo" e poi la finestra delle "Stampanti". Usando questo demo ho rilevato il GUID (il codice alfanumerico tra parentesi graffe evidenziato nelle ultime 3 righe del demo) corrispondente alla maggiorparte delle finestre della Shell; vedere ad esempio l'articolo:

Personalizzazione della Shell di Windows da registro

ExplorerMonitor

 

 

 

 

 

 

 

 

 

 


 

 


 

 

 

 

 

 

 

 

 
 
Your Ad Here