Solved

TWebBrowser -- how?

Posted on 2002-06-29
26
1,957 Views
Last Modified: 2012-06-27
Hi All,
I have a TWebBrowser component on my form, I pass a url to the component and everything is cool.

The url contains a form which I want to fill out. Javascript gives me a permission denied error. Is there a way to reference form fields in the web browser as objects and set the values to what I want?

Up to 500pts available.
-max
0
Comment
Question by:maxb
  • 12
  • 12
  • +1
26 Comments
 
LVL 7

Expert Comment

by:Motaz
ID: 7119632
You can use Indy HTTP client idHTTP to post data to a web server.

Motaz
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7120250
maxb,

1. Do you want to general principle of filling form fields for any url, or just this one?

2. When you navigate to this url using IE, can you fill the form OK (by hand) ?

3. What version of Delphi do you have?
0
 

Author Comment

by:maxb
ID: 7120852
Pretend I wanted to automate the posting of questions or something to EE. I know I can pass the parameters to their script in the URL but some people check the referring URL and know that they are being tricked.

I am doing this to automate my submission process. I submit my artwork to 12 sites 3 times a day and its tedious.

Yes you can fill the form out by hand. Its just a website on as server I DO NOT own. If i try to use javascript, it gives me a "Permission Denied" because it thinks its malicious or something.

Again, I need to fill out the form on someone elses server, I can click the submit button manually, I cant be downloading the form, filling out and then clicking submit.

I have delphi 3-6 so any is fine :)
Thanks again.
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 7

Expert Comment

by:Cynna
ID: 7120907
maxb,

Following code requires you to check html source
of the form you want to submit.
I posted 2 demos for expert-exchange form.Place WebBrowser1 and 2 Buttons on the form for demos.

Copy/Paste:
--------------------

procedure TForm1.PostToURL(URL, Data: String);
//Post data string to the specified URL
var  a,b,c,d: OLEVariant;
     DataSize, Count: Integer;
begin
  if (URL = '') then exit;
  //Set the flags:
  a:=14;
  //Get the length of the post string:
  DataSize:= Length(Data);
  //Create a Variant array of bytes:
  c:= VarArrayCreate([0, DataSize], varByte);
  //Loop through each character and set the array element to the corresponding character:
  for Count:= 0 to DataSize - 1 do c[Count]:= Ord(Data[Count+1]);
  //Add the null terminating character:
  c[DataSize]:= 0;
  //Type cast it to variant array
  TVarData(c).vtype:= varArray;
  //Set the encoding header:
  d:= 'Content-Type: application/x-www-form-urlencoded'+#13+#10+#0;
  //Keep current frame:
  b:= '_top';
  // Finally post data:
  WebBrowser1.Navigate(URL, a, b, c, d);
end;


Demo 1:
------------

procedure TForm1.Button1Click(Sender: TObject);
begin
  // submits search to ex-ex for keyword 'internet':
  PostToURL('http://www.experts-exchange.com/jsp/qSearch.jsp', 'keyWord=internet');
end;


Demo 2:
------------

procedure TForm1.Button2Click(Sender: TObject);
begin
  // logs you on ex-ex (replace string XXXXX with your password):
  PostToURL('http://www.experts-exchange.com/jsp/memberLogin.jsp',
            'loginMemberName=maxb&loginPassword=XXXXX');
end;

0
 

Author Comment

by:maxb
ID: 7120952
Thats what I meant by "I know I can pass the parameters to their script in the URL but some people check the referring URL and know that they are being tricked."

If they looked for the referring URL, they would see that the post to http://www.experts-exchange.com/jsp/qSearch.jsp came from nowhere and not http://www.experts-exchange.com for example.

Am I reading this wrong?
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7121316
maxb,

> Am I reading this wrong?

No you are not.
Sorry, didn't get your point right away.


> Is there a way to reference form fields in the web browser as objects and set the values to what I want?

I think I saw this before. I'll try and post something for you later.  
Do you need only form auto-fill or auto-fill and auto-click on Submit button?
0
 

Author Comment

by:maxb
ID: 7122767
I will click the submit button myself.
Thank you for your help.
0
 
LVL 7

Accepted Solution

by:
Cynna earned 250 total points
ID: 7123963
maxb,

