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
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)
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
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
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
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
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
> 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.
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).
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.
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/
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.