Welcome to MSDN Blogs Sign in | Join | Help

Querying information from an Explorer window

Sometimes software development is inventing new stuff. But often, it's just putting together the stuff you already have. Today's puzzle is one of the latter type of problem.

Given a window handle, you can you determine (1) whether it is an Explorer window, and if so (2) what folder it is viewing, and (3) what item is currently focused.

This is not an inherently difficult task. You just have to put together lots of small pieces.

Start with the ShellWindows object which represents all the open shell windows. You can enumerate through them all with the Item property. This is rather clumsy from C++ because the ShellWindows object was designed for use by a scripting language like JScript or Visual Basic.

 IShellWindows *psw;
 if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL,
                                IID_IShellWindows, (void**)&psw))) {
  VARIANT v;
  V_VT(&v) = VT_I4;
  IDispatch  *pdisp;
  BOOL fFound = FALSE;
  for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK;
       V_I4(&v)++) {
    ...
    pdisp->Release();
  }
  psw->Release();
 }

From each item, we can ask it for its window handle and see if it's the one we want.

   IWebBrowserApp *pwba;
   if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
     HWND hwndWBA;
     if (SUCCEEDED(pwba->get_HWND((LONG_PTR*)&hwndWBA)) &&
       hwndWBA == hwndFind) {
       fFound = TRUE;
       ...
     }
     pwba->Release();
   }

Okay, now that we have found the folder via its IWebBrowserApp, we need to get to the top shell browser. This is done by querying for the SID_STopLevelBrowser service and asking for the IShellBrowser interface.

       IServiceProvider *psp;
       if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
         IShellBrowser *psb;
         if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,
                              IID_IShellBrowser, (void**)&psb))) {
           ...
           psb->Release();
         }
         psp->Release();
       }

From the IShellBrowser, we can ask for the current shell view via the QueryActiveShellView method.

           IShellView *psv;
           if (SUCCEEDED(psb->QueryActiveShellView(&psv))) {
             ...
             psv->Release();
           }

Of course, what we really want is the IFolderView interface, which is the automation object that contains all the real goodies.

             IFolderView *pfv;
             if (SUCCEEDED(psv->QueryInterface(IID_IFolderView,
                                               (void**)&pfv))) {
               ...
               pfv->Release();
             }

Okay, now we're golden. What do you want to get from the view? How about the location of the IShellFolder being viewed. To do that, we need to use IPersistFolder2::GetCurFolder. The GetFolder method will give us access to the shell folder, from which we ask for IPersistFolder2. (Most of the time you want the IShellFolder interface, since that's where most of the cool stuff hangs out.)

               IPersistFolder2 *ppf2;
               if (SUCCEEDED(pfv->GetFolder(IID_IPersistFolder2,
                                            (void**)&ppf2))) {
                 LPITEMIDLIST pidlFolder;
                 if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder))) {
                   ...
                   CoTaskMemFree(pidlFolder);
                 }
                 ppf2->Release();
               }

Let's convert that pidl into a path, for display purposes.

                   if (!SHGetPathFromIDList(pidlFolder, g_szPath)) {
                     lstrcpyn(g_szPath, TEXT("<not a directory>"), MAX_PATH);
                   }
                   ...

What else can we do with what we've got? Oh right, let's see what the currently-focused object is.

                   int iFocus;
                   if (SUCCEEDED(pfv->GetFocusedItem(&iFocus))) {
                     ...
                   }

Let's display the name of the focused item. To do that we need the item's pidl and the IShellFolder. (See, I told you the IShellFolder is where the cool stuff is.) The item comes from the Item method (surprisingly enough).

                     LPITEMIDLIST pidlItem;
                     if (SUCCEEDED(pfv->Item(iFocus, &pidlItem))) {
                       ...
                       CoTaskMemFree(pidlItem);
                     }

(If we had wanted a list of selected items we could have used the Items method, passing SVGIO_SELECTION.)

After we get the item's pidl, we also need the IShellFolder:

                       IShellFolder *psf;
                       if (SUCCEEDED(ppf2->QueryInterface(IID_IShellFolder,
                                                          (void**)&psf))) {
                         ...
                         psf->Release();
                       }

Then we put the two together to get the item's display name, with the help of the GetDisplayNameOf method.

                         STRRET str;
                         if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem,
                                                   SHGDN_INFOLDER,
                                                   &str))) {
                           ...
                         }

We can use the helper function StrRetToBuf to convert the kooky STRRET structure into a boring string buffer. (The history of the kooky STRRET structure will have to wait for another day.)

                           StrRetToBuf(&str, pidlItem, g_szItem, MAX_PATH);

Okay, let's put this all together. It looks rather ugly because I put everything into one huge function instead of breaking them out into subfunctions. In "real life" I would have broken things up into little helper functions to make things more manageable.

Start with the scratch program and add this new function:

#include <shlobj.h>
#include <exdisp.h>

TCHAR g_szPath[MAX_PATH];
TCHAR g_szItem[MAX_PATH];

void CALLBACK RecalcText(HWND hwnd, UINT, UINT_PTR, DWORD)
{
 HWND hwndFind = GetForegroundWindow();
 g_szPath[0] = TEXT('\0');
 g_szItem[0] = TEXT('\0');

 IShellWindows *psw;
 if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL,
                                IID_IShellWindows, (void**)&psw))) {
  VARIANT v;
  V_VT(&v) = VT_I4;
  IDispatch  *pdisp;
  BOOL fFound = FALSE;
  for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK;
       V_I4(&v)++) {
   IWebBrowserApp *pwba;
   if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
     HWND hwndWBA;
     if (SUCCEEDED(pwba->get_HWND((LONG_PTR*)&hwndWBA)) &&
       hwndWBA == hwndFind) {
       fFound = TRUE;
       IServiceProvider *psp;
       if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
         IShellBrowser *psb;
         if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,
                              IID_IShellBrowser, (void**)&psb))) {
           IShellView *psv;
           if (SUCCEEDED(psb->QueryActiveShellView(&psv))) {
             IFolderView *pfv;
             if (SUCCEEDED(psv->QueryInterface(IID_IFolderView,
                                               (void**)&pfv))) {
               IPersistFolder2 *ppf2;
               if (SUCCEEDED(pfv->GetFolder(IID_IPersistFolder2,
                                            (void**)&ppf2))) {
                 LPITEMIDLIST pidlFolder;
                 if (SUCCEEDED(ppf2->GetCurFolder(&pidlFolder))) {
                   if (!SHGetPathFromIDList(pidlFolder, g_szPath)) {
                     lstrcpyn(g_szPath, TEXT("<not a directory>"), MAX_PATH);
                   }
                   int iFocus;
                   if (SUCCEEDED(pfv->GetFocusedItem(&iFocus))) {
                     LPITEMIDLIST pidlItem;
                     if (SUCCEEDED(pfv->Item(iFocus, &pidlItem))) {
                       IShellFolder *psf;
                       if (SUCCEEDED(ppf2->QueryInterface(IID_IShellFolder,
                                                          (void**)&psf))) {
                         STRRET str;
                         if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem,
                                                   SHGDN_INFOLDER,
                                                   &str))) {
                           StrRetToBuf(&str, pidlItem, g_szItem, MAX_PATH);
                         }
                         psf->Release();
                       }
                       CoTaskMemFree(pidlItem);
                     }
                   }
                   CoTaskMemFree(pidlFolder);
                 }
                 ppf2->Release();
               }
               pfv->Release();
             }
             psv->Release();
           }
           psb->Release();
         }
         psp->Release();
       }
     }
     pwba->Release();
   }
    pdisp->Release();
  }
  psw->Release();
 }
 InvalidateRect(hwnd, NULL, TRUE);
}

Now all we have to do is call this function periodically and print the results.

BOOL
OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
    SetTimer(hwnd, 1, 1000, RecalcText);
    return TRUE;
}

void
PaintContent(HWND hwnd, PAINTSTRUCT *pps)
{
  TextOut(pps->hdc, 0, 0, g_szPath, lstrlen(g_szPath));
  TextOut(pps->hdc, 0, 20, g_szItem, lstrlen(g_szItem));
}

We're ready to roll. Run this program and set it to the side. Then launch an Explorer window and watch the program track the folder you're in and what item you have focused.

Okay, so I hope I made my point: Often, the pieces you need are already there; you just have to figure out how to put them together. Notice that each of the pieces is in itself not very big. You just had to recognize that they could be put together in an interesting way.

Exercise: Change this program so it takes the folder and switches it to details view.

[Raymond is currently on vacation; this message was pre-recorded.]

Published Tuesday, July 20, 2004 7:00 AM by oldnewthing
Filed under:

Comments

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 7:28 AM by Dr. Jekyll
If everything is so nicely scoped, why not use CComPtr<>s / CComQIPtr<>s ? This very same code would be so much more readable (no ugly QueryInterfaces, Releases, uninitialized variables)...

