windows-nt/Source/XPSP1/NT/termsrv/clcreator/dirbrows.c
2020-09-26 16:20:57 +08:00

935 lines
25 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <tchar.h> // 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;
}
}