Overview
When implementing a Shell namespace extension, a developer must provide an object that implements the IShellView interface. However, Microsoft® Windows® provides a default implementation of IShellView known as the System Folder View Object (colloquially known as DefView), that can be used in place of a custom implementation. This is the same view object used by Windows Explorer to display the details of an item. The System Folder View Object is a wrapper around standard list view functionality, providing integration with a Shell namespace extension as demonstrated in the FolderViewImpl sample.
While the System Folder View Object can also be hosted in dialogs, the scope of this example is limited to creating and using it within Windows Explorer.
It is assumed that the reader is already familiar with basic Shell namespace programming. This document attempts to address all of the necessary steps to use the System Folder View Object in a Shell namespace.
Building the FolderViewImpl Sample
- To build the FolderViewImpl sample, be sure to download and install the Windows SDK.
- Download the FolderViewImpl sample
- Launch FolderViewImpl.sln in Visual Studio
- Open the properties for the project
- Add a path to the SDK includes to the C/C++ - General page
- Add a path to the SDK libs to the Linker – General page
- Build
Installing the FolderViewImpl Sample
- Once you have built the sample, copy the FolderViewImpl.dll and FolderViewImpl.propdesc to the same directory
- From an elevated cmd window, regsvr32 FolderViewImpl.dll
- Restart explorer
- Open explorer to Computer
- There should be a list item named “Folder View SDK Sample”
About the FolderViewImpl Sample
One purpose of the FolderViewImpl sample, which is a full implementation of a Shell namespace extension, is to demonstrate the interactions between the System Folder View Object and a Shell namespace extension. It does not represent any real data! All of the complications of accessing real data have been bypassed in an effort to concentrate solely on the interactions between the namespace and System Folder View Object. For the purposes of this sample, the information that results in the view that appears in the illustration above has been packed into Item Identifier List (PIDL) structures, making it easy to access information in relation to a PIDL at any time. The below code shows the structure (FVITEMID) of the PIDL as defined in ShellFolder.h.
#pragma pack(1)
typedef struct tagObject
{
USHORT cb;
WORD MyObjID;
BYTE nLevel;
BYTE nSize;
BYTE nSides;
BYTE cchName;
BOOL fIsFolder;
WCHAR szName[1];
} FVITEMID;
#pragma pack()
The basic procedures and main interfaces that are discussed in the remainder of this topic are:
- IShellFolder::CreateViewObject is called by the Shell to create the System Folder View Object.
- The System Folder View Object queries IShellFolder for IShellFolder2, through which it gets its display information.
- Grouping in the view is attained through the implementation of ICategoryProvider, which in turn creates instances of ICategorizer as needed for each set of groups.
- IShellFolder::GetUIObjectOf and IShellFolder::CreateViewObject are used to instantiate a context menu and return an IContextMenu interface.
The System Folder View Object supports callbacks for various purposes such as returning handles or sending notification when certain actions are complete. However, this functionality is not discussed in this document since it is not necessary for basic functionality.
This document was written for and the sample tested on Windows Vista (RTM). Though no guarantee can be made concerning future design decisions, an attempt has been made to make this sample forward compatible.
Getting Started: Implementing IShellFolder Methods
When implementing a Shell namespace extension with a view, you must implement IShellFolder2. This section discusses particular interface methods that are of interest when using the System Folder View Object, or information that you should know about how the System Folder View Object works.
IShellFolder::CreateViewObject
IShellFolder::CreateViewObject is called when Windows Explorer is asked to display your view object. To use the System Folder View Object rather than a custom IShellView implementation, call one of two Shell functions – SHCreateShellFolderView or SHCreateShellFolderViewEx – in the implementation of CreateViewObject. The two functions are very similar but differ in how they handle associated callback functions. This sample uses SHCreateShellFolderView.
The section of sample code in ShellFolder.cpp used to create the System Folder View Object is shown here.
HRESULT hr = E_NOINTERFACE;
if (riid == IID_IShellView)
{
SFV_CREATE csfv = { sizeof(csfv), 0 };
hr = QueryInterface(IID_PPV_ARGS(&csfv.pshf));
if (SUCCEEDED(hr))
{
csfv.psfvcb = NULL;
hr = SHCreateShellFolderView(&csfv, (IShellView**)ppv);
csfv.pshf->Release();
}
…
The CreateViewObject implementation should also be used to instantiate the ICategoryProvider, IDropTarget and IContextMenu interfaces, which provide standard functionality for the view.
Note that the IContextMenu instantiated in CreateViewObject represents the context menu for the background of the view itself. Requests for a context menu for individual items in the view go to IShellFolder::GetUIObjectOf. This, as well as ICategoryProvider, is discussed in detail in the Context Menus and Categories section of this article.
Also note that the FolderViewImpl sample does not instantiate IDropTarget, which means that nothing can be dragged to the view and dropped.
IShellFolder2::GetDetailsOf & GetDefaultColumnState
When using the System Folder View Object, the Shell makes an initial call to GetDetailsOf, using a null PIDL, to retrieve the column count, column titles, and basic formatting information. It also makes a call to IShellFolder2::GetDefaultColumnState before the initial enumeration of the columns, ensuring that at least one column (Col 0) is visible. GetDefaultColumnState is then called after each column is enumerated. If the call to GetDetailsOf/GetDetailsEx can be slow to retrieve a certain property, pass the SHCOLSTATE_SLOW flag in the SHCOLUMNINFO structure to move that retrieval to a background thread.
After the System Folder View Object has enumerated the columns, it proceeds with further calls to GetDetailsOf to fill in the data with valid PIDLs and column numbers.
IShellFolder2::MapColumnToSCID
A SHCOLUMNID structure, known colloquially as a SCID (pronounced "skid") contains a format ID and a property ID (PID). The combination of the format ID, a globally unique identifier (GUID) also used to identify a property group, and a PID uniquely defines a column. SHCOLUMNID structures are used by categorizers (ICategoryProvider) and IShellFolder2::GetDetailsEx, among others. Note that in Vista and beyond, the SCID is now referred to as a PKEY (PROPERTYKEY is identical but has a name that applies more broadly to the property system than SHCOLUMNID).
The FolderViewImpl sample uses its implementation of IShellFolder2::MapColumnToSCID to convert the column number to a SHCOLUMNID structure. FolderViewImpl then calls a helper function named _GetColumnDisplayName that accepts a PIDL and a SHCOLUMNID as parameters and returns a user-friendly string to use as the column label.
Note that the more common column names have been given standard set identifiers and property IDs. You should use those identifiers when defined rather than defining your own. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/indexsrv/html/ixrefint_7wc3.asp.
IShellFolder2::GetDetailsEx
IShellFolder2::GetDetailsEx is used to retrieve the same information as IShellFolder2::GetDetailsOf, but generally in different formats. IShellFolder2::GetDetailsOf retrieves a display string, where IShellFolder2::GetDetailsEx, which is the preferred method, retrieves a variant with a raw value. By implementing both functions, your data is available in both ways.
The FolderViewImpl sample provides a generic helper function called _GetColumnDisplayName which retrieves a column’s display text. GetDetailsEx simply calls the function using the SHCOLUMNID passed to it while GetDetailsOf must first call MapColumnToSCID to form a SHCOLUMNID before calling the helper function.
IShellFolder::CompareIDs
Clicking a column header sorts the view based on that column. The sorting is done through the IShellFolder::CompareIDs method. The column number is contained in the low word of that method's lParam parameter. It should be noted that two PIDLs compared by this method might not be single level and a comparison of the entire PIDL may be necessary. Multilevel PIDLs must be compared by binding to the IShellFolder at each level and then letting that IShellFolder instance’s CompareIDs method do the comparison. The _ILCompareRelIDs function is provided in the ShellFolder.cpp file for this purpose.
Context Menus and Categories
There are two context menus that must be considered: 1.) item menus - those menus that are specific to an item in a list view; 2.) background menu - used to set the view mode and categories. This section is not meant to be a full set of instructions on the use of context menus, but only for folder navigation (including Open and Explore) for items and groups in the System Folder View Object.

