case studies white papers downloads technology process careers sitemap contact
about us products solutions domains services projects search clients

 

Writing an Infotip shell extension in Delphi
-------------------------------------------------------------------------------------------------------

Windows 2000 (and Windows 98 with IE 5 desktop integration installed) gives us a new Shell Extension - the Infotip. This is a hint window that pops up when you hover over any file. The standard hint shows the name of the file and the size, but you can customize this, based on the extension of the file.

There is a default Infotip extension for Microsoft Word and Excel documents - you can see the name, author and title of the document in the infotip. Here's what a standard infotip looks like (Windows 2000):

What we will do now is make an infotip for Delphi form files (DFM files). Here's what we hope to achieve:

You'll find the full code for this article at http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=15151 and at http://www.agnisoft.com/downloads (dfminfotip.zip)

An Infotip shell extension is a Windows DLL that:

1.Implements IQueryInfo and IPersistFile
2. Registers itself in the registry. This step is slightly different from other shell extensions.

Implementing IQueryInfo and IPersistFileIQueryInfo gives the text of the Infotip that's shown in the hint window. IPersistFile is what the shell uses to give you information about which file the user is hovering over.

First we'll create a new automation object. Let's call it DFMInfoTip. Here's what the dialog looks like (after selecting File|New...|ActiveX|Automation Object):

This generates a simple type library and an implementation for the IDFMInfoTip interface that's automatically generated. In this file, let's support the other interfaces:

TDFMInfoTip=

class(TAutoObject,IDFMInfoTip,IQueryInfo,IPersistFile,IPersist)
Note: We need to implement IPersist also because IPersistFile inherits from IPersist.

Now let's see some code. IPersistFile has a function called Load, which is called to give us the name of the file that the mouse is hovering on.

function TDFMInfoTip.Load(pszFileName: POleStr;dwMode: Integer): HResult;
begin
 FFile := pszFileName;
 Result := S_OK;
end;

For the rest of the functions in IPersistFile (and IPersist) we'll return E_NOTIMPL.
Now let's look at IQueryInfo, which has just two functions. GetInfo is called by the shell to retrieve the text of the infotip. Here's how I've implemented it:

function TDFMInfoTip.GetInfoTip(dwFlags: DWORD;
 var ppwszTip: PWideChar): HResult;
var szTip : string;
begin
 Result := S_OK;
 // The current file name is in FFile through IPersistFile
 szTip := GetDFMInfo;
 ppwszTip := pMalloc.Alloc( sizeof(WideChar)*Length(szTip)+1);
 if (ppwszTip <> nil) then
  StringToWideChar(szTip, ppwszTip, sizeof(WideChar)*Length(szTip)+1);
end;

pMalloc is an IMalloc instance, returned by ShGetMalloc in the constructor. This is used so that the allocated memory can be freed by the shell when it's done displaying the infotip.
The function GetDFMInfo extracts some information out of a DFM file. First, we figure out if it's a binary or text dfm:

fStream := TFileStream.Create(FFile,fmOpenRead or fmShareDenyNone);
slStrings := TStringList.Create;
try
 fStream.Position := 0;
 pFirst := @First;
 fStream.Read(pFirst^, 1);
 fStream.Position := 0;
 if First = $FF then // binary DFM
 begin
  Result := Result + 'Type: Binary';
  inStream := TMemoryStream.Create;
  ObjectResourceToText( fStream, inStream );
  inStream.Position := 0;
  slStrings.LoadFromStream(inStream);
  inStream.Free;
 end
 else
 begin // Delphi 5's text DFM
  slStrings.LoadFromStream(fStream);
  Result := Result + 'Type: Text';
 end;

We now have the entire form as text in slStrings. Then let's extract fields in the DFM that are of interest to us. Here's a snippet that gets the caption:

szText := szFullText;
//get the caption
iPos := Pos(' Caption = ''', szText);
if iPos <> 0 then
begin
 Inc(iPos, Length(' Caption = '''));
 iEnd := iPos;
 while true do
 begin
 if (szText[iEnd] = '''') then
  if (Copy(szText, iEnd+1, 4)='#39''')    then
    Inc(iEnd, 4)
  else
   break;
 Inc(iEnd);
 end;
 Result := Result + #13#10 + 'Caption: ' + szText ;
end;

The code included with this article gets the caption, width and height of the selected file.
Registering an Infotip Extension

To register an Infotip Extension, you must:

1. Register the COM DLL - you can run regsvr32.exe in the Windows System directory passing the DLL file name as a parameter.

2. Create an entry under HKEY_CLASSES_ROOT/.dfm like this:

The default value for this key must evaluate to the CLSID of the COM object implementing the shell extension. I've put in the CLSID of the DFMInfoTip object implemented.
Note: The CLSID {00021500-0000-0000-C000-000000000046} is the IID of IQueryInfo.
Of course, under Windows NT and 2000, all shell extensions must be "approved." This is obvious only if you log on as user other than administrator. The registry key you must create in order to "approve" a shell extension is:

HKEY_LOCAL_MACHINE
 SOFTWARE
  Microsoft
   Windows
    CurrentVersion
     Shell Extensions
      Approved

Under this key, create a new string value with the name of the shell extension CLSID (in this case, {A6614304-6DFB-4A31-8032-C4E0CCA42D81}) and assign it any description text.
That's about all you need to do. The code sample has two .REG files that you can run to import the correct registry entries. Why two? I found that the Windows 2000 regedit tool exports the registry as Unicode instead of ASCII - so there's one file for Windows 2000 and one for Windows 98.

© 1998-2012, Agni Software (P) Ltd. All Rights reserved.