711 lines
15 KiB
C++
711 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) 1994-1998 Microsoft Corporation
|
|
|
|
Module Name :
|
|
|
|
dirbrows.cpp
|
|
|
|
Abstract:
|
|
|
|
Directory Browser Dialog. Allow browsing for directories only.
|
|
optionally allows UNC conversions for remote paths.
|
|
|
|
Author:
|
|
|
|
Ronald Meijer (ronaldm)
|
|
|
|
Project:
|
|
|
|
Internet Services Manager
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Include Files
|
|
//
|
|
#include "stdafx.h"
|
|
#include "comprop.h"
|
|
#include "dirbrows.h"
|
|
#include <dlgs.h>
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
|
|
static
|
|
int
|
|
BrowseCallbackProc(
|
|
IN HWND hwnd,
|
|
IN UINT uMsg,
|
|
IN LPARAM lParam,
|
|
IN LPARAM lpData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback function for the folder browser
|
|
|
|
Arguments:
|
|
|
|
hwnd : Handle to the browse dialog box. The callback function can
|
|
send the following messages to this window:
|
|
|
|
BFFM_ENABLEOK Enables the OK button if the wParam parameter
|
|
is nonzero or disables it if wParam is zero.
|
|
BFFM_SETSELECTION Selects the specified folder. The lParam
|
|
parameter is the PIDL of the folder to select
|
|
if wParam is FALSE, or it is the path of the
|
|
folder otherwise.
|
|
BFFM_SETSTATUSTEXT Sets the status text to the null-terminated
|
|
string specified by the lParam parameter.
|
|
|
|
uMsg : Value identifying the event. This parameter can be one of the
|
|
following values:
|
|
|
|
0 Initialize dir path. lParam is the path.
|
|
|
|
BFFM_INITIALIZED The browse dialog box has finished
|
|
initializing. lpData is NULL.
|
|
BFFM_SELCHANGED The selection has changed. lpData
|
|
is a pointer to the item identifier list for
|
|
the newly selected folder.
|
|
|
|
lParam : Message-specific value. For more information, see the
|
|
description of uMsg.
|
|
|
|
lpData : Application-defined value that was specified in the lParam
|
|
member of the BROWSEINFO structure.
|
|
|
|
Return Value:
|
|
|
|
0
|
|
|
|
--*/
|
|
{
|
|
static LPCTSTR lpstrDir = NULL;
|
|
|
|
switch(uMsg)
|
|
{
|
|
case 0:
|
|
lpstrDir = (LPCTSTR)lParam;
|
|
break;
|
|
|
|
case BFFM_INITIALIZED:
|
|
//
|
|
// Dialog initialized -- select desired folder
|
|
//
|
|
if (lpstrDir != NULL)
|
|
{
|
|
::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrDir);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
CDirBrowseDlg::CDirBrowseDlg(
|
|
IN CWnd * pParent OPTIONAL,
|
|
IN LPCTSTR lpszInitialDir OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for directory browser dialog
|
|
|
|
Arguments:
|
|
|
|
CWnd * pParent : Parent window or NULL
|
|
LPCTSTR lpszInitialDir : Initial directory, or NULL for current directory
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
: m_strInitialDir(lpszInitialDir)
|
|
{
|
|
VERIFY(m_strTitle.LoadString(IDS_BROWSE_DIRECTORY));
|
|
|
|
m_bi.pidlRoot = NULL;
|
|
m_bi.hwndOwner = pParent ? pParent->m_hWnd : NULL;
|
|
m_bi.pszDisplayName = m_szBuffer;
|
|
m_bi.lpszTitle = m_strTitle;
|
|
m_bi.ulFlags = BIF_RETURNFSANCESTORS | BIF_RETURNONLYFSDIRS,
|
|
m_bi.lpfn = BrowseCallbackProc;
|
|
m_bi.lParam = 0;
|
|
|
|
//
|
|
// Let the callback function know the default dir is
|
|
//
|
|
lpszInitialDir = !m_strInitialDir.IsEmpty()
|
|
? (LPCTSTR)m_strInitialDir
|
|
: NULL;
|
|
BrowseCallbackProc(m_bi.hwndOwner, 0, (LPARAM)lpszInitialDir, NULL);
|
|
}
|
|
|
|
|
|
|
|
CDirBrowseDlg::~CDirBrowseDlg()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for directory browser dialog
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
if (m_bi.pidlRoot != NULL)
|
|
{
|
|
LPITEMIDLIST pidl = (LPITEMIDLIST)m_bi.pidlRoot;
|
|
|
|
//
|
|
// Free using shell allocator
|
|
//
|
|
LPMALLOC pMalloc;
|
|
if (::SHGetMalloc(&pMalloc) == NOERROR)
|
|
{
|
|
pMalloc->Free(pidl);
|
|
pMalloc->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* virtual */
|
|
int
|
|
CDirBrowseDlg::DoModal()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the browser dialog, and fill in the selected directory path.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
IDOK if the OK button was pressed, IDCANCEL otherwise.
|
|
|
|
--*/
|
|
{
|
|
BOOL fSelectionMade = FALSE;
|
|
|
|
//
|
|
// Get the Shell's default allocator
|
|
//
|
|
LPMALLOC pMalloc;
|
|
if (::SHGetMalloc(&pMalloc) == NOERROR)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
|
|
if ((pidl = ::SHBrowseForFolder(&m_bi)) != NULL)
|
|
{
|
|
if (::SHGetPathFromIDList(pidl, m_szBuffer))
|
|
{
|
|
fSelectionMade = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// OK Pressed, but no path found
|
|
//
|
|
::AfxMessageBox(IDS_BAD_BROWSE);
|
|
}
|
|
|
|
//
|
|
// Free the PIDL allocated by SHBrowseForFolder.
|
|
//
|
|
pMalloc->Free(pidl);
|
|
}
|
|
|
|
//
|
|
// Release the shell's allocator.
|
|
//
|
|
pMalloc->Release();
|
|
}
|
|
|
|
return fSelectionMade ? IDOK : IDCANCEL;
|
|
}
|
|
|
|
|
|
|
|
LPCTSTR
|
|
CDirBrowseDlg::GetFullPath(
|
|
OUT CString & strName,
|
|
IN BOOL fConvertToUNC
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the full path selected. Optionally allow a remote path to be
|
|
converted to a UNC path.
|
|
|
|
Arguments:
|
|
|
|
CString & strName : String in which to return the directory path
|
|
BOOL fConvertToUNC : If TRUE, then if the drive selected is a network
|
|
drive, convert the path to a UNC path.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the directory path string or NULL in case of error.
|
|
|
|
Notes:
|
|
|
|
This function should be called only after the dialog has been dismissed.
|
|
|
|
--*/
|
|
{
|
|
LPCTSTR lp = NULL;
|
|
|
|
try
|
|
{
|
|
strName = m_szBuffer;
|
|
lp = strName;
|
|
|
|
if (fConvertToUNC && lp != NULL)
|
|
{
|
|
//
|
|
// If it's network drive, convert it to a UNC path
|
|
//
|
|
CString strDrive, strUNC;
|
|
if (IsNetworkPath(strName, &strDrive, &strUNC))
|
|
{
|
|
strUNC += (lp + 2);
|
|
strName = strUNC;
|
|
}
|
|
|
|
|
|
/*
|
|
ASSERT(strName[1] == _T(':'));
|
|
if (strName[1] == _T(':'))
|
|
{
|
|
TCHAR szDrive[] = _T("?:");
|
|
//
|
|
// Fill in actual drive letter
|
|
//
|
|
szDrive[0] = strName[0];
|
|
if (::GetDriveType(szDrive) == DRIVE_REMOTE)
|
|
{
|
|
//
|
|
// Yes, it's remote. Replace drive letter
|
|
// with UNC path
|
|
//
|
|
TCHAR szUNC[_MAX_PATH + 1];
|
|
DWORD dwSize = _MAX_PATH;
|
|
TRACEEOLID("Converting drive path to UNC");
|
|
if (::WNetGetConnection(szDrive,
|
|
szUNC, &dwSize) == NO_ERROR)
|
|
{
|
|
::_tcscat(szUNC, lp + 2);
|
|
strName = szUNC;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
lp = strName;
|
|
}
|
|
}
|
|
catch(CMemoryException * e)
|
|
{
|
|
TRACEEOLID("!!!exception getting path");
|
|
strName.Empty();
|
|
e->ReportError();
|
|
e->Delete();
|
|
}
|
|
|
|
return lp;
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
// * *
|
|
// * The code below is pre-WIN95 shell directory browsing. It is OBSOLETE *
|
|
// * *
|
|
// ***************************************************************************
|
|
|
|
//
|
|
// new look commdlg style (not defined on older systems)
|
|
//
|
|
#ifndef OFN_EXPLORER
|
|
#define OFN_EXPLORER 0x00080000
|
|
#endif // OFN_EXPLORER
|
|
|
|
#ifndef _COMSTATIC
|
|
//
|
|
// Externally available DLL handle
|
|
//
|
|
extern HINSTANCE hDLLInstance;
|
|
#endif // _COMSTATIC
|
|
|
|
|
|
|
|
CDirBrowseDlg::CDirBrowseDlg(
|
|
IN CWnd * pParent OPTIONAL,
|
|
IN LPCTSTR lpszInitialDir OPTIONAL,
|
|
IN BOOL bOpenFileDialog,
|
|
IN LPCTSTR lpszDefExt OPTIONAL,
|
|
IN DWORD dwFlags,
|
|
IN LPCTSTR lpszFilter OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor for directory browser dialog
|
|
|
|
Arguments:
|
|
|
|
CWnd * pParent : Parent window or NULL
|
|
LPCTSTR lpszInitialDir : Initial directory, or NULL for current directory
|
|
BOOL bOpenFileDialog : TRUE for open dialog, FALSE for save dialog
|
|
LPCTSTR lpszDefExt : Default extention string or NULL
|
|
DWORD dwFlags : OPENFILE flags
|
|
LPCTSTR lpszFilter : File filters
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
//
|
|
// Use a dummy filename here to allow CFileOpenDialog to
|
|
// dismiss itself. If this matches an existing directory
|
|
// name we're in trouble, so make that an unlikely event.
|
|
// It would be nice if there were a file name that
|
|
// cannot exist as a directory name.
|
|
//
|
|
: CFileDialog(
|
|
bOpenFileDialog,
|
|
lpszDefExt,
|
|
_T(" JU$NK#\t^"),
|
|
dwFlags,
|
|
lpszFilter,
|
|
pParent
|
|
),
|
|
m_strNewDirectoryName()
|
|
{
|
|
|
|
#if 0 // Keep Class Wizard happy
|
|
|
|
//{{AFX_DATA_INIT(CDirBrowseDlg)
|
|
m_strNewDirectoryName = _T("");
|
|
//}}AFX_DATA_INIT
|
|
|
|
#endif // 0
|
|
|
|
m_ofn.Flags |= OFN_ENABLETEMPLATE | OFN_NONETWORKBUTTON;
|
|
|
|
#ifdef _COMSTATIC
|
|
|
|
m_ofn.hInstance = ::AfxGetResourceHandle();
|
|
|
|
#else
|
|
|
|
m_ofn.hInstance = hDLLInstance;
|
|
|
|
#endif // _COMSTATIC
|
|
|
|
m_ofn.lpstrInitialDir = lpszInitialDir;
|
|
m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIRBROWSE);
|
|
|
|
//
|
|
// Explicitly re-set the explorer flag which is set by
|
|
// default
|
|
//
|
|
m_ofn.Flags &= (~OFN_EXPLORER);
|
|
}
|
|
|
|
|
|
|
|
CDirBrowseDlg::~CDirBrowseDlg()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor for directory browser dialog
|
|
|
|
Arguments:
|
|
|
|
N/A
|
|
|
|
Return Value:
|
|
|
|
N/A
|
|
|
|
--*/
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
void
|
|
CDirBrowseDlg::DoDataExchange(
|
|
IN CDataExchange * pDX
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialise/Store control data
|
|
|
|
Arguments:
|
|
|
|
CDataExchange * pDX - DDX/DDV control structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
CFileDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CDirBrowseDlg)
|
|
DDX_Control(pDX, IDC_EDIT_NEW_DIRECTORY_NAME, m_edit_NewDirectoryName);
|
|
DDX_Control(pDX, stc1, m_static_stc1);
|
|
DDX_Control(pDX, IDC_STATIC_DIR_NAME, m_static_stc2);
|
|
DDX_Text(pDX, IDC_EDIT_NEW_DIRECTORY_NAME, m_strNewDirectoryName);
|
|
DDV_MaxChars(pDX, m_strNewDirectoryName, _MAX_PATH);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Message Map
|
|
//
|
|
BEGIN_MESSAGE_MAP(CDirBrowseDlg, CFileDialog)
|
|
//{{AFX_MSG_MAP(CDirBrowseDlg)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
//
|
|
// Message Handlers
|
|
//
|
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
|
|
|
|
|
|
|
BOOL
|
|
CDirBrowseDlg::OnInitDialog()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
WM_INITDIALOG handler. Initialize the dialog.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if no focus is to be set automatically, FALSE if the focus
|
|
is already set.
|
|
|
|
--*/
|
|
{
|
|
CFileDialog::OnInitDialog();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
LPCTSTR
|
|
CDirBrowseDlg::GetFullPath(
|
|
OUT CString & strName,
|
|
IN BOOL fConvertToUNC
|
|
) const
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the full path selected.
|
|
|
|
Arguments:
|
|
|
|
CString & strName : String in which to return the directory path
|
|
BOOL fConvertToUNC : If TRUE, then if the drive selected is a network
|
|
drive, convert the path to a UNC path.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the directory path string or NULL in case of error.
|
|
|
|
Notes:
|
|
|
|
This function should be called only after the dialog has been dismissed.
|
|
|
|
--*/
|
|
{
|
|
LPCTSTR lp = NULL;
|
|
|
|
try
|
|
{
|
|
m_ofn.lpstrFile[m_ofn.nFileOffset-1] = _T('\0');
|
|
strName = m_ofn.lpstrFile;
|
|
if (!m_strNewDirectoryName.IsEmpty())
|
|
{
|
|
//
|
|
// Append the name of the newly created directory, unless
|
|
// it has a colon or backslash in it, in which case it is
|
|
// treated as a fully qualified path name
|
|
//
|
|
if (m_strNewDirectoryName.Find(_T(':')) != -1 ||
|
|
m_strNewDirectoryName.Find(_T('\\')) != -1)
|
|
{
|
|
strName = m_strNewDirectoryName;
|
|
}
|
|
else
|
|
{
|
|
strName += _T("\\");
|
|
strName += m_strNewDirectoryName;
|
|
}
|
|
}
|
|
|
|
lp = strName;
|
|
|
|
if (fConvertToUNC && lp != NULL)
|
|
{
|
|
//
|
|
// If it's network drive, convert it to a UNC path
|
|
//
|
|
CString strDrive, strUNC;
|
|
if (IsNetworkPath(strName, &strDrive, &strUNC))
|
|
{
|
|
strUNC += (lp + 2);
|
|
strName = strUNC;
|
|
}
|
|
|
|
/*
|
|
ASSERT(strName[1] == _T(':'));
|
|
if (strName[1] == _T(':'))
|
|
{
|
|
TCHAR szDrive[] = _T("?:");
|
|
//
|
|
// Fill in actual drive letter
|
|
//
|
|
szDrive[0] = strName[0];
|
|
if (::GetDriveType(szDrive) == DRIVE_REMOTE)
|
|
{
|
|
//
|
|
// Yes, it's remote. Replace drive letter
|
|
// with UNC path
|
|
//
|
|
TCHAR szUNC[_MAX_PATH + 1];
|
|
DWORD dwSize = _MAX_PATH;
|
|
TRACEEOLID("Converting drive path to UNC");
|
|
if (::WNetGetConnection(szDrive,
|
|
szUNC, &dwSize) == NO_ERROR)
|
|
{
|
|
::_tcscat(szUNC, lp + 2);
|
|
strName = szUNC;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
lp = strName;
|
|
}
|
|
}
|
|
catch(CMemoryException * e)
|
|
{
|
|
TRACEEOLID("!!!exception getting path");
|
|
strName.Empty();
|
|
e->ReportError();
|
|
e->Delete();
|
|
}
|
|
|
|
return lp;
|
|
}
|
|
|
|
|
|
|
|
/* protected */
|
|
void
|
|
CDirBrowseDlg::OnOK()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handler for IDOK. Called when the OK button has been pressed.
|
|
At this point, set the directory path string to the selected
|
|
string. If a new directory is entered, create it now. Do not
|
|
dismiss the dialog if the path is invalid.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Update control data
|
|
//
|
|
if (UpdateData())
|
|
{
|
|
//
|
|
// If a new directory name was entered, create it
|
|
// here.
|
|
//
|
|
if (!m_strNewDirectoryName.IsEmpty())
|
|
{
|
|
if (!::CreateDirectory(m_strNewDirectoryName, NULL))
|
|
{
|
|
//
|
|
// Failed to create the directory -- let the user
|
|
// know why, and don't dismiss the dialog box
|
|
//
|
|
::DisplayMessage(::GetLastError());
|
|
m_edit_NewDirectoryName.SetSel(0,-1);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dismiss the dialog.
|
|
//
|
|
CFileDialog::OnOK();
|
|
}
|
|
}
|
|
|
|
#endif // 0 (Obsolete)
|