First thing you need is add MSHTML_TLB, COMOBJ to your uses clause.
If the compiler complains, you probably don't have MSHTML_TLB.pas. In that case, you should import Microsoft HTML Object Library (Project->Import Type Library).
During import, you'll have to wait quite a while (it generates over 10Mb source ), so don't loose your patiance, or think your machine has frozen :) ....

Finally just Copy/Paste following function:

function FillFormField(Browser:TWebBrowser; FieldName, FieldValue: String): Boolean;
var WebDoc : IHTMLDocument2;
    pDispatch : IDISPATCH;
    FormCollection : IHTMLElementCollection;
    FormElement : IHTMLFormElement;
    FormItem : IHTMLElement;
    InputElement : IHTMLInputElement;
begin
     Result:=FALSE;
     OleCheck(Browser.Document.QueryInterface(IID_IHTMLDocument2, WebDoc));
     FormCollection := WebDoc.Get_forms;
     pDispatch := FormCollection.item(0, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLFormElement, FormElement));
     pDispatch := FormElement.item(FieldName, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLElement, FormItem));
     if FormItem.QueryInterface(IID_IHTMLInputElement, InputElement) = 0 then
     begin
        if InputElement.Get_type_ = 'text' then begin
           InputElement.Set_value(FieldValue);
           Result:=TRUE;
        end;
     end;
end;


DEMO:
-------
(place TWebBrowser and TButton on the form)


procedure TForm2.Button2Click(Sender: TObject);
begin
   WebBrowser1.Navigate('http://www.experts-exchange.com/');
   // Wait for page to fully load:
   while WebBrowser1.ReadyState<>READYSTATE_COMPLETE do begin
         Sleep(1);
         Application.ProcessMessages;
   end;
   // Fill the search field (named keyWord) with some text:
   FillFormField(WebBrowser1, 'keyWord', '....My search here....');
end;
0
 

Author Comment

by:maxb
ID: 7125560
Ok, I feel like an idiot. While playing around, I removed the Microsoft HTML Object Library. How do I readd it? :)

I tried reinstalling d4 but no luck.

Thanks guys so much.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7126470
Oh well, I have no hands-on expiriance with this type of situation...
Probably redundant question, but did you try simply repeating Project->Import Type Library, and if yes, what happened exactly?
0
 

Author Comment

by:maxb
ID: 7127584
I did, the Microsoft HTML Object Library wasnt on the list of items to import.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7127814
Just curious, what did you do during this 'playing around'?  You didn't click 'Remove' button now, didn't you?

Anyway, if you didn't do something really bad to your system, this shoud get you back:
Project->Import Type Library-> Add (opposite from Remove :-)
Then surf to your windows system folder, and look for:
mshtml.tlb

Click OK, and that's it; you should now have your Microsoft HTML Object Library again.
Click 'Install' on it and take a cup of cofee...
After a while, you should have MSHTML_TLB.pas.
Now go back and Copy/Paste my example.
0
 

Author Comment

by:maxb
ID: 7127823
Cool,
It worked but wouldnt compile. Has problems with the "fonts". Did yours compile? What version of Delphi are you using?

-max
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7128145
> Did yours compile? What version of Delphi are you using?

I'm using D5 Enterprise on WinXP, and it compiles without any problems.


> Has problems with the "fonts".

Well, that's not exactly what I'd call a "detailed bug report"... ;)

1. What error message you received exactly ? (copy/paste, please)

2. What line(s) cause this error? (copy/paste problematic line(s)and neighboring lines)
   
3. What OS do you have?


I'm a bit busy right now, so please be patient, I'll get to you later...

In the meanwhile, there are few things for you to try yourself:

1. You said you have D3-D5. Try this on D5 or D6.

2. If you're in a hacking mood, you might try just commenting out
   that line(s) in MSHTML_TLB.pas and see if it compiles OK.
   Probably won't work right away, but won't cost you much...
0
 

Author Comment

by:maxb
ID: 7128712
It only works in d4 for me, I cant find my d5.
But, d4 doesnt have a TWebBrowser component.

[Error] MSHTML_TLB.pas(97982): Undeclared identifier: 'Get_fontFamily'
[Error] MSHTML_TLB.pas(97998): Undeclared identifier: 'Get_fontStyle'

and so on.

    procedure Set_textKashida(Param1: OleVariant);
    function  Get_textKashida: OleVariant;
    procedure Set_textAutospace(const Param1: WideString);
    function  Get_textAutospace: WideString;

