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

Specfying particular folder in SHBrowseForFolder

152 views
Skip to first unread message

Karthik Venkataraman

unread,
Dec 3, 1998, 3:00:00 AM12/3/98
to
Hi,
How can I have a specific folder open within the directory list
displayed by SHBrowseForFolder?

For example I want "C:\TEST" to be the selected folder and the first visible
item when the dialog opens.

Cheers
Karthik

Metralfields

unread,
Dec 3, 1998, 3:00:00 AM12/3/98
to

ein...@wxs.nl

unread,
Dec 5, 1998, 3:00:00 AM12/5/98
to
In article <eD89CUlH#GA....@uppssnewspub05.moswest.msn.net>,

"Karthik Venkataraman" <karthik.ve...@hpa.com.au> wrote:
> Hi,
> How can I have a specific folder open within the directory list
> displayed by SHBrowseForFolder?
>
> For example I want "C:\TEST" to be the selected folder and the first visible
> item when the dialog opens.
>
> Cheers
> Karthik
>
>
Use a BrowseCallback function to set the 'initial selection'.
C code below adapted from MSDN sample Q179378 (support.microsoft.com).
I have an additional question. Although the code works fine, it gives
a warning "The device is not ready" when you start from "A:\" and there
is no floppy in the drive. Does anyone know how to suppress this warning?

Berend

--- start code ---
#define STRICT
#include <windows.h>
#include <shlobj.h>

int CALLBACK
BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM lpData)
{
switch(uMsg)
{
case BFFM_INITIALIZED:
// WParam is TRUE since you are passing a path.
// It would be FALSE if you were passing a pidl.
if (lpData)
{
SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);
}
break;
}
return 0;
}


// BrowseDir calls SHBrowseForFolder to display the standard
// Win32 directory picker window. The BrowseCallbackProc is used
// to preset the current directory selection passed in szCurDir
//
// Parameters:
// dwHwnd - IN: hwnd of parent window
// szCurDir - IN: current directory selection
// szTitle - IN: window title passed to SHBrowseForFolder
// szRetDir - OUT: returned directory selection
// wMaxRet - IN: max. capacity of szRetDir buffer
void __stdcall
BrowseDir(DWORD dwHWnd, LPSTR szCurDir, LPSTR szTitle, LPSTR szRetDir, UINT
wMaxRet)
{
BROWSEINFO bi;
TCHAR szDir[MAX_PATH];
LPITEMIDLIST pidl;
LPMALLOC pMalloc;
int iLen;

wMaxRet--;
strncpy(szRetDir, szCurDir, wMaxRet);
szRetDir[wMaxRet] = 0;

// If it is not a root dir (i.e., if length of the path is > 3)
// the path specifier may not end in '\'. In that case we trim
// off the backslash to make it work anyway.
iLen = strlen(szRetDir);
if ((iLen > 3) && (szRetDir[iLen-1] == '\\'))
{
iLen--;
szRetDir[iLen] = 0; // gets rid of last character ('\')
}


if (SUCCEEDED(SHGetMalloc(&pMalloc)))
{
ZeroMemory(&bi,sizeof(bi));
bi.hwndOwner = (HWND)dwHWnd;
bi.pszDisplayName = 0;
bi.pidlRoot = 0;
bi.ulFlags = BIF_RETURNONLYFSDIRS;
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LPARAM)szRetDir;
bi.lpszTitle = szTitle;

pidl = SHBrowseForFolder(&bi);
if (pidl)
{
if (SHGetPathFromIDList(pidl,szDir))
{
strncpy(szRetDir, szDir, wMaxRet);
}

pMalloc->lpVtbl->Free(pMalloc,pidl);
}
pMalloc->lpVtbl->Release(pMalloc);
}
}
--- end code ---

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

KEITH TINGLE

unread,
Dec 6, 1998, 3:00:00 AM12/6/98
to
Have you tried wrapping the call in a __try __except block?

Engelbrecht

unread,
Dec 6, 1998, 3:00:00 AM12/6/98
to
KEITH TINGLE wrote in message <74dt5u$m...@bgtnsc02.worldnet.att.net>...

>Have you tried wrapping the call in a __try __except block?
>
>
Thanks for the idea, it would have been an elegant solution, if only
Microsoft would have coded exceptions in a consistent way. Unfortunately it
doesn't work, the exception is handled internally in the Explorer shell and
my code doesn't get control again before the warning dialog is dismissed.

In the mean time I found a solution myself - I just create a worker thread
that polls for the warning dialog as long as the directory browser window is
active and dismisses it the first time it appears. This fixes my problem,
but it is an extremely dirty solution, so I would still be interested if
somebody has a cleaner alternative (one that also works).

I have one remaining problem: if the initial path is a network directory
instead of a local path, e.g., "\\OtherMachine\c", the BFFM_SETSELECTION
message does not select it. There is a short timeout, during which it seems
to poll the network, but nothing is selected (also no warning is shown). I
have found other posts about the same problem, but no solution. The funny
thing is that when you use SHBrowseForFolder to select a network path,
dismiss it and immediately display it again from the same process, it *does*
select the network path correctly. Smells like a bug to me.

Berend Engelbrecht

