Added function to detect the type of a drive, including detecting of "fast seeking" devices (e.g. SSD).
This commit is contained in:
parent
987685f080
commit
46098e69a3
@ -122,6 +122,20 @@ namespace MUtils
|
|||||||
}
|
}
|
||||||
network_type_t;
|
network_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This enumeration specifies drive types
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
DRIVE_TYPE_ERR = 0, ///< The drive type cannot be determined
|
||||||
|
DRIVE_TYPE_FDD = 1, ///< Floppy Drive, or Flash Card reader
|
||||||
|
DRIVE_TYPE_HDD = 2, ///< Hard Disk drive or Solid-State Drive
|
||||||
|
DRIVE_TYPE_NET = 3, ///< Remote/Network drive
|
||||||
|
DRIVE_TYPE_OPT = 4, ///< Optical disk srive, e.g. CD or DVD
|
||||||
|
DRIVE_TYPE_RAM = 5 ///< RAM disk
|
||||||
|
}
|
||||||
|
drive_type_t;
|
||||||
|
|
||||||
//System message
|
//System message
|
||||||
MUTILS_API void system_message_nfo(const wchar_t *const title, const wchar_t *const text);
|
MUTILS_API void system_message_nfo(const wchar_t *const title, const wchar_t *const text);
|
||||||
MUTILS_API void system_message_wrn(const wchar_t *const title, const wchar_t *const text);
|
MUTILS_API void system_message_wrn(const wchar_t *const title, const wchar_t *const text);
|
||||||
@ -189,6 +203,19 @@ namespace MUtils
|
|||||||
//Free diskspace
|
//Free diskspace
|
||||||
MUTILS_API bool free_diskspace(const QString &path, quint64 &freeSpace);
|
MUTILS_API bool free_diskspace(const QString &path, quint64 &freeSpace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Detect drive type
|
||||||
|
*
|
||||||
|
* This function detetcs the type of the drive to which the given path is pointing.
|
||||||
|
*
|
||||||
|
* \param path The path to the drive whose type is to be detected. On the Windows platform, only the drive letter is relevant.
|
||||||
|
*
|
||||||
|
* \param fast_seeking Pointer to a variable that will be set to TRUE, if the drive supports "fast" seeking (e.g. SSD or similar device), or to FALSE otherwise. This parameter is optional and may be NULL.
|
||||||
|
*
|
||||||
|
* \return The function returns the type of the drive as a `OS::drive_type_t` value. In case of error, the value `DRIVE_TYPE_ERR` will be returned.
|
||||||
|
*/
|
||||||
|
MUTILS_API drive_type_t get_drive_type(const QString &path, bool *fast_seeking = NULL);
|
||||||
|
|
||||||
//Shell open
|
//Shell open
|
||||||
MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const bool explore = false);
|
MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const bool explore = false);
|
||||||
MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const QString ¶meters, const QString &directory, const bool explore = false);
|
MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const QString ¶meters, const QString &directory, const bool explore = false);
|
||||||
|
@ -68,7 +68,9 @@ namespace MUtils
|
|||||||
#endif
|
#endif
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#if (_MSC_VER == 1911)
|
#if (_MSC_VER == 1911)
|
||||||
#if((_MSC_FULL_VER == 191125508) || (_MSC_FULL_VER == 191125506))
|
#if((_MSC_FULL_VER >= 191125542) && (_MSC_FULL_VER <= 191125547))
|
||||||
|
"MSVC 2017.4";
|
||||||
|
#elif((_MSC_FULL_VER >= 191125506) && (_MSC_FULL_VER <= 191125508))
|
||||||
"MSVC 2017.3";
|
"MSVC 2017.3";
|
||||||
#else
|
#else
|
||||||
#error Compiler version is not supported yet!
|
#error Compiler version is not supported yet!
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <Shellapi.h>
|
#include <Shellapi.h>
|
||||||
#include <PowrProf.h>
|
#include <PowrProf.h>
|
||||||
#include <Mmsystem.h>
|
#include <Mmsystem.h>
|
||||||
|
#include <WinIoCtl.h>
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
#pragma warning(disable:4091) //for MSVC2015
|
#pragma warning(disable:4091) //for MSVC2015
|
||||||
#include <ShlObj.h>
|
#include <ShlObj.h>
|
||||||
@ -48,6 +49,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
//Main thread ID
|
//Main thread ID
|
||||||
static const DWORD g_main_thread_id = GetCurrentThreadId();
|
static const DWORD g_main_thread_id = GetCurrentThreadId();
|
||||||
@ -1230,6 +1232,121 @@ bool MUtils::OS::free_diskspace(const QString &path, quint64 &freeSpace)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DRIVE TYPE
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static wchar_t get_drive_letter(const QString &path)
|
||||||
|
{
|
||||||
|
QString nativePath = QDir::toNativeSeparators(path);
|
||||||
|
while (nativePath.startsWith("\\\\?\\") || nativePath.startsWith("\\\\.\\"))
|
||||||
|
{
|
||||||
|
nativePath = QDir::toNativeSeparators(nativePath.mid(4));
|
||||||
|
}
|
||||||
|
if ((path.length() > 1) && (path[1] == QLatin1Char(':')))
|
||||||
|
{
|
||||||
|
const wchar_t letter = static_cast<wchar_t>(path[0].unicode());
|
||||||
|
if (((letter >= 'A') && (letter <= 'Z')) || ((letter >= 'a') && (letter <= 'z')))
|
||||||
|
{
|
||||||
|
return towupper(letter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return L'\0'; /*invalid path spec*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static QSet<DWORD> get_physical_drive_ids(const wchar_t drive_letter)
|
||||||
|
{
|
||||||
|
QSet<DWORD> physical_drives;
|
||||||
|
wchar_t driveName[8];
|
||||||
|
_snwprintf_s(driveName, 8, _TRUNCATE, L"\\\\.\\%c:", drive_letter);
|
||||||
|
const HANDLE hDrive = CreateFileW(driveName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
if (hDrive && (hDrive != INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
const size_t BUFF_SIZE = sizeof(VOLUME_DISK_EXTENTS) + (32U * sizeof(DISK_EXTENT));
|
||||||
|
VOLUME_DISK_EXTENTS *const diskExtents = (VOLUME_DISK_EXTENTS*)_malloca(BUFF_SIZE);
|
||||||
|
DWORD dwSize;
|
||||||
|
if (DeviceIoControl(hDrive, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, (LPVOID)diskExtents, (DWORD)BUFF_SIZE, (LPDWORD)&dwSize, NULL))
|
||||||
|
{
|
||||||
|
for (DWORD index = 0U; index < diskExtents->NumberOfDiskExtents; ++index)
|
||||||
|
{
|
||||||
|
physical_drives.insert(diskExtents->Extents[index].DiskNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_freea(diskExtents);
|
||||||
|
CloseHandle(hDrive);
|
||||||
|
}
|
||||||
|
return physical_drives;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool incurs_seek_penalty(const DWORD device_id)
|
||||||
|
{
|
||||||
|
wchar_t driveName[24];
|
||||||
|
_snwprintf_s(driveName, 24, _TRUNCATE, L"\\\\?\\PhysicalDrive%u", device_id);
|
||||||
|
const HANDLE hDevice = CreateFileW(driveName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
bool seeking_penalty = true;
|
||||||
|
if (hDevice && (hDevice != INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
STORAGE_PROPERTY_QUERY spq;
|
||||||
|
DEVICE_SEEK_PENALTY_DESCRIPTOR dspd;
|
||||||
|
memset(&spq, 0, sizeof(STORAGE_PROPERTY_QUERY));
|
||||||
|
spq.PropertyId = (STORAGE_PROPERTY_ID)StorageDeviceSeekPenaltyProperty;
|
||||||
|
spq.QueryType = PropertyStandardQuery;
|
||||||
|
DWORD dwSize;
|
||||||
|
if (DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, (LPVOID)&spq, (DWORD)sizeof(spq), (LPVOID)&dspd, (DWORD)sizeof(dspd), (LPDWORD)&dwSize, NULL))
|
||||||
|
{
|
||||||
|
seeking_penalty = dspd.IncursSeekPenalty;
|
||||||
|
}
|
||||||
|
CloseHandle(hDevice);
|
||||||
|
}
|
||||||
|
return seeking_penalty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_fast_seeking_drive(const wchar_t drive_letter)
|
||||||
|
{
|
||||||
|
bool fast_seeking = false;
|
||||||
|
const QSet<DWORD> physical_drive_ids = get_physical_drive_ids(drive_letter);
|
||||||
|
if (!physical_drive_ids.empty())
|
||||||
|
{
|
||||||
|
fast_seeking = true;
|
||||||
|
for (QSet<DWORD>::const_iterator iter = physical_drive_ids.constBegin(); iter != physical_drive_ids.constEnd(); ++iter)
|
||||||
|
{
|
||||||
|
fast_seeking = fast_seeking && (!incurs_seek_penalty(*iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fast_seeking;
|
||||||
|
}
|
||||||
|
|
||||||
|
MUtils::OS::drive_type_t MUtils::OS::get_drive_type(const QString &path, bool *fast_seeking)
|
||||||
|
{
|
||||||
|
drive_type_t driveType = DRIVE_TYPE_ERR;
|
||||||
|
const wchar_t driveLetter = get_drive_letter(path);
|
||||||
|
if (driveLetter)
|
||||||
|
{
|
||||||
|
wchar_t driveName[8];
|
||||||
|
_snwprintf_s(driveName, 8, _TRUNCATE, L"\\\\.\\%c:\\", driveLetter);
|
||||||
|
switch (GetDriveTypeW(driveName))
|
||||||
|
{
|
||||||
|
case DRIVE_REMOVABLE: driveType = DRIVE_TYPE_FDD; break;
|
||||||
|
case DRIVE_FIXED: driveType = DRIVE_TYPE_HDD; break;
|
||||||
|
case DRIVE_REMOTE: driveType = DRIVE_TYPE_NET; break;
|
||||||
|
case DRIVE_CDROM: driveType = DRIVE_TYPE_OPT; break;
|
||||||
|
case DRIVE_RAMDISK: driveType = DRIVE_TYPE_RAM; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fast_seeking)
|
||||||
|
{
|
||||||
|
if (driveType == DRIVE_TYPE_HDD)
|
||||||
|
{
|
||||||
|
*fast_seeking = is_fast_seeking_drive(driveLetter);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*fast_seeking = (driveType == DRIVE_TYPE_RAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return driveType;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// SHELL OPEN
|
// SHELL OPEN
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user