Writing an Infotip shell extension in Delphi
By Deepak Shenoy
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/delphi/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 IPersistFile
IQueryInfo 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:
-
Register the COM DLL - you can run regsvr32.exe in the Windows System directory
passing the DLL file name as a parameter.
-
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.
Deepak Shenoy(shenoy@agnisoft.com) is a
director at Agni Software, a software company in
India that offers consultancy and offshore development solutions. Deepak is currently
working with Windows 2000, COM+ and XML. In his spare time he tries to play the guitar,
which is why he is not allowed too much spare time.