Ricerca informazioni su Delphi

Ricerca personalizzata

23.11.08

Quel mistero che si chiama ShDocVw.pas


Quando non ci sono altre soluzioni

In un mio progetto mi sono trovato a dover interagire con alcune pagine HTML che erano online. Inizialmente ho pensato di lavorare con il codice della pagina, scaricata in locale e sulla quale avrei fatto le mie ricerche e le mie modifiche...

Inizialmente sembrava una buona idea e, soprattutto, di semplice realizzazione ma, alla realtà dei fatti, non era affatto così perchè mi ritrovavo di fronte a nuovi e più complicati problemi come il perdere i fogli di stile per strada, alcuni JavaScript risiedevano su file esterni e il loro indirizzo era mascherato/offuscato per impedirne il download, ma se almeno in parte questi problemi sono risolvibili, rimane sempre un caso per cui il mio approccio non poteva proprio essere applicato: le pagine dinamiche con script server-side come ASP, PHP, JSP o ancora altre tecnologie tipiche delle cosiddette Web Applications; in questi casi quello che ottenevo scaricando la pagina non era il codice dello script, ma il risultato di quest'ultimo che viene eseguit sul server prima dell'invio della pagina.


ShDocVw.pas: una miniera di risorse ma senza indicazioni

Come risolvere allora il problema? Dovevo guardare altrove e la soluzione era nella MSDN tra la documentazione per VB: usare la Shell Doc Object and Control library, ossia la ShDocVw.dll per la quale con Delphi viene fornita una unit con lo stesso nome ShDocVw.pas che funge da wrapper per questa DLL

Il bello di questa unit è che non si limita alla omonima DLL, ma, come se non bastasse, ci permette di utilizzare anche la MsHTML.dll che, facente parte del HTMLHelp SDK (gli help CHM) permette di editare le pagine in maniera visuale (WYSIWYG).

Sempre la stessa unit ShDocVw.pas, come se già non bastasse, continua a regalarci altre sorprese, dato che è responsabile dell'implementazione del componente TWebBrowser.

Qual'è il problema però comune a questi strumenti? Non sono minimamente documentati. Sebbene mettano a disposizione strumenti potentissimi, sia la Borland prima che la CodeGear/Embarcadero poi non hanno mai voluto fornire un sia pur minimo livello di documentazione. Oltretutto, le funzionalità più interessanti sono totalmente nascoste; prendiamo ad esempio il TWebBrowser: le proprietà e i metodi migliori non sono visibili nell'object inspector e l'help si limita a pochi accenni al resto e questa è la ragione per cui la maggior parte della gente si limita ad usarlo solo tramite il metodo Navigate e quei pochi eventi associati

Se ora vi è venuta voglia di studiarvi proprietà, metodi ed eventi di questa Unit (vi consiglio di studiarvi ben bene la documentazione della MSDN sulla MsHTML, prestando particolare cura alle classi IHTMLDocument2 e IHTMLBodyElement. Noi invece cominciamo a scrivere qualche linea di codice.


Estrarre il testo di una pagina HTML

Prima di appropriarmi di questa tecnologia, per estrarre il testo da una pagina Web, estraevo tutti i tag HTML e così quel che rimaneva era quasi tutto il testo perdendo però le parti risultanti dall'elaborazione degli script. Con questo sistema e in 3 sole linee di codice si ottiene un risultato migliore di prima.



Esempio 1:
Per compilare, creare una form con un TWebBrowser e un TMemo.
Ricordarsi di aggiungere alla clausola Uses la unit MsHTML



procedure TForm1.FormShow(Sender: TObject);
begin
Web1.Navigate('http://www.cryer.co.uk/brian/delphi/twebbrowser/twebbrowser_properties.htm');
end;

procedure
TForm1.Web1DocumentComplete(ASender: TObject; const pDisp: IDispatch; var URL: OleVariant);
var
Range: IHTMLTxtRange;
begin
// Inizializzazione della variabile Range come IHTMLTxtRange
Range := ((Web1.Document as IHTMLDocument2).body as IHTMLBodyElement).createTextRange;
Range.select; // Seleziona Tutto
Memo1.Lines.Text := Range.Text; // Mostra il risultato nel memo 1
end;




Non merita nemmeno di essere spiegato tanto è semplice. Magari rimane un po' ostico il passaggio di inizializzazione di Range ma lavorando con tipi OleVariant e con una doppia associazione è normale :)



Esempio 2:
Function per estrarre direttamente il testo, senza dover ricorrere a componenti sulla form.
Inserire nella clausola uses le unit MsHTML, ActiveX, ComObj



function StripHTMLCode(aHTML: string): string;
var
IDoc: IHTMLDocument2;
v: Variant;
begin
Idoc := CreateComObject(Class_HTMLDOcument) as IHTMLDocument2;
try
IDoc.designMode := 'on';
while IDoc.readyState <> 'complete' do Application.ProcessMessages;
v := VarArrayCreate([0, 0], VarVariant);
v[0] := aHTML;
IDoc.Write(PSafeArray(System.TVarData(v).VArray));
IDoc.designMode := 'off';
while IDoc.readyState <> 'complete' do
Application.ProcessMessages;
Result := IDoc.body.innerText;
finally IDoc := nil;
end;
end;




Come si vede facilmente, tutto il lavoro è svolto dalla funzione StripHTMLCode che lavora utilizzando direttamente IHTMLDocument2.

Per oggi ci fermiamo qui. Nel prossimo post approfondiremo IHTMLDocument2 e vedremo anche altre interessanti curiosità


Reblog this post [with Zemanta]

Una breve introduzione


Ok, ci siamo.
Siamo partiti. Cominciamo con il dire che, almeno nelle mie intenzioni iniziali, questo blog sarà dedicato a chi, anche se non conosce a fondo il Delphi, è quantomeno abituato a lavorare con linguaggi Object-Oriented.

La mia idea
La mia idea sarebbe quella di costruire una sorta di libreria di procedure e funzioni che possano servire da base ai nostri programmi... del resto non è nemmeno un'idea tanto campata in aria, visto che anche il Project Jedi è nato allo stesso modo, lavorando tramite una mailing list.
Se qualcuno volesse collaborare, potremmo allargare il discorso anche ad altri linguaggi come C++, C#, VB, ecc. e magari tradurre le stesse procedure in questi linguaggi.

In ogni caso, la strada è tracciata. Speriamo ci porti tutti molto lontano :)