Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

About SHBrowseForFolder callback function (Repost)...

135 views
Skip to first unread message

Jesús Avilés Martínez

unread,
Mar 4, 2002, 6:17:40 AM3/4/02
to
Hi all,

I posted this some days ago, but no answer has coming. Maybe this time i
have a better change.

I use SHBrowseForFolder to get a computer name from the network, with
the flag BIF_BROWSEFORCOMPUTER. I write a call back function to
enable/disable "OK" button depending on what computer is selected by the
user, when BFFM_SELCHANGED message is received. But the content of
lParam, passed to function SHGetPathFromIDList (with a cast, of course)
results on a blank name for computer, whatever it is.

The question: how can i get in this call back function the name of the
computer selected by the user?

--
JAM - Relájate y disfruta...

Angus Johnson

unread,
Mar 4, 2002, 6:46:26 AM3/4/02
to

"Jesús Avilés Martínez" <jam...@jazzfree.com> wrote in message
news:3C8357D4...@jazzfree.com...

> The question: how can i get in this call back function the name of the
> computer selected by the user?
>

The following code snippet might help ...

function BrowseProc(hwnd: HWnd; uMsg: integer; lParam, lpData: LPARAM):
integer; stdcall;
var
Dir: array[0..MAX_PATH] of char;
begin
case uMsg of
BFFM_INITIALIZED:
begin
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0, lpData);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
end;
BFFM_SELCHANGED:
if(SHGetPathFromIDList(PItemIDList(lParam), Dir)) then
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0, integer(@Dir[0]));
end;
result := 0;
end;
//---------------------------------------------------------------------

procedure CoTaskMemFree(pv: Pointer); stdcall; external 'ole32.dll' name
'CoTaskMemFree';

//---------------------------------------------------------------------

function GetFolder(OwnerHdl: THandle; var Folder: string): boolean;
var
displayname: array[0..MAX_PATH] of char;
bi: TBrowseInfo;
pidl: PItemIdList;
begin
bi.hWndOwner := OwnerHdl;
bi.pIDLRoot := nil;
bi.pszDisplayName := pchar(@displayname[0]);
bi.lpszTitle := pchar(loadstr(sSelectSaveToFolder));
bi.ulFlags := BIF_RETURNONLYFSDIRS or BIF_STATUSTEXT;
if Folder = '' then
begin
bi.lpfn := nil;
bi.lParam := 0;
end else
begin
Folder := StripPathSlash(Folder);
bi.lpfn := @BrowseProc;
bi.lParam := integer(pchar(Folder));
end;
bi.iImage := 0;
pidl := SHBrowseForFolder(bi);
result := pidl <> nil;
if not result then exit;
try
result := SHGetPathFromIDList(pidl,pchar(@displayname[0]));
Folder := displayname;
finally
CoTaskMemFree(pidl);
end;
end;
//--------------------------------------------------------------------------


Jesús Avilés Martínez

unread,
Mar 4, 2002, 6:58:01 AM3/4/02
to
Angus Johnson wrote:

Many thanks, but with your code, the user has to select a Folder, and
what i want is the user to select a computer in the network
neightbourghood. I have the function that do this, it returns the name
of the computer, but i want to know inside the callback function what
computer has selected the user just when he clicks in one of them, to
enable/disable the "OK" button. Here is the code (it works fine):

procedure SelectComputer(ParentWindow: HWND; const sTitle: string;
out sComputer: string);

var
BrowseInfo: TBrowseInfo;
RootPID: PItemIDList;
pComputer: PChar;
ShellMalloc: IMalloc;

begin
if not
Succeeded(SHGetSpecialFolderLocation(ParentWindow,CSIDL_NETWORK,RootPID))
then
Exit;

FillChar(BrowseInfo,SizeOf(TBrowseInfo),0);
if (not Succeeded(SHGetMalloc(ShellMalloc))) or (ShellMalloc = nil)
then Exit;

