Search code examples
c++comwindows-shellshell-extensions

How to create an IconList property in the Windows Property System?


Currently, my property handler provides properties that can be displayed in Windows Explorer columns of type String. My goal is to extend the handler by a property of (display) type Icon, that can be added as a column to the details view of Windows Explorer. In this column, an icon should be displayed for each file item, e. g. the icon could represent a specific state of the file out of several possible states.

However, I did not manage to assemble the necessary parts of creating a property with these characteristics on the base of the Windows Property System correctly.

The first step of my approach is to specify the XML for the property in a .propdesc file and then go through the usual PSRegisterPropertySchema registration process. This runs always successfully and the property is listed in the Windows Property System.

<propertyDescription name="myprop.icon" formatID="{c5f47221-1053-4a75-aadc-0bfbac1c3e9c}" propID="444">
    <typeInfo type="???" isInnate="true" isViewable="true"/>
    <labelInfo label="MyProp-Icon"/>
    <displayInfo defaultColumnWidth="25" alignment="Center">
        <drawControl control="IconList"/>
    </displayInfo>
</propertyDescription>

The existence of <drawControl> (drawControl) with a control attribute of type "IconList" within the <displayInfo> tag makes me feel that my idea could be feasible.

But how to set the corresponding type in the <typeInfo> tag (typeInfo)? Depending on the concept of control="IconList" this could be an integer as an index into somewhat like an imagelist. Or is it a "Buffer", "Blob" or "Stream" representing the image itself?

Last, in the GetValue() method of the Property Handler shell extension the PROPVARIANT has to be initialized according to the property description of the .propdesc file:

HRESULT PropertyHandler::GetValue (REFPROPERTYKEY key, PROPVARIANT *pPropVar)
{
    HRESULT hr = ERROR_NOT_FOUND;

    if (key.pid == 444)
    {
        // How to initialize pPropVar in case of control="IconList"?
    }
    else
    {
        // String example
        hr = InitPropVariantFromString (L"Some Text", pPropVar);
    }

    return hr;
}

Again, how to do this for "IconList" properties?

Each attempt to find a correct match between the XML specification and the PROPVARIANT initialization leaves the corresponding column in Windows Explorer blank.

Does anybody already implemented a property with a <drawControl> of type IconList?


Solution

  • There is WINDOWSPROPERTYDESCRIPTIONS resource inside propsys.dll. This resource describes all system props. Some of properties have drawcontrol equal to IconList. Example:

    <propertyDescription name="System.StorageProviderUIStatus" formatID="{E77E90DF-6271-4F5B-834F-2DD1F245DDA4}" propID="2">
      <searchInfo reIndexPatterns="" processReIndexPatternsImmediately="true" inInvertedIndex="false" isColumn="false">
      </searchInfo>
      <typeInfo type="Blob" isInnate="true" isViewable="true">
      </typeInfo>
      <labelInfo label="@propsys.dll,-42289">
      </labelInfo>
      <displayInfo defaultColumnWidth="10">
        <drawControl control="IconList">
        </drawControl>
      </displayInfo>
    </propertyDescription>
    

    ALL of such props have type equal to "Blob". So Blob is answer.

    Update

    My little investigation.

    The only known (by me) handler that shows icons is OneDrive. Screenshot:

    enter image description here

    I got value of System.StorageProviderUIStatus property of one of OneDrive files. Value dump:

    enter image description here

    As you see this is not image or icon. This is Property Store Binary File described in [MS-PROPSTORE]. Decoded form:

    System.PropList.StatusIcons = prop:System.StorageProviderState;System.StorageProviderCustomStates
    System.PropList.StatusIconsDisplayFlag = 3
    StorageProviderState = 2
    StorageProviderCustomStates = (binary data)
    

    Binary data in embedded Property Store Binary File. Its decoded form:

    StorageProviderFullyQualifiedId = OneDrive!S-1-5-21-782054983-1121033576-3753986437-1001!Personal|79D9464945C2A3B2!331 
    

    Everything looks quite hard for simple icon description. And maybe I`am wrong and Blob type is not the only answer.

    SOLUTION

    Content of propdesc file:

    <propertyDescription name="DummyUIState" formatID="{8A560909-320E-4E6A-A6C4-A95C50B77084}" propID="5001">
      <searchInfo columnIndexType="NotIndexed"/>
      <labelInfo label="DummyUIState"/>
      <typeInfo type="Blob" isInnate="true" isViewable="true"/>
      <displayInfo defaultColumnWidth="10">
        <drawControl control="IconList"/>
      </displayInfo>
    </propertyDescription>
    
    <propertyDescription name="DummyState" formatID="{8A560909-320E-4E6A-A6C4-A95C50B77084}" propID="5000">
      <searchInfo columnIndexType="NotIndexed"/>
      <labelInfo label="DummyState"/>
      <typeInfo type="UInt32" isInnate="true" isViewable="true"/>
      <displayInfo displayType="Enumerated">
        <enumeratedList>
          <enum name="None" value="0" text="@propsys.dll,-42290"/>
          <enum name="Sparse" value="1" text="@propsys.dll,-42291">
            <image res="%systemroot%\system32\imageres.dll,-1404"/>
          </enum>
          <enum name="InSync" value="2" text="@propsys.dll,-42292">
            <image res="%systemroot%\system32\imageres.dll,-1400"/>
          </enum>
          <enum name="Pinned" value="3" text="@propsys.dll,-42293">
            <image res="%systemroot%\system32\imageres.dll,-1405"/>
          </enum>
          <enum name="PendingUpload" value="4" text="@propsys.dll,-42294">
            <image res="%systemroot%\system32\imageres.dll,-1401"/>
          </enum>
          <enum name="PendingDownload" value="5" text="@propsys.dll,-42303">
            <image res="%systemroot%\system32\imageres.dll,-1401"/>
          </enum>
          <enum name="Transferring" value="6" text="@propsys.dll,-42296">
            <image res="%systemroot%\system32\imageres.dll,-1401"/>
          </enum>
          <enum name="Error" value="7" text="@propsys.dll,-42315">
            <image res="%systemroot%\system32\imageres.dll,-1402"/>
          </enum>
          <enum name="Warning" value="8" text="@propsys.dll,-42316">
            <image res="%systemroot%\system32\imageres.dll,-1403"/>
          </enum>
          <enum name="Excluded" value="9" text="@propsys.dll,-42319"/>
          <enum name="Pending" value="10" text="@propsys.dll,-42324">
            <image res="%systemroot%\system32\imageres.dll,-1401"/>
          </enum>
        </enumeratedList>
      </displayInfo>
    </propertyDescription>
    

    When shell request DummyUIState you must create blob with Property Store Binary File. Property Store Binary File must contain the following data:

    1. Key System.PropList.StatusIcons, value with type VT_LPWSTR equal to prop:DummyState
    2. Key System.PropList.StatusIconsDisplayFlag, value with type VT_UI4 equal to 2 (2 - icon only, 1 - icon + text)
    3. Key DummyState, value type VT_UI4. This value defines the icon.

    That's all. Tested on Windows 10. Screenshot:

    enter image description here