Link to home
Start Free TrialLog in
Avatar of kangxy
kangxy

asked on

about TWebBrowser's OnBeforeNavigate2

in OnBeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
so I can get the URL,but how can I get the URL title
for exp. <a href='http://www.experts-exchange.com'>E_E</a>
I can get the href's value, how can I get the 'E_E'
Avatar of kangxy
kangxy

ASKER

Who can Help me ?
first of all use ondocumentcomplete
You can't know the document title before you have received the page.
procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
var
    tit:variant;
begin
      tit:=webbrowser1.document;
      edit1.text:=tit.title;{title of the page}
end;
f15iaf, read the question carefully...
In OnBeforeNavigate2 no way to obtain URL title or any other
anchor attributes. You must implement event sink and attach it
to HTMLAnchorEvents OnClick using DHTML object model.

First you must add units SHDocVw, Mshtml, ComObj:

uses ...., SHDocVw, Mshtml, ComObj;

Next, create Event Sink


const
  Disp_OnClick = -600; // See MSHTML.pas DispID

type
  TAnchorEvent = class(TInterfacedObject, IDispatch)
  protected
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer;
      NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
      Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
  public
    Title: String;
    Form: TForm;
    constructor Create(aForm: TForm; const aTitle: String);
  end;

constructor TAnchorEvent.Create(aForm: TForm; const aTitle: String);
begin
  inherited Create;
  Form := aForm;
  Title := aTitle;
end;

function TAnchorEvent.GetTypeInfoCount(out Count: Integer): HResult; stdcall;
begin
  Result := E_NOTIMPL;
end;

function TAnchorEvent.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
begin
  Result := E_NOTIMPL;
end;

function TAnchorEvent.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
begin
  Result := E_NOTIMPL;
end;

function TAnchorEvent.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
begin
  if DispID = Disp_OnClick then
    begin
          // You actions here
    end;
  Result := S_OK;
end;

then
you define OnDocumentComplete event and expand all anchors element:

procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);

procedure ExtractAnchors(Document: OleVariant);
var
  collection: OleVariant;
  Index: Integer;
  DummyCookie: Integer;
begin
  collection := Document.all.tags('A');
  for Index := 0 to collection.length -1 do
    begin
      ListBox1.Items.Add(collection.item(Index).href);
      InterfaceConnect(IDispatch(collection.item(Index, 0)), HTMLAnchorEvents,
        TAnchorEvent.Create(self, collection.item(Index).innerText), DummyCookie);
    end;
  for Index := 0 to Document.frames.length -1 do
    begin
      ExtractAnchors(Document.frames.item(Index).document);
    end;
end;

Note: UnAdvise you events optionally if you don't refer in
  TAnchorEvent  to any DHTML interfaces.
// procedure TForm1.WebBrowser1DocumentComplete tail

begin
  if pDisp = WebBrowser1.ControlInterface then
    ExtractAnchors(WebBrowser1.Document);
end;
I suppose  you could enumerate all the anchors on the page until you find one who's href = the url parameter.  This wouldn't necessarily work if you've got multiple links pointing to the same url.

GL
Mike
but this anchors can have different title
In JScript you've got access to the window.event object, which in turns has a srcObject property.  So if you can get access to the window object (I've been trying, but haven't figured out how) you can get a variant ref. to the link in question.

GL
Mike
This is good idea, but window.event defined during processing event and not work in
BeforeNavigate2 or you will use another event ?
I just had an idea - I don't have delphi here to test it though.  What about trying webBrowser.document.activeElement?  you've clicked it so I would think that the anchor should have focus.

GL
Mike
Ok, but how you catch click ?
I think in any case need advise event sink
on every anchor in web page. But you right inside
event handler we can use window.event or
document.activeElement for obtain element interface.
Is that what kangxy is looking for?  It's a condition not in the original question.  perhaps the scope of the problem needs to be fleshed out a little more.

GL
Mike
Avatar of kangxy

ASKER

First, Thx all. this weekend, so I not check the web.

Does document.activeElement work?

Can you give me some code?

thx.
I'm currently doing a major hardware shuffle at home :), unfortunately it's unlikely that I'll have a delphi install until mon or tues.  if it does work, though, the code would look like this:

var
 doc : variant;
begin
 doc := webBrowser1.document;
//note that doc will be nil if you've not navigated anywhere.
 caption := doc.activeElement.innerText;
end;

This snippet should set the form's caption to the visible text of the active element.  You can check if doc.activeElement.className = 'A' to see if it is indeed an anchor.

GL
Mike
Mike you absolutely right !
But i think you forget about frames.
This is small modification you code, i try it and
its work fine:

procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
var
 doc, activeElement: OleVariant;
begin
  if webBrowser1.document = nil then
    Exit;
  doc := webBrowser1.document;
  activeElement := doc.activeElement;
  while not VarIsEmpty(activeElement) and
    ((activeElement.tagName = 'FRAME')
      or (activeElement.tagName = 'IFRAME')) do
     activeElement := activeElement.contentWindow.document.activeElement;
  if not VarIsEmpty(activeElement) and (activeElement.tagName = 'A') then
       ShowMessage(activeElement.innerText);
end;


Ah, very good point! I just looked it up and sure enough the activeElement _is_ document specific - you can have one for every frame.

GL
Mike
Avatar of kangxy

ASKER

I've try SChertkov's code. but have some proplem,I use delphi 5. some Exception raised, say "Method 'contentWindow' not supported by automation object" :(
What version of IE you using ?
Avatar of kangxy

ASKER

IE 5.0
Avatar of kangxy

ASKER

IE 5.0 win2000 server
ASKER CERTIFIED SOLUTION
Avatar of SChertkov
SChertkov

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of kangxy

ASKER

Wooowo, thank you very much, it's work well.
the 300 pts it's your now!
Schertkov:150
edey:150
OK?
Avatar of kangxy

ASKER

how to give the points to two answer?
:)
Do not know. I member expert-exchange four days.
Avatar of kangxy

ASKER

Does edey here? Maybe he know:)
Hi.  Actually you can post a question to the Customer Support forum asking for this question to have reduced points.  You should provide a link to this question.  Then ask another for 150. C/S is generally pretty good about this :).  Anyway - glad to see you got a solution, at first it was one of those that seemed just impossible, but turn out to be simpler then you think :).

GL
Mike