pComputer := ShellMalloc.Alloc(MAX_PATH);
try
pComputer[0] := #0;
BrowseInfo.hwndOwner := ParentWindow;
BrowseInfo.pidlRoot := RootPID;
BrowseInfo.pszDisplayName := pComputer;
BrowseInfo.lpszTitle := PChar(sTitle);
BrowseInfo.ulFlags := BIF_BROWSEFORCOMPUTER;
//BrowseInfo.lpfn := SHBrowseCallBack;
SHBrowseForFolder(BrowseInfo);
sComputer := pComputer;
finally
ShellMalloc.Free(pComputer);
end;
end;

Angus Johnson

unread,
Mar 4, 2002, 8:45:46 AM3/4/02
to
> Try modifying the callback function as per the following:

I should be asleep ... one last try:

function BrowseProc(hwnd: HWnd; uMsg: integer; lParam, lpData: LPARAM):
integer; stdcall;
var

sfi: TSHFileInfo;


begin
case uMsg of
BFFM_INITIALIZED:
begin
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0, lpData);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
end;
BFFM_SELCHANGED:

begin
ShGetFileInfo(PChar(lParam), 0,
sfi,sizeof(sfi),SHGFI_DISPLAYNAME or SHGFI_PIDL);
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0,
integer(@sfi.szDisplayName));
end;
end;


Angus Johnson

unread,
Mar 4, 2002, 8:41:06 AM3/4/02
to
> Many thanks, but with your code, the user has to select a Folder, and
> what i want is the user to select a computer in the network
> neightbourghood. I have the function that do this, it returns the name
> of the computer, but i want to know inside the callback function what
> computer has selected the user just when he clicks in one of them, to
> enable/disable the "OK" button. Here is the code (it works fine):

Sorry, I did not read you first post carefully enough.


Try modifying the callback function as per the following:

function BrowseProc(hwnd: HWnd; uMsg: integer; lParam, lpData: LPARAM):
integer; stdcall;
var
sfi: TSHFileInfo;


begin
case uMsg of
BFFM_INITIALIZED:
begin
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0, lpData);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
end;
BFFM_SELCHANGED:

Jesús Avilés Martínez

unread,
Mar 4, 2002, 10:05:52 AM3/4/02
to
Angus Johnson wrote:

Thanks again, Angus, but there is a problem: if you try to show the path
in lParam with function SHGetPathFromIDList, the result is '' (empty),
so your code doesn´t work (like mine. I was tring to use
SHGetPathFromIDList). I don´t know if there is a problem with the name
of computers on the net and when you click in one of them the lParam
parameter contains something that none function in API (i haven´t found
any) can recognize as a computer name.

Jesús Avilés Martínez

unread,
Mar 4, 2002, 10:44:22 AM3/4/02
to
If you test this function, you'll see a 0 each time you click in a
computer. No error in SHGetPathFromIDList, but no result.

uses ShlObj, ActiveX, SysUtils, Dialogs;

function SHBrowseCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData:
LPARAM): Integer; stdcall;

var
pComputer: PChar;

begin
Result := 0;
if uMsg = BFFM_SELCHANGED then begin
if SHGetPathFromIDList(PItemIDList(lParam),pComputer) then
ShowMessage(pComputer)
else
ShowMessage(IntToStr(GetLastError));
end;
end;

procedure SelectComputer(ParentWindow: HWND; const sTitle: string;
out sComputer: string);

var
BrowseInfo: TBrowseInfo;
RootPID: PItemIDList;
pComputer: PChar;
ShellMalloc: IMalloc;

begin
if not
Succeeded(SHGetSpecialFolderLocation(ParentWindow,CSIDL_NETWORK,RootPID))
then
Exit;

FillChar(BrowseInfo,SizeOf(TBrowseInfo),0);
if (not Succeeded(SHGetMalloc(ShellMalloc))) or (ShellMalloc = nil)
then Exit;

pComputer := ShellMalloc.Alloc(MAX_PATH);
try
pComputer[0] := #0;
BrowseInfo.hwndOwner := ParentWindow;
BrowseInfo.pidlRoot := RootPID;
BrowseInfo.pszDisplayName := pComputer;
BrowseInfo.lpszTitle := PChar(sTitle);
BrowseInfo.ulFlags := BIF_BROWSEFORCOMPUTER;

