2

In my application I want to copy all the text from a website into a string variable. Because of some issues with Indy, I want to use the webbrowser component.

The following code works perfectly for me:

procedure TForm1.Button1Click(Sender: TObject);
begin
  WebBrowser1.Navigate('www.tribalwars.nl');
  while WebBrowser1.Busy do
    Application.ProcessMessages;
  Memo1.Lines.Add((WebBrowser1.Document as IHTMLDocument2).body.innerText);
end;

However, in the example above I use a WebBrowser that has been manually created on my Form1. Now I want to create it during runtime. I tried the following code:

procedure TForm1.Button2Click(Sender: TObject);
var Web: TWebBrowser;
begin
  Web := TWebBrowser.Create(nil);
  Web.Navigate('www.tribalwars.nl');
  while Web.Busy do
    Application.ProcessMessages;
  Memo1.Lines.Add((Web.Document as IHTMLDocument2).body.innerText); //This line raises the error mentioned below
  Web.Free;
end;

Unfortunately it keeps raising the following error:

Project Project1.exe raised exception class $C0000005 with message 'access violation at 0x005d9b4f: read of address 0x00000000'.

I guess I'm trying to use something that hasn't been created yet, or somewhere in that direction. I hope someone can help me get this to work!

EDIT: whosrdaddy mentioned that I should make this component visible. How can I do that? I tried this, but it doesn't work:

procedure TForm1.Button2Click(Sender: TObject);
var Web: TWebBrowser;
begin
  Web := TWebBrowser.Create(nil);
  Web.Left := 50;
  Web.Top := 50;
  Web.Width := 50;
  Web.Height := 50;
  Web.Visible := True;

  Application.ProcessMessages;
  Web.Navigate('www.tribalwars.nl');
  while Web.Busy do
    Application.ProcessMessages;
  Memo1.Lines.Add((Web.Document as IHTMLDocument2).body.innerText);
  Web.Free;
end;
Teun
  • 579
  • 1
  • 7
  • 14
  • The component needs to be visible (ie an owner form) or else it wont render the page and hence the Document will be nil. Put the browser on an invisible form... – whosrdaddy Feb 29 '16 at 19:54
  • @whosrdaddy: How can I make it visible? (see edit begin post) – Teun Feb 29 '16 at 20:25
  • Just create a second form with the browser on it in design mode and set the form visible property to false, then create that form at runtime... – whosrdaddy Feb 29 '16 at 20:55
  • In Hindsight I see your problem now, you are missing a parent for your browser. Just adding TWinControl(Web).Parent := Self; after .Create will solve your problem... – whosrdaddy Feb 29 '16 at 21:07
  • Possible duplicate of [Creating TWebBrowser in Runtime with Delphi](http://stackoverflow.com/questions/1964976/creating-twebbrowser-in-runtime-with-delphi) – whosrdaddy Feb 29 '16 at 21:08
  • (Likely off-topic, but still relevant.) You need to put `try..finally` between the `TWebBrowser.Create` and `Web.Free`. Also, using `Application.ProcessMessages` is a bit of an anti-pattern. – Andreas Rejbrand Nov 25 '18 at 14:22
  • Anyhow, using a graphical web browser control to fetch text from the Internet in a programmatic, non-GUI fashion is very much not ideal. If for some reason you don't want to use Indy, you can use the native Win32 API. See, for instance, https://stackoverflow.com/questions/9239267/how-to-download-a-web-page-into-a-variable/9239361. – Andreas Rejbrand Nov 25 '18 at 14:25

2 Answers2

0

The problem is that when you create TWebBrowser dynamically and pass NIL as the owner, unfortunately the parent is also NIL. a non -NIL parent is needed to display anything.

Normally you would do this:

var pnlBrowser : TPanel; Web : TWebBrowser;

Web := TWebBrowser.Create(nil); Web.Parent := pnlBrowser;

BUT, unfortunately, you cannot (directly) do this either (you get an error message "read-only property" if you try).

But luckily, there IS a way to circumvent the problem:

TWinControl(Web).Parent := pnlBrowser; // this works OK!

I have no idea WHY the parent property of the TWebBrowser class is read-only.

Reading the Delphi documentation, also

TControl(Web).Parent := pnlBrowser; // this should also work

as a side note:

If you have TmsMediaPlayer component (the ActiveX version of Microsoft Windows Media Player), setting parent using the Delphi's Parent property will stop any video playing, but setting it directly through a windows API call does not.

IF you want to use your TWebBrowser to play videos, changing the Parent property on the fly may also stop any video playing. If so it is worth trying to change the parent using windows API call directly instead to avoid stopping a video playing in the web browser.

AHiismak
  • 119
  • 6
-2

1) try to change Your TWebBrowser component to TEmbeddedWB - the parameters/events are the same + lots of extras You can use... 2) I think the problem is with the readystate of your created browser after navigation - its not loaded completely (+maybe it has not assigned parent)

try use the following code (replace Your TWebBrowser component name):

Web.Navigate('www.tribalwars.nl')

repeat application.processmessages; until web.readystate=4;

Memo1.Lines.Add((Web.Document as IHTMLDocument2).body.innerText);

IanF
  • 45
  • 8