Welcome to shell: revealed Sign in | Join | Help
in Search

Shell Blog

Shell Namespace Extension: Creating and Using the System Folder View Object

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.



FolderViewImpl Shell Namespace Extension

 

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

  1. To build the FolderViewImpl sample, be sure to download and install the Windows SDK. 
  2. Download the FolderViewImpl sample
  3. Launch FolderViewImpl.sln in Visual Studio
  4. Open the properties for the project
  5. Add a path to the SDK includes to the C/C++ - General page
  6. Add a path to the SDK libs to the Linker – General page
  7. Build

Installing the FolderViewImpl Sample

  1. Once you have built the sample, copy the FolderViewImpl.dll and FolderViewImpl.propdesc to the same directory
  2. From an elevated cmd window, regsvr32 FolderViewImpl.dll
  3. Restart explorer
  4. Open explorer to Computer
  5. 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:

  1. IShellFolder::CreateViewObject is called by the Shell to create the System Folder View Object.
  2. The System Folder View Object queries IShellFolder for IShellFolder2, through which it gets its display information.
  3. 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.
  4. 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.



FolderViewImpl - Context Menu



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.

  1. IShellFolder::GetUIObjectOf is called to obtain an IContextMenu interface.
  2. A DEFCONTEXTMENU is created with the current IShellFolder2 implementation.
  3. 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

  

Background Context Menu - Categories 

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.

Published Thursday, March 15, 2007 6:42 PM by chrdavis

Comments

 

bhaidar said:

Hello,

I am running on Windows XP and trying to run the FolderView sample.

What are these paths?

1- Add a path to the SDK includes to the C/C++ - General page

2- Add a path to the SDK libs to the Linker – General page

I am not a C++ developer. I will be reading C++ soon, but thought of running the sample first.

Also, when I run regsvr32, I get the popup window saying:

LoadLibrary("FolderViewimpl.dll") failed - The specified module could not be found

Thanks

June 29, 2007 3:39 AM
 

chrdavis said:

bhaidar - this sample will only work on Vista and greater.

August 16, 2007 11:51 PM
 

v_lion_77 said:

I have one question regarding default menu command, which should be fired on double click. When I double click an "file" item in the FolderView  nothing happens, whereas I expect 'Display' command to be invoked.

Why this does no happen and what code  I have to add to make it work as expected?

August 25, 2007 9:11 AM
 

Shell Blog said:

Overview In my earlier post , I showed how to create a Shell Namespace Extension using the default IShellView

September 6, 2007 12:42 PM
 

chrdavis said:

v_lion_77 - yes, this doesn't work as is in this sample.  You can enable double-click to invoke the default verb (display in this case) by adding the below registry key:

HKEY_CLASSES_ROOT\CLSID\{BB8F539D-3B97-4473-9E07-C8248C53248E}\shellex\MayChangeDefaultMenu

For information about what the MayChangeDefaultMenu does, see:

http://msdn2.microsoft.com/en-us/library/aa969384.aspx

September 10, 2007 11:48 PM
 

v_lion_77 said:

Thank you very much, the problem with default menu cmd has been solved. But another one has arised :). Now I'm struggling with keyboard accelerators, I mean I want to make my custom command to be invoked directly from the keyboard, e.g. if the user press Ctrl+U  I want corresponding command to be executed. So far I have not found any ways to do this.   In the previous version of my NSE I used IShellView::TranslateAccelerator, but now I use DefView and have no ways to stick my accelerators table to the shell view.  Anybody has any ideas? Thank you in advance.

September 22, 2007 11:35 AM
 

v_lion_77 said:

One more question. Is there a way to distinguish REFRESH (when user hits F5 ) from ordinary folder browsing in  the IShellFolder::EnumObjects. As EnumObject is time-consuming in my case, I need to decide if I should load items from my own cache or load them from the origin. There should be a special flag or something but I do not know what exactly and where. Please help.

October 4, 2007 12:38 PM
 

Shell Blog said:

Overview From my past posts about implementing your own Shell Namespace, there have been some great questions

March 10, 2008 12:43 PM
 

v_lion_77 said:

>Overview From my past posts about implementing your own Shell Namespace, there have been >some great questions

No answers to my questions! No information concerning namespace extention development on Vista. What is going on??????? Is this a MS policy???? This makes me mad! Is it so difficult to publish the technical documentation (this MUST be done first) instead of making people ask questions which you leave unanswered?

April 28, 2008 9:21 AM
 

blackwell said:

Hello,

you asked for input on what to cover in future entries at this site, here's my suggestion:

Displaying the shell background context menu for a specified folder in a tiny GUI program

(Example of displaying the shell item context menu can be found here: http://www.codeproject.com/KB/shell/shellcontextmenu.aspx

Since that is partly broken, the fixed version can be found here: http://www.geocities.com/richard_hoefter/ContextMenuPlugin/

The "Microsoft" example can be found here (it allows selecting a single item only): http://www.microsoft.com/msj/0497/wicked/wicked0497.aspx)

If possible, please try to aim low, develop a tiny, self-contained example and explain it step by step (there are many articles on the net esp. related to these COM things that just very roughly explain things, like here http://www.zabkat.com/blog/08Jul07.htm (and I have next to no idea what the good fellow is talking about there, aside of the main problem he's trying to solve); if you assume that everyone is fluent with COM you'll leave out 50%+ of the people the things you cover here could be relevant for).

Thank you.

June 11, 2008 8:14 PM
Anonymous comments are disabled
Powered by Community Server, by Telligent Systems © 2006 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement.