December 28th, 2015

Determining how each Explorer window is sorted

Today’s Little Program lists all the open Explorer windows and their current sort criteria. (I will refrain from mentioning how auto-sort makes this meaningful.) Remember that Little Programs do little to no error checking.

#define STRICT
#include <windows.h>
#include <ole2.h>
#include <shlobj.h>
#include <shdispid.h>
#include <atlbase.h>
#include <atlalloc.h>
#include <stdio.h>

void ProcessOneWindow(IUnknown *punk)
{
 CComPtr<IShellBrowser> spsb;
 if (FAILED(IUnknown_QueryService(punk, SID_STopLevelBrowser,
                                  IID_PPV_ARGS(&spsb)))) return;

 CComPtr<IShellView> spsv;
 if (FAILED(spsb->QueryActiveShellView(&spsv))) return;

 CComQIPtr<IFolderView2> spfv(spsv);
 if (!spfv) return;

 CComHeapPtr<WCHAR> spszLocation;
 if (FAILED(GetLocationFromView(spsb, &spszLocation))) return;

 printf("Location = %ls\n", static_cast<PCWSTR>(spszLocation));

 int cColumns;
 if (FAILED(spfv->GetSortColumnCount(&cColumns))) return;
 if (cColumns > 10) cColumns = 10;

 SORTCOLUMN rgColumns[10]; // arbitrary number
 spfv->GetSortColumns(rgColumns, cColumns);

 for (int i = 0; i < cColumns; i++) {
  PCWSTR pszDir = rgColumns[0].direction > 0 ? L"ascending"
                                             : L"descending";
  PCWSTR pszName;
  CComHeapPtr<WCHAR> spszName;
  WCHAR szName[PKEYSTR_MAX];
  if (SUCCEEDED(PSGetNameFromPropertyKey(rgColumns[0].propkey,
                                         &spszName))) {
   pszName = spszName;
  } else {
   PSStringFromPropertyKey(rgColumns[0].propkey,
                           szName, ARRAYSIZE(szName));
   pszName = szName;
  }
  printf("Column = %ls, direction = %ls\n", pszName, pszDir);
 }
}

int __cdecl wmain(int, wchar_t **)
{
 CCoInitialize init;
 CComPtr<IShellWindows> spShellWindows;
 spShellWindows.CoCreateInstance(CLSID_ShellWindows);

 CComPtr<IUnknown> spunkEnum;
 spShellWindows->_NewEnum(&spunkEnum);
 CComQIPtr<IEnumVARIANT> spev(spunkEnum);

 for (CComVariant svar;
      spev->Next(1, &svar, nullptr) == S_OK;
      svar.Clear()) {
  ProcessOneWindow(svar.pdispVal);
 }
 return 0;
}

To process a window, we first ask for the top-level browser, and from that we ask for the active shell view, then convert it to an IFolder­View2. We ask for the 2 because that’s the one that lets us query sort columns.

If anything goes wrong up to this point, it’s probably because the window doesn’t support sorting, so we won’t bother printing it.

We print the location of the window using a helper function from a long time ago.

Now the interesting part: We ask for the number of sort columns, then ask for those columns.

That’s it. The rest is boring again: We print each of the sort columns and the sort direction.

The main program loops through all the open Shell windows (which includes both Explorer and Internet Explorer) and processes each one.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.

Feedback