Item Menus
When a request is made for the context menu for an item, a cascade of calls to your implementation of the following methods is initiated by the System Folder View Object.
- IShellFolder::GetUIObjectOf is called to obtain an IContextMenu interface.
- A DEFCONTEXTMENU is created with the current IShellFolder2 implementation.
- SHCreateDefaultContextMenu is called to create the context menu for the item.
The context menu implementation created by SHCreateDefaultContextMenu will try to add verbs (such as open/explore) based on the available associations for the item and it determines those associations by asking for IQueryAssociations. AssocCreateForClasses is the way for the shellfolder to indicate that an item is a member of a particular type (“class”) and use the associations set up for that class. In this case open/explore are verbs registered for items with the Folder class.
It should be noted here that this sample is optimized for Vista. The apis SHCreateDefaultContextMenu and AssocCreateForClasses are only available on Vista and later. For downlevel operating systems you will need to use an equivalent api. For a substitue for SHCreateDefaultContextMenu, see CDefFolderMenu_Create2. For AssocCreateForClasses, see AssocCreate and IQueryAssociations::Init.
Background Context Menu
The System Folder View Object adds multiple entries to the background context menu (depending on OS version you are running). These include entries such as View - which contains the same entries as the standard View menu on the toolbar, and Refresh - which provides the normal refresh functionality. Depending on the version of the operating system you are running, you will also see entries such as Arrange Icons By, Sort By, and/or Group By. Choosing one of these menu items displays a submenu of options by which to sort/arrange the items in category view. The first options listed are those associated with particular visible columns. Below those entries are the special categories, in this case only Value. The remainder of this document examines the steps that the System Folder View Object uses to fill these submenus.
Categories
To better understand the concept of categories, look at Computer, which is implemented using the System Folder View Object. To display the context menu, right-click on the view’s background. From that menu, choose Arrange Icons By and check Show in Groups. Then, from that same menu, select different columns to sort by and watch the groups change based on the column selected.
Each column is represented by a SHCOLUMNID and mapped in your code to a category GUID representing the set of groups. The groups themselves are represented by DWORD values. Each category (represented by the GUID), therefore, has a list of DWORD values representing the groups. In the table below, the DWORD values are presented as defined constants such as Small or Numerical.
So far our discussion has dealt only with mapping categories to columns. However, it is not required that categories map to a column. This is discussed in the ICategoryProvider section below.
The remainder of this document explores these issues based on an implementation using the following model.
Column | 0 | 1 | 2 | 3 | NA |
Title | Name | Size | Sides | Level |
|
SHCOLUMNID | SCID_NAME | SCID_SIZE | SCID_SIDES | SCID_LEVEL | CAT_GUID_VALUE |
Category GUID | CAT_GUID_NAME | CAT_GUID_SIZE | CAT_GUID_SIDES | CAT_GUID_LEVEL | CAT_GUID_VALUE |
Category/Groups | Alphabetical | Small | Circle | Numerical | Less Than Five |
|
| Med | Triangle |
| Five or Greater |
|
| Large | Rectangle |
|
|
|
|
| Polygon |
|
|
ICategoryProvider
The first thing the System Folder View Object attempts to do is query your implementation of IShellFolder::CreateViewObject for a pointer to an instance of ICategoryProvider. If this succeeds, the System Folder View Object iterates through the visible columns, passing each column’s SHCOLUMNID to ICategoryProvider::CanCategorizeOnSCID to determine whether the column can be categorized. If you have defined the column such that it can be categorized, its name is added to the list in the top section of the submenu. The illustration shows the result of success for all four of the sample columns.
As mentioned above, you can define categories that do not map to columns. The System Folder View Object requests, though ICategoryProvider::EnumCategories, a standard enumerator in the form of an IEnumGuid interface. This interface enumerates those categories that you've defined beyond those that map to columns. The illustration shows that it has processed the GUID for one additional category. ICategoryProvider::GetCategoryName was called to resolve that category’s name as “Value”. The remaining standard entries are enabled or disabled depending on the current view type. At this point the System Folder View Object has all of the information necessary to display the context menu.
ICategorizer
When one of the categories is selected from the context menu, that category’s GUID is passed to ICategoryProvider::CreateCategory in a request for an ICategorizer.
Once the categorizer is created, it is used to organize the items into groups. First, the PIDLs are passed to ICategorizer::GetCategory to retrieve the DWORD representation of the categories (the category identifiers). Next, ICategorizer::GetCategoryInfo is called to retrieve the display names of the categories. Finally, the listing order of the groups is determined by the ICategorizer::CompareCategory method.
Conclusion
This sample is provided to give developers a better understanding of how to properly implement a Shell namespace extension. This sample is also available as part of the Windows SDK moving forward. We also want to provide better samples to developers for extending the Shell. Please leave a comment to this post if there is something specific you would like for us to go deeper on with future samples.