Enumerating All Available Drive Letters in Windows

Enumerating all available drive letters in Windows

::GetLogicalDrives() returns a list of available (read: used) drives as bits in a mask. This should include mapped network drives. Thus, you can simply walk the bits to find bits that are zero, meaning no drive is present. If in doubt, you can always call ::GetDriveType() with the drive letter + ":\" (":\\" in C code, or _T(":\\") in Unicode-aware terminology, of course), and that should return DRIVE_UNKNOWN or DRIVE_NO_ROOT_DIR if the drive is available.

Get a list of the available drives and their sizes

GetLogicalDrives() is the system-provided API for that. A simple for() loop will translate its result into drive letters, like this:

DWORD d = GetLogicalDrives();
int i;
TCHAR Drive[] = _T("A:\\");
for(i=0;i<26;i++)
{
if(d & (1<<i))
{
Drive[0] = _T('A')+i;
GetDiskFreeSpaceEx(Drive, .....);
}
}

And if you're not satisfied with the level of service that Stack Overflow provides, feel free to ask for your money back.

Is there a way to list all the available Windows' drives?

import win32api

drives = win32api.GetLogicalDriveStrings()
drives = drives.split('\000')[:-1]
print drives

Adapted from:
http://www.faqts.com/knowledge_base/view.phtml/aid/4670

How can I find the drive letters for all disks on a system?

You can just get a list of available drives, and loop through them calling your function.

In recent versions of Delphi you can use IOUtils.TDirectory.GetLogicalDrives to retrieve a list of all drive letters easily.

uses
System.Types, System.IOUtils;

var
Drives: TStringDynArray;
Drive: string
begin
Drives := TDirectory.GetLogicalDrives;
for s in Drives do
FileSearch(s);
end;

For older versions of Delphi that don't contain IOUtils, you can use the WinAPI function GetLogicalDriveStrings. It's considerably more complicated to use, but here's some code that wraps it for you. (You'll need Windows, SysUtils, and Types in your uses clause.)

function GetLogicalDrives: TStringDynArray;
var
Buff: String;
BuffLen: Integer;
ptr: PChar;
Ret: Integer;
nDrives: Integer;
begin
BuffLen := 20; // Allow for A:\#0B:\#0C:\#0D:\#0#0 initially
SetLength(Buff, BuffLen);
Ret := GetLogicalDriveStrings(BuffLen, PChar(Buff));

if Ret > BuffLen then
begin
// Not enough memory allocated. Result has buffer size needed.
// Allocate more space and ask again for list.
BuffLen := Ret;
SetLength(Buff, BuffLen);
Ret := GetLogicalDriveStrings(BuffLen, PChar(Buff));
end;

// If we've failed at this point, there's nothing we can do. Calling code
// should call GetLastError() to find out why it failed.
if Ret = 0 then
Exit;

SetLength(Result, 26); // There can't be more than 26 drives (A..Z). We'll adjust later.
nDrives := -1;
ptr := PChar(Buff);
while StrLen(ptr) > 0 do
begin
Inc(nDrives);
Result[nDrives] := String(ptr);
ptr := StrEnd(ptr);
Inc(ptr);
end;
SetLength(Result, nDrives + 1);
end;

How to get the list of all drives in C

This is not "standard C" (ie: ANSI, C89, C99, etc), but it makes minimal use of operating-system specific calls (ie: just "windows.h", not MS .NET or MFC technologies). This is the minimalist approach to what you are attempting to do. Once you have a list of all drive letters, you need to query each drive recursively for its directory listings.

This is a mix of C and C++, but you'll likely be using a free version of Visual Studio to build this anyways.

Code Listing - Get drive letters


#include <windows.h>
#include <stdio.h>

