📄 ahcompbrowsefolderdlg.pas
字号:
{-----------------------------------------------------------------------------
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,v 1.3 2004/12/23 00:25:13 ahuser Exp $
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -