Solved

List Shell Windows

Posted on 2006-07-07
14
1,048 Views
Last Modified: 2008-01-09
I'm trying to get a list of Shell Windows:

procedure TForm1.Button1Click(Sender: TObject);
Var ShellWindows:    TShellWindows;
      Scan:            Integer;
begin
    ShellWindows := TShellWindows.Create(nil);
    For Scan := 0 to ShellWindows.Count - 1 Do
    Begin
      //stuff
    End;
    ShellWindows.Free;
End;

This procedure works fine on my XP computer with the original shDocvw.pas file generated in 1998. However, it did not work on other computers. I recreated the shDocvw file by importing the DLL currently on my computer, and I am now able to duplicate the error.

I get an ...raised exception class EIntfCastError with message 'Interface not supported'.... on the ShellWindows.Count statement.

I checked SHDocVw and Count is a Pubic property for TShellWindows.

Any ideas why this is not working?

Thanks in advance!
0
Comment
Question by:wavget
  • 7
  • 5
14 Comments
 
LVL 26

Accepted Solution

by:
Russell Libby earned 250 total points
Comment Utility

Very strange.... as its choking on the following:

procedure TShellWindows.Connect;
var
  punk: IUnknown;
begin
  if FIntf = nil then
  begin
    punk := GetServer;
    ConnectEvents(punk);
    Fintf:= punk as IShellWindows; <-- most likely here
  end;
end;

which gets called when the you make an interface call and the interface is not yet connected. AFAIK, the interface IID has not changed for IShellWindows, so you might try the following to see what kind of results you get (uses the IDispatch interface, requires ComObj, ActiveX in uses clause, does not need ShDocVw)

procedure TestShellWindows;
var  ovShell:       OleVariant;
     ovWindows:     OleVariant;
     ovItem:        OleVariant;
     dwIndex:       Integer;
begin

  // Get instance of shell application
  ovShell:=CreateOleObject('Shell.Application');

  // Resource protection
  try
     // Get windows
     ovWindows:=ovShell.Windows;
     // Resource protection
     try
        // Walk the count
        for dwIndex:=0 to ovWindows.Count-1 do
        begin
           // Get item
           ovItem:=ovWIndows.Item(dwIndex);
           // Resource protection
           try
              // Check for non-null dispatch
              if (TVariantArg(ovItem).vt = VT_DISPATCH) and Assigned(TVariantArg(ovItem).dispVal) then
              begin
                 // Show location url
                 ShowMessage(ovItem.LocationURL);
              end;
           finally
              // Release interface
              ovItem:=Unassigned;
           end;
        end;
     finally
        // Release interface
        ovWindows:=Unassigned;
     end;
  finally
     // Release interface
     ovShell:=Unassigned;
  end;

end;

---

Regards,
Russell


0
 
LVL 26

Expert Comment

by:EddieShipman
Comment Utility
Requires shell32.dll version 4.71 and at least IE4.01, too, I think.
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Yes, that is correct:

Version DLL      Distribution Platform
4.0             All Microsoft Windows 95/Microsoft Windows NT 4.0.
4.7             All Microsoft Internet Explorer 3.x.
4.71             All Internet Explorer 4.0. See note 2.
4.72             All Internet Explorer 4.01 and Windows 98. See note 2.
5.0             Shlwapi.dll Internet Explorer 5. See note 3.
6.0             Shlwapi.dll Internet Explorer 6 and Windows XP.
5.0             Shell32.dll Windows 2000 and Windows Millennium Edition (Windows Me). See note 3.
6.0             Shell32.dll Windows XP.
5.8             Comctl32.dll Internet Explorer 5. See note 3.
5.81             Comctl32.dll Windows 2000 and Windows Me. See note 3.
6.0             Comctl32.dll Windows XP. See note 4.

Note 1: The 4.00 versions of Shell32.dll and Comctl32.dll are found on the original versions of Windows 95 and Windows NT 4.0. New versions of Commctl.dll were shipped with all Internet Explorer releases. Shlwapi.dll first shipped with Internet Explorer 4.0, so its first version number is 4.71. The Shell was not updated with the Internet Explorer 3.0 release, so Shell32.dll does not have a version 4.70. While Shell32.dll versions 4.71 and 4.72 were shipped with the corresponding Internet Explorer releases, they were not necessarily installed (see note 2). For subsequent releases, the version numbers for the three DLLs are not identical. In general, you should assume that all three DLLs may have different version numbers, and test each one separately.

Note 2: All systems with Internet Explorer 4.0 or 4.01 will have the associated version of Comctl32.dll and Shlwapi.dll (4.71 or 4.72, respectively). However, for systems prior to Windows 98, Internet Explorer 4.0 and 4.01 can be installed with or without the integrated Shell. If they are installed with the integrated Shell, the associated version of Shell32.dll will be installed. If they are installed without the integrated Shell, Shell32.dll is not updated. No other versions of Internet Explorer update Shell32.dll. In other words, the presence of version 4.71 or 4.72 of Comctl32.dll or Shlwapi.dll on a system does not guarantee that Shell32.dll has the same version number. All Windows 98 systems have version 4.72 of Shell32.dll.

