I need help with one of my programs that pulls out available drives on a system and prints various information about the drives. I am using VC++ and am fairly new to C++ and need some high level inputs or example code from experienced programmers.
Here is my current source code:
#include "stdafx.h"
#include Windows.h
#include stdio.h
#include iostream
using namespace std;
int main()
{
// Initial Dummy drive
WCHAR myDrives[] = L" A";
// Get the logical drive bitmask (1st drive at bit position 0, 2nd drive at bit position 1... so on)
DWORD myDrivesBitMask = GetLogicalDrives();
// Verifying the returned drive mask
if(myDrivesBitMask == 0)
wprintf(L"GetLogicalDrives() failed with error code: %d\n", GetLastError());
else {
wprintf(L"This machine has the following logical drives:\n");
while(myDrivesBitMask) {
// Use the bitwise AND with 1 to identify
// whether there is a drive present or not.
if(myDrivesBitMask & 1) {
// Printing out the available drives
wprintf(L"drive %s\n", myDrives);
}
// increment counter for the next available drive.
myDrives[1]++;
// shift the bitmask binary right
myDrivesBitMask >>= 1;
}
wprintf(L"\n");
}
system("pause");
}
`
-Here is the output-
This machine has the following logical drives:
drive C
drive D
drive E
drive F
drive G
drive H
drive I
I need to output additional information about each drive (perhaps an example will tell the story in a shorter amount of time):
Drive – C:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Boot Drive
File System Type : NTFS
Free Space: 30021926912
Total Drive Size: 240055742464
Drive – D:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Application Data
File System Type : NTFS
Free Space: 42462507008
Total Drive Size: 240054693888
Which methods, libs api, etc. can I use to pull out drive type, drive status, volume label, file system type, free space, and total drive size?
*Side note, I noticed a defect with my pre-processor directives, specifically within the standard I/O header files. I know that is not the recommended way using printf and cout is type safe and the proper route to go but I couldn't figure out how to format output in cout as you would do in wprintf(L"drive %s\n", myDrives);.... so how would you do this with cout??
Thanks in advance.
You want to look at functions such as GetVolumeInformation to retrieve file system information such as free space and volume name.
GetDriveType will give you some basic information about the drive type, but USB thumb sticks and flash readers can give surprising results.
I'm not sure what you mean by "ready status". If you mean whether there is a valid volume in the drive, then you can try CreateFile with a path of "\\.\C:" to try and open the volume. If it fails then there is no volume (disk) present. This will be of use for SD card readers. To do this without an error dialog appearing you will need to call SetErrorMode(SEM_NOOPENFILEERRORBOX) first.
To check whether a drive is ready you may also use GetDiskFreeSpaceEx. If this fails, the drive is not ready/usable.
Here is some example code: http://pinvoke.net/default.aspx/coredll/GetDiskFreeSpaceEx.html
Related
I wrote application which give me info about my disk. But with one exception. I keep my application on desktop C:. Application give me right info about pendrive and disk E: but NOT FOR DISK C:.
When I copy my application on pendrive and run it (from pendrive) - i get right info about disk C: and E: but NOT FOR PENDRIVE.
Problem is in function GetVolumeInformation. This function give me wrong info (only for disk which i run my application from)
GetVolumeInformation( ListItem, volumeNameBuffer, MAX_PATH, & volumeSerialNumber, & maximumComponentLength, & fileSystemFlags, fileSystemNameBuffer, MAX_PATH );
In conclusion:
I have right info about all disk (DISK TYPE, SIZE)
and wrong info about parameters from GetVolumeInformation function but ONLY for disk which I run application from.
wrong info
right info
If I set the ListItem var to hold "C:", the code succeeds. If I then set this var to hold "D:" it fails, with FormatMessage and GetLastError reporting: The filename, directory name, or volume label syntax is incorrect.
If I instead set the var to hold "D:/" or "D:\\" then it succeeds. The same is true for all logical drive letters present in my system.
Having a closer look at the docs for GetVolumeInformation, we can see that the first parameter it expects is a string that holds the root directory of the volume to be described. Therefore, if you just pass C: or D: etc, you're passing the current directory of the drive concerned which may or may not be the root. If it's not the root, *boom*!
Also, on a side note - the volume serial number is a 32 bit number, typically displayed in hex notation. The following snippet formats it the same way that the dir command does.
printf("Vol ser#: '%X-%X'\n", (volumeSerialNumber>>16) , (volumeSerialNumber&0xFFFF) );
result
Vol ser#: 'AA25-7CEF'
As compared to either:
printf("Vol ser#: '%X'\n", volumeSerialNumber ); (result: Vol ser#: 'AA257CEF')
or
printf("Vol ser#: '%u'\n", volumeSerialNumber ); (result: Vol ser#: '2854583535')
I have the details of the mount path (specifically mount prefix) as obtained using getmntent
in the structure as defined below:
struct mntent {
char *mnt_fsname; /* name of mounted file system */
char *mnt_dir; /* file system path prefix */
char *mnt_type; /* mount type (see mntent.h) */
char *mnt_opts; /* mount options (see mntent.h) */
int mnt_freq; /* dump frequency in days */
int mnt_passno; /* pass number on parallel fsck */
};
Using mnt_dir I want to check if the mount path is still mounted after a while as it is possible that before some processing is done on it, it might have been unmounted.
What is the most efficient way to check if the path is still mounted?
Also Is there a way to get callback in case the path gets unmounted?
I'd say that the most efficient way is to cache st_dev and st_ino returned by stat() (although probably caching just st_dev should be enough).
If the volume gets unmounted, the mount point reverts to the empty subdirectory in the parent filesystem where the volume was originally mounted, and stat() will return a different device+inode, for the same file path.
As far as being notified, poke around the inotify(7) interface, paying attention to the IN_UNMOUNT event.
Why The Following Code always reports C:\ although It reports different Device Name
handle = FindFirstVolumeW(volName, sizeof(volName));
do{
wchar_t wVolName[MAX_PATH];
QString::fromWCharArray(volName).toWCharArray(wVolName);//make a copy of volName on wVolName
wVolName[wcslen(volName)-1] = L'\0';
wchar_t wDeviceName[MAX_PATH];
int charCount = 0;
charCount = QueryDosDeviceW(&wVolName[4], wDeviceName, ARRAYSIZE(wDeviceName));
qDebug() << QString::fromWCharArray(wVolName) << "Device: " << QString::fromWCharArray(wDeviceName);//print wVolName and wDeviceName
wchar_t driveName[MAX_PATH];
GetVolumePathName(wDeviceName, driveName, MAX_PATH);
CloseHandle(handle);
qDebug() << QString::fromWCharArray(driveName);
}while(FindNextVolume(handle, volName, sizeof(volName)));
FindVolumeClose(handle);
Output:
"\\?\Volume{5c77cc58-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\HarddiskVolume2"
"C:\"
"\\?\Volume{5c77cc59-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\HarddiskVolume3"
"C:\"
"\\?\Volume{5c77cc57-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\CdRom0"
"C:\"
"\\?\Volume{5c77cc56-d5ab-11e0-a0ec-806d6172696f}" Device: "\Device\Floppy0"
"C:\"
"\\?\Volume{8d974f2c-e9a1-11e0-b7da-0013d407432f}" Device: "\Device\Harddisk1\DP(1)0- 0+8"
"C:\"
Why doesn't it report D, E, etc ..
EDIT
and How can I derive the Drive Letter assigned to the Volume
The documentation for the function says it all:
You must specify a valid Win32 namespace path. If you specify an NT namespace path, for example, "\DosDevices\H:" or "\Device\HardDiskVolume6", the function returns the drive letter of the current volume, not the drive letter of that NT namespace path.
By the way, a volume can be mounted to multiple drive letters (a drive name like C: is nothing more than a symlink in the NT namespace), so it doesn't really make sense to translate in this manner.
From the GetVolumePathName documentation:
If you specify a relative directory or file name without a volume
qualifier, GetVolumePathName returns the drive letter of the current
volume.
Perhaps because you are calling CloseHandle while in the loop: don't do that.
It looks like you modeled your code after http://msdn.microsoft.com/en-us/library/cc542456%28v=vs.85%29.aspx: you'll notice the only time they call CloseHandle is AFTER the entire loop is done.
QueryDosDevice(L"E:", DeviceName, MAX_PATH);
(E: is a SD card)
DeviceName is "\Device\HarddiskVolume3"
How do I "convert" it to something like "\\.\PHYSICALDRIVE1"
Volumes are made up of one or more partitions, which reside on disks. So, E: doesn't necessarily map to a single disk in the system (think software RAID).
The way you map volumes to the PhysicalDrive names in Win32 is to first open the volume and then send IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS. This will give you a structure that has one DISK_EXTENT entry for every partition that the volume spans:
typedef struct _VOLUME_DISK_EXTENTS {
DWORD NumberOfDiskExtents;
DISK_EXTENT Extents[ANYSIZE_ARRAY];
} VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;
The extents have a disk number in them:
typedef struct _DISK_EXTENT {
DWORD DiskNumber;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER ExtentLength;
} DISK_EXTENT, *PDISK_EXTENT;
The DiskNumber is what goes into the PhsyicalDriveX link, so you can just sprintf that number with "\\.\PhysicalDrive%d"
-scott
Since you're using WMI anyway, start with Win32_LogicalDiskToPartition. On the Win32_LogicalDisk side, the Caption will be the drive letter. Then use Win32_DiskDriveToDiskPartition to see what physical drive holds that partition.
I am using Win32 API.
Really i do not understand how to get the drive letter for DevicePath of a USB stick .
can you pls explain it to me
( what i have is SP_DEVICE_INTERFACE_DETAIL_DATA DevicePath
using this Device path i get VID AND PID of the usb device
my device path looks like below
"\?\usb#vid_1a8d&pid_1000#358094020874450#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"
Is there any way to to map DRIVE LETTER to my DEVICE PATH
so please help me to map drive letter to DevicePath )
Thanks for any help.
The link I provided in your other question gives you all the information you need to do this. In semi-pseudocode:
DiskDevice = CreateFile(DiskDevicePath);
DiskDeviceNumber = DeviceIoControl(DiskDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER);
for each VolumeDevicePath in GetLogicalDriveStrings
VolumeDevice = CreateFile(VolumeDevicePath);
VolumeDeviceNumber = DeviceIoControl(VolumeDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER);
if(VolumeDeviceNumber == DiskDeviceNumber)
// volume (i.e. "G:") corresponding to VolumeDevicePath resides on disk (i.e. "XYZ USB Storage Device") corresponding to DiskDevicePath
I'm not 100% sure (it's been a while), but I think that the Disk device (GUID_DEVINTERFACE_DISK) is a child of the USB device (GUID_DEVINTERFACE_USB_DEVICE). In any event, I think DiskDevicePath needs to be the path of the Disk device (not the USB device).
Take a look at this, maybe it'll help (I don't think there's an easy way to do it ...)
http://msdn.microsoft.com/en-us/library/cc542456(VS.85).aspx