MauricioGaviria
asked on
intercepting internet explorer messages
Hi...
In my application I need to measure the time between the calling to a page and the ready state in the explorer. how can I know if the internet explorer end to loade a page?
In my application I need to measure the time between the calling to a page and the ready state in the explorer. how can I know if the internet explorer end to loade a page?
ASKER
I read about IEAK in the microsoft site. this service pack enable developers to write and distribute their custom browser program using Internet Explorer. what do you think about this solution?
MauricioGaviria,
Is the browser running stand alone or is it embedded (TWebBrowser) in your application?
The second is easier to deal with, as the events are already exposed in the delphi component wrapper. The first is still very do-able as well, the toughest part is determining (if more than one IE window is up) which IE window you wish to connect to. The enumeration is easily done through IShellWindows, and you could use the title or location url to determine which one to use. I could also provide you component source for an object that can bind to the IWebBrowser2's event interface. (using connection points). This would allow you to connect to any running IE window and be able to "listen" to all the events.
Btw: the event interface provides a couple events that you would probably find useful for measuring time. For example:
OnDownloadBegin
OnDownloadComplete (fires even if the navigation fails)
OnBeforeNavigate2
OnNavigateComplete2 (does not fire if navigatio fails)
Regards,
Russell
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
[rllibby - Russell];
If you are still watching this post.
I have added your component into a sample poject.
What I would like to ask you is the following:
( I have never messed around with actual IE before, on TEmbeddedWB, TWebBrowser )
I need to check if a page is loaded.
If it is completed loaded, Then run my code.
I see where you have the following Events in the component.
Which are like the TWebBrowser controls.
TIEDocumentCompleteEvent
Would I add my code that needs to do something in IE to this?
And how would I do it?
And also:
In addition it should detect whether the page is available, i.e. If connected to the Internet, page is done, and so forth, and if it is done, then display a message that informs you that it is unavailable.
With a button to: OK | Cancel.
Also. once you come in and are willing to assist me with this, I will post a question for you
Before you hand over the code, with 500-Points to the question.
Thank you in advance, And thank you for making the component, I test it with your demo code.
And it works great.
Carrzkiss
If you are still watching this post.
I have added your component into a sample poject.
What I would like to ask you is the following:
( I have never messed around with actual IE before, on TEmbeddedWB, TWebBrowser )
I need to check if a page is loaded.
If it is completed loaded, Then run my code.
I see where you have the following Events in the component.
Which are like the TWebBrowser controls.
TIEDocumentCompleteEvent
Would I add my code that needs to do something in IE to this?
And how would I do it?
And also:
In addition it should detect whether the page is available, i.e. If connected to the Internet, page is done, and so forth, and if it is done, then display a message that informs you that it is unavailable.
With a button to: OK | Cancel.
Also. once you come in and are willing to assist me with this, I will post a question for you
Before you hand over the code, with 500-Points to the question.
Thank you in advance, And thank you for making the component, I test it with your demo code.
And it works great.
Carrzkiss
Carrzkiss,
Yes, I am still getting notifications to questions I have helped on, and am willing to address your question(s):
1.) I need to check if a page is loaded. If it is completed loaded, Then run my code.
------
I assume you are talking about IE as in stand alone mode (seperate browser window), vs using TWebBrowser. If your using TWebBrowser in you app, then it is slightly easier, as you know what instance of the IWebBrowser2 interface you will be interacting with. Once you have obtained the web browser interface, then all the events / properties are the same. (TWebBrowser is nothing more than a delphi wrapper around the com object that IE exposes).
If your dealing with IE standalone, then the first thing that needs to be done is to get the interface you will be dealing with. This is actually pretty trivial using the CoShellWindows code (see prior comments/code); the difficult aspect is determining WHICH browser you want to hook. For example, if the user has 3 IE windows up, you must have some way of determining which browser you wish to monitor / interact with. That part you must figure out.(though I can help if you need to check certain properties or whatever in making that decision). It is also possible to hook ALL browser windows, though it would be recommended to have one event handler to one browser.
2.) I see where you have the following Events in the component.
Which are like the TWebBrowser controls.
TIEDocumentCompleteEvent
Would I add my code that needs to do something in IE to this?
And how would I do it?
------
Yes, the TIEDocumentCompleteEvent would be ONE place to add code for handling the completion of a document loading. As to the how; if you use the component code I provided above, then you would just double click on the component event which would create stub code, like the following
procedure TForm1.IEEvents1DownloadCo
begin
end;
Then you would add whatever code you needed to perform in there. If you need to access the browser interface again, then I suggest you save it to a variable for later reference, eg:
type
TForm1 = class(TForm)
Button1: TButton;
IEEvents1: TIEEvents;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure IEEvents1DownloadComplete(
procedure IEEvents1Quit(Sender: TObject);
private
// Private declarations
FTimeList: TList;
FBrowser: IWebBrowser2; // Used for referencing the browser in your code
public
// Public declarations
end;
procedure TForm1.Button1Click(Sender
var pvShell: IShellWindows;
ovIE: OleVariant;
dwCount: Integer;
begin
// Create the shell windows interface
pvShell:=CoShellWindows.Cr
// Walk the internet explorer windows
for dwCount:=0 to Pred(pvShell.Count) do
begin
// Clear any previous interface
FBrowser:=nil;
// Get the interface
ovIE:=pvShell.Item(dwCount
// At this point you can evaluate the interface (LocationUrl, etc)
// to decide if this is the one you want to connect to. For demo purposes,
// the code will bind to the first one
ShowMessage(ovIE.LocationU
// QI for the IWebBrowser2
if (IDispatch(ovIE).QueryInte
begin
// Connect to interface
IEEvents1.ConnectTo(FBrows
end;
// Clear the variant
ovIE:=Unassigned;
// Break if we connected
if IEEvents1.Connected then break;
end;
// Release the shell windows interface
pvShell:=nil;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Set default state
FBrowser:=nil
end;
procedure TForm1.FormDestroy(Sender:
begin
// Release interface
FBrowser:=nil;
end;
procedure TForm1.IEEvents1DownloadCo
begin
if Assigned(FBrowser) then
begin
// Do code...
end;
end;
procedure TForm1.IEEvents1Quit(Sende
begin
// Clear interface
FBrowser:=nil;
end;
----
The one thing that does not address is the case where you connect to a browser AFTER that browser has already loaded the document. To handle that situation, you should have code that checks the following property of the browser interface.
FBrowser.ReadyState
which will return one of the following values:
READYSTATE_UNINITIALIZED = 0,
READYSTATE_LOADING = 1,
READYSTATE_LOADED = 2,
READYSTATE_INTERACTIVE = 3,
READYSTATE_COMPLETE = 4
You would be looking for the READYSTATE_COMPLETE, which indicates that the browser is finished loading the document.
3.) And also:
In addition it should detect whether the page is available, i.e. If connected to the Internet, page is done, and so forth, and if it is done, then display a message that informs you that it is unavailable.
With a button to: OK | Cancel.
----
To detect if the browser has loaded a page from local cache, vs the internet, you would need to check:
FBrowser.Offline
Which returns true if offline and the page was read from local cache, and false if the page was downloaded from its source (for http:// protocols, the source would be from the inter/intranet). So basically, when the document is complete, handled in OnDownloadComplete, or via code checking FBrowser.ReadyState = 4, the following could be checked:
if Assigned(FBrowser) and (FBrowser.ReadyState = 4) and not(FBrowser.Offline) and
(FBrowser.LocationUrl = {whatever url you are after}) then
begin
// Document is loaded and ready
end;
4.) Also. once you come in and are willing to assist me with this, I will post a question for you Before you hand over the code, with 500-Points to the question.
------
In order to help further, it would help me to have a few more details on what you are trying to accomplish. The more detail the better, obviously. With more detail, I could provide a demo that addresses what you are trying to accomplish.
Hopefully though, this is enough to get you started in the right direction. Let me know how I can help further...
Regards,
Russell
This example here
http://www.ericcarr-tribute.com/log/IE-Login.zip
Send Username & password to page.
Check to make sure that the page is loaded, If so [Submit]
If not [Display message {Page not available} Options: Quit]
This is my first real time messing around with this type of code.
I am going to look through the example code above, and look through
The code that is in the link above.
And see if I can make heads or tells of it.
If this was in "TWebBrowser" Then I would be able to half way figure it out.
But it is not, This is hooking into IE itself. Which is something that I have always
Wanted to learn how to do.
So any help that you may be able to assist me with would be extremly great. and welcomed.
If you can also explain to me: What everything is and what it is used for I would appreciate it
As well.
The code is not mine, it is someone elses, It is wel documented as well.
Thank you Russell;
Carrzkiss
http://www.ericcarr-tribute.com/log/IE-Login.zip
Send Username & password to page.
Check to make sure that the page is loaded, If so [Submit]
If not [Display message {Page not available} Options: Quit]
This is my first real time messing around with this type of code.
I am going to look through the example code above, and look through
The code that is in the link above.
And see if I can make heads or tells of it.
If this was in "TWebBrowser" Then I would be able to half way figure it out.
But it is not, This is hooking into IE itself. Which is something that I have always
Wanted to learn how to do.
So any help that you may be able to assist me with would be extremly great. and welcomed.
If you can also explain to me: What everything is and what it is used for I would appreciate it
As well.
The code is not mine, it is someone elses, It is wel documented as well.
Thank you Russell;
Carrzkiss
Okay, the example you posted is used to hook IE using IShellWindows (just like the example I provided), checks the loaded page to see if an input for text/password can be found, and if so to set them. It also checks for a button of type submit, and if found, executes the click, which would then submit the page. Pretty straight forward stuff...
What you need to be able to do, from what I gather is:
1.) Load the specified page of your choosing, or make sure the desired page is loaded.
2.) Fill out the username/password fields and click the submit button.
3.) Wait for the post to complete and then display options based on if the submission completed or not.
Another question ...
Would it be more helpful for you to have this implemented in a TWebBrowser based control? The code would really be all the same, its just that you have more control when the browser window is embedded. (remember, the TWebBrowser is nothing more than a wrapper around the IWebbrowser2 interface set.). This gives your application control, as it specifies what is loaded, and when, vs having IE in control of the browser, where the user can do whatever they want.
Anyways, the last 2 questions I have are:
1.) Is this supposed to be a generic program, for any site/page that accepts a login?
-- and --
2.) *HOW* do you tell if the submission completed correctly (eg, valid user name and password). Many sites will send back a page indicating that the user name/password was incorrect. BUT.... from a programmatic standpoint, you will get a document back, and it will fire the OnDocumentComplete event. Only the **contents** of the page can really be used to determine if the submission was successful or not. Make sense? (if not, please say so). This makes it hard to develop something generic as each page/site may handle things a little differently.
If you let me know the answer in regards to IE external based, or TWebBrowser control based implementation, then I can probably put a sample together for you on Monday (and base it off from a specific site, like EE login for example). This would at least give you the basics for what you are after, but may require some tweaking depending on the page/site you plan on using it for.
Regards,
Russell
TWebBrowser control - No I need it in IE alone.
Cannot use the TWebBrowser in this project.
#1: Generic Site. = Yes any page that excepts Login.
#2: I understand what you are talking about, but cannot put it into words.
Hope that does not sound to beginner like, as I have been doing Delphi for almost 7yrs now.
And sometimes I get lost in the shuffle of Delphi Discussions, unless I know the routine.
And hooking into IE I am a newbie. In TWebBrowser, I know how to do. And can hold my
Own.
The example of EE's Login will probably be exactly what I am needing.
So I will just go for what you decide, since you know "way more" about handling IE.
Then I do.
Thank you so very much for taking the time with me on this. And especially
For explaining and asking me information about the project, instead of assuming that
I "Should" already know everything under the sun.
Take Care and Have a good weekend.
Wayne
Cannot use the TWebBrowser in this project.
#1: Generic Site. = Yes any page that excepts Login.
#2: I understand what you are talking about, but cannot put it into words.
Hope that does not sound to beginner like, as I have been doing Delphi for almost 7yrs now.
And sometimes I get lost in the shuffle of Delphi Discussions, unless I know the routine.
And hooking into IE I am a newbie. In TWebBrowser, I know how to do. And can hold my
Own.
The example of EE's Login will probably be exactly what I am needing.
So I will just go for what you decide, since you know "way more" about handling IE.
Then I do.
Thank you so very much for taking the time with me on this. And especially
For explaining and asking me information about the project, instead of assuming that
I "Should" already know everything under the sun.
Take Care and Have a good weekend.
Wayne
Wayne,
Thanks for waiting, and I think what I have may be of some use to you. The source below is as generic as I could possibly make it, while still attempting to meet your requirements.
1.) It walks the open IE windows to determine if any of them provide a document that allows for logging in.
2.) If so, the forms button and edit fields become enabled, allowing for entry and submission.
3.) Once submitted, the process waits until the page is done loading and then checks to see to see if the document is still providing a login mechanism (typical on failed login attempts).
If no login entry is then exposed, it is assumed through the code that the login succeeded. This is all I could really do without writing code that is specific to a site. This could be enhanced to check the actual document after the login, but it would be VERY site specific at that point.
All that you need to do to run this demo is: Create a new project, and paste the code over the unit1 code in your project. All the controls are created dynamically at run time, in an attempt to reduce confusion in regards to setting up the example. Also pay close attention to the PerformLogin code, as this is what performs the actual setting of values and submission to the site. It is much more lenient then the linked code from:
http://www.ericcarr-tribute.com/log/IE-Login.zip
as it walks the ALL element collection, which is needed for some sites; EE being one in paticular.
To test, start an instance of IE, go to EE site, then logout. The demo should then enable the button and edit fields. Enter in your info (try with both good and bad data), click the button, and you should find that it works as expected.
If you have any problems, or questions, let me know and I will try to answer them as soon as time permits.
Regards,
Russell
---------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Forms, Controls, ExtCtrls, Dialogs,
StdCtrls, ComObj, ActiveX, SHDocVW, ie_events;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
// Private declarations
FTimer: TTimer;
FLogin: TButton;
FUserID: TEdit;
FPassword: TEdit;
FEvents: TIEEvents;
function CanLoginAny: Boolean;
function CanLogin(Browser: OleVariant): Boolean;
function PerformLogin(UserID, Password: String): Boolean;
protected
// Protected declarations
procedure UpdateState(AllowLogin: Boolean);
procedure CreateRuntimeControls;
procedure OnTimer(Sender: TObject);
procedure OnButtonClick(Sender: TObject);
procedure OnQuit(Sender: TObject);
public
// Public declarations
end;
// Color constants
const
clrEnabled: Array [False..True] of TColor = (clBtnFace, clWindow);
// Global form variable
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.UpdateState(AllowLo gin: Boolean);
begin
// Update the controls state
FUserID.Enabled:=AllowLogi n;
FPassword.Enabled:=AllowLo gin;
FUserID.Color:=clrEnabled[ FUserID.En abled];
FPassword.Color:=clrEnable d[FPasswor d.Enabled] ;
FLogin.Enabled:=AllowLogin ;
end;
procedure TForm1.OnButtonClick(Sende r: TObject);
begin
// Check values
if (FUserID.Text = EmptyStr) then
ShowMessage('UserID required...')
else if (FPassword.Text = EmptyStr) then
ShowMessage('Password required...')
else
begin
// Perform the login
if PerformLogin(FUserID.Text, FPassword.Text) then
begin
// Disable state
FTimer.Enabled:=False;
try
// Disable state
UpdateState(False);
// Let the process start
while (FEvents.WebObj.ReadyState = READYSTATE_COMPLETE) do Application.ProcessMessage s;
// Wait until the login has completed
while FEvents.Connected and (FEvents.WebObj.ReadyState <> READYSTATE_COMPLETE) do
begin
// Wait until the submission has finished (or the user closes the IE window)
Application.ProcessMessage s;
end;
// Check state of web browser interface
if not(FEvents.Connected) or CanLogin(FEvents.WebObj.Do cument) then
// Failed to login
ShowMessage('Failed to log in')
else
// Logged in
ShowMessage('Logged in...');
finally
// Disconnect
FEvents.Disconnect;
// Re-enable timer
FTimer.Enabled:=True;
end;
end;
end;
end;
procedure TForm1.OnQuit(Sender: TObject);
begin
// Disconnect from interface
FEvents.Disconnect;
// Update state
UpdateState(False);
end;
procedure TForm1.OnTimer(Sender: TObject);
begin
// Timer event
if not(FEvents.Connected) then UpdateState(CanLoginAny);
end;
function TForm1.PerformLogin(UserID , Password: String): Boolean;
var pvShell: IShellWindows;
pvWeb2: IWebBrowser2;
ovIE: OleVariant;
ovDoc2: OleVariant;
ovElement: OleVariant;
ovInput: OleVariant;
ovPassword: OleVariant;
ovSubmit: OleVariant;
dwCount: Integer;
dwFrames: Integer;
dwIndex: Integer;
bSubmit: Boolean;
begin
// Set default result
result:=False;
// Create the shell windows interface
pvShell:=CoShellWindows.Cr eate;
try
// Walk the internet explorer windows
for dwCount:=0 to Pred(pvShell.Count) do
begin
// Get the interface
ovIE:=pvShell.Item(dwCount );
// QI for the IWebBrowser2
if (IDispatch(ovIE).QueryInte rface(IWeb Browser2, pvWeb2) = S_OK) then
begin
// Make sure it is ready
if not(pvWeb2.Offline) and (pvWeb2.ReadyState = READYSTATE_COMPLETE) then
begin
// Check for elements in page
if Assigned(pvWeb2.Document) then
begin
// Set defaults
ovInput:=Unassigned;
ovPassword:=Unassigned;
ovSubmit:=Unassigned;
// Get the document object
ovDoc2:=pvWeb2.Document;
try
// Walk the frames
for dwFrames:=0 to ovDoc2.Forms.Length-1 do
begin
// Walk elements
for dwIndex:=0 to ovDoc2.Forms.Item(dwFrames ).All.Leng th-1 do
begin
// Get element
ovElement:=ovDoc2.Forms.It em(dwFrame s).All.Ite m(dwIndex) ;
// Check input
if (CompareText(String(ovElem ent.tagNam e), 'input') = 0) then
begin
// Check input
if (CompareText(String(ovElem ent.Type), 'text') = 0) then
// Get input
ovInput:=ovElement
// Check password
else if (CompareText(String(ovElem ent.Type), 'password') = 0) then
// Set password
ovPassword:=ovElement
// Check for submit
else if (Pos(LowerCase('submit'), LowerCase(String(ovElement .Name))) > 0) then
begin
// Must be in the same context as user/password (eg, don't falsely pick up a search button)
if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then
begin
// Have submit
ovSubmit:=ovElement;
end;
end;
end;
// Release element
ovElement:=Unassigned;
// Do we have all elements?
if (VarType(ovInput) > varEmpty) and
(VarType(ovPassword) > varEmpty) and
(VarType(ovSubmit) > varEmpty) then
begin
// Connect to the interface
FEvents.ConnectTo(pvWeb2);
// Submit
ovInput.Value:=UserID;
ovPassword.Value:=Password ;
ovSubmit.Click;
// Set result
result:=True;
// Break
break;
end;
end;
// If success then break
if result then break;
end;
finally
// Clear refs
ovInput:=Unassigned;
ovPassword:=Unassigned;
ovSubmit:=Unassigned;
ovDoc2:=Unassigned;
end;
end;
end;
// Release the interface
pvWeb2:=nil;
end;
// Clear the variant
ovIE:=Unassigned;
// If success then break
if result then break;
end;
finally
// Release the interface
pvShell:=nil;
end;
end;
function TForm1.CanLogin(Browser: OleVariant): Boolean;
var ovElement: OleVariant;
ovInput: OleVariant;
ovPassword: OleVariant;
dwCount: Integer;
dwFrames: Integer;
dwIndex: Integer;
begin
// Set default result
result:=False;
// Walk the frames
for dwFrames:=0 to Browser.Forms.Length-1 do
begin
// Clear state
ovInput:=Unassigned;
ovPassword:=Unassigned;
// Walk elements
for dwIndex:=0 to Browser.Forms.Item(dwFrame s).All.Len gth-1 do
begin
// Get element
ovElement:=Browser.Forms.I tem(dwFram es).All.It em(dwIndex );
// Check input
if (CompareText(String(ovElem ent.tagNam e), 'input') = 0) then
begin
// Check input
if (CompareText(String(ovElem ent.Type), 'text') = 0) then
// Have input
ovInput:=ovElement
// Check password
else if (CompareText(String(ovElem ent.Type), 'password') = 0) then
// Have password
ovPassword:=ovElement;
end;
// Release element
ovElement:=Unassigned;
// Break if we have both password and input
if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then break;
end;
// Check elements
result:=(VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty);
// Release refs
ovInput:=Unassigned;
ovPassword:=Unassigned;
// Break is success
if result then break;
end;
end;
function TForm1.CanLoginAny: Boolean;
var pvShell: IShellWindows;
pvWeb2: IWebBrowser2;
ovIE: OleVariant;
ovDoc2: OleVariant;
dwCount: Integer;
begin
// Set default result
result:=False;
// Create the shell windows interface
pvShell:=CoShellWindows.Cr eate;
try
// Walk the internet explorer windows
for dwCount:=0 to Pred(pvShell.Count) do
begin
// Get the interface
ovIE:=pvShell.Item(dwCount );
// QI for the IWebBrowser2
if (IDispatch(ovIE).QueryInte rface(IWeb Browser2, pvWeb2) = S_OK) then
begin
// Make sure it is ready
if not(pvWeb2.Offline) and (pvWeb2.ReadyState = READYSTATE_COMPLETE) then
begin
// Check for elements in page
if Assigned(pvWeb2.Document) then
begin
// Get the document object
ovDoc2:=pvWeb2.Document;
try
// See if we can login to the page
result:=CanLogin(ovDoc2);
finally
// Clear document
ovDoc2:=Unassigned;
end;
end;
end;
end;
// Release the interface
pvWeb2:=nil;
// Clear the variant
ovIE:=Unassigned;
// If success then break
if result then break;
end;
finally
// Release the interface
pvShell:=nil;
end;
end;
procedure TForm1.CreateRuntimeContro ls;
begin
// Create IE event handler
FEvents:=TIEEvents.Create( Self);
FEvents.OnQuit:=OnQuit;
// Create login button
FLogin:=TButton.Create(Sel f);
with FLogin do
begin
Parent:=Self;
SetBounds(8, 8, 73, 25);
Caption:='Login';
OnClick:=OnButtonClick;
Visible:=True;
end;
// Create user id label
with TLabel.Create(Self) do
begin
Parent:=Self;
SetBounds(100, 12, 60, 13);
Caption:='User ID:';
Visible:=True;
end;
// Create password label
with TLabel.Create(Self) do
begin
Parent:=Self;
SetBounds(100, 36, 60, 13);
Caption:='Password:';
Visible:=True;
end;
// Create user id entry field
FUserID:=TEdit.Create(Self );
with FUserID do
begin
Parent:=Self;
SetBounds(164, 8, 197, 21);
Text:=EmptyStr;
Visible:=True;
end;
// Create password entry field
FPassword:=TEdit.Create(Se lf);
with FPassword do
begin
Parent:=Self;
SetBounds(164, 32, 197, 21);
Text:=EmptyStr;
PasswordChar:='*';
Visible:=True;
end;
// Create timer
FTimer:=TTimer.Create(Self );
with FTimer do
begin
Parent:=Self;
Interval:=500;
Enabled:=True;
OnTimer:=Self.OnTimer;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Set caption
Caption:='Login to IE';
// Set bounds
SetBounds((Screen.Width-40 0) div 2, (Screen.Height-120) div 2, 400, 120);
// Create run time controls
CreateRuntimeControls;
// Update state (don't allow login yet)
UpdateState(False);
end;
end.
Thanks for waiting, and I think what I have may be of some use to you. The source below is as generic as I could possibly make it, while still attempting to meet your requirements.
1.) It walks the open IE windows to determine if any of them provide a document that allows for logging in.
2.) If so, the forms button and edit fields become enabled, allowing for entry and submission.
3.) Once submitted, the process waits until the page is done loading and then checks to see to see if the document is still providing a login mechanism (typical on failed login attempts).
If no login entry is then exposed, it is assumed through the code that the login succeeded. This is all I could really do without writing code that is specific to a site. This could be enhanced to check the actual document after the login, but it would be VERY site specific at that point.
All that you need to do to run this demo is: Create a new project, and paste the code over the unit1 code in your project. All the controls are created dynamically at run time, in an attempt to reduce confusion in regards to setting up the example. Also pay close attention to the PerformLogin code, as this is what performs the actual setting of values and submission to the site. It is much more lenient then the linked code from:
http://www.ericcarr-tribute.com/log/IE-Login.zip
as it walks the ALL element collection, which is needed for some sites; EE being one in paticular.
To test, start an instance of IE, go to EE site, then logout. The demo should then enable the button and edit fields. Enter in your info (try with both good and bad data), click the button, and you should find that it works as expected.
If you have any problems, or questions, let me know and I will try to answer them as soon as time permits.
Regards,
Russell
---------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Forms, Controls, ExtCtrls, Dialogs,
StdCtrls, ComObj, ActiveX, SHDocVW, ie_events;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
// Private declarations
FTimer: TTimer;
FLogin: TButton;
FUserID: TEdit;
FPassword: TEdit;
FEvents: TIEEvents;
function CanLoginAny: Boolean;
function CanLogin(Browser: OleVariant): Boolean;
function PerformLogin(UserID, Password: String): Boolean;
protected
// Protected declarations
procedure UpdateState(AllowLogin: Boolean);
procedure CreateRuntimeControls;
procedure OnTimer(Sender: TObject);
procedure OnButtonClick(Sender: TObject);
procedure OnQuit(Sender: TObject);
public
// Public declarations
end;
// Color constants
const
clrEnabled: Array [False..True] of TColor = (clBtnFace, clWindow);
// Global form variable
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.UpdateState(AllowLo
begin
// Update the controls state
FUserID.Enabled:=AllowLogi
FPassword.Enabled:=AllowLo
FUserID.Color:=clrEnabled[
FPassword.Color:=clrEnable
FLogin.Enabled:=AllowLogin
end;
procedure TForm1.OnButtonClick(Sende
begin
// Check values
if (FUserID.Text = EmptyStr) then
ShowMessage('UserID required...')
else if (FPassword.Text = EmptyStr) then
ShowMessage('Password required...')
else
begin
// Perform the login
if PerformLogin(FUserID.Text,
begin
// Disable state
FTimer.Enabled:=False;
try
// Disable state
UpdateState(False);
// Let the process start
while (FEvents.WebObj.ReadyState
// Wait until the login has completed
while FEvents.Connected and (FEvents.WebObj.ReadyState
begin
// Wait until the submission has finished (or the user closes the IE window)
Application.ProcessMessage
end;
// Check state of web browser interface
if not(FEvents.Connected) or CanLogin(FEvents.WebObj.Do
// Failed to login
ShowMessage('Failed to log in')
else
// Logged in
ShowMessage('Logged in...');
finally
// Disconnect
FEvents.Disconnect;
// Re-enable timer
FTimer.Enabled:=True;
end;
end;
end;
end;
procedure TForm1.OnQuit(Sender: TObject);
begin
// Disconnect from interface
FEvents.Disconnect;
// Update state
UpdateState(False);
end;
procedure TForm1.OnTimer(Sender: TObject);
begin
// Timer event
if not(FEvents.Connected) then UpdateState(CanLoginAny);
end;
function TForm1.PerformLogin(UserID
var pvShell: IShellWindows;
pvWeb2: IWebBrowser2;
ovIE: OleVariant;
ovDoc2: OleVariant;
ovElement: OleVariant;
ovInput: OleVariant;
ovPassword: OleVariant;
ovSubmit: OleVariant;
dwCount: Integer;
dwFrames: Integer;
dwIndex: Integer;
bSubmit: Boolean;
begin
// Set default result
result:=False;
// Create the shell windows interface
pvShell:=CoShellWindows.Cr
try
// Walk the internet explorer windows
for dwCount:=0 to Pred(pvShell.Count) do
begin
// Get the interface
ovIE:=pvShell.Item(dwCount
// QI for the IWebBrowser2
if (IDispatch(ovIE).QueryInte
begin
// Make sure it is ready
if not(pvWeb2.Offline) and (pvWeb2.ReadyState = READYSTATE_COMPLETE) then
begin
// Check for elements in page
if Assigned(pvWeb2.Document) then
begin
// Set defaults
ovInput:=Unassigned;
ovPassword:=Unassigned;
ovSubmit:=Unassigned;
// Get the document object
ovDoc2:=pvWeb2.Document;
try
// Walk the frames
for dwFrames:=0 to ovDoc2.Forms.Length-1 do
begin
// Walk elements
for dwIndex:=0 to ovDoc2.Forms.Item(dwFrames
begin
// Get element
ovElement:=ovDoc2.Forms.It
// Check input
if (CompareText(String(ovElem
begin
// Check input
if (CompareText(String(ovElem
// Get input
ovInput:=ovElement
// Check password
else if (CompareText(String(ovElem
// Set password
ovPassword:=ovElement
// Check for submit
else if (Pos(LowerCase('submit'), LowerCase(String(ovElement
begin
// Must be in the same context as user/password (eg, don't falsely pick up a search button)
if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then
begin
// Have submit
ovSubmit:=ovElement;
end;
end;
end;
// Release element
ovElement:=Unassigned;
// Do we have all elements?
if (VarType(ovInput) > varEmpty) and
(VarType(ovPassword) > varEmpty) and
(VarType(ovSubmit) > varEmpty) then
begin
// Connect to the interface
FEvents.ConnectTo(pvWeb2);
// Submit
ovInput.Value:=UserID;
ovPassword.Value:=Password
ovSubmit.Click;
// Set result
result:=True;
// Break
break;
end;
end;
// If success then break
if result then break;
end;
finally
// Clear refs
ovInput:=Unassigned;
ovPassword:=Unassigned;
ovSubmit:=Unassigned;
ovDoc2:=Unassigned;
end;
end;
end;
// Release the interface
pvWeb2:=nil;
end;
// Clear the variant
ovIE:=Unassigned;
// If success then break
if result then break;
end;
finally
// Release the interface
pvShell:=nil;
end;
end;
function TForm1.CanLogin(Browser: OleVariant): Boolean;
var ovElement: OleVariant;
ovInput: OleVariant;
ovPassword: OleVariant;
dwCount: Integer;
dwFrames: Integer;
dwIndex: Integer;
begin
// Set default result
result:=False;
// Walk the frames
for dwFrames:=0 to Browser.Forms.Length-1 do
begin
// Clear state
ovInput:=Unassigned;
ovPassword:=Unassigned;
// Walk elements
for dwIndex:=0 to Browser.Forms.Item(dwFrame
begin
// Get element
ovElement:=Browser.Forms.I
// Check input
if (CompareText(String(ovElem
begin
// Check input
if (CompareText(String(ovElem
// Have input
ovInput:=ovElement
// Check password
else if (CompareText(String(ovElem
// Have password
ovPassword:=ovElement;
end;
// Release element
ovElement:=Unassigned;
// Break if we have both password and input
if (VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty) then break;
end;
// Check elements
result:=(VarType(ovInput) > varEmpty) and (VarType(ovPassword) > varEmpty);
// Release refs
ovInput:=Unassigned;
ovPassword:=Unassigned;
// Break is success
if result then break;
end;
end;
function TForm1.CanLoginAny: Boolean;
var pvShell: IShellWindows;
pvWeb2: IWebBrowser2;
ovIE: OleVariant;
ovDoc2: OleVariant;
dwCount: Integer;
begin
// Set default result
result:=False;
// Create the shell windows interface
pvShell:=CoShellWindows.Cr
try
// Walk the internet explorer windows
for dwCount:=0 to Pred(pvShell.Count) do
begin
// Get the interface
ovIE:=pvShell.Item(dwCount
// QI for the IWebBrowser2
if (IDispatch(ovIE).QueryInte
begin
// Make sure it is ready
if not(pvWeb2.Offline) and (pvWeb2.ReadyState = READYSTATE_COMPLETE) then
begin
// Check for elements in page
if Assigned(pvWeb2.Document) then
begin
// Get the document object
ovDoc2:=pvWeb2.Document;
try
// See if we can login to the page
result:=CanLogin(ovDoc2);
finally
// Clear document
ovDoc2:=Unassigned;
end;
end;
end;
end;
// Release the interface
pvWeb2:=nil;
// Clear the variant
ovIE:=Unassigned;
// If success then break
if result then break;
end;
finally
// Release the interface
pvShell:=nil;
end;
end;
procedure TForm1.CreateRuntimeContro
begin
// Create IE event handler
FEvents:=TIEEvents.Create(
FEvents.OnQuit:=OnQuit;
// Create login button
FLogin:=TButton.Create(Sel
with FLogin do
begin
Parent:=Self;
SetBounds(8, 8, 73, 25);
Caption:='Login';
OnClick:=OnButtonClick;
Visible:=True;
end;
// Create user id label
with TLabel.Create(Self) do
begin
Parent:=Self;
SetBounds(100, 12, 60, 13);
Caption:='User ID:';
Visible:=True;
end;
// Create password label
with TLabel.Create(Self) do
begin
Parent:=Self;
SetBounds(100, 36, 60, 13);
Caption:='Password:';
Visible:=True;
end;
// Create user id entry field
FUserID:=TEdit.Create(Self
with FUserID do
begin
Parent:=Self;
SetBounds(164, 8, 197, 21);
Text:=EmptyStr;
Visible:=True;
end;
// Create password entry field
FPassword:=TEdit.Create(Se
with FPassword do
begin
Parent:=Self;
SetBounds(164, 32, 197, 21);
Text:=EmptyStr;
PasswordChar:='*';
Visible:=True;
end;
// Create timer
FTimer:=TTimer.Create(Self
with FTimer do
begin
Parent:=Self;
Interval:=500;
Enabled:=True;
OnTimer:=Self.OnTimer;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Set caption
Caption:='Login to IE';
// Set bounds
SetBounds((Screen.Width-40
// Create run time controls
CreateRuntimeControls;
// Update state (don't allow login yet)
UpdateState(False);
end;
end.
Hello Russell;
Trying to compile the demo now.
I am getting the following errors.
Undescaired Identifier [Unassigned];
I added this in the Global Var
Unassigned: OleVariant;
So both of them are now Assigned, without adding it into each Function.
Now I have this error:
Undeclaired Identifier: [VarType];
I tried to add this:
VarType : TVarType;
Then I tried
VarType: Variant;
And both compile through, But then give these Errors:
Missing operator or simicolon;
9 places
All basically the same
(VarType(ovInput)
The the "ovPassword" & so on.
Any idea's?
By the way, I use "Delphi 6.02 Pro." under Win2k Pro SP3
Wayne
Trying to compile the demo now.
I am getting the following errors.
Undescaired Identifier [Unassigned];
I added this in the Global Var
Unassigned: OleVariant;
So both of them are now Assigned, without adding it into each Function.
Now I have this error:
Undeclaired Identifier: [VarType];
I tried to add this:
VarType : TVarType;
Then I tried
VarType: Variant;
And both compile through, But then give these Errors:
Missing operator or simicolon;
9 places
All basically the same
(VarType(ovInput)
The the "ovPassword" & so on.
Any idea's?
By the way, I use "Delphi 6.02 Pro." under Win2k Pro SP3
Wayne
Add Variants to the uses clause; Borland split the variant routines after D5 into their own unit.
uses
...., Variants;
Russell
When the program runs, I see the form and controls on it.
I have IE loaded with the login page of EE opened.
Then I receive the following Error:
-------------------------- -
Debugger Exception Notification
-------------------------- -
Project Project1.exe raised exception class EOleError with message 'Method 'Forms' not supported by automation object'. Process stopped. Use Step or Run to continue.
-------------------------- -
OK Help
-------------------------- -
Lands on line 249:
for dwFrames:=0 to Browser.Forms.Length-1 do
Then [F7] to line 322:
ovDoc2:=Unassigned;
Then line 336:
pvShell:=nil
I have IE loaded with the login page of EE opened.
Then I receive the following Error:
--------------------------
Debugger Exception Notification
--------------------------
Project Project1.exe raised exception class EOleError with message 'Method 'Forms' not supported by automation object'. Process stopped. Use Step or Run to continue.
--------------------------
OK Help
--------------------------
Lands on line 249:
for dwFrames:=0 to Browser.Forms.Length-1 do
Then [F7] to line 322:
ovDoc2:=Unassigned;
Then line 336:
pvShell:=nil
What version of IE....
5.5 on my Main Programming System.
I will take it over and test it on my other system running IE6Sp1
I will take it over and test it on my other system running IE6Sp1
Will not run on versions under IE6.
But works like a charm on IE6
Do you know what I could do to make it work under IE5.5 ?
Thank you so very much for the code.
I will post a 500-point question here in a few, and provide the link in here.
Wayne
But works like a charm on IE6
Do you know what I could do to make it work under IE5.5 ?
Thank you so very much for the code.
I will post a 500-point question here in a few, and provide the link in here.
Wayne
Wayne,
You can try replacing "forms" with the word "frames", but I don't have pre IE 6.x to test on, so I can't really say for sure.
I am glad that it worked ok on v6 though...
Also sorry for the Delphi mixup with variants; its a little annoying that borland split the routines out, because it does cause confusion with d5/d6&d7 examples. (I coded this on D5)
Regards,
Russell
You can try replacing "forms" with the word "frames", but I don't have pre IE 6.x to test on, so I can't really say for sure.
I am glad that it worked ok on v6 though...
Also sorry for the Delphi mixup with variants; its a little annoying that borland split the routines out, because it does cause confusion with d5/d6&d7 examples. (I coded this on D5)
Regards,
Russell
D5, have not used that one in a while.
D5 was when I first started on Delphi.
Cannot wait to see the new "D9" that is coming out,
The "Demo Video" looks pretty cool.
C#, .NET, Win32
All wrapped into one HUGE Program.
Here is the points for you,
I also added in the Code provided here, with the compiling changes.
For others to see and use and abuse and so on and on and on ;-)
https://www.experts-exchange.com/questions/21216625/Points-for-rllibby-Login-to-IE-Instance-without-TWebBrowser-Straight-IE-Interface.html
Thank you once again.
Wayne
D5 was when I first started on Delphi.
Cannot wait to see the new "D9" that is coming out,
The "Demo Video" looks pretty cool.
C#, .NET, Win32
All wrapped into one HUGE Program.
Here is the points for you,
I also added in the Code provided here, with the compiling changes.
For others to see and use and abuse and so on and on and on ;-)
https://www.experts-exchange.com/questions/21216625/Points-for-rllibby-Login-to-IE-Instance-without-TWebBrowser-Straight-IE-Interface.html
Thank you once again.
Wayne
Lol, I still remember programming on D1..... a long time ago.
I will keep an eye/ear out for latest release of "our" favorite language; until next time, happy coding ;-)
Kind regards,
Russell
Check this out, just in case you have not seen it yet.
http://info.borland.com/media/shockwave/delphi2005/d2005sneak.html
take Care
Wayne
http://info.borland.com/media/shockwave/delphi2005/d2005sneak.html
take Care
Wayne
In any case, no method is going to be 100% reliable because of the actual definition of "time to load a page" - do you include images, scripts, etc? Do you include the time to format and show large pages? Pop-ups?
Geoff M.