MEGA Search
20.3 Million


Sign Up
From: pascal  
Subject: writting a shell extension handler to overlay shell icon
NewsGroup: borland.public.delphi.com.activex.writing
Date Posted: 15-Dec-2004 at 10:35:26 PST
I am writting a shell extension handler to overlay shell icon like
TortoiseCVS does.

After fighting for a long night, I got some code which I will add below.
After testing again and again, it can make system default overlay icon for
link to disappear.  However, it doesn't show the overlay icon which I want
to overlay.

So I post the source code here, maybe anyone would like/be interested to
help me to find where I am wrong.
(Hope it is not too long for you)

--------------------------------------------------------
unit Unit1;

interface

uses
  ComObj, ActiveX, Types, Windows, Classes;

const
{$EXTERNALSYM SID_IShellIconOverlayIdentifier}
  SID_IShellIconOverlayIdentifier =
'{0C6C4200-C589-11D0-999A-00C04FD655E1}';
{$EXTERNALSYM ISIOI_ICONFILE}
  ISIOI_ICONFILE = $00000001; // path is returned through pwszIconFile
{$EXTERNALSYM ISIOI_ICONINDEX}
  ISIOI_ICONINDEX = $00000002; // icon index in pwszIconFile is returned
through pIndex
{$EXTERNALSYM ISIOI_SYSIMAGELISTINDEX}
  ISIOI_SYSIMAGELISTINDEX = $00000004; // system imagelist icon index is
returned through pIndex

type
{$EXTERNALSYM IShellIconOverlayIdentifier}
  IShellIconOverlayIdentifier = interface(IUnknown)
    [SID_IShellIconOverlayIdentifier]
    function IsMemberOf(pwszPath: PWideChar; dwAttrib: DWORD): HResult;
stdcall;
    function GetOverlayInfo(out pwszIconFile: PWideChar; cchMax: Integer;
var pIndex: Integer; var pdwFlags: DWORD): HResult; stdcall;
    function GetPriority(out pIPriority: Integer): HResult; stdcall;
  end;

  TOverlayIcon = class(TComObject, IShellIconOverlayIdentifier)
  private
    FFileName: string;
  protected
    { IShellIconOverlayIdentifier }
    function IsMemberOf(pwszPath: PWideChar; dwAttrib: DWORD): HResult;
