I
import
Unregistered / Unconfirmed
GUEST, unregistred user!
下面的例子是正确的,但是为什么在Callback里面,必须采用全局变量,只要采用局部变量就会出现错误?我始终无法理解,难道是内存分配的原因?只要在Callback里面分配内存,就会出现错误!不过那个Longint(pchar(path))可以用一个integer(pchar('D:'))常量来代替,却又是正确的!真的很奇怪。我用HeapAlloc来分配内存也无法达到全局变量的效果。 unit Unit1;
interface
uses
shlobj,ActiveX;
var
Form1: TForm1;
Path: string; //起始路径
implementation
{$R *.DFM}
function BrowseCallbackProc(hwnd: HWND;uMsg: UINT;lParam: Cardinal;lpData: Cardinal): integer; stdcall;
begin
if uMsg=BFFM_INITIALIZED then
result :=SendMessage(Hwnd,BFFM_SETSELECTION,Ord(TRUE),Longint(PChar(Path)))
else
result :=1
end;
function SelDir(const Caption: string; const Root: WideString; out Directory: string): Boolean;
var
WindowList: Pointer;
BrowseInfo: TBrowseInfo;
Buffer: PChar;
RootItemIDList, ItemIDList: PItemIDList;
ShellMalloc: IMalloc;
IDesktopFolder: IShellFolder;
Eaten, Flags: LongWord;
begin
Result := False;
Directory := '';
FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
begin
Buffer := ShellMalloc.Alloc(MAX_PATH);
try
RootItemIDList := nil;
if Root <> '' then begin
SHGetDesktopFolder(IDesktopFolder);
IDesktopFolder.ParseDisplayName(Application.Handle, nil, POleStr(Root), Eaten, RootItemIDList, Flags);
end;
with BrowseInfo do begin
hwndOwner := Application.Handle;
pidlRoot := RootItemIDList;
pszDisplayName := Buffer;
lpszTitle := PChar(Caption);
ulFlags := BIF_RETURNONLYFSDIRS;
lpfn :=@BrowseCallbackProc;
lParam :=BFFM_INITIALIZED;
end;
WindowList := DisableTaskWindows(0);
try
ItemIDList := ShBrowseForFolder(BrowseInfo);
finally
EnableTaskWindows(WindowList);
end;
Result := ItemIDList <> nil;
if Result then begin
ShGetPathFromIDList(ItemIDList, Buffer);
ShellMalloc.Free(ItemIDList);
Directory := Buffer;
end;
finally
ShellMalloc.Free(Buffer);
end;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
Path1: string;
begin
Path :=Edit1.Text;
SelDir('SelectDirectory Sample','d:',Path1);
Edit1.Text :=Path1
end;
end.
2002.11.14:
今天终于解决了设置初始目录必须使用全局变量的问题!高兴哪!这样可以有一个极其好用的SelectDirectory函数了!可以指定Root目录,还可以设定初始化目录!!!!原来,在CallBack里面,那个lParam参数是可以传递数据的,而MSDN中说INIT消息的时候,lParam是0,是错误的,而且MSDN中关于wParam的说法是自相矛盾的!奇怪。
下面的函数可以指定初始化目录,只要在调用之前,赋值给Path参数即可。
interface
uses
shlobj,ActiveX;
var
Form1: TForm1;
Path: string; //起始路径
implementation
{$R *.DFM}
function BrowseCallbackProc(hwnd: HWND;uMsg: UINT;lParam: Cardinal;lpData: Cardinal): integer; stdcall;
begin
if uMsg=BFFM_INITIALIZED then
result :=SendMessage(Hwnd,BFFM_SETSELECTION,Ord(TRUE),Longint(PChar(Path)))
else
result :=1
end;
function SelDir(const Caption: string; const Root: WideString; out Directory: string): Boolean;
var
WindowList: Pointer;
BrowseInfo: TBrowseInfo;
Buffer: PChar;
RootItemIDList, ItemIDList: PItemIDList;
ShellMalloc: IMalloc;
IDesktopFolder: IShellFolder;
Eaten, Flags: LongWord;
begin
Result := False;
Directory := '';
FillChar(BrowseInfo, SizeOf(BrowseInfo), 0);
if (ShGetMalloc(ShellMalloc) = S_OK) and (ShellMalloc <> nil) then
begin
Buffer := ShellMalloc.Alloc(MAX_PATH);
try
RootItemIDList := nil;
if Root <> '' then begin
SHGetDesktopFolder(IDesktopFolder);
IDesktopFolder.ParseDisplayName(Application.Handle, nil, POleStr(Root), Eaten, RootItemIDList, Flags);
end;
with BrowseInfo do begin
hwndOwner := Application.Handle;
pidlRoot := RootItemIDList;
pszDisplayName := Buffer;
lpszTitle := PChar(Caption);
ulFlags := BIF_RETURNONLYFSDIRS;
lpfn :=@BrowseCallbackProc;
lParam :=BFFM_INITIALIZED;
end;
WindowList := DisableTaskWindows(0);
try
ItemIDList := ShBrowseForFolder(BrowseInfo);
finally
EnableTaskWindows(WindowList);
end;
Result := ItemIDList <> nil;
if Result then begin
ShGetPathFromIDList(ItemIDList, Buffer);
ShellMalloc.Free(ItemIDList);
Directory := Buffer;
end;
finally
ShellMalloc.Free(Buffer);
end;
end;
end;
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
Path1: string;
begin
Path :=Edit1.Text;
SelDir('SelectDirectory Sample','d:',Path1);
Edit1.Text :=Path1
end;
end.
2002.11.14:
今天终于解决了设置初始目录必须使用全局变量的问题!高兴哪!这样可以有一个极其好用的SelectDirectory函数了!可以指定Root目录,还可以设定初始化目录!!!!原来,在CallBack里面,那个lParam参数是可以传递数据的,而MSDN中说INIT消息的时候,lParam是0,是错误的,而且MSDN中关于wParam的说法是自相矛盾的!奇怪。
下面的函数可以指定初始化目录,只要在调用之前,赋值给Path参数即可。