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

ShDocVw.ShellWindows vs. CreateObject("Shell.Application").Windows

1,761 views
Skip to first unread message

Csaba Gabor

unread,
Aug 19, 2005, 11:23:04 AM8/19/05
to
About two years back, Notre Poubelle was looking for a way to get ahold
of ShDocVw.ShellWindows via script. Now ignoring the fact that it is
essentially identical to CreateObject("Shell.Application").Windows,
this is an interesting problem because the class id was known, but that
was all.

There was a clever idea by Alexander Mueller, which was tested out,
that maybe it was possible to use IE for this, but it failed because of
the security blanket that IE surrounded the object with. However,
here's a working solution, which extends the original idea. The key
idea is that after having IE create the object, we take it away from IE
so the security restrictions will no longer exist. Even if it wasn't
clear to IE that our app could freely muck with it, it should be clear
to everybody that our VB app/script is free to go about it's own
business on its own time.


Dim ie, Tname, oWins, win, text
Set ie=CreateObject("InternetExplorer.Application")
ie.Navigate2("about:blank")
ie.Document.open
ie.Document.write "<object id=sw classid='clsid:" & _
"9BA05972-F6A8-11CF-A442-00A0C90A8F39'></object>"
ie.Document.close
Set oWins = ie.document.parentWindow.sw 'transfer object
ie.Document.parentWindow.execScript "window.sw=null" 'paranoia
ie.quit 'more of same
msgbox "oWins: " & typename(oWins)
'This loop prints out something on each instance of IE / Explorer
For each win in oWins
Tname = typename(win.document)
if mid(Tname,1,12)="HTMLDocument" Then
text = win.document.title
if text<>"" then text = "Title: " & text & vbCrLF
MsgBox text & "url: " & win.document.location
Else
MsgBox "Folder: " & win.locationURL
End If
Next

This code was adapted from:
http://groups.google.com/group/microsoft.public.scripting.jscript/browse_frm/thread/cb42d8b604de28eb/


The reason I said ShDocVw.ShellWindows was essentially the same as
CreateObject("Shell.Application").Windows was because of hooking event
handlers up. For example, in a VB project, if I do
Dim WithEvents ogSW As SHDocVw.ShellWindows
Set ogSW = New SHDocVw.ShellWindows
then I can receive events of IE/Explorer creations/destruction via:
Private Sub ogSW_WindowRegistered(ByVal lCookie As Long)
and
Private Sub ogSW_WindowRevoked(ByVal lCookie As Long)
but this approach does not work with the other.

Enjoy,
Csaba Gabor from Vienna

mr_unreliable

unread,
Aug 19, 2005, 12:02:05 PM8/19/05
to
hi Csaba from Vienna,

Always a pleasure to read about your side-trips into scripting exotica.

cheers, jw

mr_unreliable

unread,
Aug 22, 2005, 4:27:37 PM8/22/05
to
Csaba, you don't need to take a side-trip thru IE to get at
the IShellWindows interface.

You may get at it directly (or any other object not having
a progid), by using the wsf file format, and specifying your
object tag that way.

cheers, jw
____________________________________________________________

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

p.s. the attached script's extension was changed to txt,
to avoid that slanderous diagnostic "Malicious Script Detected".

wshUsingWSFObjectTag_toInstantiate_IShellWindows.wsf.txt

Csaba Gabor

unread,
Aug 23, 2005, 10:54:18 AM8/23/05
to
mr_unreliable wrote:
> Csaba, you don't need to take a side-trip thru IE to get at
> the IShellWindows interface.
>
> You may get at it directly (or any other object not having
> a progid), by using the wsf file format, and specifying your
> object tag that way.

Hi JW,

Thanks for that .wsf example. But is there anyway to move that
"header stuff" into a .vbs file? The reason that I ask is that the
stuff I am doing now is mainly for MSScriptControl.ScriptControl (and
as I understand it, I can't add objects as you are declaring with your
<objects ...> tag).

Csaba

mr_unreliable

unread,
Aug 23, 2005, 12:05:44 PM8/23/05
to
Csaba, since you are now mentioning the script control, I am
going to assume that the host language is visual basic (or
more specifically "classic" vb5 or vb6)...

If that is the case, then you don't need scripting (or IE) to
instantiate your object, you can do it in vb, and then pass
that reference into the script control for use by your script.