Guess it's a habit thing.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 7:35 AM by Raymond Chen
I try to avoid using any extra libraries in these articles. If you like those libraries, you can translate raw C++ into your library; but it's harder for others to translate a library into raw C++. (For example, I could've used a library to auto-free the pidlFolder, but that would have confused anybody who wasn't familiar with that library.)

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 7:37 AM by A. Reader
Hideous. That screams "potential memory leaks!"

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 8:17 AM by Ben Cooke
That code is hilarious. It's stuff like that which really puts me off learning about COM. Fortunately, I've managed to basically ignore COM so far, and if all this .NET stuff becomes popular maybe I can just pretend it never happened. :)

Pleaaase release me, let me gooooooo......

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 8:30 AM by Jack Mathews
Well, you could easily flatten out that code with a CComPtr class, a CComMemoryHandle class, and a function called GuaranteeSuccess that throws an exception on a bad HRESULT and catch that in the function.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 8:44 AM by Raymond Chen
Any reader who wants to make an ATL version of this function is free to do so. It would probably be a lot prettier. But I write in pure C++ in order to avoid arguing over which template library is best.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 8:51 AM by dude
cant compile : error C2065: 'StrRetToBuf' : undeclared identifier

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 9:39 AM by Ben Hutchings
Does Explorer lock windows that external clients are looking at (or indeed <em>all</em> of them while the windows are being enumerated) or is this code vulnerable to race conditions?

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 9:54 AM by Michael
>I try to avoid using any extra libraries in these articles. <

I for one am glad you approach your problems this way. It shows me what is "really going on". Keep up the good work!!

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 10:27 AM by Cedric Beust
I believe the only point you've made is that only VB or C# should ever be used to access COM :-)

--
Cedric

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 10:47 AM by drebin
I have a burning sensation in my eyes, is that normal??

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 11:51 AM by Zachary Turner
Even in pure C++, better to just stick a label at the bottom and have a goto statement if the COM call fails, rather than use deeper nesting if the call succeeds.

To the poster who said it's things like that make you not want to learn COM, it's very simple and easy to read as long as you provide an appropriate framework for making it easy to read. For example, consider the following two macros:

#define COM_CALL(pfn, lbl) \
if (FAILED(pfn)) goto lbl;

#define RELEASE(ptr) \
if (ptr) ptr->Release();

Now the RecalcText function is as follows:

void CALLBACK RecalcText(HWND hwnd, UINT, UINT_PTR, DWORD)
{
HWND hwndFind = GetForegroundWindow();
g_szPath[0] = TEXT('\0');
g_szItem[0] = TEXT('\0');

IShellWindows *psw;
COM_CALL(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**)&psw), finish);

VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
BOOL fFound = FALSE;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK; V_I4(&v)++)
{

}

IWebBrowserApp *pwba = NULL;
IServiceProvider *psp = NULL;
IShellBrowser *psb = NULL;
IShellView *psv = NULL;
IFolderView *pfv = NULL;
IPersistFolder2 *ppf2 = NULL;
LPITEMIDLIST pidlFolder = NULL;
LPITEMIDLIST pidlItem = NULL;
IShellFolder *psf = NULL;
STRRET str;
COM_CALL(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba), finish);
if (hwndWBA != hwndFind)
goto finish;
COM_CALL(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp), finish);
COM_CALL(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, (void**)&psb), finish);
COM_CALL(psb->QueryActiveShellView(&psv), finish);
COM_CALL(psv->QueryInterface(IID_IFolderView, (void**)&pfv), finish);
COM_CALL(pfv->GetFolder(IID_IPersistFolder2, (void**)&ppf2), finish);
COM_CALL(ppf2->GetCurFolder(&pidlFolder), finish);

if (!SHGetPathFromIDList(pidlFolder, g_szPath))
lstrcpyn(g_szPath, TEXT("<not a directory>"), MAX_PATH);

int iFocus;
COM_CALL(pfv->GetFocusedItem(&iFocus), finish);
COM_CALL(pfv->Item(iFocus, &pidlItem), finish);
COM_CALL(ppf2->QueryInterface(IID_IShellFolder, (void**)&psf), finish);
COM_CALL(psf->GetDisplayNameOf(pidlItem, SHGDN_INFOLDER, &str), finish);
StrRetToBuf(&str, pidlItem, g_szItem, MAX_PATH);


finish:
RELEASE(psf);
TASK_FREE(pidlItem);
TASK_FREE(pidlFolder);
RELEASE(ppf2);
RELEASE(pfv);
RELEASE(psv);
RELEASE(psb);
RELEASE(psp);
RELEASE(pwba);
RELEASE(pdisp);
RELEASE(psw);

InvalidateRect(hwnd, NULL, TRUE);
}

