The Bugs in SHLOBJ.PAS and How to Fix Them.


Note: This only applies to Delphi 2.  Delphi 3 has fixed all of these bugs.

There are currently available two units that provide access to the
Win95/NT 4.0 Shell Namesapce API.  Unfortunately, both of them have errors in
several of the function declarations.  To use this component you will have to
correct these errors.  You can do this in one of three ways.

1) Get Pat Ritchey's ShellObj unit and make the modifications to it.
2) Directly modify Borland's ShlObj.pas file in \Delphi\Source\RTL\Win\.
3) Copy Borland's ShlObj.pas file to a directory in your Library Path
   (Tools | Options | Library Path) and modify that one.

I prefer and suggest option 3.  Pat will not be supporting ShellObj now that
Borland is officially distributing ShlObj, and I don't like modifing RTL code
directly.  It makes applying patches a royal pain because I always forget to
copy the original back over it before patching.

Rename your modified copy to MyShlObj.pas (don't forget the UNIT clause name),
unless you directly modified the RTL source.  If you did that, make sure you
recompile it and update the \Delphi\Lib\ShlObj.dcu file and change the USES
clause in SystemTreeView.pas from MyShlObj to ShlObj.

1) For ShellObj unit users ONLY, do the following steps (Delphi 2.01 ShlObj
   users should skip to step 2):

   a) Search for the BindToObject declaration and change it to:
     // BDS.  riid should have been a pointer to a TIID.
     function BindToObject(pidl:PITEMIDLIST; pbcReserved:pointer;
                          const riid:TIID; var ppvOut:pointer):HResult; virtual; stdcall; abstract;

   b) Change GetDisplayNameOf to:
     // Changed lpName to a var parameter for compatiblity with v2.01 SHLOBJ.
     function GetDisplayNameOf(pidl: PITEMIDLIST; uFlags:DWORD;
                               var lpName: TSTRRET):HResult; virtual; stdcall; abstract;

   c) Change the name of the type 'BFFCallBack' to 'TFNBFFCallBack'
      everywhere it occurs.  This is for compatibility with ShlObj.

   d) Change the SHBrowseForFolder to:
     // Changed lpbi to var param for SHLOBJ compatibility.
     function SHBrowseForFolder(var lpbi:TBROWSEINFO):PItemIDList; stdcall;

   e) Change InvokeCommand to:
     // Changed lpici to var param for SHLOBJ compatibility.
     function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; virtual; stdcall; abstract;

   f) Search for SHGetMalloc declaration and change it to:
     // Needs the stdcall directive
     function SHGetMalloc(var ppMalloc: IMalloc): HResult; stdcall;

   g) Search for the SHGetMalloc implementation and change to:
     // That was not supposed to go into effect until next windows release according to
     // Microsoft SHLOBJ.H code comments.  Back to what it is supposed to be.
     function SHGetMalloc; external shell32 name 'SHGetMalloc';


2) Change BindToStorage to:

    // BDS.  riid should have been a pointer to a TIID.
    function BindToStorage(pidl:PITEMIDLIST; pbcReserved:pointer;
                           const riid:TIID; var ppvObj:pointer):HResult; virtual; stdcall; abstract;

3) Change CreateViewObject to:

    // BDS.  riid should have been a pointer to a TIID.
    function CreateViewObject(hwndOwner:HWND; const riid:TIID;
                              var ppvOut: pointer):HResult; virtual; stdcall; abstract;

4) Change GetUIObjectOf to:

    // BDS.  riid should have been a pointer to a TIID.
    // BDS.  SHLOBJ: prgfInOut is always NIL, so a VAR parameter makes no sense.
    function GetUIObjectOf(hwndOwner:HWND; cidl:UINT; var apidl: PItemIDList;
                           const riid:TIID; prgfInOut: PUINT; var ppvOut:pointer):HResult; virtual; stdcall; abstract;

5) This stuff is completely missing:
   a) Add this block right before the "implementation" section:

{ SHGetDataFromIDList }

const
  SHGDFIL_FINDDATA       = 1;
  SHGDFIL_NETRESOURCE    = 2;
  SHGDFIL_DESCRIPTIONID  = 3;

  SHDID_ROOT_REGITEM          = 1;
  SHDID_FS_FILE               = 2;
  SHDID_FS_DIRECTORY          = 3;
  SHDID_FS_OTHER              = 4;
  SHDID_COMPUTER_DRIVE35      = 5;
  SHDID_COMPUTER_DRIVE525     = 6;
  SHDID_COMPUTER_REMOVABLE    = 7;
  SHDID_COMPUTER_FIXED        = 8;
  SHDID_COMPUTER_NETDRIVE     = 9;
  SHDID_COMPUTER_CDROM        = 10;
  SHDID_COMPUTER_RAMDISK      = 11;
  SHDID_COMPUTER_OTHER        = 12;
  SHDID_NET_DOMAIN            = 13;
  SHDID_NET_SERVER            = 14;
  SHDID_NET_SHARE             = 15;
  SHDID_NET_RESTOFNET         = 16;
  SHDID_NET_OTHER             = 17;

type TSHDescriptionID = packed record
  dwDescriptionId: DWORD;
  clsid: TGUID; {???}
end;

function SHGetDataFromIDListA(const psf: IShellFolder; pidl: PItemIDList;
                              nFormat: integer; pv: pointer; cb: integer): HResult; stdcall;
function SHGetDataFromIDListW(const psf: IShellFolder; pidl: PItemIDList;
                              nFormat: integer; pv: pointer; cb: integer): HResult; stdcall;
function SHGetDataFromIDList(const psf: IShellFolder; pidl: PItemIDList;
                             nFormat: integer; pv: pointer; cb: integer): HResult; stdcall;

  b) Add this somewhere in the implementation section:

function SHGetDataFromIDListA; external shell32 name 'SHGetDataFromIDListA';
function SHGetDataFromIDListW; external shell32 name 'SHGetDataFromIDListW';
function SHGetDataFromIDList; external shell32 name 'SHGetDataFromIDListA';



Regards,
Brad Stowers
bstowers@pobox.com
May 18, 1997
