Namespace extensions - the undocumented Windows Shell (original) (raw)
Index
Functions
- IsInterfaceSupported
- PrintInterfaceName
- PrintSupportedInterfaces
- SHAlloc
- SHCreateShellFolderViewEx
- ShlExtInit
- ShlExtUninit
- SHShellFolderView_Message
- ILAppendID
- ILClone
- ILCloneFirst
- ILCombine
- ILCreate
- ILCreateFromPath
- ILGetCount
- ILGetDisplayName
- ILGetNext
- ILGetSize
- ILGlobalClone
- ILGlobalFree
- ILFindChild
- ILFindLastID
- ILFree
- ILIsEqual
- ILIsParent
- ILLoadFromStream
- ILRemoveLastID
- ILSaveToStream
Structures
- SFVCB_COLUMNINFOSTRUCT
- SFVCB_SELECTINFO
- SFVCB_TOOLBARBUTTONINFO
- SFVCB_TOOLBARINFO
- SHColInfo
- SHELLVIEWDATA
SHCreateShellFolderViewEx callback messages
- SFVCB_ADDTOOLBARITEMS
- SFVCB_CHANGENOTIFY
- SFVCB_COLUMNCLICK
- SFVCB_COLUMNCLICK2
- SFVCB_COPYHOOKCALLBACK
- SFVCB_DRAWMENUITEM
- SFVCB_EXITMENULOOP
- SFVCB_GETCHANGENOTIFYPIDL
- SFVCB_GETDETAILSOF
- SFVCB_GETNAMELENGTH
- SFVCB_GETTOOLBARTIP
- SFVCB_GETTOOLBARINFO
- SFVCB_INITMENUPOPUP
- SFVCB_INVOKECOMMAND
- SFVCB_LISTREFRESHED
- SFVCB_MEASUREMENUITEM
- SFVCB_REGISTERCOPYHOOK
- SFVCB_SELECTIONCHANGED
- SFVCB_VIEWRELEASE
- SFVCB_WINDOWCLOSING
- SFVCB_WINDOWCREATED
- SFVCB_WINDOWFOCUSED
SHShellFolderView_Message messages
- SFVM_GETARRANGECOLUMN
- SFVM_ADDOBJECT
- SFVM_GETITEMCOUNT
- SFVM_GETITEMPIDL
- SFVM_REMOVEOBJECT
- SFVM_UPDATEOBJECT
- SFVM_SETREDRAW
- SFVM_GETSELECTEDOBJECTS
- SFVM_ISDROPONSOURCE
- SFVM_MOVEICONS
- SFVM_GETDRAGPOINT
- SFVM_GETDROPPOINT
- SFVM_SETOBJECTPOS
- SFVM_ISDROPONBACKGROUND
- SFVM_CUTOBJECTS
- SFVM_TOGGLEAUTOARRANGE
- SFVM_LINEUPICONS
- SFVM_GETAUTOARRANGE
- SFVM_GETSELECTEDCOUNT
- SFVM_GETITEMSPACING
- SFVM_REFRESHOBJECT
- SFVM_SETCLIPBOARDPOINTS
Shell Messages
- CWM_GETISHELLBROWSER
- CWM_GETPATH
- CWM_GETSETCURRENTINFO
- CWM_SELECTITEM
- CWM_SETPATH
- CWM_STATECHANGE
- CWM_STOPWAITING
- CWM_TESTPATH
- CWM_WANTIDLE
Macros
- FileCabinet_GetIShellBrowser
- FileCabinet_GetSetCurrentInfo
- FileCabinet_SelectItem
- FileCabinet_StopWaiting
- FileCabinet_WantIdle
Interfaces
This article explains how you can easily create a namespace extension with lots of features without doing lots of work by using some undocumented shell functions. The most noticeable function is SHCreateShellFolderViewEx, which creates the view for you and creates all interfaces you need for displaying the contents of your folder. You can modify the behaviour of the folder by implementing a callback function. This is how Microsoft implements its own namespace extensions.
Introduction to the windows shell
The windows shell is built around COM interfaces. The browser ("explorer") calls interfaces that are implemented by a number of DLL's and these DLL's can call back into the interfaces of the browser. You can extend the behaviour of the browser by plugging in your own DLL that implements the needed interfaces.
The householding of the DLL's is maintained in the registry, as is usual for COM objects.
The shell namespace
The shell namespace is a collection of folders that contain items. These items can in turn be folders, generating a tree structure. This ressembles the directory tree structure that is found in a file system, but should not be confused with it.
The top of the shell namespace tree is the Desktop folder. This folder contains "my computer", which in turn contains the drives on your computer. The part of the shell namespace that represents a drive looks almost the same as the directory structure on that drive, but is not exactly the same. The drive can contain additional items and existing items may look very different in the shell namespace.
Shell extensions
The DLL's that are plugged into the shell are called shell extensions. There are several kinds of shell extensions:
- A context menu extension puts extra items in the context menu that is viewed in the browser.
- A property sheet extension displays extra property pages in the property sheets that are viewed in the browser.
- A namespace extension adds extra folders to the namespace.
Pidls
Every item in a folder is identified by an identifier, just like every file or directory on a drive is identified by a filename. This identifier is called a Pidl.
For someone who uses the shell to browse the namespace, a pidl is just an opaque structure that gets passed around without having any meaning.
Someone who implements a part of the namespace assigns a meaning to the pidls for his part of the namespace. The pidl is a variable-sized structure that can contain anything the implementor wants to put in. The pidl usually caches all information that is frequently needed. In a directory structure, the pidl contains the long and short filename and some other stuff.
Structure of a pidl
A item id consists of 2 parts: the length and the data. The length comes first and is the total length of the item (including the length part itself). The data is opaque to the user and only has meaning to the implementor of the namespace.
Multiple item ids are concatenated to form a pidl. A pidl is a series of concatenated item ids, ending with an id with length 0.
Absolute and relative pidls
A filename can be absolute or relative: An absulute filename is fully qualified (e.g. "c:\winnt\system32\shell32.dll"). A relative filename is relative to the directory in which it resides.
The same goes for a pidl. A pidl can be absolute or relative. The root for an absolute pidl is the desktop. A relative pidl is relative to a specific folder in the namespace.
Designing your pidls
If you implement your own namespace extension, you will have to design your own pidls.
The easiest way to assign a meaning to your pidls is by defining a struct that contains all the information you need.
You must be able to determine if a pidl that is passed to you is really a valid pidl. You can do this by starting the pidl with a signature (a few bytes that are always the same).
The pidl should contain all information that will frequently be needed and that takes some time to find out. You should always store the name and all texts that are stored in the different columns in the details view, unless you can derive them easily.
Your pidl should contain one field that uniquely identifies the item. This can be a handle, an ID,...
You will be the only one who decides wether two pidls are for the same item. You will do that through your IShellFolder
's CompareIDs. Return 0 for pidls that represent the same object, and 1 or -1 for pidls that represent different objects (even if you don't care how they are sorted).
Allocating and freeing pidls
All pidls should always be allocated and freeed by the Shell Allocater.
You can retrieve the Shell Allocator by calling SHGetMalloc
.
Shortcuts for allocating and freeing pidls are provided by the functions SHAlloc and ILFree.
Pidl functions
SHAlloc
WINSHELLAPI LPVOID WINAPI SHAlloc(UINT cb);
Description
Allocates cb bytes of memory using the Shell Allocator
Parameters
- cb: The size in bytes of the block to be allocated
Return value
A pointer to the block of memory that was allocated
ILFree
WINSHELLAPI void WINAPI ILFree(LPITEMIDLIST pidl);
Description
Frees a pidl using the Shell Allocator
Parameters
- pidl: the pidl to free
Remarks
I have no idea why there is both a SHfree function and an ILFree function. They are probably exactly the same.
ILClone
WINSHELLAPI LPITEMIDLIST WINAPI ILClone(LPCITEMIDLIST pidl);
Description
Creates a copy of the passed in pidl
Parameters
- pidl: The pidl to copy
Return value
A pointer to the newly created copy of the pidl
Remarks
The new pidl is allocated using the Shell Allocator. You should free it by calling ILFree.
ILAppendID
WINSHELLAPI LPITEMIDLIST WINAPI ILAppendID(LPITEMIDLIST pidl, LPCITEMIDLIST item,BOOL bEnd);
Description
Appends a new item identifier to an existing pidl
Parameters
- pidl: A complex pidl to which an extra item id will be added
- item: A simple pidl that constists of only one item
- bEnd: If non-zero, the item is added at the end. If zero, the item is added to the beginning.
Remarks
This function destroys the passed in complex pidl.
ILCloneFirst
WINSHELLAPI LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl);
Description
Creates a new pidl that contains the first item id of a complex pidl
Parameters
- pidl: The complex pidl from which to extract the first item id
Return value
A newly created pidl that contains the first item id of the passed in complex pidl
Remarks
The new pidl is allocated with the Shell Allocator. You should free it by calling ILFree.
ILCombine
WINSHELLAPI LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlsub);
Description
Concatenates two complex pidls
Parameters
- pidl: The left part of the pidl
- pidlsub: the right part of the pidl
Return value
The newly created pidl
Remarks
The passed in pidls are not destroyed. The newly created pidl is allocated using the Shell Allocator. You should free it by calling ILFree. This function is useful if you have a relative pidl of an item and the absolute pidl of its parent folder. The function returns the absolute pidl of the item.
ILCreateFromPath
Remarks
I didn't find out the exact signature of this function yet.
ILFindChild
WINSHELLAPI LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
Description
Compares the elements of a complex pidl
Parameters
- pidl1: the first pidl
- pidl2: the second pidl
Return value
If at least the first item id is the same, returns the location of the first item id in pidl2 that doesn't match pidl1. NULL if pidl2 is shorter than pidl1
Remarks
I never tested this function. The signature and description may not be correct.
ILFindLastID
WINSHELLAPI LPITEMIDLIST WINAPI ILFindLastID)(LPCITEMIDLIST pidl);
Description
Finds the position of the last item id in a pidl
Parameters
- pidl: A complex pidl
Return value
A pointer to the last item id in the passed in pidl
Remarks
You can call ILClone(ILFindLastID(pidl)) to create a relative pidl out of an absolute pidl.
ILGetDisplayName
Remarks
I didn't find out the exact signature of this function yet.
ILGetNext
WINSHELLAPI LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl);
Description
This function finds the location of the second item id in a complex pidl
Parameters
- pidl: A complex pidl
Return value
The position of the next item id in the pidl The pidl itself is the first item id, the next one is the second.
Remarks
You can use ILClone(ILFindNextID(pidl)) to obtain a pidl of an item that is relative to the first parent folder. This can be very useful if you were passed a complex pidl in you IShellFolder implementation. You can split off the first item id, bind a new shell folder to this id and the,n pass this new folder the remainder of the pidl.
ILGetSize
WINSHELLAPI UINT WINAPI ILGetSize(LPCITEMIDLIST pidl);
Description
Calculates the full size of a pidl
Parameters
- pidl: The complex pidl of which to calculate the size
Return value
The total size of the passed in pidl in bytes, including the zero terminator
ILGlobalClone
Remarks
I didn't find out the exact signature of this function yet.
ILGlobalFree
Remarks
I didn't find out the exact signature of this function yet.
ILIsEqual
WINSHELLAPI BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
Description
Tests two pidls for equality
Paramaters
- pidl1: The first pidl
- pidl2: The second pidl
Return value
Zero if the two pidls are different, nonzero if the pidls are equal
ILIsParent
Remarks
I didn't find out the exact signature of this function yet.
ILLoadFromStream
Remarks
I didn't find out the exact signature of this function yet.
ILRemoveLastID
WINSHELLAPI BOOL WINAPI ILRemoveLastID(LPCITEMIDLIST pidl);
Description
Removes the last item identifier from a complex pidl
Parameters
- pidl: A complex item identifier list
Return value
Nonzero if successful, zero otherwise
Remarks
This function modifies the passed in pidl by setting the last item id's byte count to zero.
To create a new pidl without the last item id, you would have to call ILRemoveLastID(ILClone(pidl)).
ILSaveToStream
Remarks
I didn't find out the exact signature of this function yet.
Object model
The shell is browsed by a Shell Browser object, which is implemented by the browser, usually Windows Explorer. This browser traverses the namespace.
The namespace is made up of Shell Folders. A Shell Folder is an object that represents a virtual folder, i.e. a filesystem directory or a namespace extension folder. The items of a Shell Folder are enumerated by an Item Enumerator. This object simply enumerates the pidls of objects.
The contents of a Shell Folder are viewed by a Shell View. The Shell View is a window that usually displays a list of items. A group of items (e.g. the items that are selected in a Shell View) is represented by a UI Object.
The Shell Browser
The Shell Browser is the application that browses the namespace (Windows Explorer). The Shell Browser implements the interface IShellBrwoser. You will never implement this interface yourself.
Shell Folders
Shell Folders represent folders in the namespace. They create new Shell Folders for their items and they create UI Objects. They provide information on their items. A Shell Folder implements a namespace extension.
Interfaces implemented by Shell Folders
A shell folder should implement IShellFolder
, IPersistFolder
, IDropTarget
, IExtractIcon
and ["#IShellDetails">IShellDetails](<span)
.
The IShellFolder
interface is used for getting information on items in a folder and as a factory for creating Item Enumerators, Shell Views and UI Objects. Most IShellFolder methods take pidls as parameters. These pidls are always relative to the Shell Folder.
The IPersistfolder
interface is only used to pass the shell folder its own absolute pidl.
The IDropTarget
interface is a standard OLE interface that is used for drag and drop.
The IExtractIcon
interface is used to get the icon for an item.
The ["#IShellDetails">IShellDetails](<span)
interface is used for communication with the Shell View. It provides some extra information about how to display items in a multi-column list: the titles for the columns and the details to fill in in these columns.
All these interfaces are well documented, except ["#IShellDetails">IShellDetails](<span)
. This interface is described later.
Item Enumerators
An item enumerator makes it possible to enumerate all items in a Shell Folder.
An Item Enumerator implements IEnumIDList. This is a common IEnumXXX
interface. This interface is well documented.
User Interface Objects (UI objects)
UI Objects handle user interaction with items. They implement shell extensions other than namespace extensions.
Possible UI objects are context menu handlers, property sheet handlers, infotip handlers.
UI Objects must be able to handle multiple selection.
Interfaces implemented by UI Objects
UI Objects implement some are all of the following interfaces:IObjectWithSite
, IExternalConnection
, IShellExtInit
, IDataSource
, IContextMenu
, IShellPropSheetExt
and IQueryInfo
.
IObjectWithSite
is a standard OLE interface that is used for setting up communication between an object and the container in which it resides. In this case the container is the Shell Browser. You can omit thhis interface.
IExternalConnection
is used for maintaining strong locks on an object. This interface is needed because the object may be marshalled to another proces (e.g. during drag and drop).
You can omit this interface. In that case, OLE will provide a default interface for you.
IShellExtInit
is implemented by property sheet handlers and context menu handlers. These should always implement the interface. The IShellExtInit
interface only has one method Initialize, which is used for setting the context of the shell extension.
IDataSource
is a standard OLE interface. It is used mainly for drag and drop and for copy and paste. You can think of the IDataSource
interface as a way of serializing the set of items.
If your namespace extension has more than one folder, you can implement your own clip formats. The IDataSource
interface is too complex to be fully covered here.
Besides its obvious usage as a source of information for displaying a context menu, the IContextMenu
interface is used for some other purposes: When the user presses a standard button in the toolbar, IContextMenu::InvokeCommand
will be invoked with a verb. This verb will be a word like cut, copy, paste, delete or properties.
The IContextMenu
interface is also used to add items to the main menu of the browser's window. When QueryContextMenu
is called, you should add commands to the menu that have identifiers of the form idCmdFirst
+ SOME_CONSTANT
. When InvokeCommand
is called, the identifier SOME_CONSTANT
will be passed.
The IShellPropSheetExt
interface is used for displaying property pages.
The IQueryInfo
interface is used for displaying info tips when the mouse is moved over an item.
All these interfaces are well documented.
Shell Views
Shell views are the windows that display a shell folder's contents. Shell views implement IShellView
and some additional interfaces. Instead of implementing this object yourself, you should call ["#SHCreateShellFolderViewEx">SHCreateShellFolderViewEx](<span)
. This function creates the Shell View for you.
Interface IShellDetails
Besides the IUnknown
functions, the IShellDetails
interface has two functions: GetDetailsOf
and ColumnClick
.
HRESULT STDMETHODCALLTYPE GetDetailsOf(LPCITEMIDLIST pidl, UINT col, ["#SHColInfo">SHColInfo](<span) *data);
Description
If pidl equals NULL, this function retrieves information about a column in the Shell View. Otherwise, it retrieves the information to display in a particular column of the view for a given pidl.
Parameters
- pidl: The identifier of the item for which to retrieve information, or NULL to retrieve information for a whole column.
- col: The index of the column (starting at 0)
- data: Pointer to the SHColInfo struct to be filled in
Return value
Return S_OK if you filled in the details, E_FAIL otherwise.
If pidl equals NULL, you should return S_OK for all columns that you support and E_FAIL for an index that is too large. This is how the Shell View will know how many columns to display.
HRESULT STDMETHODCALLTYPE ColumnClick(UINT col);
Description
This function is called when the user clicks the title of a column.
Parameters
- col: The index of the column that was clicked (starting at 0)
Remarks
You should send a SFVM_REARRANGE message to the owner of the view window.
You can use the function SHShellFolderView_Message to send the meassage. The window handle of the owner of the view window is passed to you in IShellFolder::CreateViewObject
. This is the time to save this handle.
The lparam that you should pass to SHShellFolderView_Message is the index of the column that was clicked (i.e. the col parameter).
After calling SHSHellFolderView_Message, IShellFolder::CompareIDs
will be called with an lParam that equals the index of the column that was clicked. This is contrary to the Microsoft documentation, which states that this lParam will always be zero and should be ignored.
Function SHCreateShellFolderViewEx
The function
WINSHELLAPI HRESULT WINAPI SHCreateShellFolderViewEx(["#SHELLVIEWDATA">LPSHELLVIEWDATA](<span) psvcbi, LPVOID *ppv);
Description
This is the most interesting function I discovered. This function enables you to use the same mechanism as Microsoft for displaying the contents of your namespace extensions.
This function creates the Shell View for you, including the most important interfaces like IShellView
.
This function makes sure you will handle everything the way you should. It provides an easy interface for otherwise difficult tasks like changing the toolbar.
When calling this function, you pass a callback function that gets called to handle all kinds of events, enabling you to customize the shell view.
Parameters
- psvcbi: Pointer to a SHELLVIEWDATA structure
- ppv: Receives a pointer to the Shell View's IUnknown.
Remarks
Call this function from your IShellFolder
's CreateViewObject
when riid is IID_IShellView
.
The SHELLVIEWDATA structure
typedef struct _SHELLVIEWDATA
{
DWORD dwSize;
LPSHELLFOLDER pShellFolder;
DWORD dwUserParam;
LPCITEMIDLIST pidl;
DWORD dwEventId;
SHELLVIEWPROC pCallBack;
DWORD viewmode;
} SHELLVIEWDATA, * LPSHELLVIEWDATA;
Members:
dwSize
:sizeof(SHELLVIEWDATA)
pShellFolder
: Pointer to the shell folder that is creating a view objectdwUserParam
: A user-defined value that will be passed back in the callback functionpidl
: The absolute pidl of the folder that is being vieweddwEventId
: any combination of theSHCNE_
constants as described in the SHChangeNotify function. These are the notifications that should be handled by the view object.pCallback
: Pointer to your callback function (described later)viewmode
:NF_INHERITVIEW
orNF_LOCALVIEW
The callback function
HRESULT CALLBACK SHELLVIEWPROC(DWORD dwUserParam, LPSHELLFOLDER psf, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Description
This is the prototype of a function you should implement yourself. You pass a pointer to this function in SHCreateShellFolderViewEx.
Parameters
- dwUserParam: a user-defined value that was passed in SHCreateShellFolderViewEx
- psf: Pointer to the shell folder that this view object is displaying
- hwnd: The window handle of the view. This is not the same as the owner of the window that was passed in
CreateViewObject
. This owner is actually the parent of the view window. All messages are always sent to this owner window, so i don't really see the use of this hwnd parameter. - uMsg: one of the constants that are defined below (or yet another one)
- wParam: dependent on uMsg
- lParam: dependent on uMsg
Remarks
This is the function that enables you to modify the behavior of the shell view. You can add toolbar buttons, change the menu and react on several events, all from within this function. This function is typically a large switch on uMsg. Te values for uMsg and the corresponding wParam
and lParam
are described below. The uMsg values all have a name that starts with SFVCB_
.
SFVCB_INVOKECOMMAND
Description
This message is sent when the user presses one of the toolbar buttons that you added.
wParam
The wParam value is the command id that you assigned to this toolbar button. Maybe you should use LOWORD(wParam)
.
SFVCB_GETTOOLBARTIP
Description
This message is sent either when a tooltip is needed for a toolbar button or when a text label is needed if the toolbar displays text labels beneath the buttons.
LOWORD(wParam)
This is the command ID, like in SFVCB_INVOKECOMMAND.
lParam
lParam is a pointer to a unicode buffer that will receive the text string.
HIWORD(wParam)
This is the length of the buffer in unicode characters.
Remarks
You will typically call Lo
<NOBR>adStringW(hInstance, ID_YOUR_COMMAND, (LPSTR)lParam, HIWORD(wParam))</NOBR>
to react on this message.
SFVCB_GETTOOLBARINFO
Description
This message allows you to change the toolbar. It is sent when the list view is first shown.
lParam
Pointer to a <SFVCB%5FTOOLBARINFO> structure to be filled in.
Remarks
If you return S_OK
, you will get a SFVCB_ADDTOOLBARITEMS
message that allows you to provide the details of the buttons.
SFVCB_ADDTOOLBARITEMS
Description
This message is sent if you return S_OK
to the SFVCB_GETTOOLBARINFO
message. It is sent once to fill in details for all buttons.
LOWORD(wParam)
This is a constant you should add to your command IDs, much like in IContextMenu
. When the user presses a toolbar button, you will receive the ID you filled in minus this constant.
lParam
Pointer to an array of SFVCB_TOOLBARBUTTONINFO structures. The size of the array is equal to the number of buttons that was supplied in SFVCB_GETTOOLBARINFO
.
SFVCB_INITMENUPOPUP
Description
I don't know the exact meaning of this message.
SFVCB_SELECTIONCHANGED
Description
This message is sent when the selection changes in the list view.
lParam
Pointer to a SFVCB_SELECTINFO structure.
Remarks
If the user selects/deselects multiple items at a time (e.g. using Shift), the message will be sent for every item.
SFVCB_DRAWMENUITEM
Description
I don't know the exact meaning of this message.
SFVCB_MEASUREMENUITEM
Description
I don't know the exact meaning of this message.
SFVCB_EXITMENULOOP
Description
I don't know the exact meaning of this message.
SFVCB_VIEWRELEASE
Description
I don't know the exact meaning of this message.
SFVCB_GETNAMELENGTH
Description
I don't know the exact meaning of this message. The message is sent when beginning label edit.
SFVCB_CHANGENOTIFY
Description
This message is sent when SHChangeNotify
is called for one of the items in the shell folder that is represented by this view.
wParam
Pointer to an array of the two pidls that were passed to SHChangeNotify
.
lParam
The dwEventID that represents the event (e.g. SHCNE_RENAMEITEM
)
SFVCB_WINDOWCREATED
Description
This message is sent when the window is created
wParam
The HWND
of the newly created window
SFVCB_WINDOWCLOSING
Description
I don't know the exact meaning of this message.
SFVCB_LISTREFRESHED
Description
I don't know the exact meaning of this message.
SFVCB_WINDOWFOCUSED
Description
This message is sent to inform you that the list view has received the focus.
SFVCB_REGISTERCOPYHOOK
Description
I don't know the exact meaning of this message.
SFVCB_COPYHOOKCALLBACK
Description
I don't know the exact meaning of this message.
SFVCB_GETDETAILSOF
Description
This message is sent to if you don't implement IShellDetails.
lParam
Pointer to a SFVCB_COLUMNINFOSTRUCT structure. The STRRET
has to be filled in.
wParam
The column for which the info is requested.
Remarks
The pidl in the SFVCB_COLUMNINFOSTRUCT structure will be NULL to request the title of a column.
SFVCB_COLUMNCLICK
Description
This message is sent if you don't implement IShellDetails.
wParam
The index of the column that was clicked
Remarks
The default implementation would be SHShellFolderView_Message(hWndCabinet, SFVM_REARRANGE, wParam) where hWndCabinet is the window handle that was passes in IShellFolder::GetViewObjectOf
.
SFVCB_GETCHANGENOTIFYPIDL
Description
Use this message to change the pidl to watch for change notifications. This is only useful of you will call SHChangeNotify
with another pidl than the one specified in SHCreateShellFolderViewEx
.
lParam
Pointer to a complex pidl to be filled in
Remarks
It seems that specifying a NULL pidl is just the same as failing the message. You will probably never use this one.
SFVCB_COLUMNCLICK2
Description
The same as SFVCB_COLUMNCLICK
, but called when you do implement IShellDetails.
Used structs
SHColInfo
typedef struct { DWORD fJustify; INT nWidth; STRRET text; } SHColInfo, *PSHCOLINFO;
SFVCB_COLUMNINFOSTRUCT
typedef struct tag_SFVCB_COLUMNINFOSTRUCT { LPCITEMIDLIST pidl; SHColInfo sci; } SFVCB_COLUMNINFOSTRUCT, *LPSFVCB_COLUMNINFOSTRUCT;
SFVCB_TOOLBARINFO
typedef struct tag_SFVCB_TOOLBARINFO { DWORD dwNumItems; DWORD dwPos; } SFVCB_TOOLBARINFO;
SFVCB_TOOLBARBUTTONINFO
typedef struct tag_SFVCB_TOOLBARBUTTONINFO { DWORD dwBitmap; DWORD dwCommand; DWORD dwFlags; DWORD reserved1; DWORD reserved2; } SFVCB_TOOLBARBUTTONINFO;
SFVCB_SELECTINFO
typedef struct tag_SFVCB_SELECTINFO { DWORD reserved; DWORD dwFLAGS; LPITEMIDLIST pidl; } SFVCB_SELECTINFO;
The function SHShellFolderView_Message
The function
WINSHELLAPI int WINAPI SHShellFolderView_Message(HWND hwndCabinet, UINT uMsg, LPARAM lParam);
Description
This function can be used to send some special messages to the cabinet window. These messages have mostly to do with gatherring information about items and changing some attributes of some items.
Parameters
- hwndCabinet: The window handle that was passed in
IShellFolder::CreateViewObject
- uMsg: One of the
SFVM_
constants that are described later - lParam: a message-dependant value
Return value
The return value depends on the message.
Remarks
You will need to call this function to enable sorting on a specified column. You use SFVM_REARRANGE
for that.
SFVM_REARRANGE
This message indicates that the user has clicked a column in the header of the list control. The list needs to be rearranged.
lParam
The index of the column on which to sort (starting at 0). This value will be passes to IShellFolder::CompareIDs
.
SFVM_GETARRANGECOLUMN
To be done.
SFVM_ADDOBJECT
To be done.
SFVM_GETITEMCOUNT
Description
Used to retrieve the number of items in the list.
Return value
The number of items in the list
SFVM_GETITEMPIDL
To be done.
SFVM_REMOVEOBJECT
Description
Use this message to remove an item from the list.
lParam
lParam is a relative pidl of the object to remove. You can specify NULL to remove all items.
SFVM_UPDATEOBJECT
To be done.
SFVM_SETREDRAW
To be done.
SFVM_GETSELECTEDOBJECTS
Description
Use this message to retrieve an array of pidls for all selected objects.
lParam
lParam is actually of type (LPITEMID **)
. It is a pointer to a pointer that receives the address of an array of pidls. Use SFVM_GETSELECTEDCOUNT
to learn the size of this array.
SFVM_ISDROPONSOURCE
To be done.
SFVM_MOVEICONS
To be done.
SFVM_GETDRAGPOINT
To be done.
SFVM_GETDROPPOINT
To be done.
SFVM_SETOBJECTPOS
To be done.
SFVM_ISDROPONBACKGROUND
To be done.
SFVM_CUTOBJECTS
To be done.
SFVM_TOGGLEAUTOARRANGE
To be done.
SFVM_LINEUPICONS
To be done.
SFVM_GETAUTOARRANGE
To be done.
SFVM_GETSELECTEDCOUNT
Description
This message can be used to learn how many items are selected in the list.
Return value
The number of selected items
SFVM_GETITEMSPACING
To be done.
SFVM_REFRESHOBJECT
To be done.
SFVM_SETCLIPBOARDPOINTS
To be done.
Shell messages
There are some undocumented messages that can be sent to a cabinet window. This is again the window that is passed as hwndOwner in IShellFolder::CreateViewObject.
CWM_SETPATH
wParam
A combination of one or more of the flags CSP_HANDLE
and CSP_REPOST
. CSP_REPOST
indicates the message should not be handled immediately.
lParam
If CSP_HANDLE
is specified, lParam is a HGLOBAL
that contains a string. This memory will be freed when the message is handled.
Otherwise, lParam points to a string.
CWM_WANTIDLE
Macro
This message can be sent using the following macro:FileCabinet_WantIdle(_hwnd, _user, _lpidlproc)
Description
Use this message if you created a window using SHCreateShellFolderViewEx and you want to do idle processing in your window.
wParam
wParam (the _user in the macro) is a user-defined value that will be passed to the idle proc.
lParam
lParam (the _lpidlproc in the macro) is the idle proc that should be called. This function is of the type FCIDLEPROC
.
Return value
non-zero if successful, zero otherwise
CWM_GETSETCURRENTINFO
Macro
FileCabinet_GetSetCurrentInfo(_hwnd, _bSet, _lpfs)
Description
This message is used to retrieve or change the current folder settings.
wParam
wParam is the _bSet
in the macro. If it is zero, the settings are being retrieved. Otherwise, they are being set.
lParam
lParam is the _lpfs in the macro. It points to a FOLDERSETTINGS
structure that contains the values to set or receives the current values, depending on wParam.
CWM_SELECTITEM
Macro
FileCabinet_SelectItem(_hwnd, _bSel, _lpidl)
Description
Use this message to select/deselect an item.
wParam
wParam is the _bSel in the macro. If it is zero, the item is selected. Otherwise, the item is deselected.
lParam
lParam is the _lpidl in the macro. It is the pidl of the item to select/deselect. Use NULL to select/deselect all items.
CWM_STOPWAITING
Macro
FileCabinet_StopWaiting(_hwnd
)
Remarks
One source defines the same message as CWM_SELECTITEMSTR
. I don't know which one is right.
CWM_GETISHELLBROWSER
Macro
FileCabinet_GetIShellBrowser(_hwnd)
Description
Returns an IShellBrowser
interface pointer of the shell browser that created the window.
Remarks
The returned IShellFolder interface is not AddRef'ed, so you should not call Release on the interface. This message is sent frequently by all microsoft namespace extensions and is the most important one. This message is described in the Microsoft Knowledge Base article Q157247.
CWM_TESTPATH
To be done.
CWM_STATECHANGE
To be done.
CWM_GETPATH
To be done.
FCIDLEPROC
typedef BOOL (CALLBACK *FCIDLEPROC)(void FAR *lpsv, UINT uID);
Description
This is the idle proc that will be called if you send CWM_WANTIDLE
.
Paramaeters
- lpsv : pointer to the shell view that requested idle time processing
- uID : the user-defined value that wass passen to
CWM_WANTIDLE
Return value
Return non-zero if you want to continue idle time processing. The function will be called again.
Return zero if your idle-time processing has finished.
Remarks
you should make this function as short as possible. To perform multiple tasks, process one atomic task in every call and return non-zero until all jobs are finished.
Some helper functions
ShlExtInit
void ShlExtInit()
Description
Performs dynamic binding to the shell32 functions.
ShlExtUninit
void ShlExtUninit()
Description
Cleans up the dynamic binding that was set up by ShlExtInit.
ILCreate
LPITEMIDLIST ILCreate(LPVOID pData, DWORD dwLen)
Description
Allocates and initializes a simple pidl
Parameters
- pData: The item id to put in the pidl (without the header)
- dwLen:The length of pData (in bytes)
Return value
The newly created pidl
ILGetCount
int ILGetCount(LPCITEMIDLIST pidl)
Description
calculates teh number of item IDs in a complex pidl
Parameters
- pidl: The comple pidl on which to perform the calculation
Return value
The number of item IDs that make up this complex pidl
PrintInterfaceName
void PrintInterfaceName(REFIID riid)
Description
Sends the name of an interface to the debugger
Useful to trace QueryInterface calls
Parameters
- riid: The GUID of the interface for which to print the name
IsInterfaceSupported
BOOL IsInterfaceSupported(IUnknown *punk, REFIID riid)
Description
Determines wether an object supports a given interface
Parameters
- punk: The IUnknown of the object to test
- REFIID: the GUID of the interface to test for
Return value
Non-zero if the interface is supported, zero otherwise.
PrintSupportedInterfaces
void PrintSupportedInterfaces(IUnknown *punk)
Description
Sends the names of all interfaces of an object to the debugger.
When you receive an interface while debugging, this function can come in very handy.
Parameters
- punk: The
IUnknown
interface of the object for which to print the interfaces
Implementing "View as Web Page"
You don't have to do anything in your code to implement a web view. You only have to create your web page and link your class id to it in the registry.
The web page
You should base your web page on the web pages that are created by Microsoft. On windows NT, you can find them in the directory winnt\web. A typical example is folder.htt, the web page for a normal folder. Just copy this web page and edit it to suit your needs.
There is one little problem: Microsoft changed the look of these web pages with every release of Windows, so you would have to provide separate web pages for all operating system versions.
Registry enteries
Explorer will rely on the class id that is returned by your IPersistFolder
's GetClassID
. As you know (and is very well documented), all information about your class is gathered in HKEY_CLASSES_ROOT\CLSID\{yourclassid}. There should already be a subkey shellex. In this shellex, you should create a subkey ExtShellFolderView, which again contains a subkey {5984FFE0-28D4-11CF-AE66-08002B2E1262}. In this subkey, you create an entry with the name PersistMoniker. It's value should be the full path of your web page.
References
Most of this stuff wasn't invented by me. You can find more information on the following locations:
You should also take a look at the shlext.h header file. It contains some information that is not included on this page.
Feedback
If you use the information on this page, you will probably discover things that are still missing here. You can see that there are lots of "to be done" bits. It is important to make that information available, so that you make the life of other developers a little easier. Please send me all your comments, sugestions and discoveries by email or leave comments on the codeproject site. All new discoveries will be available on my home page as soon as possible, and major updates will be posted on the codeproject site.