/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
// PROGRAM: ENUMDRV.C
//
// PURPOSE: Determines all drives in the system, both local and remote,
// and their file system type
//
#define STRICT
#include "cfiler.h"
LPTSTR lpDriveStrings = NULL;
extern CRITICAL_SECTION gDrvCS; // Drive list critical section var.
extern LPDINFO glpDrives;
/********************************************************************************\
* FUNCTION: CheckRM(LPTSTR)
*
* PURPOSE: Verifies that a removeable media drive contains a disk
*
* COMMENTS:
*
* This function is called each time a drive type is determined to be
* removeable (DRIVE_REMOVEABLE). An attempt is made to open a
* file in the root directory of the drive. If the attempt succeeds,
* then media is present in the drive and subsequent calls to the
* drive can be safely made. If the call fails, then there is no media
* present in the drive and no attempts should be made to access this
* drive. The Error Mode is temporarily set to 1 to allow failures
* to immediately return to the calling program. This eliminates
* unwanted dialog boxes that prompt for disks to be placed in the
* drive.
*
* INPUT: szDriveName - removeable media drive name (ex - "a:")
*
* OUTPUT: Returns TRUE if media present
* FALSE if media is not present
\*********************************************************************************/
BOOL CheckRM( LPTSTR lpszDriveName )
{
TCHAR szFileName[DIRECTORY_STRING_SIZE];
DWORD dwHold;
SetErrorMode( SEM_FAILCRITICALERRORS );
lstrcpy( szFileName, lpszDriveName );
lstrcat( szFileName, TEXT(".") );
dwHold = GetFileAttributes( szFileName );
SetErrorMode( 0 );
// If no error, media must be in drive.
if( dwHold != 0xFFFFFFFF ){
return(TRUE);
}
else{
dwHold = GetLastError();
if( dwHold != ERROR_NOT_READY )
ErrorMsg(TEXT("CheckRM: Get Removable Media Info Failure."));
return(FALSE);
}
}
/*********************************************************************************\
* FUNCTION: DWORD EnumDrives(*LPDINFO)
*
* PURPOSE: Enumerates available drives, and information on them. If the
* DINFO structure passed in is NULL, it creates a linked list
* of DINFO structures, reporting information on each available
* drive. If DINFO points to an existing structure, the list
* is updated.
*
* COMMENTS:
* The number of available drives is first determined by a call to
* GetLogicalDrives. This provides a bit mask of all logical drives.
*
* For each logical drive, a call is made to GetDriveType to determine
* the drive type. If the logical drive is not in the bit mask that
* was created with the GetLogicalDrives call, then this drive is
* bypassed.
*
* INPUT: LPDINFO dINfo: A pointer to a DRVINFO Structure.
*
* OUTPUT: Returns the number of DINFO structures in the linked
* list pointed to by dInfo. Value is negative if error.
\**********************************************************************************/
void EnumDrives(LPDINFO *lplpRoot)
{
DWORD dwDriveMask;
DWORD dwCount;
LPTSTR lpszRootPathName=TEXT("?:\\");
LPTSTR lpParse;
LPDINFO lpDInfo = (LPDINFO)0, // new node ptr
lpHold = (LPDINFO)0, // list walking ptrs
lpBack = (LPDINFO)0,
lpRoot = *lplpRoot; // root ptr
EnterCriticalSection(&gDrvCS);
dwCount=GetLogicalDriveStrings( 0, lpDriveStrings);
if( !dwCount ){
LeaveCriticalSection(&gDrvCS);
ErrorMsg(TEXT("EnumDrives: Get Drive Strings error"));
ExitThread((DWORD)-1);
}
// allocate memory, +1 for trailing NULL
lpDriveStrings = (LPTSTR)malloc((dwCount + 1) * sizeof(TCHAR));
if( lpDriveStrings == NULL){
LeaveCriticalSection(&gDrvCS);
ErrorMsg(TEXT("EnumDrives: Allocation error"));
ExitThread((DWORD)-2);
}
if(dwCount < GetLogicalDriveStrings( dwCount, lpDriveStrings) ){
LeaveCriticalSection(&gDrvCS);
ErrorMsg(TEXT("EnumDrives: Drive String size Changed!"));
ExitThread((DWORD)-3);
}
lpParse = lpDriveStrings;
dwDriveMask=GetLogicalDrives();
//
// walk list, inserting, deleting, & updating nodes as necessary
//
dwCount = 0;
lpHold = lpBack = lpRoot;
for (*lpszRootPathName=TEXT('a');*lpszRootPathName<=TEXT('z');(*lpszRootPathName)++){
if (dwDriveMask & 1){ // drive exists. Insert or update.
dwCount++;
//
// if lpHold (the list walking ptr) is NULL, or the drive that exists
// does not already have a node in the list, allocate a node.
//
if( !lpHold || lpHold->DriveLetter > *lpszRootPathName ){
//
// Allocating memory for DRVINFO node
//
lpDInfo = (LPDINFO) malloc((DWORD)sizeof(DRVINFO));
if( lpDInfo == NULL){
LeaveCriticalSection(&gDrvCS);
ErrorMsg(TEXT("EnumDrives: DRVINFO Allocation error"));
ExitThread((DWORD)-4);
}
//
// insert new node into list
//
if( lpHold == lpRoot ){
lpDInfo->next = lpRoot;
lpRoot = lpDInfo;
}
else{
lpDInfo->next = lpBack->next;
lpBack->next = lpDInfo;
}
lpBack = lpDInfo;
lpHold = lpDInfo->next;
lpDInfo->DriveLetter = *lpszRootPathName;
}
else{
if( lpBack != lpHold )
lpBack = lpBack->next;
lpHold = lpHold->next;
}
lpBack->DriveType = GetDriveType(lpszRootPathName);
lpBack->DriveName = lpParse;
lpParse += lstrlen(lpParse)+1;
}
else{ // drive does not exist.
if( lpHold ) // if node exists, delete it.
if( lpHold->DriveLetter == *lpszRootPathName ){
if( lpHold == lpRoot )
lpRoot = lpBack = lpHold->next;
else
lpBack->next = lpHold->next;
free((LPVOID)lpHold);
lpHold = lpBack->next;
}
}
dwDriveMask >>= 1;
} // end for
*lplpRoot = lpRoot;
LeaveCriticalSection(&gDrvCS);
ExitThread(dwCount);
}