Search code examples
windowsshellshell-extensionsshell-namespace-extension

Default column index for sorting in Shell Namespace Extension


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.


Solution

  • 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.