First off, set a reference in your vb project to the
shdocvu.dll.

Then this is the code you will need to pass the
(IShellWindows interface) object into the script
control:

--- <snip> ---
Dim oSDV As SHDocVw.ShellWindows

' create a reference to the IShellWindows interface...
Set oSDV = New SHDocVw.ShellWindows

' pass the reference(s) into the script control...
scScript.AddObject "IShellWindows", oSDV, True
--- </snip> ---

From then on you should be able to use the "oSDV" object
in your script by referring to it as "IShellWindows",
just as if you had created it yourself (er, created it in
the script, that is).

Or, if you find "IShellWindows" too lengthy, you could
use something more simple and direct, such as "oWins"...

cheers, jw
____________________________________________________________

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

Csaba Gabor

unread,
Aug 23, 2005, 3:23:10 PM8/23/05
to
mr_unreliable wrote:
> Csaba, since you are now mentioning the script control, I am
> going to assume that the host language is visual basic (or
> more specifically "classic" vb5 or vb6)...

Sorry, JW. My Bad. I am using the MSScriptControl from PHP. Example:

<?php
$script = new COM("MSScriptControl.ScriptControl");
$script->language = "VBScript";
$script->eval('MsgBox ("Hi Mom")');
?>


I guess I should backup. This post is sort of a side branch to a side
branch of my main problem, but it was interesting in and of its own
right so I figured it merited a post.

Here's the real deal (which may get its own separate post as my
frustration mounts), but just in case...

I've got a Web server (Apache 2.0.53 / PHP 5.1 as module / Win XP Pro,
SP 2). When a request for a certain page comes in, I want to be able
to loop through all instances of IE. The reason for that is that
there's going to be a PHP program running the background and its going
to have a huge data structure in memory and the idea is for the server
PHP scripts (hereafter referred to as CGI PHP even though it is hooked
into Apache as a module) to be able to access the resident PHP script
directly. Now the glue for connecting these two (the resident CLI
(command line) PHP and the server/CGI PHP) is IE. [Note that in the
context of the scenario I am outlining, the resident/CLI PHP is the
data server, while the CGI PHP that runs upon a web request is actually
the client to the data server. However, I will continue to use the
term CLI/resident and CGI PHP to minimize the confusion from the double
use of web/data server/client]

If I use two (or more) instances of CLI php, everyone is happy, the
process works nicely. I have a demo where each CLI PHP instance brings
up its own associated instance of IE (based on a common base title).
Everybody (that is, all the IE's and hence their associated PHPs) finds
each other and as you type anything in any such instance of IE, all the
other instances immediately reflect it. Nifty. Of course the way that
the IEs find each other is through
CreateObject("Shell.Application").Windows

This does not work when one of the PHP instances (we're back to two
now) is a web server script (CGI PHP). Specifically, there ought to be
two ways to connect the two instances of IE. Either the CGI PHP script
should be able to see the (resident) CLI php's IE (via wsCGI =
CreateObject("Shell.Application").Windows) or the CLI PHP should get a
notification of the creation of the CGI PHP's IE =
CreateObject("InternetExplorer.Application") by hooking the
WindowRegistered event of wsCLI =
CreateObject("Shell.Application").Windows

When you try it, the CGI PHP silently fails in looping through the
windows. Furthermore, even though an IE object is created by the CGI
PHP it never registers itself with the shell so that the event in CLI
PHP is never fired. I say that it doesn't register with the shell
because the "cookie" parameter in the event handler is an integer that
is incremented each time a new IE / Explorer window is created.
Bringing up a new IE, subsequent to a hit to the web server, shows an
integer one larger than that with the previous visible IE window.

All this has been a very long winded way of saying that the program
which Apache invokes to handle the request is severly restricted. I
should in theory be able to bypass this restriction by right clicking
Apache in the System Tray and opening services, then right clicking on
Apache there and going to Properties, and then in the Logon section
allowing Apache to interact with the desktop. Didn't work.

So my real question is, is there any way that I can bypass this
restriction, especially on a per page basis? Oh, and it's a VBScript
question because I can shove everything that I just talked about into
the MSScriptControl.ScriptControl and it happens the same way there,
too.

And now you know,
Csaba Gabor from Vienna

0 new messages