1. Tech

Your suggestion is on its way!

An email with a link to:

http://delphi.about.com/od/windowsshellapi/l/aa122803a.htm

was emailed to:

Thanks for sharing About.com with others!

Centering the Select Directory dialog
Here's how to take the full control over the SHBrowseForFolder API call. Find out how to implement an application-defined callback function that the browse dialog calls, to notify the caller about its events.
 Win prizes by sharing code!
Do you have some Delphi code you want to share? Are you interested in winning a prize for your work?
Delphi Programming Quickies Contest
 Join the Discussion
"Post your views, comments, questions and doubts to this article."
Discuss!
 Related Resources
• Browse for folders, files, printers and computers
• TShBrowse - full source code Delphi component
• Callback functions explained
• Windows Shell articles

In Windows, there are several ways to display directory structure of a computer. Most Delphi programmers know how to use the TOpenDialog component to allow the user to browse for folders and files to open.

By encapsulating the SHBrowseForFolder Windows API function we can invoke a Windows system dialog used to browse for files and folders on users hard drive as well as network computers and printers.
By default, Delphi provides the SelectDirectory function - a RTL version of the BrowseForFolder Windows API function.

In either of the two cases, the dialog that is displayed tends to appear at a random position on the screen.

Our task in this article is to see how to tak ethe full control over the SHBrowseForFolder call.

Recall, that the SHBrowseForFolder API function accepts only one, rather complicated, TBrowseInfo parameter - to initialize and customize the Browse For Folder dialog box.
Two of the main elements of BrowseInfo are the lpszTitle and ulFlags fields. The dialog box displays the contents of lpszTitle in a static text control above the treeview. The ulFlags element sets the value which determines what the dialog displays and allows the user to select.

Another interesting parameter is the lpfn flag. This parameter is of a TFNBFFCallBack type, the lpfn can be used to assign an application-defined function that the dialog box calls when events occur. This function is a callback function, and can be used to control and update the dialog box as the user interacts with it.

Below, you'll find an example usege of the TFNBFFCallBack function type. The idea is to center the browse dialog on the work area of the screen (using the WorkAreaRect property of the global TScreen object)...

uses ShellAPI, ShlObj;

...

function BrowseDialogCallBack
  (Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): 
  integer stdcall;
var
  wa, rect : TRect;
  dialogPT : TPoint;
begin
  //center in work area
  if uMsg = BFFM_INITIALIZED then
  begin
    wa := Screen.WorkAreaRect;
    GetWindowRect(Wnd, Rect);
    dialogPT.X := ((wa.Right-wa.Left) div 2) - 
                  ((rect.Right-rect.Left) div 2);
    dialogPT.Y := ((wa.Bottom-wa.Top) div 2) - 
                  ((rect.Bottom-rect.Top) div 2);
    MoveWindow(Wnd,
               dialogPT.X,
               dialogPT.Y,
               Rect.Right - Rect.Left,
               Rect.Bottom - Rect.Top,
               True);
  end;

  Result := 0;
end; (*BrowseDialogCallBack*)

Browse dialog

function BrowseDialog
 (const Title: string; const Flag: integer): string;
var
  lpItemID : PItemIDList;
  BrowseInfo : TBrowseInfo;
  DisplayName : array[0..MAX_PATH] of char;
  TempPath : array[0..MAX_PATH] of char;
begin
  Result:='';
  FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);
  with BrowseInfo do begin
    hwndOwner := Application.Handle;
    pszDisplayName := @DisplayName;
    lpszTitle := PChar(Title);
    ulFlags := Flag;
    lpfn := BrowseDialogCallBack;
  end;
  lpItemID := SHBrowseForFolder(BrowseInfo);
  if lpItemId <> nil then begin
    SHGetPathFromIDList(lpItemID, TempPath);
    Result := TempPath;
    GlobalFreePtr(lpItemID);
  end;
end;

Sample usage:

procedure TForm1.Button1Click(Sender: TObject);
var
  sFolder : string;
begin
  sFolder := BrowseDialog('Select a folder', 
                          BIF_RETURNONLYFSDIRS);

  if sFolder <> '' then
    ShowMessage('Selected: ' + #13#10 + sFolder);
end;

©2014 About.com. All rights reserved.