Greetings fellow coders, I have read many tutorials, and tried many different code snippets but I have hit a brick wall and decided its time to give my brain a rest and see if other coders can find a solution.
with the push of a button I will log into a web site, do some tasks, then log out.

I got the log in no problem, however my wall is going to the next link...

The page is NOT waiting to load before continuing.

As the code is NOW it logs in and before logging i even completes it goes to the next link so log in actually fails.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ToolWin, ComCtrls, Menus, ActnMan, ActnCtrls, ActnMenus,
  TabNotBk, jpeg, ExtCtrls, OleCtrls, SHDocVw, StdCtrls, PNGButton, mshtml,
  Buttons, inifiles;

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    Options1: TMenuItem;
    opt_switch: TMenuItem;
    opt_exit: TMenuItem;
    Help1: TMenuItem;
    hlp_about: TMenuItem;
    Panel1: TPanel;
    Image2: TImage;
    Panel2: TPanel;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    Panel3: TPanel;
    WebBrowser1: TWebBrowser;
    CoolBar1: TCoolBar;
    Animate1: TAnimate;
    ToolBar1: TToolBar;
    png_btn_home: TPNGButton;
    png_btn_back: TPNGButton;
    png_btn_forward: TPNGButton;
    png_btn_stop: TPNGButton;
    png_btn_refresh: TPNGButton;
    URLs: TEdit;
    StaticText1: TStaticText;
    StaticText2: TStaticText;
    StaticText3: TStaticText;
    StaticText4: TStaticText;
    StaticText5: TStaticText;
    Button1: TButton;
    cur_user: TEdit;
    Button2: TButton;
    TabSheet2: TTabSheet;
    updates: TMemo;
    Button3: TButton;
    StaticText6: TStaticText;
    procedure png_btn_homeClick(Sender: TObject);
    procedure png_btn_backClick(Sender: TObject);
    procedure png_btn_forwardClick(Sender: TObject);
    procedure png_btn_stopClick(Sender: TObject);
    procedure png_btn_refreshClick(Sender: TObject);
    procedure WebBrowser1CommandStateChange(Sender: TObject;
      Command: Integer; Enable: WordBool);
    procedure FormCreate(Sender: TObject);
    procedure FindAddress;
    procedure WebBrowser1BeforeNavigate2(Sender: TObject;
      const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
      Headers: OleVariant; var Cancel: WordBool);
    procedure opt_exitClick(Sender: TObject);
    procedure WebBrowser1DownloadBegin(Sender: TObject);
    procedure WebBrowser1DownloadComplete(Sender: TObject);
    procedure URLsKeyPress(Sender: TObject; var Key: Char);
    procedure Button1Click(Sender: TObject);
    procedure WebBrowser1NavigateComplete2(Sender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
    procedure WebBrowser1DocumentComplete(Sender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);


  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  CurDispatch: IDispatch; {save the interface globally }

implementation

{$R *.dfm}



procedure TForm1.FormCreate(Sender: TObject);
begin
            { Load the animation from the AVI file in the startup directory.}
    Animate1.FileName := ExtractFilePath(Application.ExeName) + 'cool.avi';
    WebBrowser1.Navigate('http://MYSITE.com/');
  end;

procedure TForm1.FindAddress;
var
  Flags: OLEVariant;

begin
  Flags := 0;
  WebBrowser1.Navigate(WideString(Urls.Text), Flags, Flags, Flags, Flags);
end;

procedure TForm1.png_btn_homeClick(Sender: TObject);
  begin
    WebBrowser1.Navigate('MYSITE.com');
  end;

procedure TForm1.png_btn_backClick(Sender: TObject);
  begin
    WebBrowser1.GoBack; //This will GoBack in the browser
  end;

procedure TForm1.png_btn_forwardClick(Sender: TObject);
  begin
    WebBrowser1.GoForward; //This will go Forward
  end;

procedure TForm1.png_btn_stopClick(Sender: TObject);
  begin
    WebBrowser1.Stop; //This will stop the browser
    Animate1.Active := False; // Stop the avi and show the first frame
  end;

procedure TForm1.png_btn_refreshClick(Sender: TObject);
  var
    vRefresh : OleVariant;
  begin
    vRefresh := 3;
    WebBrowser1.Refresh2(OLEVariant(vRefresh));
  end;

procedure TForm1.WebBrowser1CommandStateChange(Sender: TObject;
  Command: Integer; Enable: WordBool);
  begin
    case Command of
      CSC_NAVIGATEBACK: png_btn_back.Enabled := Enable;
      CSC_NAVIGATEFORWARD: png_btn_forward.Enabled := Enable;
    end;
  end;

procedure TForm1.WebBrowser1BeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
    begin
      URLs.Text := URL;
    end;

procedure TForm1.WebBrowser1DownloadBegin(Sender: TObject);
  begin
    Animate1.Active := True; //Play the avi from the first frame indefinitely
  end;

procedure TForm1.WebBrowser1DownloadComplete(Sender: TObject);
  begin
    Animate1.Active := False; // Stop the avi and show the first frame
  end;

procedure TForm1.WebBrowser1NavigateComplete2(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
  begin
    if CurDispatch = nil then
      CurDispatch := pDisp; { save for comparison }
  end;

procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
  begin
    if (pDisp = CurDispatch) then
      begin
        CurDispatch := nil; {clear the global variable }
      end;
  end;

procedure TForm1.URLsKeyPress(Sender: TObject; var Key: Char);
  begin
    if (Key=#13) then
      begin
        WebBrowser1.Navigate(URLs.Text);
      end;
  end;


procedure TForm1.Button1Click(Sender: TObject);
  var iDoc: IHtmlDocument2;
    i: integer;
    ov: OleVariant;
    iDisp: IDispatch;
    iColl: IHTMLElementCollection;
    iInputElement: IHTMLInputElement;
    accINI : TIniFile;
  begin
    accINI := TIniFile.Create(ExtractFilePath(Application.EXEName) + 'acc.ini');
    WebBrowser1.ControlInterface.Document.QueryInterface(IHtmlDocument2, iDoc);
      if not assigned(iDoc) then begin
        ShowMessage(' !!!??? Nothing dowloaded ... ');
        Exit;
      end;
  ov := 'INPUT';
  IDisp := iDoc.all.tags(ov);
    if assigned(IDisp) then begin
      IDisp.QueryInterface(IHTMLElementCollection, iColl);
    if assigned(iColl) then begin
      for i := 1 to iColl.Get_length do begin
        iDisp := iColl.item(pred(i), 0);
        iDisp.QueryInterface(IHTMLInputElement, iInputElement);
    if assigned(iInputElement) then begin
    if iInputElement.Get_name = 'ctl00$ctl00$cpMain$cpMain$LoginBox$Email_Textbox'
//user account e-mail
      then iInputElement.Set_value(accINI.ReadString('email','em1',''));
    if iInputElement.Get_name = 'ctl00$ctl00$cpMain$cpMain$LoginBox$Password_Textbox'
// password
      then iInputElement.Set_value(accINI.ReadString('password','psd1',''));
 //Submit Button
     if iInputElement.Get_name = 'dlb'
      then iInputElement.Get_form.submit;
// Show the Titel of the currently active Webpage in the titlebar
      Caption := Webbrowser1.OleObject.Document.Title
          end;
        end;
      end;
    end;
  cur_user.Text := accINI.ReadString('email','em1','');
  accINI.Free;
  WebBrowser1.Navigate('http://MYOTHERSITE.com/');	// here is where my wall is... the above procedure "WebBrowser1NavigateComplete2" I can ot figure how to recall it and use it here to force a "wait til page fully loads"
  end;

procedure TForm1.opt_exitClick(Sender: TObject);
  begin
    Application.Terminate;
  end;

end.

Thank you all.

Found this to be a cleaner bit:

procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OLEvariant);
  var
    CurWebrowser : IWebBrowser;
    TopWebBrowser: IWebBrowser;
    Document     : OLEvariant;
    WindowName   : string;
      begin { TForm1.WebBrowser1DocumentComplete }
        CurWebrowser := pDisp as IWebBrowser;
        TopWebBrowser := (Sender as TWebBrowser).DefaultInterface;
          if CurWebrowser=TopWebBrowser then
            begin
              ShowMessage('Document is complete.')
            end
          else
            begin
              Document := CurWebrowser.Document;
              WindowName := Document.ParentWindow.Name;
              ShowMessage('Frame ' + WindowName + ' is loaded.')
            end;
      end;

However I still haven't found how to recall the instance and it work...
I may just be overly tired as it is 12am no.

102 views and not one person has a solution to this?

ready_state does NOT work because the page I am waiting on is loading multiple frames (hence firing document complete multiple times)

The new code snip I found DOES work (in that it pops up the message at the end of each frame, when main frame is loaded, and about 3 more times for advertising frames).

after the "submit" button for the account info is pressed I want the page to wait until the log in has completed (meaning it redirects to another page and fully loads) before continuing with next line of code.

I am disappointed, when I joined this web site the PHP and html sections were jumping and everyone was out to help each other.

I am sensing (with 102 views to this page) there are a lot of leechers out there just looking for free code.
24 hours I expected some sort of response. This is very disappointing.

Do I need to remove this site from my bookmarks as I have other sites that are no longer "supportive"

Edited 7 Years Ago by casper_wang: n/a

Well, you ask for help, but please, don't demand it!

If 210 reads your question and don't understand it, or don't know any usefull answer, may be your question is too dificult, or too long (IT IS TOOOOO LONG in it's initial form) or described too poorly.

Anyway, I will make a little try... I never used IWebBrowser, but it is just a IExplorer showed in your form using something similar to a TOLEContainer, so you could know it by checking if iexplorer.exe is iddle (0% of CPU usage) looking at the procces explorer. Easy to say!

I came into a similar problem with Word, and solved it this way, it was not easy to find out all those internals, but here you have, hope it solves your problem (it detects 1%CPU, change it to 0% if you need it).

I copy it here in two flavours: Passing a thandle of the procces (dificult way) or passing a exe file name (easy way) that is internally converted to a thandle:

//Wait for a proccess to be below 1%CPU using its filename
function WaitExeIddle(ExeFileName: string; MinSeg: double = 0.1; MaxSeg: double = 10): double;
begin
  result:= WaitProcIddle(GetProcHandle(ExeFileName), MinSeg, MaxSeg);
end;

//Convert 'WINWORD.EXE' to a valid proccess THandle
function GetProcHandle(ExeFileName: string): THandle;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  result:= 0;
  FSnapshotHandle:= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize:= Sizeof(FProcessEntry32);
  ContinueLoop:= Process32First(FSnapshotHandle, FProcessEntry32);
  while integer(ContinueLoop) <> 0 do begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) = UpperCase(ExeFileName))
     or (UpperCase(FProcessEntry32.szExeFile) = UpperCase(ExeFileName))) then begin
      result:= OpenProcess(PROCESS_ALL_ACCESS, FALSE, FProcessEntry32.th32ProcessID);
      break;
    end;
    ContinueLoop:= Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;