I probably introduced a few bugs here, but I just typed this in notepad and didn't bother compiling. The point is obvious, just change the logic flow and COM is much easier to follow. Don't listen to what they say, that you should "never" use goto statements.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 12:55 PM by Larry Osterman
Never use goto statements? I LOVE goto statements :)

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 1:05 PM by Jack Mathews
Zach: Ummm, except now you can't use C++ construction/destruction semantics with yoru code...

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 1:14 PM by Nicole DesRosiers
Having had to actually code up a program using a raw dispatch interface in C++, I really appreciate that you wrote this example without libraries. When I was trying to design my program I nearly tore my hair out trying to translate the things written on MSDN with the wrapper code into raw function calls that were actually useful to me.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 2:23 PM by MadHungarian :)
The thing that bugs me is the use of Hungarian notation. 'psf' doesn't say much, 'shellFolder' does.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 2:39 PM by Raymond Chen
Zachary: Note however that some of your code goto's over variable initialization - for example if the initial CoCreateInstance fails. This results in the RELEASE trying to use an uninitialized variable.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 3:49 PM by Joe
Zachary, you have to make sure that when you make macros you take care to write them correctly. For instance, this hypothetical code is wrong:
if(--i == 0) // we have no more use for the object
RELEASE(pObj);
else
COM_CALL(pObj->foo(), finish);

First, because the RELEASE() macro has a semi-colon, you end up with two semi-colons and that'll terminate the if statement before the else. If you remove the extra semi-colon, then the else clause gets attached to the if statement in the macro, and not the if(--i == 0).

I think the usual way of handling this is to use:
#define RELEASE(ptr) \
if (ptr) ptr->Release(); else

So that the semi-colon at the end of RELEASE(foo); will close the else.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 4:35 PM by Jack Mathews
Or instead of a macro, you use something like a CComPtr, and to fix the nesting, you do like this:

enum EBadResult
{
kBadResult
};

void Succeed( HRESULT hr )
{
if ( !SUCCEEDED(hr) )
{
throw kBadResult;
}
}

... then in your code, you can simply do ...

try
{
Object obj;

Succeed( incoming->DoThis( obj.GetPtrPtr() ) );
Succeed( obj->DoThisNow() );
}
catch ( EBadResult )
{
// Do what you need to in order to fail
}

... and you will get automatic destruction of the intermediate objects that you didn't use. You write a small amount more code, you get similar ease of use as goto, and much MUCH more robust error handling in the language.

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 6:25 PM by John Schroedl
Great post. Keep 'em coming with more good stuff for the shell!

# re: Querying information from an Explorer window

Tuesday, July 20, 2004 8:25 PM by Steven Engelhardt
For writing anything but the simplest macros, I typically recommend enclosing in a do { ... } while(0) block as follows:

#define DoStuff() \
do { \
// statement 1; \
// statement 2; \
// ...; \
} while (0)

The if (...) else trick should work as well.

I also explained my C/C++ error-handling style which uses gotos, along with its limitations, in:

http://www.livejournal.com/users/sengelha/35640.html
http://www.livejournal.com/users/sengelha/37087.html
http://www.livejournal.com/users/sengelha/37182.html

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 2:30 AM by Tim Robinson
> I try to avoid using any extra libraries in these articles.

Even the Microsoft C++ runtime library includes COM support classes. For most Windows developers, that's hardly an 'extra library'.

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 6:05 AM by Stewart Tootill
I tend to use the exception concept and ATL com smart pointers. I know the example wasn't written in ATL, but even if thats the only ATL functionality you use its worth it in my opinion.

As for the macro, I typically use

inline HRESULT TestComCall( HRESULT hr ) throw (_com_error)
{
if ( FAILED( hr ) )
_com_issue_error( hr );
return hr;
}

it returns hr so you can use it with the Next method on IEnum interfaces. You can replace the _com_error with your favourite exception. Also its a shame, but the microsoft compiler whinges about the exception specification.

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 7:31 AM by Tudor Tihan
Hy,

Is there any way to similarly get a handle of the text inputs in the Internet Explorer ?

If it could be a write-only way (for setting texts inside) that would be great, because it would mean that I could write a program to fill my credentials on my visited sites without sharing them with password manager and such.

So, is it possible?
Could you give me some guidelines, please, as I am new to advanced COM programming.

