c++windowswinapiminifilter

Setting Status icon for CFAPI does not work as expected


I try to set the status icon of the placeholder file created with CFAPI to error. (see below)

screen with error icon

content of folder T:
screen with cloud symbol

I set the error state on the file, but it does not display the error. However the error is displayed on the containing folder.

I use following code to set the error on the file (the complete code is published on github):

void SetTransferStatus(_In_ PCWSTR fullPath, _In_ SYNC_TRANSFER_STATUS status)
{
    // Tell the Shell so File Explorer can display the progress bar in its view
    try
    {
        // First, get the Volatile property store for the file. That's where the properties are maintained.
        winrt::com_ptr<IShellItem2> shellItem;
        winrt::check_hresult(SHCreateItemFromParsingName(fullPath, nullptr, __uuidof(shellItem), shellItem.put_void()));

        winrt::com_ptr<IPropertyStore> propStoreVolatile;
        winrt::check_hresult(
            shellItem->GetPropertyStore(
                GETPROPERTYSTOREFLAGS::GPS_READWRITE | GETPROPERTYSTOREFLAGS::GPS_VOLATILEPROPERTIESONLY,
                __uuidof(propStoreVolatile),
                propStoreVolatile.put_void()));

        // Set the sync transfer status accordingly
        PROPVARIANT transferStatus;
        winrt::check_hresult(
            InitPropVariantFromUInt32(
                status,
                &transferStatus));
        winrt::check_hresult(propStoreVolatile->SetValue(PKEY_SyncTransferStatus, transferStatus));

        // Without this, all your hard work is wasted.
        winrt::check_hresult(propStoreVolatile->Commit());

        // Broadcast a notification that something about the file has changed, so that apps
        // who subscribe (such as File Explorer) can update their UI to reflect the new progress
        SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, static_cast<LPCVOID>(fullPath), nullptr);

        //wprintf(L"Succesfully Set Transfer Progress on \"%s\" to %llu/%llu\n", fullPath, completed, total);
    }
    catch (...)
    {
        // winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
        // otherwise the exception will get rethrown and this method will crash out as it should
        wprintf(L"Failed to Set Transfer Progress on \"%s\" with %08x\n", fullPath, static_cast<HRESULT>(winrt::to_hresult()));
    }
}

In addition, if I delete the file and create a new file the state will still be on error.


Solution

  • Someone pointed me to an pull request in the windows cloud mirror sample that shows how to accomplish this.

    This is the code:

    void Utilities::UpdateErrorOnItem(PCWSTR path, bool setError)
    {
        try
        {
            winrt::com_ptr<IShellItem2> item;
            winrt::check_hresult(SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(item.put())));
    
            winrt::com_ptr<IPropertyStore> propertyStore;
            winrt::check_hresult(item->GetPropertyStore(GPS_READWRITE | GPS_EXTRINSICPROPERTIESONLY, IID_PPV_ARGS(propertyStore.put())));
    
            PROPVARIANT propVar{};
            if (setError)
            {
                propVar.vt = VT_UI4;
                propVar.ulVal = static_cast<unsigned long>(E_FAIL);
                winrt::check_hresult(propertyStore->SetValue(PKEY_LastSyncError, propVar));
            }
            else
            {
                // Clear by setting to empty
                propVar.vt = VT_EMPTY;
                winrt::check_hresult(propertyStore->SetValue(PKEY_LastSyncError, propVar));
            }
    
            winrt::check_hresult(propertyStore->Commit());
        }
        catch (...)
        {
            // winrt::to_hresult() will eat the exception if it is a result of winrt::check_hresult,
            // otherwise the exception will get rethrown and this method will crash out as it should
            wprintf(L"Failed to set error state with %08x\n", static_cast<HRESULT>(winrt::to_hresult()));
        }