/*++ 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 #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)