locked
How to change a Cloud File placeholder's status icon? RRS feed

  • Question

  • I'm using the Cloud Filter API to integrate a sync provider, I can use CfSetInSync API to switch the placeholder's status between sync-pending and in-sync, but how to set to other status? 

    e.g.  how to set the placeholder to error status like what OneDrive does? 

    OneDrive error status

    As I understand, System.StorageProviderState property has the following values:

    <propertyDescription name="System.StorageProviderState" formatID="{E77E90DF-6271-4F5B-834F-2DD1F245DDA4}" propID="3">
    			<searchInfo reIndexPatterns="" processReIndexPatternsImmediately="true" inInvertedIndex="false" isColumn="false">
    			</searchInfo>
    			<typeInfo type="UInt32" isInnate="true" groupingRange="Discrete" isViewable="true">
    			</typeInfo>
    			<displayInfo displayType="Enumerated">
    				<enumeratedList>
    					<enum name="None" value="0" text="@propsys.dll,-42290">
    					</enum>
    					<enum name="Sparse" value="1" text="@propsys.dll,-42291">
    						<image res="%systemroot%\system32\imageres.dll,-1404">
    						</image>
    					</enum>
    					<enum name="InSync" value="2" text="@propsys.dll,-42292">
    						<image res="%systemroot%\system32\imageres.dll,-1400">
    						</image>
    					</enum>
    					<enum name="Pinned" value="3" text="@propsys.dll,-42293">
    						<image res="%systemroot%\system32\imageres.dll,-1405">
    						</image>
    					</enum>
    					<enum name="PendingUpload" value="4" text="@propsys.dll,-42294">
    						<image res="%systemroot%\system32\imageres.dll,-1401">
    						</image>
    					</enum>
    					<enum name="PendingDownload" value="5" text="@propsys.dll,-42303">
    						<image res="%systemroot%\system32\imageres.dll,-1401">
    						</image>
    					</enum>
    					<enum name="Transferring" value="6" text="@propsys.dll,-42296">
    						<image res="%systemroot%\system32\imageres.dll,-1401">
    						</image>
    					</enum>
    					<enum name="Error" value="7" text="@propsys.dll,-42315">
    						<image res="%systemroot%\system32\imageres.dll,-1402">
    						</image>
    					</enum>
    					<enum name="Warning" value="8" text="@propsys.dll,-42316">
    						<image res="%systemroot%\system32\imageres.dll,-1403">
    						</image>
    					</enum>
    					<enum name="Excluded" value="9" text="@propsys.dll,-42319">
    					</enum>
    					<enum name="Pending" value="10" text="@propsys.dll,-42324">
    						<image res="%systemroot%\system32\imageres.dll,-1401">
    						</image>
    					</enum>
    				</enumeratedList>
    			</displayInfo>
    			<labelInfo label="@propsys.dll,-42288">
    			</labelInfo>
    		</propertyDescription>

    How can I update the value of a placeholder's System.StorageProviderState property, so that it will display a different status icon in explorer?  Or is there another way to achieve this?


    • Edited by wangfu91 Tuesday, June 23, 2020 7:17 AM
    Tuesday, June 23, 2020 7:09 AM