Thank you!

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 7:43 AM by Raymond Chen
mshtml.h contains the interfaces you need. I leave filling in the details as an exercise. (Besides, this is an IE question and that's not my area.)

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 9:48 AM by Michael Geary
Steve, I'm curious about the use of do...while(0) in your macro. I've written scads of multiline code macros, and all I ever do is enclose them in braces. So your example would be:

#define DoStuff() \
{ \
// statement 1; \
// statement 2; \
// ...; \
}

Is there a situation where that would fail and do...while(0) would fix it?

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 11:32 AM by Steven Engelhardt
Michael Geary: The #define DoStuff() { ... } style works in most cases but not all. See http://www.livejournal.com/users/sengelha/38124.html for details.

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 11:36 AM by Zachary Turner
Well as I said, I typed it in notepad and didn't compile anything ;-) The point was just to illustrate a general concept, which when applied would simplify readability. Thanks for pointing out the errors though. To respond to the individual comments (I'm sure everyone knows everything I'm about to say, but I might as well say it anyway for the sake of completeness):

Raymond: Skipping over variable initialization is easily handled by moving all declarations and setting them equal to 0. The release macro checks whether or not the value of the pointer is 0, and if it is it does nothing. So you never release garbage that way. Obviously you know that already, but like I said just pointing it out for completeness' sake.

Jack: Are you referring to construction/destruction semantics with regards to COM smart pointers auto add-refing and releasing? You can use whatever you want, this was just an attempt to simplify readability in a way that didn't use any smart pointer template library, which was Raymond's initial goal as well. Since some readers said "it sucks, you can't read it without smart pointers", I was just providing a way by which you could ;-)

Joe: Good point, thanks :)

Jack (2nd message): Raymond's original goal was specifically NOT to use any library such as that, so that people didn't have to argue over which template library was best.

Michael: Yes, the do while macro allows you to put a semicolon at the end Consider your macro to be called DOMICHAEL, and steve's to be called DOSTEVE. Now consider the following code:

if (1)
DOMIKE();
else
DOSTEVE();

if (1)
DOSTEVE();
else
DOMIKE();

The first if/else block generates a compiler error, because a ; after DOMIKE() terminates the if block, as Joe pointed out earlier. The second if block does NOT generate a compiler error, however, as you are required to put a ; to terminate the do while.

That's the only difference that I see. This only applies for single line if blocks as well, if you already had enclosing braces for the if block there would be no difference.

# The old goto problem

Wednesday, July 21, 2004 2:46 PM by Otaku, Cedric's weblog
I was once reminded of the constant controversy that surrounds the use of goto by the two following posts: Raymond Chen's article on a COM trick to track the Explorer...

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 1:12 PM by Michael Moore
Seems to me you might as well stick with the simple braces method since a do { ... } while (0) approach also results in a syntax error if you leave off the semicolon.

i.e. this won't compile either:

if ( expression )
do { a(); b(); } while (0)
else
c();

so its really just a question of whether you think semicolon's should be used to terminate macro usage.

I'll grant you the lack of a semicolon is a bit more obvious a syntax error for the macro than a mismatched else.

-Michael

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 5:22 PM by Michael Geary
Stephen and Zachary, many thanks for the explanation on the do...while(0) bit. All makes sense now, and I'll start doing my own macros that way.

Michael M., when I write a code macro like this, I like to do it in such a way that I can use the semicolon when I use the macro. The idea is that the code that calls the macro should look the same whether it's a macro or a function.

Taking a simpler example, I would write a macro like this:

#define DoStuff() CallSomething()

and not like this:

#define DoStuff() CallSomething();

because when I call DoStuff, I want to call it like this:

DoStuff();

and not like this:

DoStuff()

The latter style means that the caller has to know it's a macro, which I wouldn't want.

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 5:57 PM by Raymond Chen
The semicolon-less style also messes up most code auto-formatters / syntax colorers.

# re: Querying information from an Explorer window

Wednesday, July 21, 2004 10:52 PM by sir
buncha jealous heytah's ;-)

# re: Querying information from an Explorer window

Thursday, July 22, 2004 9:07 AM by Kyle Lahnakoski
Looks like this turned into a discussion about code readability and the use of gotos.

Gotos are not good, but suggest the need for better error handling than the inadequate try-catch semantics. I suggest Structured Cascaded Exception Handling solves this problem and should be adopted in the next generation of languages.

# re: Querying information from an Explorer window

Thursday, July 22, 2004 9:52 PM by Steve Donie
You forgot to mention the Accessibilty Interfaces! Go straight to the focused item, get notified when it changes rather than polling...

Run the magnifier (Start->Programs->Accessories->Accessibility->Magnifier) or Narrator (same place) to see what those can do. Then see http://microsoft.com/enable/ for a ling to the developer docs.

# Kind of cool

Sunday, January 09, 2005 2:40 PM by crashBlog

# Using script to query information from Internet Explorer windows

Tuesday, July 05, 2005 10:00 AM by The Old New Thing
The ShellWindows object was designed for scripting.
New Comments to this post are disabled
 
Page view tracker