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.
|