stdcall;
    function GetOverlayInfo(out pwszIconFile: PWideChar; cchMax: Integer;
var pIndex: Integer; var pdwFlags: DWORD): HResult; stdcall;
    function GetPriority(out pIPriority: Integer): HResult; stdcall;
  end;

  TOverlayIconFactory = class(TComObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;

const
  Class_OverlayIcon: TGUID = '{65961FC9-6C38-4043-A632-92ACD0A217EA}';

implementation

uses
  SysUtils, Registry, ComServ;

{ TOverlayIcon }

function TOverlayIcon.GetOverlayInfo(out pwszIconFile: PWideChar; cchMax:
Integer; var pIndex: Integer; var pdwFlags: DWORD): HResult;
begin
  pwszIconFile := StringToOleStr('c:\a.ico');
  pdwFlags := ISIOI_ICONFILE;
  Result := S_OK;
end;

function TOverlayIcon.GetPriority(out pIPriority: Integer): HResult;
begin
  pIPriority := 0;
  Result := S_OK;
end;

function TOverlayIcon.IsMemberOf(pwszPath: PWideChar; dwAttrib: DWORD):
HResult;
begin
  WideCharToStrVar(pwszPath, FFileName);
  Result := S_OK;
end;

{ TOverlayIconFactory }

procedure TOverlayIconFactory.UpdateRegistry(Register: Boolean);
const
  KeyName =
'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifi
ers\DMS';
var
  ClassID: string;
begin
  if Register then
  begin
    inherited UpdateRegistry(Register);

    ClassID := GUIDToString(Class_OverlayIcon);
    with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      OpenKey(KeyName, True);
      WriteString('', ClassID);
      if (Win32Platform = VER_PLATFORM_WIN32_NT) then
      begin
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell
Extensions', True);
        OpenKey('Approved', True);
        WriteString(ClassID, 'Delphi OverlayIcon Shell Extension Example');
      end;
    finally
      Free;
    end;
  end
  else
  begin
    with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      DeleteKey(KeyName);
      if (Win32Platform = VER_PLATFORM_WIN32_NT) then
      begin
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell
Extensions', True);
        OpenKey('Approved', True);
        DeleteValue(ClassID);
      end;
    finally
      Free;
    end;
    inherited UpdateRegistry(Register);
  end;
end;

initialization
  TOverlayIconFactory.Create(ComServer, TOverlayIcon, Class_OverlayIcon, '',
'DMS OverlayIcon', ciMultiInstance, tmApartment);

end.
-------------------------------------------------------

Something I need to write here.  As you saw, I put some declaration of
IShellIconOverlayIdentifier in my code.  The reason is I think there is a
bug for IShellIconOverlayIdentifier  in ShlObj.pas.
I am not sure, but I think the param pwszIconFile of method GetOverlayInfo
need a out/var reserved word.  So I add it.  Am I right?

Search web for a night, including borland news search, I don't find any
example for IShellIconOverlayIdentifier with Delphi.
Although I do find some example in C++, I cannot read it.

Hope anyone can give me some hint to help me, thank.

By the way, the overlay icon file 'c:\A.ico' mentioned in source is copied
from TortoiseCVS's icon file, just renamed.

---Pascal, using D7 ent



From: Jim  
Subject: Re: writting a shell extension handler to overlay shell icon
NewsGroup: borland.public.delphi.com.activex.writing
Date Posted: 16-Dec-2004 at 20:34:33 PST
Hi,

> Thank you, I got answer from your code.

Great.  Please also read about the bug in the Delphi and CBuilder RTL
that has existed since at least D4 and likely D2.  It will eventually
crash Explorer if you don't do it.   Also note that with my package you
can create a column handler DLL that is less than 200k.  Lastly I say
that the implementation of the COM Server in the VCL does not follow
the rules of COM.  If this will cause strange hidden problems in
Explorer I don't know.  Hence the existence of EasyNSE.  It fixes the
RTL bug, creates most extensions without sucking Forms and about 250k
of bloat into the DLL, and creates COM objects in a way that is 100%
compliant with COM rules.

Jim
-- 
www.mustangpeak.net

From: pascal  
Subject: Re: writting a shell extension handler to overlay shell icon
NewsGroup: borland.public.delphi.com.activex.writing
Date Posted: 17-Dec-2004 at 12:0:34 PST
Jim,

Thank you, I got answer from your code.

---Pascal

I put my working source here to help others....

----------------------------------------------------------------------------
------------------------

unit Unit1;

interface

uses
  ComObj, ActiveX, Types, Windows, Classes, ShlObj;

type
  TOverlayIcon = class(TComObject, IShellIconOverlayIdentifier)
  private
    FFileName: string;
  protected
    { IShellIconOverlayIdentifier }
    function IsMemberOf(pwszPath: PWideChar; dwAttrib: DWORD): HResult;
stdcall;
    function GetOverlayInfo(pwszIconFile: PWideChar; cchMax: Integer; var
pIndex: Integer; var pdwFlags: DWORD): HResult; stdcall;
    function GetPriority(out pIPriority: Integer): HResult; stdcall;
  end;

  TOverlayIconFactory = class(TComObjectFactory)
  public
    procedure UpdateRegistry(Register: Boolean); override;
  end;

const
  Class_OverlayIcon: TGUID = '{65961FC9-6C38-4043-A632-92ACD0A217EA}';

implementation

uses
  SysUtils, Registry, ComServ;

{ TOverlayIcon }

function TOverlayIcon.GetOverlayInfo(pwszIconFile: PWideChar; cchMax:
Integer; var pIndex: Integer; var pdwFlags: DWORD): HResult;
var
  FileName: Widestring;
  Ext: Widestring;
begin
  Result := S_OK;
  try
    ZeroMemory(pwszIconFile, cchMax * 2);
    Filename:='C:\a.ico';
    Ext := LowerCase(ExtractFileExt(FileName));
    if (Ext = '.exe') or (Ext = '.dll') or (Ext = '.ico') or (Ext = '') then
    begin
      if Length(FileName) < cchMax then
      begin
        CopyMemory(pwszIconFile, PWideChar(FileName), Length(FileName) * 2);
        if Filename <> '' then
          pdwFlags := pdwFlags or ISIOI_ICONFILE;
        if (pIndex > -1) and (LowerCase(ExtractFileExt(FileName)) <> '.ico')
then
          pdwFlags := pdwFlags or ISIOI_ICONINDEX;
      end
      else
        Result := S_FALSE
    end
    else
      Result := S_FALSE;
  except
    Result := S_FALSE;
  end
end;

function TOverlayIcon.GetPriority(out pIPriority: Integer): HResult;
begin
  pIPriority := 0;
  Result := S_OK;
end;

function TOverlayIcon.IsMemberOf(pwszPath: PWideChar; dwAttrib: DWORD):
HResult;
begin
  WideCharToStrVar(pwszPath, FFileName);
  Result := S_OK;
end;

{ TOverlayIconFactory }

procedure TOverlayIconFactory.UpdateRegistry(Register: Boolean);
const
  KeyName =
'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifi
ers\DMS';
var
  ClassID: string;
begin
  if Register then
  begin
    inherited UpdateRegistry(Register);

    ClassID := GUIDToString(Class_OverlayIcon);
    with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      OpenKey(KeyName, True);
      WriteString('', ClassID);
      if (Win32Platform = VER_PLATFORM_WIN32_NT) then
      begin
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell
Extensions', True);
        OpenKey('Approved', True);
        WriteString(ClassID, 'Delphi OverlayIcon Shell Extension Example');
      end;
    finally
      Free;
    end;
  end
  else
  begin
    with TRegistry.Create do
    try
      RootKey := HKEY_LOCAL_MACHINE;
      DeleteKey(KeyName);
      if (Win32Platform = VER_PLATFORM_WIN32_NT) then
      begin
        RootKey := HKEY_LOCAL_MACHINE;
        OpenKey('\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell
Extensions', True);
        OpenKey('Approved', True);
        DeleteValue(ClassID);
      end;
    finally
      Free;
    end;
    inherited UpdateRegistry(Register);
  end;
end;

initialization
  TOverlayIconFactory.Create(ComServer, TOverlayIcon, Class_OverlayIcon, '',
'DMS OverlayIcon', ciMultiInstance, tmApartment);

end.




From: Jim  
Subject: Re: writting a shell extension handler to overlay shell icon
NewsGroup: borland.public.delphi.com.activex.writing
Date Posted: 16-Dec-2004 at 17:56:47 PST
Hi,

> After fighting for a long night, I got some code which I will add
> below.  After testing again and again, it can make system default
> overlay icon for link to disappear.  However, it doesn't show the
> overlay icon which I want to overlay.

Stop fighting and download EasyNSE from my website....

Jim
-- 
www.mustangpeak.net

From: pascal  
Subject: Re: writting a shell extension handler to overlay shell icon
NewsGroup: borland.public.delphi.com.activex.writing
Date Posted: 18-Dec-2004 at 22:47:46 PST
"Jim"  ¼¶¼g©ó¶l¥ó·s»D
:41c261d9@newsgroups.borland.com...
>
>
> Great.  Please also read about the bug in the Delphi and CBuilder RTL
> that has existed since at least D4 and likely D2.  It will eventually
> crash Explorer if you don't do it.   Also note that with my package you
> can create a column handler DLL that is less than 200k.  Lastly I say
> that the implementation of the COM Server in the VCL does not follow
> the rules of COM.  If this will cause strange hidden problems in
> Explorer I don't know.  Hence the existence of EasyNSE.  It fixes the
> RTL bug, creates most extensions without sucking Forms and about 250k
> of bloat into the DLL, and creates COM objects in a way that is 100%
> compliant with COM rules.
>
> Jim

Oh?  Thanks for your warning.
And thanks for your struggle and open.
You are the man.

---Pascal