CURRENT WORK ITEM - PREVIEW ONLY

SHGetViewStatePropertyBag

This function presents a folder’s view state as a property bag.

Declaration

HRESULT
SHGetViewStatePropertyBag (
    LPCITEMIDLIST pidl,
    LPCWSTR pszBagName,
    DWORD dwFlags,
    REFIID riid,
    void **ppv);

Parameters

The pidl argument provides the address of an Item Identifier List that represents the folder for which properties are sought. This argument may be NULL.

The pszBagName argument provides the address of a null-terminated Unicode string that names the desired property bag.

The dwFlags argument provides bit flags:

SHGVSPB_PERUSER (0x00000001)  
SHGVSPB_ALLUSERS (0x00000002)  
SHGVSPB_PERFOLDER (0x00000004)  
SHGVSPB_ALLFOLDERS (0x00000008)  
SHGVSPB_INHERIT (0x00000010)  
SHGVSPB_ROAM (0x00000020)  
SHGVSPB_NOAUTODEFAULTS (0x80000000)  

The riid argument is a reference to an IID for the requested interface to the property bag.

The ppv argument addresses a variable that is to receive the interface pointer.

Return Value

The function returns zero for success, else an error code.

Behaviour

In the general case, each call to this function creates a property bag for the given folder, bag name and flags. However, the function remembers the property bag created most recently (per-process), so that a series of calls for the same folder, bag name and flags therefore do not create multiple bags.

View states are not supported for folders on removable drives. If pidl identifies a folder on a removable drive, the function fails, returning E_FAIL.

Creation of a view-state property bag is just a matter of obtaining memory and saving the arguments. If this fails for lack of memory or because pszBagName is NULL, then the function fails, returning E_OUTOFMEMORY.

With the property bag either remembered or created, the function queries it for the interface given by riid, returning the interface pointer at the address given by ppv. The property bag implements the IPropertyBag and IPropertyBag2 interfaces. However, the IPropertyBag2 methods are all implemented to fail, returning E_NOTIMPL.

The value of the function lies almost entirely in what can be done subsequently with what the function has created. Except for the brief checks noted above, about removable drives and a non-NULL bag name, the function does nothing with the arguments except to save them for later, when the bag is read or written. Note especially that (contrary to the documentation) the function imposes no requirements on various combinations of bits in dwFlags. Of course, some combinations are very nearly useless, in the sense that the Read and Write methods of the returned property bag must in almost cases fail, but no combination causes the function itself to fail.

View States

A property bag created by SHGetViewStatePropertyBag provides highly generalised storage of essentially arbitrary properties for any shell folder. Different clients can store their properties for a folder in differently named bags. Microsoft’s clients of this function use the names “Desktop” and “Shell”. Those clients are concerned primarily with the visual presentation of folders when browsed, hence the name View State, but the interface is in no way restricted just to visual appearance.

One restriction does apply, however, and is significant. The storage arranged by SHLWAPI persists in most-recently-used (MRU) lists and can get discarded. This is clearly intended as a property of the interface. Indeed, pretty much all that the documentation says usefully about this function is to warn that it not be used for storing critical information: “if a folder is not visited for a long time, its view state is eventually deleted.”

The implementation details of how view states are supported through MRU lists have been a long-running problem, all the way back to the original Windows 95 and reports of desktop icons seeming to rearrange spontaneously when the desktop was returned to after browsing many other folders. Even Windows XP sometimes treats users to large icons despite their having set some other viewing option to “Apply to All Folders”.

Writing

SHLWAPI provides two broadly distinct implementations for writing a view state: one by SHELL32.DLL, which is perhaps maintained only for backwards compatibility; and one by SHLWAPI itself with support from SHDOCVW for the MRU lists.

Bag of Bags

What this function creates is (typically) a property bag of property bags. The inner bags are not created until required for a read or write of the outer bag.

The general idea is that for some folder, the current user’s preference for some property may be stored in any of several places perhaps with very different implementations and even under the control of different executables. For instance, if the property is not stored specifically for that folder and that user (in the so-called Pidl bag), perhaps it is covered by that user’s preference for all folders (in the User Defaults bag). The following inner bags are available, in the following order:

