Customizing item enumeration with IShellItem


If you are using the original IShell­Folder interface, then you can use SHCONTF values to customize how child items are enumerated. But what if you're using IShell­Item?

Let's take it one step at a time. First, the basic program. (Remember, Little Programs do little to no error checking.)

#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#include <windows.h>
#include <shlobj.h>
#include <atlbase.h>
#include <atlalloc.h>
#include <propsys.h>
#include <stdio.h>

int __cdecl wmain(int argc, wchar_t **argv)
{
 CCoInitialize init;

 if (argc < 2) return 0;
 CComPtr<IShellItem> spsiFolder;
 SHCreateItemFromParsingName(argv[1], nullptr,
                             IID_PPV_ARGS(&spsiFolder));

 CComPtr<IEnumShellItems> spesi;
 spsiFolder->BindToHandler(nullptr, BHID_EnumItems,
                              IID_PPV_ARGS(&spesi));

 for (CComPtr<IShellItem> spsi;
      spesi->Next(1, &spsi, nullptr) == S_OK;
      spsi.Release()) {
  PrintDisplayName(spsi, SIGDN_NORMALDISPLAY, L"Display Name");
  PrintDisplayName(spsi, SIGDN_FILESYSPATH, L"File system path");
  wprintf(L"\n");
 }
 return 0;
}

Run this program with the fully-qualified path to a directory as the command line argument, and it enumerates all the items in the folder. This uses the default enumeration, which is "include both folders and non-folders, and include hidden items, but not super-hidden items."

But what if we want to customize the enumeration?

We saw that the IBindCtx parameter acts as a catch-all options parameter. In this case, we need to look at the options available for BHID_Enum­Items and see if any of them help us.

Fortunately, we have STR_ENUM_ITEMS_FLAGS which lets us override the default enumeration mode. Let's say that we want only folders, and we want to respect the user's preferences for hidden items (which means that we omit SHCONTF_HIDDEN).

I'm goint to do this two ways. First the flat version:

 ...
 CComPtr<IBindCtx> spbcEnum;
 CreateDwordBindCtx(STR_ENUM_ITEMS_FLAGS, SHCONTF_FOLDERS,
                    &spbcEnum);

 CComPtr<IEnumShellItems> spesi;
 spsiFolder->BindToHandler(spbcEnum, BHID_EnumItems,
                              IID_PPV_ARGS(&spesi));

Now the fluent version:

 ...
 CBindCtxBuilder builder;
 builder.SetVariantDword(STR_ENUM_ITEMS_FLAGS, SHCONTF_FOLDERS);

 CComPtr<IEnumShellItems> spesi;
 spsiFolder->BindToHandler(builder.GetBindCtx(), BHID_EnumItems,
                              IID_PPV_ARGS(&spesi));

(Don't forget that error checking has been elided for expository purposes.)

The STR_ENUM_ITEMS_FLAGS bind context string was added in Windows 8, so it has no effect on older versions of Windows. We'll address this next week.

Note that the IEnum­Shell­Items interface is incorrectly-named. The convention for enumeration interfaces is to name them IEnum­XXX, where XXX is singular.

Comments (5)
  1. I wrote one myself earlier.

    But my current challenge is to customize all icons that shell displays with a replacement from a local resource. (You already wrote about this.) The current belief in my workplace is that we can gain a market edge if we use a custom shared library containing the Crystal Clear icons to improve the visuals of our program, especially because Windows 10 icons are hideous.

  2. Neil says:

    @Fleet Command: Assuming you mean Windows 10 Technical Preview build 9926 icons, then I agree, they definitely look worse than the previous build. (And I don't like what they've done to the start menu either; I had to pin RDC to the taskbar as a workaround.)

  3. nikos z says:

    does this work for SHCONTF_INCLUDESUPERHIDDEN in windows 8?

    [What makes you think it wouldn't? -Raymond]
  4. nikos z says:

    Before you mentioned this magic bind context, item enumeration in windows 8 was "broken" in terms of superhidden files. I will try this new approach and as you say it should work — thanks!

    It looks like IShellItem enumeration is basically built on top of traditional IShellFolder enumeration. This would mean that working with IShellItems is perhaps not the most efficient way, if one is looking for maximum speed and efficiency, right? I am working on a desktop search engine (zabkat.com/…/deskrule-desktop-indexed-search-engine.htm) and speed is of the essense

    [All the bind context does is let you customize the shcontf passed to IShellFolder::EnumObjects. If there's a problem with IShellFolder::EnumObjects, that's a separate issue unrelated to IShellItem. -Raymond]
  5. @Neil: Well, at my workplace, what I like or dislike doesn't matter. It is my boss that matters.

    I have no personal comment on Windows 10 in this blog, but I'd like to say Crystal Clear by EC rocks!

Comments are closed.

Skip to main content