All replies

  • Hi wangfu91,

    To update the custom status icon, we need to implement the customer state provider. And you can refer the code below in CloudMirror code sample:

    CustomStateProvider.cpp

        Windows::Foundation::Collections::IIterable<Windows::Storage::Provider::StorageProviderItemProperty> CustomStateProvider::GetItemProperties(hstring const& itemPath)
        {
            std::hash<std::wstring> hashFunc;
            auto hash = hashFunc(itemPath.c_str());
    
            auto propertyVector{ winrt::single_threaded_vector<winrt::StorageProviderItemProperty>() };
    
            if ((hash & 0x1) != 0)
            {
                winrt::StorageProviderItemProperty itemProperty;
                itemProperty.Id(2);
                itemProperty.Value(L"Value2");
                // This icon is just for the sample. You should provide your own branded icon here
                itemProperty.IconResource(L"shell32.dll,-14");
                propertyVector.Append(itemProperty);
            }
    
            return propertyVector;
        }

    Utilities.cpp

    void Utilities::ApplyCustomStateToPlaceholderFile(PCWSTR path, PCWSTR filename, winrt::StorageProviderItemProperty& prop)
    {
        try
        {
            std::wstring fullPath(path);
            fullPath.append(L"\\");
            fullPath.append(filename);
    
            auto customProperties{ winrt::single_threaded_vector<winrt::StorageProviderItemProperty>() };
            customProperties.Append(prop);
    
            winrt::IStorageItem item = winrt::StorageFile::GetFileFromPathAsync(fullPath).get();
            winrt::StorageProviderItemProperties::SetAsync(item, customProperties).get();
        }
        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 custom state with %08x\n", static_cast<HRESULT>(winrt::to_hresult()));
        }
    }

    Placeholders.cpp

    void Placeholders::Create( _In_ PCWSTR sourcePath, _In_ P

    Build a Cloud Sync Engine that Supports Placeholder FilesCWSTR sourceSubDirstr, _In_ PCWSTR destPath) { try { WIN32_FIND_DATA findData; HANDLE hFileHandle; CF_PLACEHOLDER_CREATE_INFO cloudEntry; // make this either "subdirname\" or "" so that we can just always // append it without worry std::wstring sourceSubDir(sourceSubDirstr); if (sourceSubDir[0]) { sourceSubDir.append(L"\\"); } std::wstring fileName(sourcePath); fileName.append(sourceSubDir); fileName.append(L"\\*"); hFileHandle = FindFirstFileEx( fileName.data(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY); if (hFileHandle != INVALID_HANDLE_VALUE) { do { if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L"..")) { continue; } std::wstring relativeName(sourceSubDir); relativeName.append(findData.cFileName); cloudEntry.FileIdentity = relativeName.data(); cloudEntry.FileIdentityLength = (USHORT)(wcslen(relativeName.data()) + 1) * sizeof(WCHAR); cloudEntry.RelativeFileName = relativeName.data(); cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC; cloudEntry.FsMetadata.FileSize.QuadPart = ((ULONGLONG)findData.nFileSizeHigh << 32) + findData.nFileSizeLow; cloudEntry.FsMetadata.BasicInfo.FileAttributes = findData.dwFileAttributes; cloudEntry.FsMetadata.BasicInfo.CreationTime = Utilities::FileTimeToLargeInteger(findData.ftCreationTime); cloudEntry.FsMetadata.BasicInfo.LastWriteTime = Utilities::FileTimeToLargeInteger(findData.ftLastWriteTime); cloudEntry.FsMetadata.BasicInfo.LastAccessTime = Utilities::FileTimeToLargeInteger(findData.ftLastAccessTime); cloudEntry.FsMetadata.BasicInfo.ChangeTime = Utilities::FileTimeToLargeInteger(findData.ftLastWriteTime); if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { cloudEntry.Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION; cloudEntry.FsMetadata.FileSize.QuadPart = 0; } try { wprintf(L"Creating placeholder for %sx\n", relativeName.data()); winrt::check_hresult(CfCreatePlaceholders(destPath, &cloudEntry, 1, CF_CREATE_FLAG_NONE, NULL)); } 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 create placeholder for %s with %08x\n", relativeName.data(), static_cast<HRESULT>(winrt::to_hresult())); // Eating it here lets other files still get a chance. Not worth crashing the sample, but // certainly noteworthy for production code continue; } try { winrt::StorageProviderItemProperty prop; prop.Id(1); prop.Value(L"Value1"); // This icon is just for the sample. You should provide your own branded icon here prop.IconResource(L"shell32.dll,-44"); wprintf(L"Applying custom state for %sx\n", relativeName.data()); Utilities::ApplyCustomStateToPlaceholderFile(destPath, relativeName.data(), prop); if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { Create(sourcePath, relativeName.data(), destPath); } } 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 custom state on %s with %08x\n", relativeName.data(), static_cast<HRESULT>(winrt::to_hresult())); // Eating it here lets other files still get a chance. Not worth crashing the sample, but // certainly noteworthy for production code } } while (FindNextFile(hFileHandle, &findData)); FindClose(hFileHandle); } } catch (...) { wprintf(L"Could not create cloud file placeholders in the sync root with %08x\n", static_cast<HRESULT>(winrt::to_hresult())); // Something weird enough happened that this is worth crashing out throw; } }

    Please refer docs below for more details about cloud sync engine:

    Build a Cloud Sync Engine that Supports Placeholder Files

    Regards & Fei


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.



    Monday, June 29, 2020 7:09 AM
  • A call to ApplyCustomStateToPlaceholderFile() will set a new icon next to the existing one:

    It does not replace an existing icon. Can we set a new custom icon, so there is only one icon is displayed?


    • Edited by WebDAV Thursday, July 23, 2020 5:37 AM
    Thursday, July 23, 2020 4:54 AM