-1

In my Shell Namespace Extension I am using SHCreateShellFolderView to obtain IShellView when it is requested:

IFACEMETHODIMP ShellFolder::CreateViewObject(HWND hwnd, REFIID riid, void** ppv)
{
    if (IsEqualIID(riid, IID_IShellView))
    {
        HRESULT hr = S_OK;
        // Use default shell folder view
        SFV_CREATE sfvContext = { sizeof(sfvContext), 0 };
        // Query IShellFolder interface from this and put it into csfv.pshf
        hr = QueryInterface(IID_PPV_ARGS(&sfvContext.pshf));

        // Add IShellFolderViewCB for various callbacks
        ShellFolderViewCBHandler* pfvcb = new ShellFolderViewCBHandler(p_folder);

        hr = pfvcb->QueryInterface(IID_PPV_ARGS(&sfvContext.psfvcb));

        
        return ::SHCreateShellFolderView(&sfvContext, (IShellView**)ppv);
    }

Here ShellFolderViewCBHandler is implementing the only interface IShellFolderViewCB with the only intention to set third column as default for sorting in descending order:

IFACEMETHODIMP ShellFolderViewCBHandler::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case SFVM_GETSORTDEFAULTS:
        {
            int* const iDirection = reinterpret_cast<int*>(wParam);
            int* const iColumn = reinterpret_cast<int*>(lParam);
            *iDirection = -1;
            *iColumn = 2;

            return S_OK;
        }
        default:
            return E_NOTIMPL;
    }
}

What currently happens is:

  1. SFVM_GETSORTDEFAULTS switch case is getting executed and column and direction are set successfully. I can see that in debugger plus because p.2
  2. ShellFolder::MapColumnToSCID with column equal to 2 is called (I guess explorer is querying information about default sorting column).
  3. ShellFolder::CompareIDs is start being called with valid pidls but lParam set to 32761 (Applying int column = lParam & SHCIDS_COLUMNMASK returns same 32761 for column index). It does not matter what value I will set for iColumn in SFVM_GETSORTDEFAULTS switch case, it will always sort with this magic column index.

In the end I don't see that items were sort by column, they are always displayed sorted by display name in ascending order.

So my question is: how to set default sorting column and order?

P.S. I have removed clean up (like Release() calls) and error checking code to make code samples in question more readable.

ElDorado
  • 448
  • 6
  • 19
  • Only 95/98 used pure column indices (IShellDetails). 2000+ uses IShellFolder2 and pkeys to map data to columns. – Anders Aug 03 '22 at 20:20
  • I have tried using pkeys as well: implemented `ShellFolder::MapColumnToSCID` and `ShellFolder::GetDetailsEx` with one pkey per column index . Still same result. I have updated the question. – ElDorado Aug 03 '22 at 20:35
  • Get IFolderView2 from IShellView and call IFolderView2::SetSortColumns https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifolderview2-setsortcolumns PS: 32761 value for CompareIDs seems weird – Simon Mourier Aug 04 '22 at 07:49
  • @SimonMourier I assume that would work but it does require pkeys while the SFVM stuff technically goes all the way back to 95 and should be possible without using other interfaces. – Anders Aug 04 '22 at 22:36
  • @Anders - all columns have pkeys anyway with current Windows version (SHCOLUMNID=PROPERTYKEY) – Simon Mourier Aug 05 '22 at 05:42
  • You can also implement IFolderViewSettings https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ifolderviewsettings in your implementation of IShellFolder2 but my experience is GetSortColumns is never called (other methods are) ... it may depend on some context that works for you. – Simon Mourier Aug 05 '22 at 06:14
  • I was thinking about IFolderViewSettings and even tried that, but in my understanding I will need to take care of preserving user view settings then (i.e. selected sort columns, column visibility, view mode, etc.). I prefer leave that to the shell – ElDorado Aug 05 '22 at 15:25

1 Answers1

1

I don't see CompareIDs being called with a crazy number. In my hacked up minimal NSE I can confirm that SFVM_GETSORTDEFAULTS is called but DefView ignores its values.

There is a undocumented SFVM value that seems to work:

STDMETHODIMP MessageSFVCB(UINT uMsg, WPARAM wp, LPARAM lp)
{
    switch (uMsg)
    {
    case 27:
        return (*((int*)lp) = FVM_DETAILS, S_OK);
    case 53:
        {
        int*const iDirection = reinterpret_cast<int*>(wp), *const iColumn = reinterpret_cast<int*>(lp);
        *iDirection = 1, *iColumn = 1;
        }
        return S_OK;
    case 92: // When was this added? XP? 2003? Vista?
        UINT*data = (UINT*) lp;
        MessageSFVCB(27, 0, (SIZE_T) &data[0]); // SFVM_DEFVIEWMODE
        data[1] = 0;
        MessageSFVCB(53, (SIZE_T) &data[3], (SIZE_T) &data[2]); // SFVM_GETSORTDEFAULTS
        return S_OK;
    }
    return E_NOTIMPL;
}

Another alternative is calling IShellFolderView::Rearrange but it is hard to control the sort direction if you do this.

Anders
  • 97,548
  • 12
  • 110
  • 164
  • SFVM_REARRANGE probably calls IShellFolderView::Rearrange but as a view callback you don't really have a HWND to use with SHShellFolderView_Message. – Anders Aug 04 '22 at 22:38
  • 1
    92 = SFVM_GETDEFERREDVIEWSETTINGS added with Windows XP http://218.94.103.156:8090/download/developer/xpsource/Win2K3/NT/shell/published/inc/shlobj.w with struct parameter = `SFVM_DEFERRED_VIEW_SETTINGS {FOLDERVIEWMODE fvm; BOOL fGroupView; UINT uSortCol; int iSortDirection; FOLDERFLAGS fFlags};` – Simon Mourier Aug 05 '22 at 05:37