Note 3: Version 5.80 of Comctl32.dll and version 5.0 of Shlwapi.dll are distributed with Internet Explorer 5. They will be found on all systems on which Internet Explorer 5 is installed, except Windows 2000. Internet Explorer 5 does not update the Shell, so version 5.0 of Shell32.dll will not be found on Windows NT, Windows 95, or Windows 98 systems. Version 5.0 of Shell32.dll will be distributed with Windows 2000 and Windows Me, along with version 5.0 of Shlwapi.dll, and version 5.81 of Comctl32.dll.

Note 4: ComCtl32.dll version 6 is not redistributable. If you want your application to use ComCtl32.dll version 6, you must add an application manifest that indicates that version 6 should be used if it is available.



0
 
LVL 1

Author Comment

by:wavget
Comment Utility
Thanks rllibby,

I don't understand why this doesn't work...is this something that Microsoft broke in their DLL?

I tried a work-around:

IShell:  IShellWindows;

    ShellWindows := TShellWindows.Create(nil);
    Try
      IShell := ShellWindows.DefaultInterface;
      Num := IShell.Count;

but I get the error on the IShell := ShellWindows.DefaultInterface; line.

Anyway... your example works for Windows Explorer windows but I'd like to list both Windows Explorer and Internet Explorer windows which (when it worked) the first procedure did.

Is there an equivalent procedure to list IE windows?

Thanks!
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

The example I gave does work for both Explorer and IE, assuming that the underlying interface supports it. Perhaps you could give us some info as to browser version, OS version, and version of shell32.dll.

Russell
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

Btw, did you happen to pay attention to the interface and CLSID's for IShellWindows before AND after you reimported?

Russell
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

by:wavget
Comment Utility
I'm using IE Verison 6.0.2900.2180.xpsp_sp2_gdr.050301-1519 on an up-to-date XP machine.

It did not work on another machine with the exact same IE version. They are using Outlook 2003 SP2  which I do not have installed.

My Shell32.dll version is 6.0.2900.2869.

The IDs in the TShellWindows.InitServerData procedure are the same in the old and the new SHDocVw.pas file.

I have both SHDocVw files, so if there is a specific item you are looking for, let me know.
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

Just wanted to ensure that the components were new enough to support the functionality, and that the interface ID's did not  change between the 2 imports (indicating a newer/older interface). I have tested the code on XP Pro/Media Center SP2 with

shell version 6.0.2900.2869

And it is able to list BOTH IE windows as well as explorer shell windows. The problem lies in the libraries somewhere, (BHO problem, IE not registered in the ROT, etc) but I am not sure what. I will ask around to see if anyone else has come across this before

Regards,
Russell
0
 
LVL 1

Author Comment

by:wavget
Comment Utility
I don't use IE on this computer, so the only BHO is Java 1.5.

Since both IE and Explorer windows were listed before I re-imported the DLL, I'm thinking IE is registered OK.

One tester reported that after a reboot the program worked OK until he started Outlook.

Thanks for all your help.
0
 
LVL 1

Author Comment

by:wavget
Comment Utility
Could the GetRunningObjectTable API be a way to get the same information?
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Nope, sorry... you will find that the Explorer(IE) windows are not listed in the ROT:

// Will display the same count regardless of # of IE/Explorer windows that are open
var  pvROT:         IRunningObjectTable;
     pvUnknown:     IUnknown;
     pvEnum:        IEnumMoniker;
     pvMoniker:     IMoniker;
     dwCount:       Integer;
     cFetch:        LongInt;
begin

  dwCount:=0;

  // Get the running object table
  if Succeeded(GetRunningObjectTable(0, pvROT)) then
  begin
     // Resource protection
     try
        // Get the enumerator
        if Succeeded(pvROT.EnumRunning(pvEnum)) then
        begin
           // Resource protection
           try
              // Reset
              pvEnum.Reset;
              // Enumerate the items in the running object table
              while ((pvEnum.Next(1, pvMoniker, @cFetch) = S_OK) and (cFetch = 1)) do
              begin
                 // Resource protection
                 try
                    // Get the object
                    if Succeeded(pvROT.GetObject(pvMoniker, pvUnknown)) then
                    begin
                       // Resource protection
                       try
                          Inc(dwCount);
                       finally
                          // Release interface
                          pvUnknown:=nil;
                       end;
                    end;
                 finally
                    // Release interface
                    pvMoniker:=nil;
                 end;
              end;
           finally
              // Release interface
              pvEnum:=nil;
           end;
        end;
     finally
        // Release interface
        pvROT:=nil;
     end;
  end;

  Caption:=Format('%d items in ROT', [dwCount]);

end;

I double checked my systems though, and noticed a discrepency between what you are running and what I am running. For my IE version, it is:

6.0.2900.2180.xpsp_sp2_rtm.xxxx

vs the gdr version that you are running. I have downloaded a number of updates and made registry tweaks in an attempt to duplicate your problem, but have been unsucessful so far. Perhaps you could check for IE updates on your side (to see if that make any difference)

Russell



0
 
LVL 1

Author Comment

by:wavget
Comment Utility
I was reading the borland.public.delphi.activex.controls.using newsgroup and found some postings related to issues with the D6 library importer:

http://groups.google.com/group/borland.public.delphi.activex.controls.using/search?group=borland.public.delphi.activex.controls.using&q=D6+Type+library+import+bugs&qt_g=1&searchnow=Search+this+group

Could this be the reason why it no longer works after I import the library?

I'm Using D6 SP2. Could I import the library in D4 and then use the resulting file in D6?

Thanks.
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

AFAIK it should work without a problem. You may have to tweak the uses statement clause at most, but other than that it should work.

Russell
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now