Jesús Avilés Martínez

unread,
Mar 4, 2002, 11:05:51 AM3/4/02
to
I have been consulting to MSDN and see this in SHBrowseForFolder:

"If the BIF_RETURNONLYFSDIRS flag is set in the ulFlags member of the
BROWSEINFO structure, the OK button will remain enabled for "\\server"
items, as well as "\\server\share" and directory items. However, if the
user selects a "\\server" item, passing the PIDL returned by the dialog
box to SHGetPathFromIDList will fail.
"

So i supose that the PIDL i get in callback function are not valid for
SHGetPathFromIDList.

And this is the question of one million dollars: How can i turn a PIDL
referred to a computer name to a string or something i can read?

Angus Johnson

unread,
Mar 4, 2002, 5:26:51 PM3/4/02
to
OK, I've had some sleep ... here's a working demo.

(Add a button to a blank form, add ShlObj and ShellApi to the uses clause,
and assign the button's onclick event.)

(nb: from WinApi.hlp: SHGetPathFromIDList() returns false if "the location
specified by the pidl parameter is not part of the file system" which is why
you
were having problems.)


function BrowseProc(hwnd: HWnd; uMsg: integer; lParam, lpData: LPARAM):
integer; stdcall;
var
sfi: TSHFileInfo;
begin
case uMsg of
BFFM_INITIALIZED:
begin
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0, lpData);
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
end;
BFFM_SELCHANGED:
begin
ShGetFileInfo(PChar(lParam), 0,
sfi,sizeof(sfi),SHGFI_DISPLAYNAME or SHGFI_PIDL);
SendMessage(hwnd, BFFM_SETSTATUSTEXT,0,
integer(@sfi.szDisplayName));
end;
end;

result := 0;
end;
//---------------------------------------------------------------------

procedure CoTaskMemFree(pv: Pointer); stdcall; external 'ole32.dll' name
'CoTaskMemFree';

//---------------------------------------------------------------------

function GetComputer(OwnerHdl: THandle;
const Title: string; out Computer: string): boolean;


var
displayname: array[0..MAX_PATH] of char;
bi: TBrowseInfo;

pidl, netPidl: PItemIdList;
sfi: TSHFileInfo;
begin
result := false;
bi.hWndOwner := OwnerHdl;
if not Succeeded(SHGetSpecialFolderLocation(OwnerHdl,
CSIDL_NETWORK,netPidl)) then exit;
try
bi.pIDLRoot := netPidl;


bi.pszDisplayName := pchar(@displayname[0]);

bi.lpszTitle := pchar(Title);
bi.ulFlags := BIF_BROWSEFORCOMPUTER or BIF_STATUSTEXT;
bi.lpfn := @BrowseProc;
bi.lParam := integer(nullStr);


bi.iImage := 0;
pidl := SHBrowseForFolder(bi);

finally
CoTaskMemFree(netPidl);
end;
if not assigned(pidl) then exit;
try
ShGetFileInfo(PChar(pidl), 0,
sfi,sizeof(sfi),SHGFI_DISPLAYNAME or SHGFI_PIDL);
Computer := sfi.szDisplayName;


finally
CoTaskMemFree(pidl);
end;
end;
//--------------------------------------------------------------------------


procedure TForm1.Button1Click(Sender: TObject);
var
computer: string;
begin
GetComputer(handle,'Select the Computer ...', computer);
caption := computer;
end;


Angus Johnson

unread,
Mar 4, 2002, 5:49:20 PM3/4/02
to

> And this is the question of one million dollars: How can i turn a PIDL
> referred to a computer name to a string or something i can read?

Do I get my million dollars now? <g>

a.


Jesús Avilés Martínez

unread,
Mar 5, 2002, 5:45:39 AM3/5/02
to
Angus Johnson wrote:

You get it!!!

Many thanks. I was going crazy with this.
I'll send you by Pony Express the money, because by e-mail is impossible
(the money is bigger than my band width).

--
JAM - Relįjate y disfruta...

0 new messages