int main()
{
char buf[255];
// get the drive letters as a set of strings
int sz = GetLogicalDriveStrings(sizeof(buf), buf);
if( sz > 0)
{
// buf now contains a list of all the drive letters. Each drive letter is
// terminated with '\0' and the last one is terminated by two consecutive '\0' bytes.
char* p1 = buf;
char* p2;
while( *p1 != '\0' && (p2 = strchr(p1,'\0')) != NULL )
{
printf("%s\n", p1);
p1 = p2+1;
}
}
else
{
// Oops! something went wrong so display the error message
DWORD dwError = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, dwError, 0, buf, sizeof(buf), 0);
printf("%s\n", buf);

}
}

Code Listing - Directory listing


#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#pragma comment(lib, "User32.lib")

void DisplayErrorBox(LPTSTR lpszFunction);

int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;

// If the directory is not specified as a command-line argument,
// print usage.

if(argc != 2)
{
_tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
return (-1);
}

// Check that the input path plus 3 is not longer than MAX_PATH.
// Three characters are for the "\*" plus NULL appended below.

StringCchLength(argv[1], MAX_PATH, &length_of_arg);

if (length_of_arg > (MAX_PATH - 3))
{
_tprintf(TEXT("\nDirectory path is too long.\n"));
return (-1);
}

_tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);

// Prepare string for use with FindFile functions. First, copy the
// string to a buffer, then append '\*' to the directory name.

StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, TEXT("\\*"));

// Find the first file in the directory.

hFind = FindFirstFile(szDir, &ffd);

if (INVALID_HANDLE_VALUE == hFind)
{
DisplayErrorBox(TEXT("FindFirstFile"));
return dwError;
}

// List all the files in the directory with some info about them.

do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);

dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
DisplayErrorBox(TEXT("FindFirstFile"));
}

FindClose(hFind);
return dwError;
}

void DisplayErrorBox(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code

LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );

// Display the error message and clean up

lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}

References


  1. List Windows Logical Drive Letters, Accessed 2014-08-01, <http://www.daniweb.com/software-development/c/code/237803/list-windows-logical-drive-letters>
  2. Listing the Files in a Directory, Accessed 2014-08-01, <http://msdn.microsoft.com/en-us/library/windows/desktop/aa365200%28v=vs.85%29.aspx>

How to Sort Out Drive Letters from Powershell Output

there are two ways to get the drive info you my seem to want from that cmdlet. one gets just the letter [the .Name, ex = C], and the other gets the root of the drive [the .Root, ex = C:\].

drive letter only ...

(Get-PSDrive -PSProvider FileSystem).Name
# result is an array of just the drive letters
# C, D, E, etc.

the root of the drives ...

(Get-PSDrive -PSProvider FileSystem).Root
# result is an array of drive roots
# C:\, D:\, E:\, etc.

How to enumerate disk volume names?

The answer to your question is hidden inside Naming a Volume. When using a volume GUID path, the rules are slightly different:

All volume and mounted folder functions that take a volume GUID path as an input parameter require the trailing backslash. [...] but this is not the case with the CreateFile function. You can open a volume by calling CreateFile and omit the trailing backslash from the volume name you specify. CreateFile processes a volume GUID path with an appended backslash as the root directory of the volume.

The solution is easy: Strip the trailing backslash from a volume GUID path to open the volume using CreateFile.

In other words, while volume management functions such as:

  • GetVolumeInformation
  • GetVolumePathNamesForVolumeName

do take the full volume name returned by FindFirstVolume/FindNextVolume, CreateFile requires the returned trailing backslash removed:

  • \\?\Volume{0b777018-3313-11e2-8ccd-806e6f6e6963}
  • \\?\Volume{0b777019-3313-11e2-8ccd-806e6f6e6963}
  • \\?\Volume{758a2cf2-cf3a-11e4-8dce-c86000d0b92a}
  • \\?\Volume{4f81d34b-34f4-11e2-9f6e-c86000d0b92a}

Find all drive letters in Java

http://docs.oracle.com/javase/7/docs/api/java/io/File.html#listRoots()

File[] roots = File.listRoots();
for(int i = 0; i < roots.length ; i++)
System.out.println("Root["+i+"]:" + roots[i]);

google: list drives java, first hit:-)



Related Topics



Leave a reply



Submit