line 32447, this is in D6. I am running XP.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7129340
maxb,

> I cant find my d5.

Then it looks like we're in trouble. I can only speculate about possible solutions, because I can only access D5.


> It only works in d4 for me...
> But, d4 doesnt have a TWebBrowser component

Did you try this:
- Components->Import ActiveX Control,
- select "Microsoft Internet Controls"
- if you can't see it, I think this file is SHDOCVW.DLL; it should be in your system folder.


As for D6:

> Undeclared identifier: 'Get_fontFamily'.... in D6 ...

Well, D6 TLIBIMP.EXE (type library importer) seem to be buggy.
As far as I can see, you have two choices:

1) Update to newest D6 service pack. Also, it might be good  
   idea to search for newest (hopeffuly fixed) TLIBIMP.EXE
   for D6.
   
2) There is a "beta" & "unofficial" version of TLIBIMP.EXE
   that claims to solve some of the problems:
   
   http://www.pdmagic.com/download/tlibimp.zip

  If you decide to give it a try, make a backup of the
  existing one, of course.

0
 

Author Comment

by:maxb
ID: 7133077
Cool, ill try it over the weekend.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7144413
Well, did it work?
0
 

Author Comment

by:maxb
ID: 7144475
Sorry, I was on a business trip. No, it still will not compile. Is there any way someone could compile it and give it to me or is there a way to do it with d4?

Thank you.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7145527
What happens in D4?

> It only works in d4 for me...
> But, d4 doesnt have a TWebBrowser component

Do you mean you can import MSHTML_TLB.pas from D4, but
don't have TWebBrowser? What happened when you tried importing "Microsoft Internet Controls" as I suggested?


> Is there any way someone could compile it and give it to me
If none of the proposed ways for D6 didn't work out,
you need access to a machine with D5.
There, you should generate MSHTML_TLB.pas and copy it to
your Imports directory.
Unfortunately, MSHTML_TLB.pas is about 10Mb, which makes
it very hard for download from someone else, unless, of course, you have fixed net connection.
0
 

Author Comment

by:maxb
ID: 7147131
Ok, sweet.

[Error] Unit1.pas(56): Not enough actual parameters

AT:

WebBrowser1.Navigate('http://www.experts-exchange.com/');

It wants 4 more OLEVariant type parameters. I have no idea what to put there.

Please advise.
0
 

Author Comment

by:maxb
ID: 7148339
Got it to work. Ill post final code and grade of A with 250pts if you can tell me how to check and uncheck a checkbox, radio button, change selection in a dropdown

Thank you again so much.
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7148882
So, what was the problem?

About your additional requests... well, I don't know this exactly offhand - will have to search MSDN a while. This is a bit of work, especially if you want working copy/paste demo. I'm kind of short on time right now, so please be patient...
0
 

Author Comment

by:maxb
ID: 7150940
Thank you. The key was to read the MSHTML_TLB.pas
0
 
LVL 7

Expert Comment

by:Cynna
ID: 7159269
Here you go:

function FillFormField(Browser:TWebBrowser; FieldName, FieldValue: String): Boolean;
var WebDoc : IHTMLDocument2;
    pDispatch : IDISPATCH;
    FormCollection : IHTMLElementCollection;
    FormElement : IHTMLFormElement;
    FormItem : IHTMLElement;
    InputElement : IHTMLInputElement;
begin
     Result:=FALSE;
     OleCheck(Browser.Document.QueryInterface(IID_IHTMLDocument2, WebDoc));
     FormCollection := WebDoc.Get_forms;
     pDispatch := FormCollection.item(0, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLFormElement, FormElement));
     pDispatch := FormElement.item(FieldName, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLElement, FormItem));
     if FormItem.QueryInterface(IID_IHTMLInputElement, InputElement) = 0 then
     begin
        if InputElement.Get_type_ = 'text' then begin
           InputElement.Set_value(FieldValue);
           Result:=TRUE;
        end;
     end;
end;

function CheckFormField(Browser:TWebBrowser; FieldName: String; CheckBoxIndex: Integer; CheckIt: Boolean): Boolean;
var WebDoc : IHTMLDocument2;
    pDispatch : IDISPATCH;
    FormCollection : IHTMLElementCollection;
    FormElement : IHTMLFormElement;
    FormItem : IHTMLElement;
    InputElement : IHTMLInputElement;