//Waits for a process to drop below 1% CPU usage.
//If doesn't find the proc, it waits MinSeg, and if it doesn't drop under 1%, it wait a maximum of MaxSeg.
function WaitProcIddle(H: THandle; MinSeg: double = 1; MaxSeg: double = 30): double;
var
  LastProcTime, NewProcTime, UsedTime: integer; //Milisegundos todo
  CreaTime, ExitTime, UserTime, KernelTime: TFileTime;
const
  WAIT_FOR_MS: integer = 1000; //Cada 1 segundo (1000 ms) vuelves a mirar
  IDDLE_LOWER: integer =    5; //Usados < 5 ms = (%CPU<0.5) salimos
begin
  //Llevo esperando 0 segundos...
  result:= 0;
  //Igual no lo encuentro...
  if (H=0) then begin
    //Pues no esta, espero algo y me voy...
    sleep(round(MinSeg*1000));
  end else begin
    //Proceso encontrado, a esperar...
    if GetProcessTimes(H, CreaTime, ExitTime, KernelTime, UserTime)=BOOL(0) then exit;
    LastProcTime:= FileTime2Milliseconds(KernelTime) + FileTime2Milliseconds(UserTime);
    //Cada decima de segundo, recalculo...
    repeat
      sleep(WAIT_FOR_MS);
      result:= result + (WAIT_FOR_MS/1000);
      //Rescato tiempo dle proceso actualizado...
      if GetProcessTimes(H, CreaTime, ExitTime, KernelTime, UserTime)=BOOL(0) then exit;
      NewProcTime:= FileTime2Milliseconds(KernelTime) + FileTime2Milliseconds(UserTime);
      UsedTime:= (NewProcTime - LastProcTime);
      if (UsedTime) < IDDLE_LOWER then
        break;
      LastProcTime:= NewProcTime;
    until (result >= MaxSeg);
  end;
end;

Ops, sorry the code comments are in spanish... they don't say nothing specially interesting anyhow!

You also need this to compile:

function FileTime2Milliseconds(FileTime: TFileTime): integer;
var ST: TSystemTime;
begin
  FileTimeToSystemTime(FileTime, ST);
  result:= ST.wMilliseconds + 1000 *
          (ST.wSecond + 60 * (ST.wMinute + 60 * ST.wHour)) ;
end;

Hi there!
I would recommend you to try to find an html element you know is in the page you're going to be redirected to know that the login process is completed: you can place a while loop just after the submit to wait until you find any element in the document that tells you that you're done with login, or, to inspect if the document is fully loaded and what page the browser has loaded, then you can continue to navigate to the other page. Also you can put a timeout and advise to the user that the request has taken longer in case of timeout, or there is a login error (Just inspecting what is in the loaded page in the case of a login error) in case you cannot find the element you're waiting for.
Hope this help you, because I didn't provide any code I tryed to give some ideas I already use to set an AP Wep Key and to send SMS Messages via Web.

This article has been dead for over six months. Start a new discussion instead.