home *** CD-ROM | disk | FTP | other *** search
- {-----------------------------------------------------------------------------}
- { A component and a function (use the one you prefer) to encapsulate the }
- { Win95 style directory selection dialog SHBrowseForFolder(). }
- { Copyright 1996, Brad Stowers. All Rights Reserved. }
- { This component can be freely used and distributed in commercial and private }
- { environments, provied this notice is not modified in any way and there is }
- { no charge for it other than nomial handling fees. Contact me directly for }
- { modifications to this agreement. }
- {-----------------------------------------------------------------------------}
- { Feel free to contact me if you have any questions, comments or suggestions }
- { at bstowers@pobox.com or 72733,3374 on CompuServe. }
- { The lateset version will always be available on the web at: }
- { http://www.pobox.com/~bstowers/delphi/delphi.html }
- {-----------------------------------------------------------------------------}
- { Date last modified: 03/17/96 }
- {-----------------------------------------------------------------------------}
-
- { ----------------------------------------------------------------------------}
- { TBrowseDirectory v1.00 }
- { ----------------------------------------------------------------------------}
- { Description: }
- { A dialog that displays the user's system in a heirarchial manner and }
- { allows a selection to be made. It is a wrapper for SHBrowseForFolder(), }
- { which is rather messy to use directly. }
- { Notes: }
- { * Requires Pat Ritchey's ShellObj unit. It is freely available on his }
- { web site at http://ourworld.compuserve.com/homepages/PRitchey/ }
- { * Callbacks are not implemented in this version. }
- { ----------------------------------------------------------------------------}
- { Revision History: }
- { 1.00: + Initial release }
- { ----------------------------------------------------------------------------}
-
- unit BrowseDr;
-
- {$IFNDEF WIN32}
- ERROR! This unit only available on Win32!
- {$ENDIF}
-
- interface
-
- uses ShellObj, Controls, Classes, DsgnIntf;
-
- type
- { These are equivalent to the CSIDL_* constants in the Win32 (95?) API. }
- { They are used to specify the root of the heirarchy. }
- { NOTE: the idDesktopExpanded is not docuemnted, but it seems to be used }
- { by the Win95 Explorer. I find it useful, but use at your own }
- { risk. It may be "fixed" in some future release of Win95. }
- TRootID = (
- idDesktop, idDesktopExpanded, idPrograms, idControlPanel, idPrinters,
- idPersonal, idFavorites, idStartup, idRecent, idSendTo, idRecycleBin,
- idStartMenu, idDesktopDirectory, idDrives, idNetwork, idNetHood, idFonts,
- idTemplates
- );
- { These are equivalent to the BIF_* constants in the Win32 (95?) API. }
- { They are used to specify what items can be expanded, and what itmes }
- { can be selected. }
- TBrowseFlag = (
- bfDirectoriesOnly, bfDomainOnly, bfAncestors, bfComputers, bfPrinters
- { , bfStatusText // Will be added when callback is implemented. }
- );
- TBrowseFlags = set of TBrowseFlag;
-
- { For those of you who prefer to, you can display this dialog with only a }
- { function call, no component necessary. Actually, the component simply }
- { collects parameters and calls this function. }
- function BrowseDirectory(var Dest: string; // Receives selected path
- const AParent: TWinControl; // Who owns the window
- const Title: string; // Text shown above list
- Root: TRootID; // Root to browse from
- Flags: TBrowseFlags // What is legal to select
- ): boolean; // True if selection made
-
- { For the component lover in all of us }
- type
- TBrowseDirectoryDlg = class(TComponent)
- private
- { Property variables }
- FTitle: string;
- FRoot: TRootID;
- FOptions: TBrowseFlags;
- { Internal variables }
- FSelected: string;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- { Displays the dialog. Returns true if user selected an item and }
- { pressed OK, otherwise it returns false. }
- function Execute: boolean; virtual;
- { Runtime only property containing the item selected. This will only }
- { be valid after Execute is called and it returns TRUE. At any other }
- { time, it should be an empty ('') string. }
- property Selected: string read FSelected;
- published
- { Text to display above the selection tree. }
- property Title: string read FTitle write FTitle;
- { Item that is to be treated as the root of the display. }
- property Root: TRootID read FRoot write FRoot default idDesktopExpanded;
- { Options to control what is allowed to be selected and expanded. }
- property Options: TBrowseFlags read FOptions write FOptions default [];
- end;
-
- { A component editor (not really) to allow on-the-fly testing of the }
- { dialog. Right click the component and select 'Test Dialog', or simply }
- { double click the component, and the browse dialog will be displayed }
- { with the current settings. }
- TBrowseDialogEditor = class(TDefaultEditor)
- public
- procedure ExecuteVerb(Index : Integer); override;
- function GetVerb(Index : Integer): string; override;
- function GetVerbCount : Integer; override;
- procedure Edit; override;
- end;
-
- procedure Register;
-
- implementation
-
- uses Windows, OLE2, Forms, Dialogs, SysUtils;
-
- // Utility functions used to convert from Delphi set types to API constants.
- function ConvertRoot(Root: TRootID): integer;
- const
- RootValues: array[TRootID] of integer = (
- CSIDL_DESKTOP, $0001, CSIDL_PROGRAMS, CSIDL_CONTROLS, CSIDL_PRINTERS,
- CSIDL_PERSONAL, CSIDL_FAVORITES, CSIDL_STARTUP, CSIDL_RECENT, CSIDL_SENDTO,
- CSIDL_BITBUCKET, CSIDL_STARTMENU, CSIDL_DESKTOPDIRECTORY, CSIDL_DRIVES,
- CSIDL_NETWORK, CSIDL_NETHOOD, CSIDL_FONTS, CSIDL_TEMPLATES
- );
- begin
- Result := RootValues[Root];
- end;
-
- function ConvertFlags(Flags: TBrowseFlags): UINT;
- const
- FlagValues: array[TBrowseFlag] of UINT = (
- BIF_RETURNONLYFSDIRS, BIF_DONTGOBELOWDOMAIN, BIF_RETURNFSANCESTORS,
- BIF_BROWSEFORCOMPUTER, BIF_BROWSEFORPRINTER
- {, BIF_STATUSTEXT // Will be added when callback is implemented. }
- );
- var
- Opt: TBrowseFlag;
- begin
- Result := 0;
- { Loop through all possible values }
- for Opt := Low(TBrowseFlag) to High(TBrowseFlag) do
- if Opt in Flags then
- Result := Result OR FlagValues[Opt];
- end;
-
-
- function BrowseDirectory(var Dest: string; const AParent: TWinControl;
- const Title: string; Root: TRootID;
- Flags: TBrowseFlags): boolean;
- var
- ShellMalloc: IMALLOC;
- shBuff: PChar;
- BrowseInfo: TBrowseInfo;
- idRoot, idBrowse: PItemIDList;
- begin
- Result := FALSE; // Assume the worst.
- Dest := ''; // Clear it out.
- SetLength(Dest, MAX_PATH); // Make sure their will be enough room in dest.
- if SHGetMalloc(ShellMalloc) = NOERROR then begin
- try
- shBuff := PChar(ShellMalloc.Alloc(MAX_PATH)); // Shell allocate buffer.
- if assigned(shBuff) then begin
- try
- // Get id for desired root item.
- SHGetSpecialFolderLocation(AParent.Handle, ConvertRoot(Root), idRoot);
- try
- with BrowseInfo do begin // Fill info structure
- hwndOwner := AParent.Handle;
- pidlRoot := idRoot;
- pszDisplayName := shBuff;
- lpszTitle := PChar(Title);
- ulFlags := ConvertFlags(Flags);
- lpfn := NIL;
- lParam := 0;
- end;
- idBrowse := SHBrowseForFolder(@BrowseInfo);
- if assigned(idBrowse) then begin
- try
- SHGetPathFromIDList(idBrowse, shBuff); // Turn into real path.
- Dest := shBuff; // Put it in user's variable.
- Result := TRUE; // Success!
- finally
- ShellMalloc.Free(idBrowse); // Clean up after ourselves
- end;
- end;
- finally
- ShellMalloc.Free(idRoot); // Clean-up.
- end;
- finally
- ShellMalloc.Free(shBuff); // Clean-up.
- end;
- end;
- finally
- ShellMalloc.Release; // Clean-up.
- end;
- end;
- end;
-
-
- constructor TBrowseDirectoryDlg.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FTitle := '';
- FRoot := idDesktopExpanded;
- FOptions := [];
- FSelected := '';
- end;
-
- destructor TBrowseDirectoryDlg.Destroy;
- begin
- inherited Destroy;
- end;
-
- function TBrowseDirectoryDlg.Execute: boolean;
- var
- S: string;
- Parent: TWinControl;
- begin
- { Determine who the parent is. }
- if Owner is TWinControl then
- Parent := Owner as TWinControl
- else
- Parent := Application.MainForm;
- { Call the function }
- Result := BrowseDirectory(S, Parent, FTitle, FRoot, FOptions);
- { If selectino made, update property }
- if Result then
- FSelected := S;
- end;
-
- // Component Editor (not really) to allow on the fly testing of the dialog
- procedure TBrowseDialogEditor.ExecuteVerb(Index: Integer);
- begin
- {we only have one verb, so exit if this ain't it}
- if Index <> 0 then Exit;
- Edit;
- end;
-
- function TBrowseDialogEditor.GetVerb(Index: Integer): AnsiString;
- begin
- Result := 'Test Dialog';
- end;
-
- function TBrowseDialogEditor.GetVerbCount: Integer;
- begin
- Result := 1;
- end;
-
- procedure TBrowseDialogEditor.Edit;
- begin
- with TBrowseDirectoryDlg(Component) do
- if Execute then
- MessageDlg(Format('Item selected:'#13#13'%s', [Selected]),
- mtInformation, [mbOk], 0);
- end;
-
-
- procedure Register;
- begin
- { You may prefer it on the Dialogs page, I like it on Win95 because it is
- only available on Win95. }
- RegisterComponents('Win95', [TBrowseDirectoryDlg]);
- RegisterComponentEditor(TBrowseDirectoryDlg, TBrowseDialogEditor);
- end;
-
-
- end.
-