Link to home
Start Free TrialLog in
Avatar of E-T
E-T

asked on

Checking if a value exists in a form (TWebBrowser)

Hi,

I'm having a little problem with checking if a value exists in an HTML form. I have a TWebBrowser control. It navigates to a website where the user performs a registration process. I need to pull a value from the form to see how far along the process the user has gone. Now, if there is any problem, and the form is not loaded, obviously that value will not be in the page. I use the following code to retrieve the value :

RegProcStr := WebBrowser.OleObject.Document.getElementByID('RegProc').value;

How do i check if the value exists before i retrieve it, if the value is not there, i get an error.

Thanks in advance.
Avatar of fsurfer
fsurfer

hi,

do you mean you have an error on this line or do you want to perform a check before the page loads ?

in the first case, you can use a
try
    RegProcStr := WebBrowser.OleObject.Document.getElementByID('RegProc').value;
except
    .. do whatever in case of an error
End;

in the second case, if you manage on your web server the registration process, add a value to the form (like test=1)
and, using a TidHTTP (Indy non visual component), load the URL to check if there's the wanted value in the reponse.
if the requested value is present, then load the url (with test=0) in the WebBrowser object.

HTH,

Guillaume
Avatar of E-T

ASKER

I'm checking on the document complete event, so the form has already been requested. However, this application is going to be mass marketed, so it is quite likely someone will try and run it without a net connection being present, if so, the value will not be in the form.

I would like to know if there is a way to check if the value is in the form before i retrieve it. I know that putting it into a try...execept will handle the error, but that means that every time i'm doing offline testing, delphi will interrupt the program when that exception happens. Which leads me to another question. How do i tell delphi not to interrupt program execution when an exception is found?

Surely there is a way to test for the presence of a value before retrieving it.

If i put the result of :
WebBrowser.OleObject.Document.getElementByID('RegProc') into a variant, it will either be an object, which has a useablel value parameter, or it will be something else which tells me that the requested item is not found. There are various different variant types, for instance varInteger, or varString. When i tested that variable. Whether or not the value was present, it told me that the varient type was varDispatch.

How do i determine what the result of that request was? Checking for nil is not allowed on variants, checking if it is 0 does nothing usefull.....
hi,

WebBrowser.OleObject.Document.getElementByID('RegProc')  will return an objet of type IHTMLElement. You can check all this in {$DELPHI}/source/internet/MSHTML.PAS (which mean it is an interface object, which has properties and methods you can use)

BTW, you should let your application being able to be halted on severe exceptions. Else you could have your application in a hazardous state and it couldn't work properly after that.

the best, and easiest way, IMHO, is to code all your 'internet' access in a unit and manage the exceptions in it. as you know whenever you access the net, it'll be easier to manage.

the thing to know if you have a net access is ti write a function which will check (with a try ...except) if you can ping, or "http open" a page. if you have an error, your function can return a boolean which will tell if you can open the form (or check the value).

HTH,

Guillaume
Avatar of E-T

ASKER

Ok, well, checking the variant is rather difficult though, i still don't know how to do type checking on a variant that uses an external type, ie the IHTMLElement. The "is" operator is not allowed.

Anyway, i found the solution, it is as follows :

Found := False;
for Cnt := 0 to WebBrowser.OleObject.Document.All.Length - 1 do
begin
    if Pos('RegProc',WebBrowser.OleObject.Document.All.Item(Cnt).ID) <> 0 then
    begin
        Found := True;
    end;
end;
If (Found) Then ShowMessage('Found') else ShowMessage('Not Found');

You have been quite helpfull, and i'll give you the points if you can give me a few tips on how to check if an internet connection is present. I cannot use a ping because there is a problem with the hosting my client is using. Ping resolves the IP, but does not get a response. The website IS working though.

I found some other code which checks for a net connection using a windows API call, but it only seems to work if the computer is connected directly though a modem. If it is on a network, it says there is no connection.

So there's the initial problem if just seeing if a connection is available. Secondly, there is checking if the website itself is up using an HTTPGet of some kind. Could you post a bit of code showing how one uses the TidHTTP class?

If you can help me with both of these, i'll give you the initial 150, plus an extra 100 points.
Hi,

In case of a computer on an LAN, i'm not sure about the way to know if an internet connection exists or not except by doing a ping (using TidICMPClient and getting the answer in the OnReply event). or a http reqest with a timeout.
The thing is that if you use a ping or http request, you may trigger a connection dialog if the computer uses a modem and is not constantly connected. For info, here's a sample code from the PingGUI Indy Demo :

(starring in alphabetical order : a form, an edit box - edtHost - an ICMP client and a ListBox - lstReplies)

procedure TfrmPing.btnPingClick(Sender: TObject);
var
  i: integer;
begin
  ICMP.OnReply := ICMPReply;
  ICMP.ReceiveTimeout := 1000;
  btnPing.Enabled := False;
  try
    ICMP.Host := edtHost.Text;
    for i := 1 to 4 do begin
      ICMP.Ping;
      Application.ProcessMessages;
    end;
  finally
     btnPing.Enabled := True;
  end;
end;

procedure TfrmPing.ICMPReply(ASender: TComponent; const ReplyStatus: TReplyStatus);
var
  sTime: string;
