Getting Windows Explorer's Current Directory Sort Order

TLDR code at the bottom

Motivation

When I upgraded from Windows 7 to Windows 10 a few years ago, I noticed Windows Photo Viewer was replaced with the "Photos App". Thankfully for backwards compatibility reasons, it still exists in Windows and can be re-enabled by editing the Windows Registry.

The new Photos App is way too bloated for me
I prefer the minimalist UI of the old Windows Photo Viewer

Since Windows Photo Viewer probably hasn't been updated since Windows XP days, it doesn't support modern image formats like webp. In the above example, while it can still decode the image, the colours are slightly off.

For the past couple of years, this hasn't been a major issue for me but was still an irritating annoyance. Last month, I finally decided to build my own Windows Photo Viewer replacement as an excuse to play with new C++23 features.

One feature from both Windows Photo Viewer and Photos App that I wanted to implement was the ability to browse through all the images in the same directory as my initial image. In addition, the browsing was in the same order as the Explorer window.

When I open one of these images I want to be able to navigate to other images sorted by file size

I initially tried using std::filesystem::directory_iterator; however, the order was not what I expected. From my personal observation and this Raymond Chen blog post, the order appears to be dependant on the underlying filesystem:

  • On NTFS, files are returned in B-tree order which is approximately alphabetical
  • ON FAT32, files are returned in order that they appear on disk i.e. file creation date

And thus began my journey to figure out how to obtain the Explorer sort order…

First Attempt with ChatGPT

A quick Google search led me to the Win32 API IFolderView2::GetSortColumns. I initially thought this would be easy as it's just a simple function that returns exactly what I wanted. Turns out that couldn't be further from the truth.

The first problem was how do I get a Windows object that implements the IFolderView2 interface? For my first attempt, I tried using ChatGPT to figure out which Win32 API functions to call. I was surprised I got code that almost compiled but I still had to fix a few errors.

To my disappointment, calling GetSortColumns from this IFolderView2 always returned PKEY_ItemNameDisplay i.e. telling me to sort files alphabetically. With no additional information on why in the Windows documentation, I decided to mark this approach as a deadend.

Second Attempt with Windows Registry

My next thought was to check the Windows Registry since information about Explorer sort order must be saved somewhere on my computer and the Registry is usually where this kind of data is stored.

As it turns out, the Registry does indeed store information about Explorer in what's colloquially known as "ShellBags".

Since all the ShellBag data is encoded in binary, it would be a lot of wasted work if it didn't contain the exact information that I wanted. Instead I decided to first use a third-party application to inspect my computer's ShellBags before doing it manually.

While ShellBags Explorer didn't reveal the sort order, one key thing that I've noticed was that my desired directory's last registry write time was over a month ago. Therefore even if it's possible to get the sort order out of ShellBags, that information would probably be stale and thus this is another deadend.

Third Attempt by Reverse Engineering Windows Photo Viewer

At this point I was pretty frustrated. Before I gave up and settle with sorting my file list alphabetically, I decided one last attempt to try and reverse engineer Windows Photo Viewer.

I began by opening up PhotoViewer.dll in IDA and looked for Win32 API symbols since this is the same library where IFolderView2::GetSortColumns is from.

That's an interesting Win32 API symbol!

One particular symbol that caught my eye was SHCoCreateInstance (now deprecated in favor of CoCreateInstance). From what I understand from the documentation, this function is used to start a communication bridge with Explorer process itself.

This was when it hit me: Windows Photo Viewer and Photos App were probably just communicating directly with the Explorer window process (explorer.exe) when the image is initially opened to get the sort order.

In hindsight, this also makes since if there are two open Explorer windows, both windows' sort order cannot be saved in the same place on my computer — thus it probably only exists in memory.

Solution

  1. At the start of the program (e.g. at the top of main() and before creating own window), get a reference HWND to the computer's current foreground window. This should be the Explorer window process containing the image that I just opened i.e. the window that I just double-clicked to open said image.
  2. Create a communication bridge with all open Explorer window processes with CoCreateInstance.
  3. Iterate over all the windows to find the one with the same handle as the initial window handle recorded in step one. In addition, this window should also have the same directory as the image's directory.
  4. Starting from the IDispatch interface that the Explorer window implements, query my way down to the IFolderView2 interface (thanks ChatGPT).

For the sake of brevity, I ommited error checking and garbage collection. However if you wish to use this code, you should also:

  • Check the return codes of each API call to ensure there's no error and you don't have null pointers
  • Clean up the communication bridge with CoUninitialize and every queried interface with Release()