/*++ Copyright (c) 1994 Microsoft Corporation Module Name: DirBrows.H Abstract: Directory browser dialog box functions Author: Bob Watson (a-robw) Revision History: 17 Feb 94 Written --*/ // // Windows Include Files // #include #include #include #include // unicode macros // // app include files // #include "otnboot.h" #include "otnbtdlg.h" // // static data // static PDB_DATA pDbData = NULL; static TCHAR szSaveCurrentDir[MAX_PATH]; static TCHAR szReturnPath[MAX_PATH+1]; static BOOL UpdateReturnPath ( LPCTSTR szNewDir ) /*++ Routine Description: appends the "new dir" from the argument and updates the current fully qualified path in the return buffer (this is to accomodate relative directory entries (e.g. "..")). Arguments: directory to add to current path Return Value: TRUE if path updated FALSE if an error occured --*/ { LPTSTR szLocalPath; DWORD dwLength; szLocalPath = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szLocalPath != NULL) { lstrcpy (szLocalPath, szReturnPath); if (szLocalPath[lstrlen(szLocalPath)-1] != cBackslash) { lstrcat (szLocalPath, cszBackslash); } lstrcat (szLocalPath, szNewDir); GetFullPathName ( szLocalPath, MAX_PATH, szReturnPath, NULL); FREE_IF_ALLOC (szLocalPath); // remove trailing backslash if not the root dir dwLength = lstrlen(szReturnPath); if (dwLength > 3) { if (szReturnPath[dwLength-1] == cBackslash) { szReturnPath[dwLength-1] = 0; } } return TRUE; } else { return FALSE; } } static LPCTSTR GetDefaultDisplayDir ( IN LPCTSTR szPath ) /*++ Routine Description: returns a valid and existing path based on the path passed in the argument list using the following logic: if szPath is valid as is, then return it else search up the path to the root until a valid dir is found in the path and return that if the path is completely bogus, then use the current default direcotry Arguments: IN LPCTSTR szPath initial path to try Return Value: pointer to read only string containg a path from the logic described above. --*/ { static TCHAR szLocalPath[MAX_PATH]; BOOL bFound; LONG lBsCount; LPTSTR szLastBs; LPTSTR szThisChar; LPTSTR szRootBs = NULL; if (IsPathADir(szPath)) { // this one is valid so return it lstrcpy(szLocalPath, szPath); } else if ((pDbData->Flags & PDB_FLAGS_NOCHECKDIR) == PDB_FLAGS_NOCHECKDIR) { // they don't care about a valid path so just give it back lstrcpy(szLocalPath, szPath); } else { // is this a valid DRIVE? if (MediaPresent(szPath, TRUE)) { // well the drive is valid, so start backing up the path // until a valid dir is found lstrcpy (szLocalPath, szPath); // get a local copy of the path bFound = FALSE; while (!bFound) { if (IsUncPath(szPath)) { // goto "root" backslash and save pointer lBsCount = 0; szThisChar = &szLocalPath[0]; while (*szThisChar != 0) { if (*szThisChar == cBackslash) lBsCount++; if (lBsCount == 4) { szRootBs = szThisChar; break; } } if (lBsCount != 4) { // bogus path GetCurrentDirectory (MAX_PATH, szLocalPath); bFound = TRUE; } // else all should be OK so far } else { szRootBs = &szLocalPath[2]; // dos "root" backslash if (*szRootBs != cBackslash) { // then this is a bogus path so return the current GetCurrentDirectory (MAX_PATH, szLocalPath); bFound = TRUE; } } if (!bFound) { szLastBs = szThisChar = &szLocalPath[0]; while (*szThisChar != 0) { if (*szThisChar == cBackslash) szLastBs = szThisChar; szThisChar++; } // szThisChar should point to the last backslash found in // the string. If this isn't the "root" backslash, then // replace it with a NULL, otherwise just use the root path if ((szThisChar != szLocalPath) && // not the beginning char (szThisChar != szRootBs)) { // not the root dir *szLastBs = 0; // terminate at the BS and see if // this is a valid dir. if (IsPathADir(szLocalPath)) { // this works so use it bFound = TRUE; } } else { // hit the root so terminate AFTER the BS and // return what's in the buffer *++szLastBs = 0; bFound = TRUE; } } } } else { // this isnt' a valid drive so load current directory GetCurrentDirectory (MAX_PATH, szLocalPath); } } return (LPCTSTR)&szLocalPath[0]; } static BOOL ListDirsInEditPath ( IN HWND hwndDlg, IN LPCTSTR szPath ) /*++ Routine Description: Loads directory list box in dialog box using dirs found in path Arguments: IN HWND hwndDlg, handle to dialog box window IN LPCTSTR szPath path to list dirs in. Return Value: TRUE if list box updated FALSE if error --*/ { LPTSTR szLocalPath; szLocalPath = GlobalAlloc (GPTR, (lstrlen(szPath) + 1) * sizeof(TCHAR) ); if (szLocalPath != NULL) { lstrcpy (szLocalPath, szPath); if (IsPathADir (szLocalPath)) { // make a local copy of the path since this call will modify the value if (DlgDirList ( hwndDlg, szLocalPath, NCDU_DIR_LIST, NCDU_DIR_PATH, DDL_DIRECTORY | DDL_EXCLUSIVE)) { // select dir in new list SendDlgItemMessage (hwndDlg, NCDU_DIR_LIST, LB_SETCURSEL, (WPARAM)0, 0); SendDlgItemMessage (hwndDlg, NCDU_DIR_LIST, LB_SETCARETINDEX, (WPARAM)0, MAKELPARAM(TRUE,0)); } } else { SendDlgItemMessage (hwndDlg, NCDU_DIR_LIST, LB_RESETCONTENT, (WPARAM)0, (LPARAM)0); SetDlgItemText (hwndDlg, NCDU_DIR_PATH, szLocalPath); } FREE_IF_ALLOC (szLocalPath); return TRUE; } else { return FALSE; } } static LPCTSTR GetVolumeName ( IN LPCTSTR szPath ) /*++ Routine Description: looks up the volume name (or net path for redirected dirs) and return's it to the caller. The caller is assumed to check for the existence of the path to prevent any OS errors. Arguments: IN LPCTSTR szPath path containing drive to look up Return Value: volume name string if name or path found, otherwise an empty string if an error. --*/ { static TCHAR szVolumeName[MAX_PATH]; TCHAR szRootDir[4]; DWORD dwBufLen; szVolumeName[0] = 0; // initialize string if (!IsUncPath(szPath)) { szRootDir[0] = szPath[0]; // create DriveName and root path szRootDir[1] = cColon; szRootDir[2] = cBackslash; szRootDir[3] = 0; dwBufLen = MAX_PATH * sizeof(TCHAR); if (OnRemoteDrive (szRootDir)) { // look up server and share of redirected drive LookupRemotePath ( szRootDir, szVolumeName, &dwBufLen); // remove trailing backslash if (szVolumeName[lstrlen(szVolumeName)-1] == cBackslash) { szVolumeName[lstrlen(szVolumeName)-1] = 0; } } else { // look up volume name GetVolumeInformation ( szRootDir, szVolumeName, dwBufLen / sizeof(TCHAR), NULL, NULL, NULL, NULL, 0); } } else { lstrcpy (szVolumeName, szPath); } return (LPCTSTR)&szVolumeName[0]; } static DWORD LoadVolumeNames ( DWORD dwArg ) /*++ Routine Description: scans the combo box entries of the drive list and adds the corresponding volume names to the drives in the list. This routine is meant to be called by the CreateThread function. Arguments: Handle to dialog box window (passed in as a DWORD to conform to the CreateThread calling format) Return Value: ERROR_SUCCESS if successful WIN32 Error if not --*/ { HWND hwndDlg; HWND hwndDriveList; LONG lItems; LONG lThisItem; LONG lCurrentSel; DWORD dwReturn; LPTSTR szListBoxText; TCHAR szRootDir[4]; szListBoxText = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szListBoxText == NULL) { dwReturn = ERROR_OUTOFMEMORY; } else { hwndDlg = (HWND)ULongToPtr(dwArg); hwndDriveList = GetDlgItem (hwndDlg, NCDU_DRIVE_LIST); lItems = (LONG)SendMessage (hwndDriveList, CB_GETCOUNT, 0, 0); szRootDir[1] = cColon; szRootDir[2] = cBackslash; szRootDir[3] = 0; for (lThisItem = 0; lThisItem < lItems; lThisItem++) { lCurrentSel = (LONG)SendMessage (hwndDriveList, CB_GETCURSEL, 0, 0); *szListBoxText = 0; SendMessage (hwndDriveList, CB_GETLBTEXT, (WPARAM)lThisItem, (LPARAM)szListBoxText); szRootDir[0] = szListBoxText[0]; if (MediaPresent(szRootDir, TRUE)) { lstrcpy (&szListBoxText[2], csz2Spaces); lstrcat (szListBoxText, GetVolumeName(szRootDir)); SendMessage (hwndDriveList, CB_DELETESTRING, (WPARAM)lThisItem, 0); SendMessage (hwndDriveList, CB_INSERTSTRING, (WPARAM)lThisItem, (LPARAM)szListBoxText); if (lCurrentSel == lThisItem) { szRootDir[2] = 0; SendMessage (hwndDriveList, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)szRootDir); szRootDir[2] = cBackslash; } } } dwReturn = ERROR_SUCCESS; } FREE_IF_ALLOC (szListBoxText); return dwReturn; } static BOOL LoadDriveList ( IN HWND hwndDlg, IN LPCTSTR szPath ) /*++ Routine Description: initializes the drive list combo box with the drive letters of the valid drives then calls the LoadVolumeNames function as a separate thread to add the volume names. Arguments: IN HWND hwndDlg window handle of dialog box IN LPCTSTR szPath path to initialize as default Return Value: TRUE if successful FALSE if not --*/ { HWND hwndDriveList; LPTSTR szDriveName; TCHAR szRootDir[4]; LONG nCurrentDrive; DWORD idThread; szDriveName = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szDriveName != NULL) { hwndDriveList = GetDlgItem (hwndDlg, NCDU_DRIVE_LIST); SendMessage (hwndDriveList, CB_RESETCONTENT, 0, 0); szRootDir[0] = 0; szRootDir[1] = cColon; szRootDir[2] = cBackslash; szRootDir[3] = 0; for (szRootDir[0] = ca; szRootDir[0] <= cz; szRootDir[0] += 1) { // load floppy disks always if ((szRootDir[0] == ca) || (szRootDir[0] == cb)) { szRootDir[2] = 0; // make it just a drive SendMessage (hwndDriveList, CB_ADDSTRING, 0, (LPARAM)szRootDir); szRootDir[2] = cBackslash; } else { if (MediaPresent(szRootDir, TRUE)) { szRootDir[2] = 0; // make it just a drive SendMessage (hwndDriveList, CB_ADDSTRING, 0, (LPARAM)szRootDir); szRootDir[2] = cBackslash; } } } if (!IsUncPath(szPath)) { szRootDir[0] = szPath[0]; szRootDir[1] = szPath[1]; szRootDir[2] = 0; } else { GetCurrentDirectory (MAX_PATH, szDriveName); szRootDir[0] = szDriveName[0]; szRootDir[1] = szDriveName[1]; szRootDir[2] = 0; } _tcslwr (szRootDir); nCurrentDrive = (int)SendMessage (hwndDriveList, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)szRootDir); if (nCurrentDrive == CB_ERR) { szRootDir[0] = cc; nCurrentDrive = (int)SendMessage (hwndDriveList, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)szRootDir); if (nCurrentDrive == CB_ERR) { SendMessage (hwndDriveList, CB_SETCURSEL, (WPARAM)2, 0); } } } // start thread to fill in volume names CreateThread ((LPSECURITY_ATTRIBUTES)NULL, 0, (LPTHREAD_START_ROUTINE)LoadVolumeNames, (LPVOID)hwndDlg, 0, &idThread); FREE_IF_ALLOC (szDriveName); return TRUE; } static BOOL DirBrowseDlg_WM_INITDIALOG ( IN HWND hwndDlg, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: Process the WM_INITDIALOG windows message. Initializea the values in the dialog box controls to reflect the current values of browser struct passed in. Arguments: IN HWND hwndDlg handle to dialog box window IN WPARAM wParam Not Used IN LPARAM lParam address of a DIR_BROWSER_STRUCT used to pass args back & forth Return Value: FALSE --*/ { TCHAR szTitle[MAX_PATH]; if (lParam != 0) { pDbData = (PDB_DATA)lParam; if (pDbData->dwTitle != 0) { if (LoadString ( (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE), pDbData->dwTitle, szTitle, MAX_PATH) > 0) { SetWindowText (hwndDlg, szTitle); } } // save the current directory GetCurrentDirectory (MAX_PATH, szSaveCurrentDir); if (*pDbData->szPath != 0) { lstrcpy (szReturnPath, GetDefaultDisplayDir (pDbData->szPath)); } else { lstrcpy (szReturnPath, szSaveCurrentDir); } LoadDriveList (hwndDlg, szReturnPath); ListDirsInEditPath (hwndDlg, szReturnPath); SetFocus (GetDlgItem (hwndDlg, NCDU_DIR_LIST)); } else { EndDialog (hwndDlg, IDCANCEL); // error } return FALSE; } static BOOL DirBrowseDlg_IDOK ( IN HWND hwndDlg ) /*++ Routine Description: Processes the IDOK button click. Validates the entries and looks up the distribution path to try and translate it to a UNC path. Then ends the dialog and calls the next dialog box. Arguments: IN HWND hwndDlg handle to the dialog box window Return Value: FALSE --*/ { lstrcpy(pDbData->szPath, szReturnPath); EndDialog (hwndDlg, IDOK); return TRUE; } static BOOL DirBrowseDlg_IDCANCEL ( IN HWND hwndDlg ) /*++ Routine Description: ends the dialog box (and ultimately the app) Arguments: IN HWND hwndDlg Return Value: FALSE --*/ { EndDialog (hwndDlg, IDCANCEL); return TRUE; } static BOOL DirBrowseDlg_WM_COMMAND ( IN HWND hwndDlg, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: Processes the WM_COMMAND windows message and dispatches to the routine that corresponds to the control issuing the message. Arguments: IN HWND hwndDlg Handle to dialog box window IN WPARAM wParam LOWORD has ID of control initiating the message IN LPARAM lParam Not Used Return Value: TRUE if message not processed by this routine, otherwise the value of the dispatched routine . --*/ { LPTSTR szTempPath; BOOL bCheckDrive; BOOL bNewDriveOk; UINT nMessageBoxButton; switch (LOWORD(wParam)) { case IDCANCEL: return DirBrowseDlg_IDCANCEL (hwndDlg); case IDOK: return DirBrowseDlg_IDOK (hwndDlg); case NCDU_DIR_LIST: // test notification message switch (HIWORD(wParam)) { case LBN_DBLCLK: if (SendDlgItemMessage(hwndDlg, NCDU_DIR_LIST, LB_GETCOUNT, 0, 0) > 0) { szTempPath = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szTempPath != NULL) { // there's items in the list box and the // selection changed so update dlg contents DlgDirSelectEx ( hwndDlg, szTempPath, MAX_PATH, NCDU_DIR_LIST); UpdateReturnPath (szTempPath); ListDirsInEditPath ( hwndDlg, szReturnPath); FREE_IF_ALLOC (szTempPath); return TRUE; } else { // unable to allocate memory return FALSE; } } else { // no list box items return FALSE; } default: return FALSE; } case NCDU_DRIVE_LIST: switch (HIWORD(wParam)) { case CBN_SELCHANGE: case CBN_DBLCLK: szTempPath = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szTempPath != NULL) { SendDlgItemMessage (hwndDlg, NCDU_DRIVE_LIST, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szTempPath); szTempPath[2] = cBackslash; szTempPath[3] = 0; if ((pDbData->Flags & PDB_FLAGS_NOCHECKDIR) == PDB_FLAGS_NOCHECKDIR) { bCheckDrive = FALSE; bNewDriveOk = TRUE; } else { bCheckDrive = TRUE; bNewDriveOk = FALSE; } while (bCheckDrive) { if (!MediaPresent(szTempPath, TRUE)) { nMessageBoxButton = DisplayMessageBox ( hwndDlg, NCDU_DRIVE_NOT_AVAILABLE, 0, MB_ICONEXCLAMATION | MB_RETRYCANCEL | MB_TASKMODAL); if (nMessageBoxButton == IDCANCEL) { bCheckDrive = FALSE; bNewDriveOk = FALSE; } } else { bCheckDrive = FALSE; bNewDriveOk = TRUE; } } if (bNewDriveOk) { // update dir list for new drive lstrcpy (szReturnPath, szTempPath); ListDirsInEditPath ( hwndDlg, szReturnPath); } else { // reset drive list selection szTempPath[0] = szReturnPath[0]; szTempPath[1] = cColon; szTempPath[2] = 0; SendDlgItemMessage (hwndDlg, NCDU_DRIVE_LIST, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)szTempPath); } FREE_IF_ALLOC (szTempPath); return TRUE; } else { return FALSE; } default: return FALSE; } case NCDU_BROWSE_NETWORK: WNetConnectionDialog (hwndDlg, RESOURCETYPE_DISK); // update dir list LoadDriveList (hwndDlg, szReturnPath); ListDirsInEditPath (hwndDlg, szReturnPath); return TRUE; default: return FALSE; } } static BOOL DirBrowseDlg_WM_VKEYTOITEM ( IN HWND hwndDlg, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: Processes the WM_COMMAND windows message and dispatches to the routine that corresponds to the control issuing the message. Arguments: IN HWND hwndDlg Handle to dialog box window IN WPARAM wParam LOWORD has Virtual Key code of key pressed HIWORD has current caret position IN LPARAM lParam Handle of list box issuing message Return Value: -2 if no further action required by DefWindowProc -1 if default action for key should be taken by DefWindowProc >=0 if default action should be take on the n'th item in the list --*/ { HWND hwndListBox; WORD wCaretPos = 0; int nLbItemCount = 0; BOOL bSetCaretPos = FALSE; int nReturn; LPTSTR szTempPath; hwndListBox = GetDlgItem(hwndDlg, NCDU_DIR_LIST); if ((HWND)lParam == hwndListBox) { // this is from the dir list box wCaretPos = HIWORD(wParam); switch (LOWORD(wParam)) { // take action on specific key code. case VK_UP: case VK_LEFT: // go up one item if not at top if (wCaretPos > 0){ wCaretPos -= 1; // decrement one } bSetCaretPos = TRUE; nReturn = -2; break; case VK_RIGHT: case VK_DOWN: // go down one if not at bottom nLbItemCount = (int)SendDlgItemMessage ( hwndDlg, NCDU_DIR_LIST, LB_GETCOUNT, 0, 0); // adjust to be Max Index nLbItemCount -= 1; if ((int)wCaretPos < nLbItemCount) { wCaretPos += 1; } bSetCaretPos = TRUE; nReturn = -2; break; case VK_SPACE: if (SendDlgItemMessage(hwndDlg, NCDU_DIR_LIST, LB_GETCOUNT, 0, 0) > 0) { szTempPath = GlobalAlloc (GPTR, MAX_PATH_BYTES); if (szTempPath != NULL) { // select this item DlgDirSelectEx ( hwndDlg, szTempPath, MAX_PATH, NCDU_DIR_LIST); UpdateReturnPath (szTempPath); ListDirsInEditPath (hwndDlg, szReturnPath); bSetCaretPos = FALSE; FREE_IF_ALLOC (szTempPath); } } else { // no items in list box so ignore. } nReturn = -2; break; default: bSetCaretPos = FALSE; nReturn = -1; break; } if (bSetCaretPos) { SendDlgItemMessage (hwndDlg, NCDU_DIR_LIST, LB_SETCURSEL, (WPARAM)wCaretPos, 0); SendDlgItemMessage (hwndDlg, NCDU_DIR_LIST, LB_SETCARETINDEX, (WPARAM)wCaretPos, MAKELPARAM(TRUE,0)); } return (BOOL)nReturn; } else { return (BOOL)-1; } } INT_PTR CALLBACK DirBrowseDlgProc ( IN HWND hwndDlg, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: Main Dialog Box Window Procedure for the Initial configuration screen Processes the following windows messages by dispatching the appropriate routine. WM_INITDIALOG: dialog box initialization WM_COMMAND: user input All other windows messages are processed by the default dialog box procedure. Arguments: Standard WNDPROC arguments Return Value: FALSE if the message is not processed by this routine, otherwise the value returned by the dispatched routine. --*/ { switch (message) { case WM_INITDIALOG: return (DirBrowseDlg_WM_INITDIALOG (hwndDlg, wParam, lParam)); case WM_COMMAND: return (DirBrowseDlg_WM_COMMAND (hwndDlg, wParam, lParam)); case WM_VKEYTOITEM: return (DirBrowseDlg_WM_VKEYTOITEM (hwndDlg, wParam, lParam)); case WM_DESTROY: SetCurrentDirectory (szSaveCurrentDir); return TRUE; default: return FALSE; } }