The choice of which inner bags are consulted depends mostly on which bits were set in dwFlags.

The Pidl Bag

The inner bag that is most closely associated with a particular user’s preferences for a particular folder’s presentation is apparently called the Pidl bag. To have it be consulted for reading a property through the outer bag, set both  SHGVSPB_PERUSER and SHGVSPB_PERFOLDER in dwFlags.

For a given bag name, the Pidl bag distinguishes both users and folders. The properties in a Pidl bag are stored as registry values under the key

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\ShellNoRoam\Bags\slot\bag

where bag is the bag’s name as given by the pszBagName argument and the folder identified by the pidl argument is represented by the decimal number slot according to the folder’s place in an MRU list. Further details of this MRU list, which is implemented in SHDOCVW.DLL, are beyond the scope of this article.

The Desktop Upgrade Bag

One inner bag is perhaps of historical interest only, since it exists solely for reading properties of the desktop from an old format. This inner bag is accessible only if the (case-sensitive) bag name given by the pszBagName argument is “Desktop”. The pidl and dwFlags arguments are irrelevant, except that SHGVSPB_NOAUTODEFAULTS and SHGVSPB_INHERIT must be clear (as for all the inner bags).

The old format has values stored in different subkeys of Software\Microsoft\Windows\CurrentVersion\Explorer in the HKEY_CURRENT_USER branch of the registry. A request to read any property whose name begins with ItemPos is handled by extracting from the data for the value ViewView2, if it exists and is not empty, else ViewView, in the Streams\Desktop subkey. A request to read a property named FFlags is handled by extracting from the data for the value Settings in the DeskView subkey. Further details of interpretation are beyond the scope of this article.

The Inherit Bag

Properties for a folder and user may be inferred from the per-folder per-user properties of an ancestor folder through the action of the Inherit bag. As for the Pidl bag, the SHGVSPB_PERUSER and SHGVSPB_PERFOLDER bits must both be set in the dwFlags argument.

The User Defaults Bag

For the User Defaults bag to be read through the outer bag, the SHGVSPB_PERUSER flag must be set in dwFlags, along with either (or both) of SHGVSPB_PERFOLDER or SHGVSPB_ALLFOLDERS.

For a given bag name, the User Defaults bag distinguishes users but not folders. The properties for a User Defaults bag are stored as registry values under the key

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\ShellNoRoam\Bags\AllFolders\bag

where bag is the bag’s name as given by the pszBagName argument. The pidl argument is irrelevant.

The Folder Defaults Bag

Inclusion of the Folder Defaults bag requires either of the following combinations for set bits of dwFlags:

Also, the folder identified by the pidl argument must be a so-called system folder, in the sense tested by the documented PathIsSystemFolder function and meaning specifically a file system directory that has either (or both) of the read-only and system attributes. This requirement arises because the per-folder defaults are handled by SHELL32.DLL using DESKTOP.INI files, and although you might search long and hard through Microsoft’s documentation to find a clear statement of this, DESKTOP.INI files are recognised as significant to the shell only if they are in directories that have either the read-only or system attribute. Further details of how SHELL32 implements per-folder defaults are beyond the scope of this article.

The point to the Folder Defaults bag is presumably that it distinguishes folders but not users (though this makes a mystery of the involvement of the all-folders and per-user flags in the conditions for access). The implementation of these per-folder defaults is external to SHLWAPI and the same implementation is invoked whatever the bag name, i.e., the pszBagName argument is irrelevant.

The Global Defaults Bag

The type of inner bag that provides the least specific storage of folder properties is the Global Defaults bag. To include it in reads through the outer bag, set

For a given bag name, the Global Defaults bag distinguishes neither the folder nor the user. The properties for a Global Defaults bag are stored as registry values under the key

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Shell\Bags\AllFolders\bag

where bag is the bag’s name as given by the pszBagName argument. The pidl argument is irrelevant.

Availability

The SHGetViewStatePropertyBag function is exported from SHLWAPI as ordinal 515 in version 6.00 and higher.

This function was documented among the Settlement Program Interfaces in late 2002. It appears in a section headed Shell Functions whose other entries are all implemented in SHELL32. The documentation for the function itself correctly assigns the function to SHLWAPI but declares it as requiring “version 5.0 or later”.