begin
     Result:=FALSE;
     OleCheck(Browser.Document.QueryInterface(IID_IHTMLDocument2, WebDoc));
     FormCollection := WebDoc.Get_forms;
     pDispatch := FormCollection.item(0, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLFormElement, FormElement));
     pDispatch := FormElement.item(FieldName, CheckBoxIndex);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLElement, FormItem));
     if FormItem.QueryInterface(IID_IHTMLInputElement, InputElement) = 0 then
        if InputElement.Get_type_ = 'checkbox' then  InputElement.checked:=CheckIt;
end;

function RadioFormField(Browser:TWebBrowser; FieldName: String; RadioIndex: Integer): Boolean;
var WebDoc : IHTMLDocument2;
    pDispatch : IDISPATCH;
    FormCollection : IHTMLElementCollection;
    FormElement : IHTMLFormElement;
    FormItem : IHTMLElement;
    InputElement : IHTMLInputElement;
begin
     Result:=FALSE;
     OleCheck(Browser.Document.QueryInterface(IID_IHTMLDocument2, WebDoc));
     FormCollection := WebDoc.Get_forms;
     pDispatch := FormCollection.item(0, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLFormElement, FormElement));
     pDispatch := FormElement.item(FieldName, RadioIndex);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLElement, FormItem));
     if FormItem.QueryInterface(IID_IHTMLInputElement, InputElement) = 0 then
        if InputElement.Get_type_ = 'radio' then InputElement.checked:=TRUE;
end;

function SelectFormField(Browser:TWebBrowser; FieldName, SelectionIndex: String): Boolean;
var WebDoc : IHTMLDocument2;
    pDispatch : IDISPATCH;
    FormCollection : IHTMLElementCollection;
    FormElement : IHTMLFormElement;
    FormItem : IHTMLElement;
    SelectElement: IHTMLSelectElement;
begin
     Result:=FALSE;
     OleCheck(Browser.Document.QueryInterface(IID_IHTMLDocument2, WebDoc));
     FormCollection := WebDoc.Get_forms;
     pDispatch := FormCollection.item(0, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLFormElement, FormElement));
     pDispatch := FormElement.item(FieldName, 0);
     OleCheck(pDispatch.QueryInterface(IID_IHTMLElement, FormItem));
     if FormItem.QueryInterface(IID_IHTMLSelectElement, SelectElement) = 0 then
        SelectElement.selectedIndex:=StrToInt(SelectionIndex);
end;



// DEMO
// -------------
// (you'll need Button1 and Button2)

procedure TForm1.Button1Click(Sender: TObject);
var site: String;
begin
   site:='http://edit.yahoo.com/config/eval_register?.intl=us&new=1&.done=&.src=ym&.partner=&.p=&promo=&.last=';
   WebBrowser1.Navigate(site);
   // Wait for page to fully load:
   while WebBrowser1.ReadyState<>READYSTATE_COMPLETE do begin
         Sleep(1);
         Application.ProcessMessages;
   end;
   // Fill first name:
   FillFormField(WebBrowser1, '.fn', 'maxb');
   // Uncheck  special offers.. field:
   CheckFormField(WebBrowser1, '.offer', 0, FALSE);
   // Check Entertainment and Computers & Technology fields
   CheckFormField(WebBrowser1, '.userPrefs', 0, TRUE);
   CheckFormField(WebBrowser1, '.userPrefs', 5, TRUE);
   // Select 5. element from Industry field (Computers):
   SelectFormField(WebBrowser1, '.ind' , '5');
end;

procedure TForm1.Button2Click(Sender: TObject);
var site: String; // Radio button demo
begin
   site:='http://www.altavista.com/sites/search/webadv';
   WebBrowser1.Navigate(site);
   // Wait for page to fully load:
   while WebBrowser1.ReadyState<>READYSTATE_COMPLETE do begin
         Sleep(1);
         Application.ProcessMessages;
   end;
   // check 'only this host or URL'::
   RadioFormField(WebBrowser1, 'rc', 2);
   // check 'by date range':
   RadioFormField(WebBrowser1, 'dt', 1);
end;

0
 
LVL 2

Expert Comment

by:ozi_lion
ID: 21832801
Hello, I know this is very old question but I need to use those codes with SSL enabled sites and frame enabled sites, I have tried to change the code but no chance,  can someone help me about it. Thanks in advance.
0

Featured Post

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

820 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question