The full code of my version of a SHBrowseForFolder directory picker function
is listed below, in case anyone is interested. If the function is located in
a DLL, it can be called from Visual Basic, Delphi, etc.
Visual Basic code is also shown.

--- start C code ---


#define STRICT
#include <windows.h>
#include <shlobj.h>

//// Prototypes of private functions


int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM

lpData);
DWORD WINAPI BrowseThreadProc(LPVOID lpParameter);


//// Exported function

bi.lParam = (LPARAM)szRetDir; // passed as lpData to BrowseCallbackProc
bi.lpszTitle = szTitle;

pidl = SHBrowseForFolder(&bi);
if (pidl)
{
if (SHGetPathFromIDList(pidl,szDir))
{
strncpy(szRetDir, szDir, wMaxRet);
}
pMalloc->lpVtbl->Free(pMalloc,pidl);
}
pMalloc->lpVtbl->Release(pMalloc);
}
}


// The BrowseCallbackProc is used to set the initial selection
// of the directory browser to the currently selected path.
// The lpData parameter is used by BrowseDir to pass this path
// as a string.


int CALLBACK
BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM lpData)
{

DWORD dwThreadId;

switch(uMsg)
{
case BFFM_INITIALIZED:
// If the current path is "A:\" and there is no floppy in the
// drive, SHBrowseForFolder displays a warning
// "The device is not ready" before displaying the directory
// browser. To correct this unwanted behavior, we start a worker
// thread, that polls for a warning box and simply cancels it
// when it appears. The thread terminates after an error box was
// dismissed, or when the directory browser itself is closed.
CreateThread(NULL,0, BrowseThreadProc, (LPVOID)hwnd, 0, &dwThreadId);

// WParam is TRUE since you are passing a path.
// It would be FALSE if you were passing a pidl.

SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData);
break;

}
return 0;
}


// Thread procedure watching for warning dialog.
// The procedure uses the following assumptions to locate the
// warning dialog:
// - It is a dialog window (window class == MAKEINTRESOURCE(32770U))
// - It has the same title as the directory browser (both have
// the title "Browse for Folder" in the US English version of
// Windows)
// - It has the same process id (both have the process ID of the
// parent application when the hwndOwner member of the BROWSEINFO
// is not NULL).
//
// The hwnd of the directory browser window is passed in lpParameter.
//
DWORD WINAPI BrowseThreadProc( LPVOID lpParameter )
{
HWND hwndBrowse = (HWND)lpParameter;
HWND hwndDlg, hwndCtl;
DWORD dwMyProcess, dwDlgProcess;
char szTitle[80];
BOOL bFoundMyself;

// Get title and process id for the Browse window
GetWindowText(hwndBrowse, szTitle, sizeof(szTitle));
GetWindowThreadProcessId(hwndBrowse, &dwMyProcess);
do
{
// Find all dialog windows with the same title ("Browse for Folder"
// in English). If there is a different one with matching title and
// ProcesId, we assume it is the retry/cancel warning box and
// dismiss it.
hwndDlg = (HWND)NULL;
bFoundMyself = FALSE;
do
{
hwndDlg = FindWindowEx(NULL, hwndDlg, MAKEINTRESOURCE(32770U),
szTitle);
if (hwndDlg)
{
// Check if we can still find the directory browser.
// If it is gone, this thread must also end.
if (hwndDlg == hwndBrowse)
bFoundMyself = TRUE;
else
{
// Check the process ID for another window with the same
// title. We do not touch it if it is not part of the same
// process as our directory browser.
GetWindowThreadProcessId(hwndDlg, &dwDlgProcess);
if (dwMyProcess == dwDlgProcess)
{
// Send the warning dialog a Cancel button command, so that
// it goes away. We must use Postmessage (async) because we
// are not running in the same thread.
hwndCtl = GetDlgItem(hwndDlg, IDCANCEL);
if (hwndCtl)
{
PostMessage(hwndDlg, WM_COMMAND,
(WPARAM)IDCANCEL, (LPARAM)hwndCtl);
return 0; // end thread when we got rid of the warning dlg
}
}
}
}
}
while (hwndDlg);

Sleep(50); // Briefly suspend thread before polling again, to give
// other threads and processes a chance to run.
}
while (bFoundMyself); // End thread if browser window is no longer found
return 0;
}
--- end C code ---
--- start VB code ---
Option Explicit

Private Declare Sub BrowseDir Lib "IFTPWD32.DLL" (ByVal hWnd As Long, ByVal
szCurDir As String, ByVal szTitle As String, ByVal szRetDir As String, ByVal
wMaxRet As Integer)
Private Const MAX_PATH = 260

' ShowDirList shows a directory selection window (directory browser).
' Parameters:
' hwnd - IN: hwnd property of form calling ShowDirList
' sDir - IN: Current directory selection
' OUT: New directory selection (same if directory browser was
canceled)
' sTitle - IN: 'Title' prompt to be used in directory browser window
'
Public Sub ShowDirList(sDir As String, ByVal sTitle As String)
Dim sRet As String

sDir = sDir & vbNullChar
sTitle = sTitle & vbNullChar
sRet = Space(MAX_PATH)
BrowseDir Me.hWnd, sDir, sTitle, sRet, MAX_PATH
sDir = Left(sRet, InStr(sRet, vbNullChar) - 1)
End Sub
--- end VB code ---

0 new messages