I.T. Discussion Community!
-Collapse +Expand
Search Delphi Group:

-Collapse +Expand Delphi To/From
-Collapse +Expand Delphi Store

Prestwood eMagazine

October Edition
Subscribe now! It's Free!
Enter your email:

   ► KBProgrammingDelphi for W...   Print This     
  From the August 2008 Issue of Prestwood eMag
Delphi for Win32:
Delphi: Windows Shell Extensions
Posted 17 years ago on 3/20/2003 and updated 6/20/2007
Take Away: How to add functionality to the existing Windows™ shell.


With each new release of Windowsâ„¢, its shell becomes more and more advanced and adds many new useful features. One of the ways this is done is through shell extensions. These extensions allow developers to add functionality to the existing Windowsâ„¢ shell. Some examples of shell extensions are Context Menus (menus that change based on what object has focus when you right-click), Property Sheet Handlers (tabbed pages that appear when the Properties menu item is selected from an object's context menu), Icon Overlays (appear as the arrow on top of an icon that points to a shortcut or the hand that appears on shared folders), Folder Customizations, and many, many more. Over the course of a few articles we will examine several of these extensions and in particular, how to build them in Delphi. There is plenty of information about shell extensions available from the Microsoft web site, but these articles will bring it to the Delphi audience. In this first article we will look at the InfoTip Shell Extension, which lets us, control the information that appears in Explorer when the mouse hovers over a file.
Important Note The following paragraph from Dino Esposito's article, "Windows 2000 UI Innovations: Enhance Your User's Experience with New Infotip and Icon Overlay Shell Extensions" (MSDN Magazine, March 2000) is a good description of what versions of Windows these extensions apply to:   ""¦I should point out that not all the features I'll cover here are completely new. Many of them were already introduced with the Desktop Update "“ a separate shell update available both for Windows 9x and Windows NT® 4.0. The Desktop Update shipped with Microsoft Internet Explorer 4.0 and Windows 98. Note that the Desktop Update is not part of Internet Explorer 5.0. So if you want to install it on Windows NT 4.0, you need to install Internet Explorer 4.0 first, making sure you select the Desktop Update option. Internet Explorer 5.0 will upgrade an existing Desktop Update on Windows NT 4.0 and Windows 95, but will not install it from scratch."

Shell Extension "“ Quick Overview

Shell Extensions are implemented as In Process COM servers. Windowsâ„¢ Explorer invokes the appropriate extension in response to shell-wide events. Explorer was designed to respond in very specific ways when the user performs various functions within its shell. The first thing Explorer does is check for any modules that have been registered for a specific event and if one exists it attempts to load the module. To be a valid shell extension, the COM server must implement an interface that defines the specific behavior for the desired extension and it must implement an interface that defines its initialization behavior. Finally, to be a valid shell extension, the COM server must follow the approved method of registering itself with the system. The following table from Dino Esposito's article "Windows 2000 UI innovations: Enhance Your User's Experience with New Infotip and Icon Overlay Shell Extensions" (MSDN Magazine, March 2000), lists all the types of shell extensions available today, the minimum shell version each requires, the involved interfaces, and a brief description:
Type Apply To Version Interface Involved Description
Context Menu File class and shell's object Windows 95+ IContextMenu, IContextMenu2, or IContextMenu3 Allows you to add new items to a shell object's context menu.
Right Drag and Drop File class and shell's object Windows 95+ IContextMenu, IContextMenu2, or IContextMenu3 Allows you to add new items to the context menu that appears after your right drag and drop files.
Drawing Shell Icons File class and shell's object Windows 95+ IExtractIcon Lets you decide at runtime which icon should be displayed for a given file within a file class.
Property Sheet File class and shell's object Windows 95+ IShellPropSheetExt Lets you insert additional property sheet pages to the file class Properties dialog. It also works for Control Panel applets.
Left Drag and Drop File class and shell's object Windows 95+ IDropTarget Lets you decide what to do when an object is being dropped (using the left mouse button) onto another one within the shell.
Clipboard File class and shell's object Windows 95+ IDataObject Lets you define how an object is to be copied to and extracted from the clipboard.
File Hook   Windows 95+ ICopyHook Lets you control any file operation that goes through the shell. While you can permit or deny them, you aren't informed about success or failure.
Program Execution Explorer Desktop Update IShellExecuteHook Lets you hook any program's execution that passes through the shell.
Infotip File class and shell's object Desktop Update IQueryInfo Lets you display a short text message when the mouse hovers over documents of a certain file type.
Column Folders Windows 2000 IColumnProvider Lets you add a new column to the Details view of Explorer.
Icon Overlay Explorer Windows 2000 IShellIconOverlay Lets you define custom images to be used as icon overlays.
Search Explorer Windows 2000 IContextMenu Lets you add a new entry on the Start menu's Search menu.
Cleanup Cleanup Manager Windows 2000 IEmptyVolumeCache2 Lets you add a new entry to the Cleanup Manager to recover disk space.

InfoTip "“ Introduction and Overview

Infotip's are hint windows that pop up when the mouse hovers over any file. If an extension has not been registered for the file type a default Infotip appears (see Figure 1 for an example of this), but you can create your own extension to display any information you want for the specific file type. Office 2000 installs default handlers for MS Wordâ„¢ and MS Excelâ„¢ that display the Name, Author and Title from the document's properties. Infotip extensions differ from other shell extensions in its registration, we'll discover the differences later when we talk about registration of our Infotip extensions.   Click to Enlarge
FIGURE 1 "“ Standard Infotip  

Implementing Infotip Extensions

An Infotip Extension is an In-Process (Inproc) COM Server. This just means that it is a Windows DLL that exports the necessary methods to be a valid ActiveX control. Infotip Extensions also implement IQueryInfo and IPersistFile and must register itself into the registry. Because IQueryInfo and IPersistFile are interfaces, they don't contain code for their defined methods. It is required that our object implement every method defined in both of these interfaces; however, some of the methods are not necessary for our Infotip extension so we simply return E_NOTIMPL to indicate that these are not implemented.   IQueryInfo provides the text to display in the hint window and contains two methods:
  • GetInfoFlags "“ Retrieves the information flags for an item. Microsoft states that this is currently unused, so we return E_NOTIMPL.
  • GetInfoTip "“ Retrieves the text of the Infotip.
  GetInfoTip is defined as follows:   function GetInfoTip(dwFlags: DWORD;   var ppwszTip: PWideChar): HResult; stdcall;  
  • dwFlags "“ currently not used
  • ppwszTip "“ Address of a Unicode string pointer that receives the tip string pointer.

Important Note

The ppwszTip parameter of the GetInfoTip method is a pointer to a Unicode string buffer that contains the text to display in the tip. This buffer must be allocated using the standard shell memory allocator because the buffer is allocated by our application, but freed by the shell. To ensure that everything happens in a thread-safe way, use SHGetMalloc to get the pointer to the shell's memory allocator "“ an object implementing IMalloc. Then, use IMalloc's Alloc method to allocate the memory needed to hold the Unicode representation of the Infotip text.   The accompanying source code contains the standard code you will use for all Infotip Extensions you create. Simply use the same code and your extensions will be shell friendly and thread-safe.
  IPersistFile is what the shell uses to provide the extension with information about the file the user is hovering over. The interface defines five methods:
  • IsDirty "“ checks an object for changes since it was last saved to its current file. We don't need this for Infotip extensions so we return E_NOTIMPL.
  • Load "“ opens the specified file and initializes an object from the file contents. We use this method to retrieve the name of the file the user is hovering over.
  • Save "“ saves the object into the specified file. We don't use it, so return E_NOTIMPL.
  • SaveCompleted "“ notifies the object that it can revert from NoScribble mode to Normal mode. We don't use it, so return E_NOTIMPL.
  • GetCurFile "“ gets the current name of the file associated with the object. We don't use it, so return E_NOTIMPL.
Load is defined as follows: function Load(pszFileName: PoleStr;   dwMode: LongInt ): HResult; stdcall;  
  • pszFileName "“ points to a zero-terminated string containing the absolute path of the file to open.
  • dwMode "“ specifies some combination of the values from the STGM enumeration to indicate the access mode to use when opening the file.
We are only using the IPersistFile interface to obtain the path and filename of the file; we are not actually using the interface to access the file so we can ignore the flags. Our standard implementation of the Load method will be to store the contents of pszFileName to a private variable to be used by IQueryInfo::GetInfoTip to locate the file.

Implementing Infotip Extensions

The accompanying source code contains a complete Infotip Extension for .DPR (Delphi Project files). This Infotip will display the FileName, the project type (Program or Library), the Project Name (from the source file), and the size of the file in bytes.   To begin, we need to create an automation object called DPRInfoTip. First, click File | New... to open the Object Repository, then click on the ActiveX tab and select the ActiveX Library. This will generate an empty ActiveX library and export the necessary function required to be a valid automation object.   Next, click File | New... again and select the ActiveX tab and select the Automation Object. When the Automation Object Wizard opens, enter DPRInfoTip as the CoClass name (see Figure 2 below for an example of how the dialog should look). Leave the remaining options with their default values and click OK, this will generate the basic Type Library and implement a skeleton for the IDPRInfoTip interface, which gets automatically generated.   FIGURE 2 "“ Automation Object Wizard     Once the files have been created the next thing we need to do is to add support for the additional interfaces that must be supported:   TDPRInfoTip = class(TAutoObject, IDPRInfoTip,                     IQueryInfo, IPersistFile,                     IPersist); (Note: We need to implement IPersist also because IPersistFile inherits from IPersist.)   The accompanying source code can be used for all InfoTip Extensions, the only code that must be altered is the GenerateTip method. This is the method that determines the text to display in the InfoTip.   In the Initialization method, we call SHGetMalloc, which causes Windows to allocate some memory and return a pointer to it in the pMalloc private variable. In the destructor, we set pMalloc equal to Nil. This releases our hold on the memory so the Windows shell can release the memory when necessary.  
When the mouse hovers over a file, the shell calls the Load method to provide the name of the file. Our implementation stores the name of the file in a private variable, FFile,  so it will be available when we need to generate the InfoTip text.  
    function TDPRInfoTip.Load(pszFileName: POleStr;                           dwMode: Integer): HResult;   begin      FFile  := pszFileName;      Result := S_OK;   end;  
  For all remaining IPersistFile methods, simply return E_NOTIMPL.
When the shell is ready to display the InfoTip, it calls the GetInfoTip method to retrieve the text to display. Our implementation calls the custom GenerateTip method in order to determine the text to display. It then is converted to a Windows compatible WideString and returned in the ppwszTip parameter. The GenerateTip method opens the .DPR file and reads contents into a string. The text to be returned first is assigned the filename of the selected file, then the type is assigned the first word in the project file; which is either Program or Library. Finally the project name is extracted from the remainder of the first line and the size of the file in bytes is determined by the size of the stream. The GenerateTip method can be customized to fit the needs of the InfoTip Extension being developed.

Registering Infotip Extensions

There are two steps to register an InfoTip Extension:
  1. Register the COM DLL using regsvr32.exe
regsvr32 "C:\Program Files\InfoTip\DPRInfoTip.dll"
  1. Add a reference to the associated extension (.dpr) to the HKEY_CLASSES_ROOT registry key.
  2. The default value for this new key must be the CLSID of the COM object that implements the Shell Extension. This can be obtained from the Type Library file that was generated by Delphi (the filename ends in "_TLB.pas"). For our example extension the CLSID is named CLASS_DPRInfoTip and contains the value "{B20433A8-D083-11D4-993A-00D00912C440}".
The easiest way to make the registry changes is to make a copy of the .REG file provided with the source code for this project. Change the CLSID and file extension to the associated values.

One important note, it is necessary to "approve" shell extensions under Windows NT and 2000. This means that you must be logged into the machine with Administrator rights in order to register the extension.


Share a thought or comment...
Write a Comment...
Sign in...

If you are a member, Sign In. Or, you can Create a Free account now.

Anonymous Post (text-only, no HTML):

Enter your name and security key.

Your Name:
Security key = P1262A1
Enter key:
Article Contributed By Larry J. Rutledge :
I worked for Prestwood Software as a Delphi developer from 1997 through 2002. During that time I enjoyed working with Mike Prestwood and the other developers at Prestwood.
Visit Profile

 KB Article #100189 Counter
Since 4/2/2008

Follow PrestwoodBoards on: 

©1995-2020 PrestwoodBoards  [Security & Privacy]
Professional IT Services: Coding | Websites | Computer Tech