I'm adding a checkbox to the BrowseForFolder dialog using the following calls...
ControlCreateStyles := WS_CHILD or {WS_CLIPSIBLINGS or} WS_VISIBLE or WS_TABSTOP or BS_CHECKBOX;
ChkBoxHdl := CreateWindow('BUTTON', PChar(ChkBoxCap), ControlCreateStyles,
Left, Top, Width, Height, Wnd, FB_CHECKBOX_ID, HInstance, nil);
The checkbox displays and operates correctly. However, when I resize the dialog down to its smallest size, the checkbox and caption disappear. Resizing the dialog causes the checkbox to reappear but not consistently. I tried enabling WS_CLIPSIBLINGS but doing so causes the component to not display at all.
Here is my test unit...
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
function BrowseForFolder(Title, Caption: string; const InitFolder: string = ''; DoNewBtn: Boolean = True; DoCheckBox: Boolean = False): string;
var
Form1: TForm1;
ShowCheckBox: Boolean = False;
DialogCaption: string;
implementation
{$R *.dfm}
uses
ShlObj, FileCtrl;
const
BIF_NEWDIALOGSTYLE = $40;
BIF_NONEWFOLDERBUTTON = $200;
FB_CHECKBOX_ID = 4005;
var
lg_StartFolder: String;
OldWndProc: Pointer;
function WndProcLocal(HWindow: HWND; MsgId: UINT; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;
var
NewFolder: string;
Cnt: Integer;
maxwidth: Integer;
MyFB: HWND;
begin
if (MsgId = WM_COMMAND) and (wP = FB_CHECKBOX_ID) then begin
Result := 0;
NewFolder := '';
Cnt := 0;
if (IsDlgButtonChecked(HWindow, FB_CHECKBOX_ID) = 0) then begin
CheckDlgButton(HWindow, FB_CHECKBOX_ID, BST_CHECKED);
// Do Something
end
else begin
CheckDlgButton(HWindow, FB_CHECKBOX_ID, BST_UNCHECKED);
// Do Something
end;
end
else begin
if (MsgId = WM_SHOWWINDOW) then begin
// Do Something
end
else if (MsgId = WM_SIZE) then begin
// Do Something
end
else if (MsgId = WM_MOVE) then begin
// Do Something
end;
Result := CallWindowProc(OldWndProc, HWindow, MsgId, wP, lP);
end;
end;
function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer stdcall;
var
ControlCreateStyles: Integer;
ChkBoxCap: String;
ChkBoxHdl: HWND;
Left, Top, Width, Height: Integer;
PPI: Integer;
Cnv: TCanvas;
TempFont: TFont;
begin
Result := 0;
if uMsg = BFFM_INITIALIZED then begin
if ShowCheckBox then begin
Left := 16;
Top := 32;
//Width := ?; { Calculated next based on caption }
Height := 16;
ChkBoxCap := 'Checkbox Caption';
Cnv := TCanvas.Create;
try
Cnv.Handle := GetDC(Wnd);
Width := Height * 2 + Cnv.TextWidth(ChkBoxCap);
finally
Cnv.Free;
end;
ControlCreateStyles := WS_CHILD or {WS_CLIPSIBLINGS or} WS_VISIBLE or WS_TABSTOP or BS_CHECKBOX;
ChkBoxHdl := CreateWindow('BUTTON', PChar(ChkBoxCap), ControlCreateStyles,
Left, Top, Width, Height, Wnd, FB_CHECKBOX_ID, HInstance, nil);
TempFont := nil;
TempFont := TFont.Create;
TempFont.Assign(Screen.IconFont);
try
PostMessage(ChkBoxHdl, WM_SETFONT, Longint(TempFont.Handle), MAKELPARAM(1, 0));
finally
TempFont.Free;
end;
CheckDlgButton(Wnd, FB_CHECKBOX_ID, BST_UNCHECKED); { Should always default to False }
//EnableWindow(ChkBoxHdl, True); { Necessary? }
end; { ShowCheckBox }
SetWindowText(Wnd, PChar(DialogCaption));
SendMessage(Wnd, BFFM_SETSELECTION, 1, Integer(@lg_StartFolder[1]));
OldWndProc := Pointer(GetWindowLong(Wnd, GWL_WNDPROC));
SetWindowLong(Wnd, GWL_WNDPROC, Longint(@WndProcLocal));
end;
end;
function BrowseForFolder(Title, Caption: string; const InitFolder: string = ''; DoNewBtn: Boolean = True; DoCheckBox: Boolean = False): string;
var
lpItemID: PItemIDList;
BrowseInfo: TBrowseInfo;
DisplayName: array[0 .. MAX_PATH] of Char;
find_context: PItemIDList;
ptrWindows: Pointer;
begin
DialogCaption := Caption;
ShowCheckBox := DoCheckBox;
FillChar(BrowseInfo, SizeOf(BrowseInfo), #0);
FillChar(DisplayName, SizeOf(DisplayName), #0);
lg_StartFolder := InitFolder;
with BrowseInfo do begin
hwndOwner := Application.Handle;
pszDisplayName := @DisplayName[0];
lpszTitle := PChar(Title);
ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE;
if not DoNewBtn then
ulFlags := ulFlags or BIF_NONEWFOLDERBUTTON; { Hide New Folder Button }
if (InitFolder <> '') then
lpfn := @BrowseForFolderCallBack;
LPARAM := 0;
end;
ptrWindows := DisableTaskWindows(0);
try
lpItemID := SHBrowseForFolder(BrowseInfo);
finally
EnableTaskWindows(ptrWindows);
end;
if Assigned(lpItemID) then
begin
if SHGetPathFromIDList(lpItemID, DisplayName) then
Result := DisplayName
else
Result := '';
GlobalFreePtr(lpItemID);
end
else
Result := '';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Dir: String;
begin
BrowseForFolder('Title', 'Caption', 'C:\', True, True);
end;
end.
As recommended by Embarcadero, it looks like I would need to go this route.
JAM Software ShellBrowser Delphi Components
Creating Custom File Dialogs: ShellBrowser Delphi Components
Yes, I am aware these libraries are only supported on Delphi XE3 and later.