JohnStevenson
asked on
ShBrowseForFolder with Make New Folder button
Could someone please post an example of how to call ShBrowseForFolder which displays the Make New Folder button, and which uses a callback function to set the initial directory.
Thanks
Thanks
are you asking how to add a "Make New Folder button" to a ShBrowseForFolder Dialog box?
ASKER
No, I know how to do this, by adding the BIF_NEWDIALOGSTYLE flag to the ulFlags parameterof the BrowseInfo structure.
My problem is that when I do this, I get a working "Make New Folder" button but I loose the initial directory setting of the folder dialog. Here's the code:
function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer; stdcall;
var
Path: array[0..MAX_PATH] of Char;
ptPos: TPoint;
Rect : TRect;
begin
case uMsg of
BFFM_INITIALIZED:
begin
{Position folder window}
GetWindowRect(hWnd, Rect);
ptPos := GetFormPosition(frmMain, Rect.Right - Rect.Left,
Rect.Bottom - Rect.Top, 1);
MoveWindow(hWnd, ptPos.X, ptPos.Y, Rect.Right - Rect.Left,
Rect.Bottom - Rect.Top, True);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, lpData);
end;
BFFM_SELCHANGED:
begin
{Set the status text to the currently selected path.}
if SHGetPathFromIDList(Pointe r(lParam), Path) then
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, Integer(@Path));
end;
end;
Result := 0;
end; { BrowseCallbackProc }
function SelectDirectory(const Caption, InitialDir: string; const Root: WideString;
ShowStatus: Boolean; out Directory: string): Boolean;
var BrowseInfo: TBrowseInfo;
Buffer: PChar;
RootItemIDList,
ItemIDList: PItemIDList;
ShellMalloc: IMalloc;
IDesktopFolder: IShellFolder;
Eaten, Flags: LongWord;
Windows: Pointer;
Path: String;
begin
Result := False;
Directory := '';
Path := InitialDir;
if (Length(Path) > 0) and (Path[Length(Path)] = '\') then
Delete(Path, Length(Path), 1);
FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
begin
Buffer := ShellMalloc.Alloc(MAX_PATH );
try
SHGetDesktopFolder(IDeskto pFolder);
IDesktopFolder.ParseDispla yName(Appl ication.Ha ndle, nil, PWideChar(Root),
Eaten, RootItemIDList, Flags);
with BrowseInfo do
begin
hwndOwner := Application.Handle;
pidlRoot := RootItemIDList;
pszDisplayName := Buffer;
lpszTitle := PChar(Caption);
ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE;
if ShowStatus then
ulFlags := ulFlags or BIF_STATUSTEXT;
lParam := Integer(PChar(Path));
lpfn := BrowseCallbackProc;
end;
Result := ItemIDList <> nil;
if Result then
begin
ShGetPathFromIDList(ItemID List, Buffer);
ShellMalloc.Free(ItemIDLis t);
Directory := Buffer;
end;
finally
ShellMalloc.Free(Buffer);
end;
end;
end; { SelectDirectory }
My problem is that when I do this, I get a working "Make New Folder" button but I loose the initial directory setting of the folder dialog. Here's the code:
function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer; stdcall;
var
Path: array[0..MAX_PATH] of Char;
ptPos: TPoint;
Rect : TRect;
begin
case uMsg of
BFFM_INITIALIZED:
begin
{Position folder window}
GetWindowRect(hWnd, Rect);
ptPos := GetFormPosition(frmMain, Rect.Right - Rect.Left,
Rect.Bottom - Rect.Top, 1);
MoveWindow(hWnd, ptPos.X, ptPos.Y, Rect.Right - Rect.Left,
Rect.Bottom - Rect.Top, True);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, lpData);
end;
BFFM_SELCHANGED:
begin
{Set the status text to the currently selected path.}
if SHGetPathFromIDList(Pointe
SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, Integer(@Path));
end;
end;
Result := 0;
end; { BrowseCallbackProc }
function SelectDirectory(const Caption, InitialDir: string; const Root: WideString;
ShowStatus: Boolean; out Directory: string): Boolean;
var BrowseInfo: TBrowseInfo;
Buffer: PChar;
RootItemIDList,
ItemIDList: PItemIDList;
ShellMalloc: IMalloc;
IDesktopFolder: IShellFolder;
Eaten, Flags: LongWord;
Windows: Pointer;
Path: String;
begin
Result := False;
Directory := '';
Path := InitialDir;
if (Length(Path) > 0) and (Path[Length(Path)] = '\') then
Delete(Path, Length(Path), 1);
FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
begin
Buffer := ShellMalloc.Alloc(MAX_PATH
try
SHGetDesktopFolder(IDeskto
IDesktopFolder.ParseDispla
Eaten, RootItemIDList, Flags);
with BrowseInfo do
begin
hwndOwner := Application.Handle;
pidlRoot := RootItemIDList;
pszDisplayName := Buffer;
lpszTitle := PChar(Caption);
ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE;
if ShowStatus then
ulFlags := ulFlags or BIF_STATUSTEXT;
lParam := Integer(PChar(Path));
lpfn := BrowseCallbackProc;
end;
Result := ItemIDList <> nil;
if Result then
begin
ShGetPathFromIDList(ItemID
ShellMalloc.Free(ItemIDLis
Directory := Buffer;
end;
finally
ShellMalloc.Free(Buffer);
end;
end;
end; { SelectDirectory }
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks Slick812.
I got it working using your sample. Incidentally, using BFFM_SETEXPANDED (WM_USER + 106) in the callback and passing a Pidl rather than a pointer to a wide string, seems to work better than using BFFM_SETSELECTION. I had problems with this when my BrowseInfo.pidlRoot was something other than the Desktop (or null).
I got it working using your sample. Incidentally, using BFFM_SETEXPANDED (WM_USER + 106) in the callback and passing a Pidl rather than a pointer to a wide string, seems to work better than using BFFM_SETSELECTION. I had problems with this when my BrowseInfo.pidlRoot was something other than the Desktop (or null).