420 lines
13 KiB
ObjectPascal
420 lines
13 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: AHCompBrowseFolderDlg.pas, released on 2003-12-07.
|
|
|
|
The Initial Developer of the Original Code is Andreas Hausladen
|
|
(Andreas dott Hausladen att gmx dott de)
|
|
Portions created by Andreas Hausladen are Copyright (C) 2003 Andreas Hausladen.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s): -
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL
|
|
home page, located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: AHCompBrowseFolderDlg.pas 10610 2006-05-19 13:35:08Z elahn $
|
|
|
|
unit AHCompBrowseFolderDlg;
|
|
|
|
{$I jvcl.inc}
|
|
{$I windowsonly.inc}
|
|
|
|
{$IFDEF COMPILER6_UP}
|
|
{$WARN UNIT_PLATFORM OFF}
|
|
{$WARN SYMBOL_PLATFORM OFF}
|
|
{$ENDIF}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Graphics, Controls, Forms, Classes, Dialogs,
|
|
ActiveX, ComObj, ShlObj, FileCtrl;
|
|
|
|
type
|
|
{ TBrowseFolderDialog }
|
|
|
|
TBrowseKind = (bfFolders, bfComputers);
|
|
TDialogPosition = (dpDefault, dpScreenCenter);
|
|
|
|
TCustomizeEvent = procedure(Sender: TObject; Handle: HWND) of object;
|
|
TWndProcEvent = procedure(Sender: TObject; var Msg: TMessage; var Handled: Boolean) of object;
|
|
TCommandEvent = procedure(Sender: TObject; var Msg: TWMCommand; var Handled: Boolean) of object;
|
|
TEnableOKBtnEvent = procedure(Sender: TObject; var Enable: Boolean) of object;
|
|
|
|
TBrowseFolderDialog = class(TCommonDialog)
|
|
private
|
|
FDefWndProc: Pointer;
|
|
FHelpContext: THelpContext;
|
|
FHandle: HWND;
|
|
FObjectInstance: Pointer;
|
|
FDesktopRoot: Boolean;
|
|
FBrowseKind: TBrowseKind;
|
|
FPosition: TDialogPosition;
|
|
FText: string;
|
|
FDisplayName: string;
|
|
FSelectedName: string;
|
|
FFolderName: string;
|
|
FImageIndex: Integer;
|
|
FOnInitialized: TNotifyEvent;
|
|
FOnSelChanged: TNotifyEvent;
|
|
FOnCustomize: TCustomizeEvent;
|
|
FOnWndProc: TWndProcEvent;
|
|
FOnCommand: TCommandEvent;
|
|
FOnEnableOKBtn: TEnableOKBtnEvent;
|
|
procedure SetSelPath(const Path: string);
|
|
procedure SetOkEnable(Value: Boolean);
|
|
procedure DoInitialized;
|
|
procedure DoSelChanged(Param: PItemIDList);
|
|
procedure DoCustomize;
|
|
function DoWndProc(var Msg: TMessage): Boolean;
|
|
function DoCommand(var Msg: TMessage): Boolean;
|
|
procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
|
|
procedure WMCommand(var Message: TMessage); message WM_COMMAND;
|
|
protected
|
|
function TaskModalDialog2(var Info: TBrowseInfo): PItemIDList;
|
|
public
|
|
procedure DefaultHandler(var Message); override;
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function Execute: Boolean; override;
|
|
|
|
function GetOKBtnID: Integer;
|
|
function GetOKBtn: THandle;
|
|
property Handle: HWND read FHandle;
|
|
property DisplayName: string read FDisplayName;
|
|
property SelectedName: string read FSelectedName write FSelectedName;
|
|
property ImageIndex: Integer read FImageIndex;
|
|
published
|
|
property BrowseKind: TBrowseKind read FBrowseKind write FBrowseKind default bfFolders;
|
|
property DesktopRoot: Boolean read FDesktopRoot write FDesktopRoot default True;
|
|
property DialogText: string read FText write FText;
|
|
property FolderName: string read FFolderName write FFolderName;
|
|
property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
|
|
property Position: TDialogPosition read FPosition write FPosition default dpScreenCenter;
|
|
property OnInitialized: TNotifyEvent read FOnInitialized write FOnInitialized;
|
|
property OnSelChanged: TNotifyEvent read FOnSelChanged write FOnSelChanged;
|
|
property OnCustomize: TCustomizeEvent read FOnCustomize write FOnCustomize;
|
|
property OnWndProc: TWndProcEvent read FOnWndProc write FOnWndProc;
|
|
property OnCommand: TCommandEvent read FOnCommand write FOnCommand;
|
|
property OnEnableOKBtn: TEnableOKBtnEvent read FOnEnableOKBtn write FOnEnableOKBtn;
|
|
end;
|
|
|
|
function BrowseDirectory(var AFolderName: string; const DlgText: string;
|
|
AHelpContext: THelpContext): Boolean;
|
|
function BrowseComputer(var ComputerName: string; const DlgText: string;
|
|
AHelpContext: THelpContext): Boolean;
|
|
|
|
procedure CenterWindow(wnd: HWND);
|
|
|
|
implementation
|
|
|
|
resourcestring
|
|
STR_HELPBTN = '&Help';
|
|
|
|
procedure CenterWindow(wnd: HWND);
|
|
var r: TRect;
|
|
begin
|
|
GetWindowRect(wnd, r);
|
|
r := Rect((GetSystemMetrics(SM_CXSCREEN) - r.Right + r.Left) div 2,
|
|
(GetSystemMetrics(SM_CYSCREEN) - r.Bottom + r.Top) div 2,
|
|
r.Right - r.Left, r.Bottom - r.Top);
|
|
SetWindowPos(wnd, 0, r.Left, r.Top, 0, 0, SWP_NOACTIVATE or
|
|
SWP_NOSIZE or SWP_NOZORDER);
|
|
end;
|
|
|
|
function ExplorerHook(wnd: HWnd; Msg: UINT; LParam: LPARAM; Data: LPARAM): Integer; stdcall;
|
|
begin
|
|
Result := 0;
|
|
if Msg = BFFM_INITIALIZED then
|
|
begin
|
|
if TBrowseFolderDialog(Data).Position = dpScreenCenter then CenterWindow(wnd);
|
|
TBrowseFolderDialog(Data).FHandle := wnd;
|
|
TBrowseFolderDialog(Data).FDefWndProc := Pointer(SetWindowLong(wnd, GWL_WNDPROC,
|
|
Longint(TBrowseFolderDialog(Data).FObjectInstance)));
|
|
TBrowseFolderDialog(Data).DoInitialized;
|
|
end
|
|
else if Msg = BFFM_SELCHANGED then
|
|
begin
|
|
TBrowseFolderDialog(Data).FHandle := wnd;
|
|
TBrowseFolderDialog(Data).DoSelChanged(PItemIDList(LParam));
|
|
end;
|
|
end;
|
|
|
|
const
|
|
HelpButtonId = $FFFF;
|
|
|
|
function RemoveBackSlash(const s: String): String;
|
|
begin
|
|
Result := s;
|
|
if (Result <> '') and (Result[length(Result)] = '\') then
|
|
Delete(Result, length(Result), 1);
|
|
end;
|
|
|
|
function DirExists(const dir: String): Boolean;
|
|
var
|
|
Attr: DWord;
|
|
begin
|
|
Attr := GetFileAttributes(PChar(dir));
|
|
Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY <> 0);
|
|
end;
|
|
|
|
|
|
// *****************************************************************************
|
|
constructor TBrowseFolderDialog.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FOnCustomize := nil;
|
|
FOnWndProc := nil;
|
|
FOnCommand := nil;
|
|
FOnEnableOKBtn := nil;
|
|
|
|
FObjectInstance := MakeObjectInstance(WndProc);
|
|
FDesktopRoot := True;
|
|
FBrowseKind := bfFolders;
|
|
FPosition := dpScreenCenter;
|
|
SetLength(FDisplayName, MAX_PATH);
|
|
end;
|
|
|
|
destructor TBrowseFolderDialog.Destroy;
|
|
begin
|
|
if FObjectInstance <> nil then FreeObjectInstance(FObjectInstance);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TBrowseFolderDialog.GetOKBtnID: Integer;
|
|
begin
|
|
Result := GetDlgCtrlID(GetOKBtn);
|
|
end;
|
|
|
|
function TBrowseFolderDialog.GetOKBtn: THandle;
|
|
begin
|
|
Result := 0;
|
|
if FHandle = 0 then Exit;
|
|
Result := FindWindowEx(FHandle, 0, 'BUTTON', 'OK');
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.DoInitialized;
|
|
const
|
|
SBtn = 'BUTTON';
|
|
var
|
|
BtnHandle, HelpBtn, BtnFont: THandle;
|
|
BtnSize: TRect;
|
|
begin
|
|
if (FBrowseKind = bfComputers) or DirExists(FFolderName) then
|
|
SetSelPath(FFolderName);
|
|
if FHelpContext <> 0 then
|
|
begin
|
|
BtnHandle := FindWindowEx(FHandle, 0, SBtn, nil);
|
|
if (BtnHandle <> 0) then
|
|
begin
|
|
GetWindowRect(BtnHandle, BtnSize);
|
|
ScreenToClient(FHandle, BtnSize.TopLeft);
|
|
ScreenToClient(FHandle, BtnSize.BottomRight);
|
|
BtnFont := SendMessage(FHandle, WM_GETFONT, 0, 0);
|
|
HelpBtn := CreateWindow(SBtn, PChar(STR_HELPBTN),
|
|
WS_CHILD or WS_CLIPSIBLINGS or WS_VISIBLE or BS_PUSHBUTTON or WS_TABSTOP,
|
|
12, BtnSize.Top, BtnSize.Right - BtnSize.Left, BtnSize.Bottom - BtnSize.Top,
|
|
FHandle, HelpButtonId, HInstance, nil);
|
|
if BtnFont <> 0 then
|
|
SendMessage(HelpBtn, WM_SETFONT, BtnFont, MakeLParam(1, 0));
|
|
UpdateWindow(FHandle);
|
|
end;
|
|
end;
|
|
if Assigned(FOnInitialized) then FOnInitialized(Self);
|
|
DoCustomize;
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.DoSelChanged(Param: PItemIDList);
|
|
var Temp: Array[0..MAX_PATH] of Char;
|
|
begin
|
|
if (FBrowseKind = bfComputers) then
|
|
FSelectedName := DisplayName
|
|
else
|
|
begin
|
|
if SHGetPathFromIDList(Param, Temp) then
|
|
begin
|
|
FSelectedName := StrPas(Temp);
|
|
SetOkEnable(DirExists(FSelectedName));
|
|
end
|
|
else
|
|
begin
|
|
FSelectedName := '';
|
|
SetOkEnable(False);
|
|
end;
|
|
end;
|
|
if Assigned(FOnSelChanged) then FOnSelChanged(Self);
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.DoCustomize;
|
|
begin
|
|
if Assigned(FOnCustomize) then FOnCustomize(Self, Handle);
|
|
end;
|
|
function TBrowseFolderDialog.DoWndProc(var Msg: TMessage): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FOnWndProc) then FOnWndProc(Self, Msg, Result);
|
|
end;
|
|
function TBrowseFolderDialog.DoCommand(var Msg: TMessage): Boolean;
|
|
begin
|
|
Result := False;
|
|
if Assigned(FOnCommand) then FOnCommand(Self, TWMCommand(Msg), Result);
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.SetSelPath(const Path: string);
|
|
begin
|
|
if FHandle <> 0 then
|
|
SendMessage(FHandle, BFFM_SETSELECTION, 1, Longint(PChar(Path)));
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.SetOkEnable(Value: Boolean);
|
|
begin
|
|
if Assigned(FOnEnableOKBtn) then FOnEnableOKBtn(Self, Value);
|
|
if FHandle <> 0 then SendMessage(FHandle, BFFM_ENABLEOK, 0, Ord(Value));
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.DefaultHandler(var Message);
|
|
begin
|
|
if FHandle <> 0 then
|
|
if not DoWndProc(TMessage(Message)) then
|
|
begin
|
|
with TMessage(Message) do
|
|
Result := CallWindowProc(FDefWndProc, FHandle, Msg, WParam, LParam)
|
|
end
|
|
else
|
|
inherited DefaultHandler(Message);
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.WMCommand(var Message: TMessage);
|
|
begin
|
|
if (Message.wParam = HelpButtonId) and
|
|
(LongRec(Message.lParam).Hi = BN_CLICKED) and (FHelpContext <> 0) then
|
|
Application.HelpContext(FHelpContext)
|
|
else
|
|
if not DoCommand(Message) then inherited;
|
|
end;
|
|
|
|
procedure TBrowseFolderDialog.WMNCDestroy(var Message: TWMNCDestroy);
|
|
begin
|
|
inherited;
|
|
FHandle := 0;
|
|
end;
|
|
|
|
function TBrowseFolderDialog.Execute: Boolean;
|
|
var
|
|
BrowseInfo: TBrowseInfo;
|
|
ItemIDList: PItemIDList;
|
|
Temp: Array[0..MAX_PATH] of Char;
|
|
begin
|
|
if FDesktopRoot and (FBrowseKind = bfFolders) then
|
|
BrowseInfo.pidlRoot := nil
|
|
else
|
|
begin
|
|
if FBrowseKind = bfComputers then { root - Network }
|
|
OleCheck(SHGetSpecialFolderLocation(0, CSIDL_NETWORK, BrowseInfo.pidlRoot))
|
|
else { root - MyComputer }
|
|
OleCheck(SHGetSpecialFolderLocation(0, CSIDL_DRIVES, BrowseInfo.pidlRoot));
|
|
end;
|
|
try
|
|
SetLength(FDisplayName, MAX_PATH);
|
|
with BrowseInfo do
|
|
begin
|
|
pszDisplayName := PChar(DisplayName);
|
|
if DialogText <> '' then lpszTitle := PChar(DialogText) else lpszTitle := nil;
|
|
if FBrowseKind = bfComputers then
|
|
ulFlags := BIF_BROWSEFORCOMPUTER
|
|
else
|
|
ulFlags := BIF_RETURNONLYFSDIRS or BIF_RETURNFSANCESTORS;
|
|
lpfn := ExplorerHook;
|
|
lParam := Longint(Self);
|
|
hWndOwner := Application.Handle;
|
|
iImage := 0;
|
|
end;
|
|
ItemIDList := TaskModalDialog2(BrowseInfo);
|
|
Result := ItemIDList <> nil;
|
|
if Result then
|
|
try
|
|
if FBrowseKind = bfFolders then
|
|
begin
|
|
Win32Check(SHGetPathFromIDList(ItemIDList, Temp));
|
|
FFolderName := RemoveBackSlash(StrPas(Temp));
|
|
end
|
|
else
|
|
FFolderName := DisplayName;
|
|
FSelectedName := FFolderName;
|
|
FImageIndex := BrowseInfo.iImage;
|
|
finally
|
|
CoTaskMemFree(ItemIDList);
|
|
end;
|
|
finally
|
|
if BrowseInfo.pidlRoot <> nil then CoTaskMemFree(BrowseInfo.pidlRoot);
|
|
end;
|
|
end;
|
|
|
|
function TBrowseFolderDialog.TaskModalDialog2(var Info: TBrowseInfo): PItemIDList;
|
|
var
|
|
ActiveWindow: HWnd;
|
|
WindowList: Pointer;
|
|
begin
|
|
ActiveWindow := GetActiveWindow;
|
|
WindowList := DisableTaskWindows(0);
|
|
try
|
|
try
|
|
Result := SHBrowseForFolder(Info);
|
|
finally
|
|
FHandle := 0;
|
|
FDefWndProc := nil;
|
|
end;
|
|
finally
|
|
EnableTaskWindows(WindowList);
|
|
SetActiveWindow(ActiveWindow);
|
|
end;
|
|
end;
|
|
|
|
function BrowseDirectory(var AFolderName: string; const DlgText: string;
|
|
AHelpContext: THelpContext): Boolean;
|
|
begin
|
|
if NewStyleControls then
|
|
begin
|
|
with TBrowseFolderDialog.Create(Application) do
|
|
try
|
|
DialogText := DlgText;
|
|
FolderName := AFolderName;
|
|
HelpContext := AHelpContext;
|
|
Result := Execute;
|
|
if Result then AFolderName := FolderName;
|
|
finally
|
|
Free;
|
|
end;
|
|
end
|
|
else
|
|
Result := SelectDirectory(AFolderName, [], AHelpContext);
|
|
end;
|
|
|
|
function BrowseComputer(var ComputerName: string; const DlgText: string;
|
|
AHelpContext: THelpContext): Boolean;
|
|
begin
|
|
with TBrowseFolderDialog.Create(Application) do
|
|
try
|
|
BrowseKind := bfComputers;
|
|
DialogText := DlgText;
|
|
FolderName := ComputerName;
|
|
HelpContext := AHelpContext;
|
|
Result := Execute;
|
|
if Result then ComputerName := FolderName;
|
|
finally
|
|
Free;
|
|
end;
|
|
end;
|
|
|
|
end.
|