/*++ Copyright (c) 1993 Microsoft Corporation Module Name: Drives.c Abstract: This module contains support for displaying the Drives dialog. Author: David J. Gilman (davegi) 19-Mar-1993 Gregg R. Acheson (GreggA) 7-Sep-1993 Environment: User Mode --*/ // For LargeInteger routines #include #include #include #include "dialogs.h" #include "dlgprint.h" #include "drives.h" #include "msg.h" #include "strtab.h" #include "strresid.h" #include "winmsd.h" #include #include #include // // Macro to support freeing of NULL pointers. // #define Free( p ) \ { if(p) free(p); } // // Object used to pass information around about a logical drive. // typedef struct _DRIVE_INFO { DECLARE_SIGNATURE TCHAR DriveLetter[ 3 ]; UINT DriveType; TCHAR RemoteNameBuffer[ MAX_PATH ]; DWORD SectorsPerCluster; DWORD BytesPerSector; DWORD FreeClusters; DWORD Clusters; TCHAR VolumeNameBuffer[ MAX_PATH ]; DWORD VolumeSerialNumber; DWORD MaximumComponentLength; DWORD FileSystemFlags; TCHAR FileSystemNameBuffer[ MAX_PATH ]; BOOL ValidDetails; } DRIVE_INFO, *LPDRIVE_INFO; // // Internal function prototypes. // LPDRIVE_INFO CreateDriveInfoStructure( void ); BOOL FreeDriveInfoStructures( HWND hWnd ); BOOL GetDriveInfo( IN LPDRIVE_INFO di ); HICON GetIcon (int nImage, int nImageSize ); BOOL DestroyDriveInfo( IN LPDRIVE_INFO DriveInfo ); BOOL GeneralDriveDetailsDlgProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ); BOOL FilesystemDetailsDlgProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ); BOOL InitializeDrivesTab( IN HWND hWnd ); HTREEITEM AddTreeViewItem( HWND hwndTV, LPTV_INSERTSTRUCT lpis ); HTREEITEM FindOrAddTreeViewItem ( HWND hWndTV, LPTV_INSERTSTRUCT lpis ); BOOL DisplaySCSIDevices( HWND hWnd, HWND hTreeView ); BOOL FillTreeViewWithDrives( IN HWND hWnd, IN HWND hTreeView, IN int nStyle ); BOOL DisplayDrivePropertySheet( HWND hWnd, LPDRIVE_INFO di ); int GetDriveImage ( int nDriveType ); BOOL GetDriveInfo( LPDRIVE_INFO di ) /*++ Routine Description: Fills in a given DRIVE_INFO object based on the DriveLetter member. Arguments: Required: di.DriveLetter - the root directory of the drive (e.g. c:\) Return Value: LPDRIVE_INFO - Returns a pointer to a DRIVE_INFO object with information about the supplied drive completed. --*/ { UINT OldErrorMode; DWORD SizeOfRemoteNameBuffer; HCURSOR hSaveCursor; hSaveCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ) ); DbgHandleAssert( hSaveCursor ); // // Get the type of this drive. // di->DriveType = GetDriveType( di->DriveLetter ); // // If this is a network drive, get the share its connected to. // if( di->DriveType == DRIVE_REMOTE ) { DWORD WNetError; // // WinNet APIs want the drive name w/o a trailing slash so use the // remove it temporarily // di->DriveLetter[ 2 ] = TEXT( '\0' ); SizeOfRemoteNameBuffer = sizeof( di->RemoteNameBuffer ); WNetError = WNetGetConnection( di->DriveLetter, di->RemoteNameBuffer, &SizeOfRemoteNameBuffer ); di->DriveLetter[ 2 ] = TEXT( '\\' ); DbgAssert( ( WNetError == NO_ERROR ) || ( WNetError == ERROR_VC_DISCONNECTED )); } // // Disable pop-ups (especially if there is no media in the // removable drives.) // OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS ); // // Get the space statistics for this drive. // di->ValidDetails = GetDiskFreeSpace( di->DriveLetter, &di->SectorsPerCluster, &di->BytesPerSector, &di->FreeClusters, &di->Clusters ); if( di->ValidDetails == FALSE ) { // // Reenable pop-ups. // SetErrorMode( OldErrorMode ); SetCursor ( hSaveCursor ); return FALSE; } // // Get information about the volume for this drive. // di->ValidDetails = GetVolumeInformation( di->DriveLetter, di->VolumeNameBuffer, sizeof( di->VolumeNameBuffer ), &di->VolumeSerialNumber, &di->MaximumComponentLength, &di->FileSystemFlags, di->FileSystemNameBuffer, sizeof( di->FileSystemNameBuffer ) ); SetErrorMode (OldErrorMode); SetCursor ( hSaveCursor ); return di->ValidDetails; } LPDRIVE_INFO CreateDriveInfoStructure( void ) /*++ Routine Description: Create a DRIVE_INFO object for the supplied drive. Arguments: None Return Value: LPDRIVE_INFO - Allocates and returns a pointer to a DRIVE_INFO object --*/ { LPDRIVE_INFO DriveInfo; // // Allocate a DRIVE_INFO object. // DriveInfo = AllocateObject( DRIVE_INFO, 1 ); DbgPointerAssert( DriveInfo ); if( DriveInfo == NULL ) { return NULL; } // // Initialize buffers with empty strings. // ZeroMemory( DriveInfo, sizeof(DRIVE_INFO) ); // // Set the signature // SetSignature( DriveInfo ); // // Mark Structure as invalid since it is not filled out yet. // DriveInfo->ValidDetails = FALSE; return DriveInfo; } BOOL FreeDriveInfoStructures( HWND hWnd ) /*++ Routine Description: Walks the tree in the tree view window, freeing DRIVE_INFO objects. Arguments: hWnd - tab window handle Return Value: BOOL true if successful --*/ { HWND hWndTree = GetDlgItem(hWnd, IDC_TV_DRIVE_LIST); TV_ITEM tvi; TV_ITEM tviChild; LPDRIVE_INFO lpdi; tvi.mask = tviChild.mask = TVIF_HANDLE | TVIF_PARAM; tvi.hItem = TreeView_GetRoot( hWndTree ); tvi.hItem = TreeView_GetChild( hWndTree, tvi.hItem); // // Walk the TreeView, freeing memory associated with the tvis.item.lParam // while( tvi.hItem ){ if ( TreeView_GetItem(hWndTree, &tvi) ){ // // If we have found a pointer to a DRIVE_INFO, free it // lpdi = (LPDRIVE_INFO) tvi.lParam; if( ( lpdi != NULL ) && ( CheckSignature( lpdi ) ) ){ FreeObject( lpdi ); } } // // Check the children as well // tviChild.hItem = TreeView_GetChild( hWndTree, tvi.hItem); while( tviChild.hItem ) { if ( TreeView_GetItem(hWndTree, &tviChild) ){ // // If we have found a pointer to a DRIVE_INFO, free it // lpdi = (LPDRIVE_INFO) tviChild.lParam; if( ( lpdi != NULL ) && ( CheckSignature( lpdi ) ) ){ FreeObject( lpdi ); } } tviChild.hItem = TreeView_GetNextSibling(hWndTree, tviChild.hItem); } // // Get next tree item // tvi.hItem = TreeView_GetNextSibling(hWndTree, tvi.hItem); } return(TRUE); } BOOL DestroyDriveInfo( IN LPDRIVE_INFO DriveInfo ) /*++ Routine Description: Destroys a DRIVE_INFO object by freeing it, only after making sure it is valid Arguments: LPDRIVE_INFO - Supplies a pointer to a DRIVE_INFO object. Return Value: BOOL - Returns TRUE if the DRIVE_OBJECT is succesfully destroyed --*/ { BOOL Success; DbgPointerAssert( DriveInfo ); DbgAssert( CheckSignature( DriveInfo )); if(( DriveInfo == NULL ) || ( !CheckSignature( DriveInfo ))) { return FALSE; } // // Delete the DRIVE_INFO object itself. // Success = FreeObject( DriveInfo ); DbgAssert( Success ); return TRUE; } BOOL DrivesTabProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: DrivesTabProc processes messages when the Drives Tab is currently selected. Arguments: Standard WINPROC entry. Return Value: BOOL - Depending on input message and processing options. --*/ { BOOL Success; HWND hTreeView; switch( message ) { case WM_INITDIALOG: InitializeDrivesTab(hWnd); break; case WM_DESTROY: FreeDriveInfoStructures( hWnd ); break; case WM_NOTIFY: { switch( ((LPNMHDR)lParam)->code ){ case TVN_GETDISPINFO: { // TVN_GETDISPINFO is sent my I_IMAGECALLBACK to determine // folder state if ((((TV_DISPINFO *)lParam)->item.state) & TVIS_EXPANDED) { ((TV_DISPINFO *)lParam)->item.iImage = ((TV_DISPINFO *)lParam)->item.iSelectedImage = IMAGE_FOLDER_OPEN; } else { ((TV_DISPINFO *)lParam)->item.iImage = ((TV_DISPINFO *)lParam)->item.iSelectedImage = IMAGE_FOLDER_CLOSED; } break; } case TVN_SELCHANGED: { // // Enable or disable the Properties button, depending on whether // this item has any children--only allow properties for items // with no children // TV_ITEM tvi; tvi = ((LPNM_TREEVIEW)lParam)->itemNew; tvi.mask = TVIF_CHILDREN; TreeView_GetItem (GetDlgItem(hWnd, IDC_TV_DRIVE_LIST), &tvi); Success = EnableControl( GetParent(hWnd), IDC_PUSH_PROPERTIES, (tvi.cChildren == 0) ? TRUE : FALSE ); break; } case NM_DBLCLK: { // pretend we have clicked the Property button PostMessage( GetParent(hWnd), WM_COMMAND, MAKEWPARAM( IDC_PUSH_PROPERTIES, BN_CLICKED ), 0 ); break; } } } case WM_COMMAND: { LPDRIVE_INFO DriveInfo; switch( LOWORD( wParam )) { case IDC_PUSH_DRIVE_TYPE: case IDC_PUSH_DRIVE_LETTER: case IDC_PUSH_REFRESH: FreeDriveInfoStructures( hWnd ); FillTreeViewWithDrives( hWnd, GetDlgItem(hWnd, IDC_TV_DRIVE_LIST), LOWORD( wParam ) ); EnableControl( GetParent(hWnd), IDC_PUSH_PROPERTIES, FALSE); break; case IDC_PUSH_SCSI_CHAIN: DisplaySCSIDevices( hWnd, GetDlgItem(hWnd, IDC_TV_DRIVE_LIST) ); break; case IDC_PUSH_PHYSICAL_DISKS: //WORKITEM break; case IDC_PUSH_PROPERTIES: if (HIWORD( wParam) == BN_CLICKED) { TV_ITEM tvi; TCHAR szBuffer[512]; tvi.mask = TVIF_TEXT | TVIF_CHILDREN | TVIF_PARAM; tvi.hItem = TreeView_GetSelection( GetDlgItem(hWnd, IDC_TV_DRIVE_LIST) ); tvi.pszText = szBuffer; tvi.cchTextMax = sizeof(szBuffer); TreeView_GetItem (GetDlgItem(hWnd, IDC_TV_DRIVE_LIST), &tvi); if ( !tvi.cChildren ) { if ( GetDriveInfo( (LPDRIVE_INFO) tvi.lParam ) ) { DisplayDrivePropertySheet( hWnd, (LPDRIVE_INFO) tvi.lParam); } else { TCHAR Buffer[256]; wsprintf( Buffer, (LPCTSTR) GetString( IDS_APPLICATION_FULLNAME )); MessageBox ( hWnd, (LPCTSTR) GetString( IDS_DRIVE_PROPERTY_NOT_AVAILABLE ), Buffer, MB_ICONSTOP | MB_OK ); } } break; } } break; } } return(FALSE); } BOOL GeneralDriveDetailsDlgProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: GeneralDriveDetailsDlgProc supports the display of the General information tab of the Drive Details Property Dialog. Arguments: Standard DLGPROC entry. Return Value: BOOL - Depending on input message and processing options. --*/ { BOOL Success; LARGE_INTEGER LargeInt; HANDLE hIcon; switch( message ) { case WM_INITDIALOG: { int i; TCHAR szBuffer[ MAX_PATH ]; LPDRIVE_INFO DriveInfo; // // Retrieve and validate the DRIVE_INFO object. // DriveInfo = (LPDRIVE_INFO) ( ( LPPROPSHEETPAGE ) lParam)->lParam ; DbgPointerAssert( DriveInfo ); DbgAssert( CheckSignature( DriveInfo )); DbgAssert( DriveInfo->ValidDetails ); if( ( DriveInfo == NULL ) || ( ! CheckSignature( DriveInfo )) || ( ! DriveInfo->ValidDetails )) { EndDialog( hWnd, 0 ); return FALSE; } // // If the drive is remote, display its connection name in the title. // if( DriveInfo->DriveType == DRIVE_REMOTE ) { SetDlgItemText( hWnd, IDC_DRIVE_NAME, DriveInfo->RemoteNameBuffer ); } // // Set the appropriate Icon // hIcon = GetIcon (GetDriveImage(DriveInfo->DriveType), 32); if ( hIcon ) { hIcon = (HICON)SendDlgItemMessage(hWnd, IDC_DRIVE_ICON, STM_SETICON, (WPARAM)hIcon, 0L); if (hIcon) DestroyIcon(hIcon); } // // Fill in drive label // SetDlgItemText( hWnd, IDC_DRIVE_LABEL, DriveInfo->VolumeNameBuffer ); // // Fill in serial number // wsprintf( szBuffer, L"%X - %X", HIWORD( DriveInfo->VolumeSerialNumber ), LOWORD( DriveInfo->VolumeSerialNumber )); SetDlgItemText( hWnd, IDC_DRIVE_SERIAL_NUMBER, szBuffer ); // // Display the space statistics. // SetDlgItemText( hWnd, IDC_SECTORS_PER_CLUSTER, FormatBigInteger( DriveInfo->SectorsPerCluster, FALSE ) ); SetDlgItemText( hWnd, IDC_BYTES_PER_SECTOR, FormatBigInteger( DriveInfo->BytesPerSector, FALSE ) ); SetDlgItemText( hWnd, IDC_FREE_CLUSTERS, FormatBigInteger( DriveInfo->FreeClusters, FALSE ) ); SetDlgItemText( hWnd, IDC_USED_CLUSTERS, FormatBigInteger( DriveInfo->Clusters - DriveInfo->FreeClusters, FALSE ) ); SetDlgItemText( hWnd, IDC_TOTAL_CLUSTERS, FormatBigInteger( DriveInfo->Clusters, FALSE ) ); // // Use LargeInteger routines for large drives ( > 4G ) // LargeInt.QuadPart = UInt32x32To64( DriveInfo->FreeClusters, (DriveInfo->SectorsPerCluster * DriveInfo->BytesPerSector) ); SetDlgItemText( hWnd, IDC_FREE_BYTES, FormatLargeInteger( &LargeInt, FALSE ) ); LargeInt.QuadPart = UInt32x32To64( (DriveInfo->Clusters - DriveInfo->FreeClusters), (DriveInfo->SectorsPerCluster * DriveInfo->BytesPerSector) ); SetDlgItemText( hWnd, IDC_USED_BYTES, FormatLargeInteger( &LargeInt, FALSE ) ); LargeInt.QuadPart = UInt32x32To64( DriveInfo->Clusters, (DriveInfo->SectorsPerCluster * DriveInfo->BytesPerSector) ); SetDlgItemText( hWnd, IDC_TOTAL_BYTES, FormatLargeInteger( &LargeInt, FALSE ) ); return TRUE; } case WM_COMMAND: { switch( LOWORD( wParam )) { case IDOK: case IDCANCEL: EndDialog( hWnd, 1 ); return TRUE; } break; } } return( FALSE ); } BOOL FilesystemDetailsDlgProc( IN HWND hWnd, IN UINT message, IN WPARAM wParam, IN LPARAM lParam ) /*++ Routine Description: DriveDetailsDlgProc supports the display of the drives detail dialog which displays information about a logical drive, including, label, serial number, file system information and a host of space statistics. Arguments: Standard DLGPROC entry. Return Value: BOOL - Depending on input message and processing options. --*/ { BOOL Success; HICON hIcon; switch( message ) { case WM_INITDIALOG: { int i; TCHAR szBuffer[ MAX_PATH ]; LPDRIVE_INFO DriveInfo; VALUE_ID_MAP FSFlags[ ] = { FS_CASE_IS_PRESERVED, IDC_TEXT_CASE_IS_PRESERVED, FS_CASE_SENSITIVE, IDC_TEXT_CASE_SENSITIVE, FS_UNICODE_STORED_ON_DISK, IDC_TEXT_UNICODE_STORED_ON_DISK, FS_FILE_COMPRESSION, IDC_TEXT_FILE_COMPRESSION, FS_PERSISTENT_ACLS, IDC_TEXT_PERSISTENT_ACLS }; // // Retrieve and validate the DRIVE_INFO object. // DriveInfo = (LPDRIVE_INFO) ( ( LPPROPSHEETPAGE ) lParam)->lParam ; DbgPointerAssert( DriveInfo ); DbgAssert( CheckSignature( DriveInfo )); DbgAssert( DriveInfo->ValidDetails ); if( ( DriveInfo == NULL ) || ( ! CheckSignature( DriveInfo )) || ( ! DriveInfo->ValidDetails )) { EndDialog( hWnd, 0 ); return FALSE; } // // If the drive is remote, display its connection name in the title. // if( DriveInfo->DriveType == DRIVE_REMOTE ) { SetDlgItemText( hWnd, IDC_DRIVE_NAME, DriveInfo->RemoteNameBuffer ); } // // Set the appropriate Icon // hIcon = GetIcon (GetDriveImage(DriveInfo->DriveType), 32); if (hIcon) { hIcon = (HICON)SendDlgItemMessage(hWnd, IDC_DRIVE_ICON, STM_SETICON, (WPARAM)hIcon, 0L); if (hIcon) DestroyIcon(hIcon); } // // Fill in drive label // SetDlgItemText( hWnd, IDC_DRIVE_LABEL, DriveInfo->VolumeNameBuffer ); // // Fill in serial number // wsprintf( szBuffer, L"%X - %X", HIWORD( DriveInfo->VolumeSerialNumber ), LOWORD( DriveInfo->VolumeSerialNumber )); SetDlgItemText( hWnd, IDC_DRIVE_SERIAL_NUMBER, szBuffer ); // // Display the file system information. // SetDlgItemText( hWnd, IDC_FILESYSTEM_NAME, DriveInfo->FileSystemNameBuffer ); SetDlgItemText( hWnd, IDC_EDIT_FS_MAX_COMPONENT, FormatBigInteger( DriveInfo->MaximumComponentLength, FALSE ) ); for( i = 0; i < NumberOfEntries( FSFlags ); i++ ) { Success = EnableControl( hWnd, FSFlags[ i ].Id, DriveInfo->FileSystemFlags & FSFlags[ i ].Value ); DbgAssert( Success ); } return TRUE; } } return FALSE; } BOOL BuildDrivesReport( IN HWND hWnd, IN UINT iDetailLevel ) /*++ Routine Description: Formats and adds DrivesData to the report buffer. Arguments: hWnd - Main window handle iDetailLevel - summary or complete details? Return Value: BOOL - TRUE if report is build successfully, FALSE otherwise. --*/ { TCHAR LogicalDrives[ MAX_PATH ], OutputBuffer[MAX_PATH], szBuffer[MAX_PATH], szBuffer2[MAX_PATH]; LPTSTR Drive; DWORD Chars; BOOL Success; UINT OldErrorMode; DRIVE_INFO di; LARGE_INTEGER LargeInt; TCHAR szTotalBytes [ 64 ], szFreeBytes [ 64 ]; if(_fIsRemote){ return(TRUE); } AddLineToReport( 1, RFO_SKIPLINE, NULL, NULL ); AddLineToReport( 0, RFO_SINGLELINE, (LPTSTR) GetString( IDS_DRIVES_REPORT ), NULL ); AddLineToReport( 0, RFO_SEPARATOR, NULL, NULL ); // // Retrieve the logical drive strings from the system. // Chars = GetLogicalDriveStrings( sizeof( LogicalDrives ), LogicalDrives ); DbgAssert(( Chars != 0 ) && ( Chars <= sizeof( LogicalDrives ))); Drive = LogicalDrives; // // Disable pop-ups (especially if there is no media in the // removable drives.) // OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS ); while( *Drive ) { TCHAR VolumeNameBuffer[512]; TCHAR FileSystemNameBuffer[512]; TCHAR DriveLetter[3]; TCHAR szKB[64]; DriveLetter[ 0 ] = Drive [ 0 ]; DriveLetter[ 1 ] = Drive [ 1 ]; DriveLetter[ 2 ] = TEXT( '\\'); ZeroMemory( &di, sizeof(DRIVE_INFO)); // // Skip floppies // if ((Drive[0] == 'A') || (Drive[0] == 'B')) { Drive += _tcslen( Drive ) + 1; continue; } // // GetDrive info // _tcsncpy( di.DriveLetter, Drive, 4 ); GetDriveInfo( &di ); // // Skip empty drives // if (di.Clusters == 0) { Drive += _tcslen( Drive ) + 1; continue; } // // skip unknown types // if (( di.DriveType < DRIVE_REMOVABLE) || ( di.DriveType > DRIVE_CDROM )){ Drive += _tcslen( Drive ) + 1; continue; } // // Display summary information // lstrcpy(szBuffer, GetString( IDS_DRV_BASE + di.DriveType ) ); lstrcpy(szBuffer2, GetString( IDS_TOTAL_MB ) ); // // Calculate the total and free bytes (Use LargeInteger routines for large drives ( > 4G ) // LargeInt.QuadPart = UInt32x32To64( di.FreeClusters, (di.SectorsPerCluster * di.BytesPerSector) ); LargeInt.QuadPart = Int64ShraMod32(LargeInt.QuadPart, 10); lstrcpy( szFreeBytes, FormatLargeInteger( &LargeInt, FALSE )); LargeInt.QuadPart = UInt32x32To64( di.Clusters, (di.SectorsPerCluster * di.BytesPerSector) ); LargeInt.QuadPart = Int64ShraMod32(LargeInt.QuadPart, 10); lstrcpy( szTotalBytes, FormatLargeInteger( &LargeInt, FALSE )); lstrcpy( szKB, GetString( IDS_KB ) ); if (di.DriveType == DRIVE_REMOTE) { wsprintf(OutputBuffer, L"%.2s (%s - %s) %s %s %s %s %s, %s %s %s", di.DriveLetter, szBuffer, di.FileSystemNameBuffer, di.RemoteNameBuffer, di.VolumeNameBuffer, szBuffer2, szTotalBytes, szKB, GetString( IDS_FREE_MB ), szFreeBytes, szKB); AddLineToReport(0,RFO_SINGLELINE,OutputBuffer,NULL); } else { wsprintf(OutputBuffer, L"%s (%s - %s) %s %s %s %s, %s %s %s", di.DriveLetter, szBuffer, di.FileSystemNameBuffer, di.VolumeNameBuffer, szBuffer2, szTotalBytes, szKB, GetString( IDS_FREE_MB ), szFreeBytes, szKB); AddLineToReport(0,RFO_SINGLELINE,OutputBuffer,NULL); } // // If we are making a detailed report, display additional info // if (iDetailLevel == IDC_COMPLETE_REPORT) { wsprintf( szBuffer, L"%X - %X", HIWORD( di.VolumeSerialNumber ), LOWORD( di.VolumeSerialNumber )); AddLineToReport( SINGLE_INDENT, RFO_RPTLINE, (LPTSTR) GetString( IDS_DRIVE_SERIAL_NUM ), szBuffer ); wsprintf(szBuffer, L"%d", di.BytesPerSector); AddLineToReport( SINGLE_INDENT, RFO_RPTLINE, (LPTSTR) GetString( IDS_BYTES_PER_CLUSTER ), szBuffer ); wsprintf(szBuffer, L"%d", di.SectorsPerCluster); AddLineToReport( SINGLE_INDENT, RFO_RPTLINE, (LPTSTR) GetString( IDS_SECTORS_PER_CLUSTER ), szBuffer ); wsprintf(szBuffer, L"%d", di.MaximumComponentLength); AddLineToReport( SINGLE_INDENT, RFO_RPTLINE, (LPTSTR) GetString( IDS_CHARS_IN_FILENAME ), szBuffer ); } // // Examine the next logical drive. // Drive += _tcslen( Drive ) + 1; } // // Restore error mode // SetErrorMode (OldErrorMode); return TRUE; } BOOL FillTreeViewWithDrives( HWND hWnd, HWND hTreeView, int nStyle ) /*++ Routine Description: FillTreeViewWithDrives - fills tree view with list of drives Arguments: hWnd - Handle of Dialog hTreeView - Handle of TreeView nStyle - either IDC_RADIO_TYPES or IDC_RADIO_LETTERS Return Value: BOOL - TRUE if tree is built successfully, FALSE otherwise. --*/ { TCHAR LogicalDrives[ MAX_PATH ]; LPTSTR Drive; DWORD Chars; HTREEITEM hParent; HTREEITEM hMyComputer; TV_INSERTSTRUCT tvis; HCURSOR hSaveCursor; UINT OldErrorMode; static UINT nDisplayStyle; // // Set the style iff we get a valid style // if ((nStyle == IDC_PUSH_DRIVE_TYPE) || (nStyle == IDC_PUSH_DRIVE_LETTER) ){ nDisplayStyle = nStyle; } // // Set the pointer to an hourglass - this could take a while // hSaveCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ) ) ; DbgHandleAssert( hSaveCursor ) ; //initialize the basic TV structures tvis.hParent = TVI_ROOT; tvis.hInsertAfter = TVI_LAST; tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; // create the ROOT entry tvis.item.pszText = (LPTSTR) GetString ( IDS_MY_COMPUTER ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_MY_COMPUTER; tvis.item.lParam = 0; //clear the treeview TreeView_DeleteAllItems( hTreeView ); //add a root entry hMyComputer = AddTreeViewItem(hTreeView, &tvis); // // Retrieve the logical drive strings from the system. // Chars = GetLogicalDriveStrings( sizeof( LogicalDrives ), LogicalDrives ); DbgAssert(( Chars != 0 ) && ( Chars <= sizeof( LogicalDrives ))); Drive = LogicalDrives; // // Disable pop-ups (especially if there is no media in the // removable drives.) // OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS ); // // For each logical drive, create a DRIVE_INFO object and display // its name and type. // while( *Drive ) { LPDRIVE_INFO DriveInfo; TCHAR VolumeNameBuffer[512]; TCHAR FileSystemNameBuffer[512]; TCHAR DriveLetter[3]; DriveLetter[ 0 ] = Drive [ 0 ]; DriveLetter[ 1 ] = Drive [ 1 ]; DriveLetter[ 2 ] = TEXT( '\0'); switch( GetDriveType( Drive ) ) { case 1: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_NO_ROOT_DIR ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_FOLDER_OPEN; break; case DRIVE_REMOVABLE: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_REMOVABLE ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_REMOVABLE; break; case DRIVE_FIXED: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_FIXED ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_HARD; break; case DRIVE_REMOTE: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_REMOTE ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_NET_CARD; break; case DRIVE_CDROM: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_CDROM ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_CDROM; break; case DRIVE_RAMDISK: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_RAMDISK ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_RAM; break; case 0: tvis.item.pszText =(LPTSTR) GetString ( IDS_DRIVE_UNKNOWN ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_FOLDER_OPEN; break; } tvis.hParent = hMyComputer; tvis.hInsertAfter = TVI_LAST; if ( nDisplayStyle == IDC_PUSH_DRIVE_TYPE ) { tvis.item.lParam = 0; hParent = FindOrAddTreeViewItem ( hTreeView, &tvis); } else { hParent = hMyComputer; } tvis.hParent = hParent; tvis.item.pszText = DriveLetter; tvis.item.lParam = (DWORD) CreateDriveInfoStructure(); ((LPDRIVE_INFO) tvis.item.lParam)->DriveLetter[0]= Drive[0]; ((LPDRIVE_INFO) tvis.item.lParam)->DriveLetter[1]= Drive[1]; ((LPDRIVE_INFO) tvis.item.lParam)->DriveLetter[2]= Drive[2]; switch( GetDriveType( Drive ) ) { case 1: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_HARD; break; case DRIVE_REMOVABLE: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_REMOVABLE; break; case DRIVE_FIXED: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_HARD; break; case DRIVE_REMOTE: { // Get the remote name DWORD WNetError; TCHAR RemoteNameBuffer[512]; DWORD SizeOfRemoteNameBuffer; NETRESOURCE NetResource; TCHAR ResourceInformationBuffer[ 1024 ]; DWORD cchResourceInformationBuffer; TCHAR SystemBuffer[ MAX_PATH ]; TCHAR DisplayName[ MAX_PATH ]; SizeOfRemoteNameBuffer = sizeof( RemoteNameBuffer ); WNetError = WNetGetConnection( DriveLetter, RemoteNameBuffer, &SizeOfRemoteNameBuffer ); wsprintf(DisplayName, L"%s %s", tvis.item.pszText, RemoteNameBuffer); tvis.item.pszText = DisplayName; // // Call code to determine which tiny icon to display // /* NetResource.dwType = RESOURCETYPE_DISK; NetResource.lpProvider = NULL; WNetGetResourceInformation( &NetResource, (void *) &ResourceInformationBuffer, &cchResourceInformationBuffer, &SystemBuffer); */ // BUGBUG: subst hits this error //if (WNetError == NO_ERROR) { tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_NET; //} //else //{ // tvis.item.iImage = // tvis.item.iSelectedImage = IMAGE_DRIVE_NET_X; // } break; } case DRIVE_CDROM: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_CDROM; break; case DRIVE_RAMDISK: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_RAM; break; case 0: tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_DRIVE_HARD; break; } AddTreeViewItem (hTreeView, &tvis); // // Examine the next logical drive. // Drive += _tcslen( Drive ) + 1; } TreeView_Expand(GetDlgItem(hWnd, IDC_TV_DRIVE_LIST), hMyComputer, TVE_EXPAND); // // Lengthy operation completed. Restore Cursor, and error mode // SetCursor ( hSaveCursor ) ; SetErrorMode ( OldErrorMode ) ; return(TRUE); } BOOL DisplaySCSIDevices( HWND hWnd, HWND hTreeView ) /*++ Routine Description: DisplaySCSIDevices - fills tree view with list of SCSI Devices Arguments: hWnd - Handle of Dialog hTreeView - Handle of TreeView Return Value: BOOL - TRUE if tree is built successfully, FALSE otherwise. --*/ { TCHAR LogicalDrives[ MAX_PATH ]; LPTSTR Drive; DWORD Chars; HTREEITEM hParent; HTREEITEM hMyComputer; TV_INSERTSTRUCT tvis; HCURSOR hSaveCursor; // // Set the pointer to an hourglass - this could take a while // hSaveCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ) ) ; DbgHandleAssert( hSaveCursor ) ; //initialize the basic TV structures tvis.hParent = TVI_ROOT; tvis.hInsertAfter = TVI_LAST; tvis.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; // create the ROOT entry tvis.item.pszText = (LPTSTR) GetString ( IDS_MY_COMPUTER ); tvis.item.iImage = tvis.item.iSelectedImage = IMAGE_MY_COMPUTER; //clear the treeview TreeView_DeleteAllItems( hTreeView ); //add a root entry hMyComputer = AddTreeViewItem(hTreeView, &tvis); TreeView_Expand(GetDlgItem(hWnd, IDC_TV_DRIVE_LIST), hMyComputer, TVE_EXPAND); // // Lengthy operation completed. Restore Cursor. // SetCursor ( hSaveCursor ) ; return(TRUE); } BOOL DisplayDrivePropertySheet( HWND hWnd, LPDRIVE_INFO di ) /*++ Routine Description: Displays the property pages for the current drive Arguments: hWnd - Handle of the owner window LPDRIVE_INFO - pointer to DRIVE_INFO structure Return Value: BOOL - TRUE if succesful --*/ { PROPSHEETPAGE psp[2]; PROPSHEETHEADER psh; TCHAR Tab1[256]; TCHAR Tab2[256]; // Get Tab names wsprintf (Tab1, (LPTSTR) GetString( IDS_GENERAL_TAB )); wsprintf (Tab2, (LPTSTR) GetString( IDS_FILESYSTEM_TAB )); //Fill out the PROPSHEETPAGE data structure for the General info sheet psp[0].dwSize = sizeof(PROPSHEETPAGE); psp[0].dwFlags = PSP_USETITLE; psp[0].hInstance = _hModule; psp[0].pszTemplate = MAKEINTRESOURCE(IDD_GENERAL_DRIVE_PAGE); psp[0].pfnDlgProc = GeneralDriveDetailsDlgProc; psp[0].pszTitle = Tab1; psp[0].lParam = (LONG) di; //Fill out the PROPSHEETPAGE data structure for the filesystem info sheet psp[1].dwSize = sizeof(PROPSHEETPAGE); psp[1].dwFlags = PSP_USETITLE; psp[1].hInstance = _hModule; psp[1].pszTemplate = MAKEINTRESOURCE(IDD_FILESYSTEM_PAGE); psp[1].pfnDlgProc = FilesystemDetailsDlgProc; psp[1].pszTitle = Tab2; psp[1].lParam = (LONG) di; //Fill out the PROPSHEETHEADER psh.dwSize = sizeof(PROPSHEETHEADER); psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_PROPTITLE; psh.hwndParent = hWnd; psh.hInstance = _hModule; psh.pszIcon = MAKEINTRESOURCE(IDI_WINMSD); psh.pszCaption = di->DriveLetter; psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE); psh.ppsp = (LPCPROPSHEETPAGE) &psp; //And finally display the dialog with the two property sheets. return PropertySheet(&psh); } int GetDriveImage ( int nDriveType ) /*++ Routine Description: Returns and ImageList index based on drive type Arguments: nDriveType - Drive type Return Value: int - Index to drive image --*/ { int nImage = 0; switch (nDriveType) { case 1: nImage = IMAGE_MY_COMPUTER; break; case DRIVE_REMOVABLE: nImage = IMAGE_DRIVE_REMOVABLE; break; case DRIVE_FIXED: nImage = IMAGE_DRIVE_HARD; break; case DRIVE_REMOTE: nImage = IMAGE_DRIVE_NET; break; case DRIVE_CDROM: nImage = IMAGE_DRIVE_CDROM; break; case DRIVE_RAMDISK: nImage = IMAGE_DRIVE_RAM; break; case 0: nImage = IMAGE_MY_COMPUTER; break; } return(nImage); } HTREEITEM AddTreeViewItem( HWND hwndTV, LPTV_INSERTSTRUCT lpis ) /*++ Routine Description: AddTreeViewItem - adds items to a tree-view control. Arguments: hwndTV - handle of the tree-view control TV_INSERTSTRUCT - structures to add Return Value: HWND - Returns the handle of the newly added item. --*/ { // // Use nImage for iImage unless this is a // folder, in which case use a callback for image, // so we can open and close folders. // if (lpis->item.iImage == IMAGE_FOLDER_CLOSED) { lpis->item.iImage = lpis->item.iSelectedImage = I_IMAGECALLBACK; } // Add the item to the tree-view control. return TreeView_InsertItem( hwndTV, lpis ); } HTREEITEM FindOrAddTreeViewItem ( HWND hWndTV, LPTV_INSERTSTRUCT lpis ) /*++ Routine Description: FindOrAddTreeViewItem: This function will add an item to a TreeView in the right spot. You must specify the parent node of where this item is to be added, and then this function will check to see if a node already exists with this name. If a node with this name already exists, then its handle is returned. If the node does not exist, then the AddTreeViewItem function from above is called to add the item. See how this function is used in the FillTreeView function down below. Arguments: none Return Value: none --*/ { TV_ITEM tvItem; // Temporary item HTREEITEM hItem; // Handle to item TCHAR szBuffer[512]; // Temporary buffer // Get the first child of the passed in parent hItem = TreeView_GetChild ( hWndTV, lpis->hParent ); // Loop through all children, looking for an already existing // child. while ( hItem ) { tvItem.mask = TVIF_TEXT; // We want the text tvItem.hItem = hItem; // Indicate the item to fetch tvItem.pszText = szBuffer; // Indicate the buffer tvItem.cchTextMax = sizeof(szBuffer); // Indicate buffer's size TreeView_GetItem ( hWndTV, &tvItem ); // Get Text if (!lstrcmpi (tvItem.pszText, lpis->item.pszText)) // Found it! Just return item return hItem; // Get the next sibling item in the TreeView, if any. hItem = TreeView_GetNextSibling ( hWndTV, hItem ); } // If we made it here, then the item needs to be added // onto the end of the list return AddTreeViewItem ( hWndTV, // Handle of TreeView lpis // pass through the original TV_INSERTSTRUCT ); } HICON GetIcon (int nImage, int nImageSize ) /*++ Routine Description: GetIcon extracts an Icon from the applications image list Arguments: nImage -- index of Image nImageSize -- 16 or 32 Return Value: HICON -- Handle to Icon --*/ { HANDLE hImageList; if (nImageSize == 16) { hImageList = _h16x16Imagelist; } else { hImageList = _h32x32Imagelist; } return( ImageList_ExtractIcon(_hModule, hImageList, nImage) ); } BOOL InitializeDrivesTab( HWND hWnd ) /*++ Routine Description: Adds the appropriate controls to the drives tab control and initializes any needed structures. Arguments: hWnd - to the main window Return Value: BOOL - TRUE if successful --*/ { HWND hWndTV; // handle of tree-view control HCURSOR hSaveCursor; DLGHDR *pHdr = (DLGHDR *) GetWindowLong( GetParent(hWnd), GWL_USERDATA); static BOOL fInitialized = FALSE; // // Set the pointer to an hourglass // hSaveCursor = SetCursor ( LoadCursor ( NULL, IDC_WAIT ) ) ; DbgHandleAssert( hSaveCursor ) ; // // set state of global buttons // EnableControl( GetParent(hWnd), IDC_PUSH_PROPERTIES, FALSE); EnableControl( GetParent(hWnd), IDC_PUSH_REFRESH, TRUE); // // Size and position the child dialog // SetWindowPos(hWnd, HWND_TOP, pHdr->rcDisplay.left, pHdr->rcDisplay.top, pHdr->rcDisplay.right - pHdr->rcDisplay.left, pHdr->rcDisplay.bottom - pHdr->rcDisplay.top, SWP_SHOWWINDOW); // // Initialize the Drive Type selection buttons // SendDlgItemMessage( hWnd, IDC_PUSH_DRIVE_TYPE, BM_SETCHECK, BST_CHECKED, 0 ); UpdateWindow ( hWnd ); // get handle to Tree view control hWndTV = GetDlgItem(hWnd, IDC_TV_DRIVE_LIST); // // Set the image list used with this TV // TreeView_SetImageList (hWndTV, _h16x16Imagelist, TVSIL_NORMAL); // // Fill the treeview with drives // FillTreeViewWithDrives( hWnd, hWndTV, IDC_PUSH_DRIVE_TYPE); SetCursor ( hSaveCursor ); fInitialized = TRUE; return( TRUE ); }