Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Programmatic clicking and new windows

19 views
Skip to first unread message

Csaba Gabor

unread,
Jan 11, 2008, 1:21:32 PM1/11/08
to
Subject to the popup blocker, the code below will bring up
two instances of IE. The first one is identified by the
variable ie below. What is the cleanest way to get
ahold of the second one that gets created in the
last line (lnk.click)?

Also, is there a cleaner way to force ie to bring
up the new page in a new IE besides modifying
the DOM (by putting in lnk.target = "_blank")?
What I'm getting at by this is a possible snythetic
click.

Thanks for any ideas,
Csaba Gabor from Vienna

PS. I know that I can explicitly create an IE and then
tell it to Navigate2 to site implied by the lnk.href,
but I'd rather have IE do the work for me.

Set ie=CreateObject("InternetExplorer.Application")
ie.visible=true
ie.Navigate2 ("about:blank")
While ie.ReadyState<4: WScript.Sleep 200: Wend

demoPage = _
"<a id=mylink href='http://google.com'>foo</a>"

ie.document.body.innerHTML = demoPage
Set lnk = ie.document.getElementById("mylink")
lnk.target = "_blank"
lnk.Click

mr_unreliable

unread,
Jan 11, 2008, 3:20:29 PM1/11/08
to

Csaba Gabor wrote:
> Subject to the popup blocker, the code below will bring up
> two instances of IE. The first one is identified by the
> variable ie below. What is the cleanest way to get
> ahold of the second one that gets created in the
> last line (lnk.click)?
>

hi Csaba,

You might be able to use the "shell.application" to do
what you want. You can search through the window objects
and find the instances of IE, and then use the document
title to find the specific instance you want.

Here is a script that illustrates this (not exactly, but
close enough).

--- <code> ---
' extract the (body part) html, from a running IE Window, jw 11 June 05
Option Explicit

' cHTML := ctlWebBrowser1:Document:All:Item(0):outerHTML
' document.documentElement.outerHTML will give you the html as IE renders it

Dim oShellApp : Set oShellApp = CreateObject("Shell.Application")
Dim oShellAppWindows : Set oShellAppWindows = oShellApp.Windows
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1, ForWriting = 2
' --- end of instantiations ----------------------

Dim oWin ' as window object
Dim sBody ' as string

Const sOutFileName = "source"
Dim oOutFile ' as file object
' construct output filespec...
Dim oSH : Set oSH = WScript.CreateObject("WScript.Shell")
Dim oEnv : Set oEnv = oSH.Environment("PROCESS")
Dim sTmpPath : sTmpPath = oEnv("TEMP") & "\"
Set oSH = nothing
Set oEnv = nothing
Dim sOutFileSpec

Dim i : i = 0 ' file index

for each oWin in oShellAppWindows
MsgBox(Typename(oWin.document))
if LCase(Typename(oWin.document)) = "htmldocument" then

msgbox("location(url): " & oWin.document.location) ' window name
sBody = oWin.document.body.innerHTML

i = i + 1 ' bump index
sOutFileSpec = sTmpPath & sOutFileName & CStr(i) & ".htm"
' open output file...
Set oOutFile = fso.CreateTextFile(sOutFileSpec, True) ' allow
overwrite...
oOutFile.Write(sBody)
oOutFile.Close
End If
Next ' oWin

set oShellAppWindows = nothing
set oShellApp = nothing
Set fso = nothing
--- </code> ---

As you see, look through the windows for type "htmldocument".
Then look for the title. You also have access to the doc
object model for each IE window.

cheers, jw
____________________________________________________________

You got questions? WE GOT ANSWERS!!! ..(but,
no guarantee the answers will be applicable to the questions)

mr_unreliable

unread,
Jan 11, 2008, 3:38:26 PM1/11/08
to
Aside from the shell.application approach, there is a vb-centric
approach by Eduardo Anthony Morcillo, entitled: "How to get
the DOM of a WebBrowser control from a window handle",
found here:

http://www.mvps.org/emorcillo/en/code/vb6/iedom.shtml

So from vb, enum the windows, then get the window handle of
the IE window you want from the title (a.k.a. "the caption"),
work down to the webbrowser window, get THAT handle, and then
use the handle with Edanmo's code to get the dom.

cheers, jw

Csaba Gabor

unread,
Jan 14, 2008, 10:49:48 PM1/14/08
to
On Jan 11, 9:20 pm, mr_unreliable <kindlyReplyToNewsgr...@notmail.com>
wrote:

> Csaba Gabor wrote:
> > Subject to the popup blocker, the code below will bring up
> > two instances of IE. The first one is identified by the
> > variable ie below. What is the cleanest way to get
> > ahold of the second one that gets created in the
> > last line (lnk.click)?
>
> hi Csaba,
>
> You might be able to use the "shell.application" to do
> what you want. You can search through the window objects
> and find the instances of IE, and then use the document
> title to find the specific instance you want.
>
> Here is a script that illustrates this (not exactly, but
> close enough).
...
Example script
...

