6

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?

Zub
  • 808
  • 3
  • 12
  • 23

1 Answers1

8

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

Denis Anisimov
  • 3,297
  • 1
  • 10
  • 18
  • Thanks a lot, Blob is definitely correct. I'm still stuck in setting the `pPropVar->blob.pBlobData` to the expected data (image) format. I tried a `HBITMAP` as the data itself, a byte array extracted from the bitmap by `GetDIBits()` and a byte array of the file content of a BMP, PNG and ICO file. Unfortunately, the icon column still remains blank in all of these combinations. – Stefan Niemann Dec 14 '17 at 14:33
  • Very interesting and mysterious. Your hint regarding the resources in `propsys.dll` leads me to properties like `System.OfflineStatus`. It uses a `displayType="Enumerated"` and the `` in the `` contain an `` tag referencing an image resource in a DLL. This sounds completely reasonable and I built such a property, but unfortunately the images never get displayed. Instead the column shows the text resource that is also specified in the `` tag. Now I'll track further the Blob path and try to get an understanding of the Property Store Binary File format. – Stefan Niemann Dec 15 '17 at 21:00
  • Actually, until now I've seen no icon in a Windows Explorer column at all from whatever application, except the file icon. Even OneDrive provides no icon property on my system. That makes me suspect it could be impossible to implement an icon property. Thanks very much for your investigation! – Stefan Niemann Dec 15 '17 at 21:00
  • 2
    I added screenshot of OneDrive icons. So it is possible. The only question is - how? – Denis Anisimov Dec 16 '17 at 05:26
  • @DenisAnisimow: Brilliant, that's it! I never would have found out the relationship between those two properties. Again, thanks very much for your investigation. By the way, in your first screenshot there are icons in the `Status` column also for **directories**. How to do this could be the answer of my former SO question [How to register a Property Handler on folders](https://stackoverflow.com/questions/41912219/how-to-register-a-property-handler-on-folders). May I ask if you know how to implement custom properties that can be displayed on folders? – Stefan Niemann Dec 17 '17 at 11:34
  • 2
    Imho, icons in OneDrive is a part of shell. I think so because System.StorageProviderUIStatus, System.StorageProviderState and System.StorageProviderCustomStates are system properties. There is no way to create property store handler for folders. NSE is the only solution. – Denis Anisimov Dec 17 '17 at 11:53
  • Could you explain why this involves two different property definitions? I don't quite understand how it works. –  Jun 12 '19 at 18:37
  • @amt528 No. I used my own code based on [MS-PROPSTORE] specification. – Denis Anisimov Jul 05 '19 at 17:05
  • I followed Denis approach by building the binary layout of the necessary PROPSTORE in a byte buffer by code, which finally succeeded. Because the property system itself releases this byte buffer it has to be allocated on the heap. I can not explain on the fast why your `PSCreateMemoryPropertyStore` attempt does not work. Your `.propdesc` file looks correct. Remember that it is not possible to display any custom property on folders. Windows properties can only be provided for file items. When I'm back to work in a few days I can give you some more details on my implementation. – Stefan Niemann Jul 05 '19 at 22:17