begin
  // TODO: check for error on ping reply (ReplyStatus.MsgType?)
  if (ReplyStatus.MsRoundTripTime = 0) then
    sTime := '<1'
  else
    sTime := '=';

  lstReplies.Items.Add(Format('%d bytes from %s: icmp_seq=%d ttl=%d time%s%d ms',
    [ReplyStatus.BytesReceived,
    ReplyStatus.FromIpAddress,
    ReplyStatus.SequenceId,
    ReplyStatus.TimeToLive,
    sTime,
    ReplyStatus.MsRoundTripTime]));
end;

concerning the use of TidHTTP, in one of my application, i'm doing a http request on a website to get some information. This request has a timeout. Basically, it's to know if there's a new version of my application, but doesn't prevent my app from running if no connection is available. here's part of the code :

          ...
          aHttp:=TidHTTP.Create(Nil);
          try
             s:=aHttp.Get(url);
          Except
             s:='';
          End;
          FreeAndNil(aHttp);
          if s<>'' then
          ...
         
By default, the http timeout of a TIdHTTP object is set to 1 second (cf ReadTimeOut property in the online help).
BTW, this is a non-visual component.

HTH,

Guillaume
Avatar of E-T

ASKER

OK, Consider problem one solved, i'll be using a ping. I'm having problems with that code you gave me for the TidHTTP object though.

I've entered various urls. For instance 'http://www.google.com' or 'www.google.com'.

When i do, i get one of two errors. The first (Connection timed out) i assume is to do with the TimeOut property , i've looked around in the help, but can't find where to set the timeout.

The second says the following :

"Project PingApp.exe raised exception class EIdSocketError with message 'Socket Error # 10061 Connection refused.'. Process stopped."

Any idea why this is happening? (I am on a network with a proxy server...)
ASKER CERTIFIED SOLUTION
Avatar of fsurfer
fsurfer

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 E-T

ASKER

Ah, the wonderfull world of development.

This question has evolved quite a bit, i must say. ;)

I can use a ping to check if there is an internet connection.
The current problem is checking if the website is up.

I can do that in two ways. Unfortunately the methods mentioned here get pretty complicated.

First i'd need to know how to check if the user is on a proxy, or a normal connection.
Next, how do i detect the proxy settings.
Lastly i find out how to put that all together using the idHTTP object.

The other option is that i create another TWebBrowser object in the background and request a page from it. I then use the previously posted code to check for a value. If it finds one, that means the site is up. This option is a lot simpler, since it sorts out the connectivity problems for me, but it will use a fair amount of memory for a simple check, not exactly a prime example of good coding. ;)

Still, it doesn't matter too much. What i need to do is spawn a thread, retrieve one value from the website, and then free all the things i used to do that with, so they'll only be in existance for a few seconds...

What do you think? Option 1 is definately more efficient, but it is a lot harder to ensure that it works properly. Option 2 is more costly, but i'm fairly certain i can get it working perfectly....
Avatar of E-T

ASKER

Ok fsurfer, thanks for your help, I've resolved all the problems. Looks like I'll have this app's registration system up and running by the end of the week. :)

As for the points issue, i've added an extra 50. Since you couldn't help with the second part of the problem, i'm using the solution mentioned in my previous post. It works perfectly, so no worries.

If you read this, i'd like to know one little thing. What version of Indy do you get with Delphi 6? I've looked all over and can't find any mention of the version.
Avatar of E-T

ASKER

By the way, for anyone else reading this question, the code I posted earlier (Which checks if a value exists on the form) was a bit incorrect, the Pos is unneccesary. This is the final version of it:

For Cnt := 0 to FWeb.OleObject.Document.All.Length - 1 do Begin
    If (FWeb.OleObject.Document.All.Item(Cnt).ID = 'StatusVal') Then
        Begin
           UValExists := True;
           UVal := FWeb.OleObject.Document.GetElementById('StatusVal').value;
        end;
End;
Hi E-T,

sorry if i haven't answered your last post, but i wasn't at my office.
for the proxy settings, i have no answer yet. I will have a look at the Wininet.pas API.

here are some specifications about getting proxy settings and the use of wininet api :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/handling_authentication.asp

Your solution (for the proxy) isn't a masterpiece in programming matters, but... it works ;)  (i use the same sometimes ;)

for the Indy version, look for the Indy's source code directory. there should be a 'IdVers.inc' file. In it, you have the current version you're using.

thanks for the accepted answer :)

HTH,

Guillaume
Avatar of E-T

ASKER

Sure, no problem. You've been rather helpfull. ;)

There is no IdVers.inc file in the Indy directory by the way. I guess it doesn't matter too much, I'll just update to the latest one and be done with it.

I'm hoping it'll fix another little annoyance I'm having with TidHTTPServer. I have it set up serving fairly large html documents, you nagivate them using a treeview. When you click too fast, an exception is raised, saying either "Connection closed gracefully", or some socket error. It is meant to be using multiple threads to serve content, and it can't have more than about 10 running no matter how fast I click, still, it stuffs up.

It doesn't kill the app or anything, but it does cause the internet connection dialog to pop up (if enabled), which is pretty damn annoying, especially since it is meant to run offline most of the time.