> As you see, look through the windows for type "htmldocument".
> Then look for the title. You also have access to the doc
> object model for each IE window.
>
> cheers, jw
> ____________________________________________________________
>
> You got questions? WE GOT ANSWERS!!! ..(but,
> no guarantee the answers will be applicable to the questions)

Hi jw,
Thanks for your thoughts, here's a follow up. I am
aware of your approach of iterating through
Set Wins = CreateObject("Shell.Application").Windows
In fact, Eduardo's code would be simplified, methinks,
(and doable in VBScript) if he just compared the hwnd
property of each window within Wins.
The trouble is that neither approach is iron clad.

I found an ancient thread which gave the recommended way at
http://groups.google.com/group/microsoft.public.vb.general.discussion/browse_frm/thread/ada57def698a129/
in RND's last post: he used IE's NewWindow2 event (there
is also NewWindow3). Now this is sort of a funny sort of
creature - the event handler wants its first argument set
to a newly created IE to override the default IE that would
be created. Unfortunately, VBScript can't pass the
modified ByRef argument. So you can watch it, and know
it's about to happen, but you can't do anything about it.

However, PHP is able to work with this event handler
(sort of) and it works. Unfortunately, PHP has a bug
as far as I can tell in setting the (first arg's object) value.
Somewhere in the process they corrupt the variable (the
new IE object), but by then I've got its hwnd (ha ha),
so it is no longer able to hide from me. The problem is
that after running beautifully, this little copying maneuvre
prevents PHP from quitting gracefully - I get a nasty error
each time, presumably reference counts are messed up.
So all I hope is that a developer responds to the bug
report I made.

Regards,
Csaba

Csaba Gabor

unread,
Jan 15, 2008, 8:28:59 AM1/15/08
to
> I found an ancient thread which gave the recommended way athttp://groups.google.com/group/microsoft.public.vb.general.discussion...

> in RND's last post: he used IE's NewWindow2 event (there
> is also NewWindow3). Now this is sort of a funny sort of
> creature - the event handler wants its first argument set
> to a newly created IE to override the default IE that would
> be created. Unfortunately, VBScript can't pass the
> modified ByRef argument. So you can watch it, and know
> it's about to happen, but you can't do anything about it.
>
> However, PHP is able to work with this event handler
> (sort of) and it works. Unfortunately, PHP has a bug
> as far as I can tell in setting the (first arg's object) value.
> Somewhere in the process they corrupt the variable (the
> new IE object), but by then I've got its hwnd (ha ha),
> so it is no longer able to hide from me. The problem is
> that after running beautifully, this little copying maneuvre
> prevents PHP from quitting gracefully - I get a nasty error
> each time, presumably reference counts are messed up.
> So all I hope is that a developer responds to the bug
> report I made.
>
> Regards,
> Csaba

Just a quick followup. I have found a way to terminate
my php program without it complaining. I get its
process id ($pid=getmypid()) and then I forcefully
kill it on my Win XP system with:
exec ("taskkill /F /PID $pid"); or to write it as vbscript:
CreateObject("WScript.Shell").Exec("taskkill /F /PID " & pid)

I hope they fix the bug,
Csaba

mr_unreliable

unread,
Jan 15, 2008, 12:48:16 PM1/15/08
to
hi Casba,

Nothing you do is ever simple.

I suppose you have seriously complicated projects,
that require seriously complicated solutions.

Or, are you the sort of person who delights in
complications?

cheers, jw

Csaba Gabor

unread,
Jan 15, 2008, 1:44:45 PM1/15/08
to
On Jan 15, 6:48 pm, mr_unreliable <kindlyReplyToNewsgr...@notmail.com>
wrote:

> hi Casba,
>
> Nothing you do is ever simple.

Well, by the time I get around to asking about it,
I have 98% of the time done my level best to figure
out a solution so only the hard stuff is left. The
other 2% I pie-in-the-sky it, and hope the question
is trivial.

> I suppose you have seriously complicated projects,
> that require seriously complicated solutions.

Actually, I usually want to do reasonable things.
In this case, I want to sequence IE (that is to say,
I want to tell it to go to page 1 (say to Google),
when it has made sufficient progress, muck with
the page (for example, fill in a search term, identify
a button to click), then initiate the next navigation
action. When that page loading has resulted in
sufficient progress, do the next thing that needs
doing (e.g. identify the search results) and so on.
Perfectly reasonable.

One could, of course, scrape the page. Yuucch!
Furthermore, if a page uses javascript, it may
not be possible to reasonably scrape it.
So I would like to use a live IE so I have access
to the DOM, and do it on an event driven basis
(that way I could do concurrent requests for
example, and be more efficient). All perfectly
reasonble to want.

And all this was working fine. By hooking
the DownloadComplete, DocumentComplete,
OnReadyStateChange, and NavigateComplete2
events I can monitor navigation progress quite
well, thank you very much. In fact, even the
timeouts are event driven (ie. If the page hasn't
loaded in 75 seconds, then execute such and
such a function. Specifically, I have written a
timer function which is called like so:
timer(75000, "timeoutFunction")). The only
loop is at the end of the vbscript file to
prevent termination of the main vbscript.
The scripts fly, and life was good.
Even if it was non trivial.

Then I realized that somebody could have a
target=_blank in a link or form. Or even that I
might want to have it for my own purposes.
So there you have it, another perfectly reasonable
thing to want to do in an already perfectly
reasonable app. Of course the trick is to
find the new IE and hook it up to the event
handlers, and oh yea, better tell those event
handlers what to do when sufficient navigation
progress has been made. Suddenly, the
complexity has escalated quite a bit (for
example, this means that I have to hook in
new event handlers within executing event
handlers).

> Or, are you the sort of person who delights in
> complications?

Um, ... sometimes. Been known to happen.
Actually, I delight most in simple solutions.

> cheers, jw

PS. You're one to talk. Who do you think I
learned many of my VBScript methods from?
:)

Best regards,
Csaba

mayayana

unread,
Jan 15, 2008, 2:23:20 PM1/15/08
to
> The trouble is that neither approach is iron clad.
>
What do you mean that it's not iron clad? I've never
heard of an IE instance not showing up in the
Shell.windows collection.

> I found an ancient thread which gave the recommended way at
>
http://groups.google.com/group/microsoft.public.vb.general.discussion/browse
_frm/thread/ada57def698a129/

Unfortunately, I can't see your link. It's loading a blank
Google groups page with no entries for me.

Csaba Gabor

unread,
Jan 15, 2008, 4:23:21 PM1/15/08
to
On Jan 15, 8:23 pm, "mayayana" <mayaXXyan...@mindXXspring.com> wrote:
> > The trouble is that neither approach is iron clad.
>
> What do you mean that it's not iron clad? I've never
> heard of an IE instance not showing up in the
> Shell.windows collection.

As you say, as far as I know, IE will show up in the
Shell.windows collection unless you instantiate it within
a web server context. But my discussion is not meant to
involve servers, so that aspect should be OK. That's not
what I was referring to, however.

The issue is that of tieing the newly created IE to info
destined for it. That is, let's suppose I have some data
I want to "transfer" to this new IE (such as which function
should execute when sufficient navigational progress has
been made, and for that matter what 'sufficient' means
on this particular invocation). In that case, I need to
identify that the newly created IE is indeed the one I want.

I don't have an hWnd at the time that the new IE is about
to be created (when in NewWindow2). Now you might
suggest that I cycle through all the existing Shell
windows noting each hwnd, So the new IE will clearly
be one with a different hWnd. However, there may be
multiple IE's getting created at about the same time, so
this approach is not guaranteed (is not ironclad) to yield
only one new hWnd. Similar comments apply to
stricter criteria such as matching titles or even (I'm not
sure if it's possible) referer. Even the fact that they
come from the same 'parent' would not be suficcient
since the info that needs to transferred is specific to
an instance invoked.

> > I found an ancient thread which gave the recommended way at
>

> http://groups.google.com/group/microsoft.public.vb.general.discussion...


> _frm/thread/ada57def698a129/
>
> Unfortunately, I can't see your link. It's loading a blank
> Google groups page with no entries for me.

Sorry about that - it's due to wrapping. Copy everything from
'http' through to 'discussion' and append to that the following
text starting with the underscore:
_frm/thread/ada57def698a129/
(The thread is in microsoft.public.vb.general.discussion
titled: HWND of an IE Window Opened via Javascript
started by RMD (not RND) on Jun 6, 2003).

mayayana

unread,
Jan 15, 2008, 7:45:17 PM1/15/08
to
> I don't have an hWnd at the time that the new IE is about
> to be created (when in NewWindow2). Now you might
> suggest that I cycle through all the existing Shell
> windows noting each hwnd, So the new IE will clearly
> be one with a different hWnd. However, there may be
> multiple IE's getting created at about the same time, so
> this approach is not guaranteed (is not ironclad) to yield
> only one new hWnd. Similar comments apply to
> stricter criteria such as matching titles or even (I'm not
> sure if it's possible) referer. Even the fact that they
> come from the same 'parent' would not be suficcient
> since the info that needs to transferred is specific to
> an instance invoked.
>

I see what you mean. I suppose you could do something
like send each new IE to a local, custom homepage before
sending it on. That way you could always just look for
which IE instance has that local homepage as title.
That's kind of clunky, though.

> > > I found an ancient thread which gave the recommended way at
> >
> > http://groups.google.com/group/microsoft.public.vb.general.discussion...
> > _frm/thread/ada57def698a129/
> >
> > Unfortunately, I can't see your link. It's loading a blank
> > Google groups page with no entries for me.
>
> Sorry about that - it's due to wrapping.

The wrapping wasn't a problem. It just didn't load
anything. And when I look at the source there's
nothing in there, either. I don't know what might cause
that. Google groups work fine for me if I just go to the
current postings.

Csaba Gabor

unread,
Jan 15, 2008, 8:53:42 PM1/15/08
to
On Jan 16, 1:45 am, "mayayana" <mayaXXyan...@mindXXspring.com> wrote:
> > I don't have an hWnd at the time that the new IE is about
> > to be created (when in NewWindow2). Now you might
> > suggest that I cycle through all the existing Shell
> > windows noting each hwnd, So the new IE will clearly
> > be one with a different hWnd. However, there may be
> > multiple IE's getting created at about the same time, so
> > this approach is not guaranteed (is not ironclad) to yield
> > only one new hWnd. Similar comments apply to
> > stricter criteria such as matching titles or even (I'm not
> > sure if it's possible) referer. Even the fact that they
> > come from the same 'parent' would not be suficcient
> > since the info that needs to transferred is specific to
> > an instance invoked.
>
> I see what you mean. I suppose you could do something
> like send each new IE to a local, custom homepage before
> sending it on. That way you could always just look for
> which IE instance has that local homepage as title.
> That's kind of clunky, though.

I'm not sure I follow you. How do you get each new IE to
go to a distinct custom home page (essentially you
could set it to about:blank and generate a sequential
series for the Title)? That is to say, how do you get
ahold of it, and then match it to receive the actual
intended navigation?

Anyway, what I first thought of when I read your idea
was the BeforeNavigate2 event, with which one can play fun
little games. By the way, this is one of the first events
to fire after the NewWindow2 event and the first argument
contains the new IE! Of course to hook this event handler
you already would need to have the new IE in NewWindow2
(unless you are able to hook all IEs, in which case most
of this discussion is moot).


> > > > I found an ancient thread which gave the recommended way at
>
> > >http://groups.google.com/group/microsoft.public.vb.general.discussion...
> > > _frm/thread/ada57def698a129/
>
> > > Unfortunately, I can't see your link. It's loading a blank
> > > Google groups page with no entries for me.
>
> > Sorry about that - it's due to wrapping.
>
> The wrapping wasn't a problem. It just didn't load
> anything. And when I look at the source there's
> nothing in there, either. I don't know what might cause
> that. Google groups work fine for me if I just go to the
> current postings.

Unfortunately, the link that I described in my previous post
was off (it worked, sort of, in the original). So here it is as
regular text (I hope). Just concatenate the following 4 lines
into one:

http://
groups.google.com/
group/microsoft.public.vb.general.discussion/
browse_frm/thread/ada57def698a129/

mayayana

unread,
Jan 16, 2008, 12:36:14 AM1/16/08
to
>
> I'm not sure I follow you. How do you get each new IE to
> go to a distinct custom home page (essentially you
> could set it to about:blank and generate a sequential
> series for the Title)? That is to say, how do you get
> ahold of it, and then match it to receive the actual
> intended navigation?
>

On the new window part, I haven't tried this, but according
to the docs you can use Navigate's 1 flag to open in a new
window:

Set ie=CreateObject("InternetExplorer.Application")
ie.visible=true
ie.Navigate2 ("about:blank")
While ie.ReadyState<4: WScript.Sleep 200: Wend

ie.Navigate "http://www.google.com", 15

(I usually use the other flags to avoid involving
IE history and cache, but 1 is the only flag needed
for a new window.)

But there seems to be no way to get passed the
IE object for the new window.

I'm afraid I really don't understand exactly what you're
doing... or why just creating an IE instance is not adequate...
or why you need access during first page load...
So I'd better quit now before I waste your time. :)
I don't think that I can add anything useful.

> Unfortunately, the link that I described in my previous post
> was off (it worked, sort of, in the original). So here it is as
> regular text (I hope). Just concatenate the following 4 lines
> into one:
>
> http://
> groups.google.com/
> group/microsoft.public.vb.general.discussion/
> browse_frm/thread/ada57def698a129/

Thanks for trying, but I got the link fine. Your link worked
the first time and the second. I arrived at Google Groups.
And there was the treeview box on the left, with the main center
area for posts and the box of links on the right. It's just
that they're all empty! I have no idea why. The source code
was too much of a mess to try to figure out what's wrong.

0 new messages