From ad87baee700a5fcd008fb40dd40353baa91b14d7 Mon Sep 17 00:00:00 2001 From: Alexander Shaduri Date: Sat, 11 Nov 2017 18:19:57 +0000 Subject: [PATCH] Windows: Show volume names beside drives letters in tooltips. --- .../src/applib/storage_detector_win32.cpp | 58 +++++++++++++------ gsmartcontrol/src/applib/storage_device.cpp | 13 +++-- gsmartcontrol/src/applib/storage_device.h | 9 +-- gsmartcontrol/src/gsc_info_window.cpp | 2 +- gsmartcontrol/src/gsc_main_window.cpp | 2 +- gsmartcontrol/src/gsc_main_window_iconview.h | 8 ++- 6 files changed, 61 insertions(+), 31 deletions(-) diff --git a/gsmartcontrol/src/applib/storage_detector_win32.cpp b/gsmartcontrol/src/applib/storage_detector_win32.cpp index f22670d..296fe16 100644 --- a/gsmartcontrol/src/applib/storage_detector_win32.cpp +++ b/gsmartcontrol/src/applib/storage_detector_win32.cpp @@ -88,13 +88,20 @@ The drives may be duplicated as pdX (with X and N being unrelated). */ + +struct DriveLetterInfo { + std::set physical_drives; ///< N in pdN + std::string volume_name; ///< Volume name +}; + + namespace { /// Check which physical drives each drive letter (C, D, ...) spans across. -std::map > win32_get_drive_letter_map() +std::map win32_get_drive_letter_map() { - std::map > drive_letter_map; + std::map drive_letter_map; std::bitset<32> drives(GetLogicalDrives()); @@ -130,12 +137,27 @@ std::map > win32_get_drive_letter_map() continue; } - std::set drive_numbers; + std::set physical_drives; for (int i = 0; i < vde.NumberOfDiskExtents; ++i) { - drive_numbers.insert(vde.Extents[i].DiskNumber); + physical_drives.insert(vde.Extents[i].DiskNumber); debug_out_dump("app", "Windows drive " << drive << " corresponds to physical drive " << vde.Extents[i].DiskNumber << ".\n"); } - drive_letter_map[drive] = drive_numbers; + + std::string volume_name; + wchar_t volume_name_w[MAX_PATH+1] = {0}; + DWORD dummy = 0; + hz::scoped_array drive_name(hz::win32_utf8_to_utf16((drive + std::string(":\\")).c_str())); + if (drive_name && GetVolumeInformationW(drive_name.get(), + volume_name_w, MAX_PATH+1, + NULL, &dummy, &dummy, NULL, 0)) { + volume_name = hz::win32_utf16_to_utf8_string(volume_name_w); + } + + DriveLetterInfo dli; + dli.physical_drives = physical_drives; + dli.volume_name = volume_name; + + drive_letter_map[drive] = dli; } return drive_letter_map; @@ -148,7 +170,7 @@ std::map > win32_get_drive_letter_map() /// conflict with pd* devices, and we like pd* better than sd*. std::string get_scan_open_multiport_devices(std::vector& drives, ExecutorFactoryRefPtr ex_factory, - const std::map >& drive_letter_map, + const std::map& drive_letter_map, std::set& equivalent_pds) { debug_out_info("app", "Getting multi-port devices through smartctl --scan-open...\n"); @@ -215,13 +237,13 @@ std::string get_scan_open_multiport_devices(std::vector& dr std::string full_dev = dev + "," + port_str; StorageDeviceRefPtr drive(new StorageDevice(full_dev, type)); - std::vector drive_letters; - for (std::map >::const_iterator iter = drive_letter_map.begin(); iter != drive_letter_map.end(); ++iter) { - if (iter->second.count(drive_num) > 0) { - drive_letters.push_back(iter->first); + std::map letters_volnames; + for (std::map::const_iterator iter = drive_letter_map.begin(); iter != drive_letter_map.end(); ++iter) { + if (iter->second.physical_drives.count(drive_num) > 0) { + letters_volnames[iter->first] = iter->second.volume_name; } } - drive->set_drive_letters(drive_letters); + drive->set_drive_letters(letters_volnames); drives.push_back(drive); } @@ -632,7 +654,7 @@ std::string detect_drives_win32(std::vector& drives, Execut // Construct drive letter map debug_out_info("app", "Checking which drive corresponds to which \\\\.\\PhysicalDriveN device...\n"); - std::map > drive_letter_map = win32_get_drive_letter_map(); + std::map drive_letter_map = win32_get_drive_letter_map(); hz::intrusive_ptr smartctl_ex = ex_factory->create_executor(ExecutorFactory::ExecutorSmartctl); @@ -711,14 +733,14 @@ std::string detect_drives_win32(std::vector& drives, Execut StorageDeviceRefPtr drive(new StorageDevice(hz::string_sprintf("pd%d", drive_num))); - std::vector letters; - for (std::map >::iterator iter = drive_letter_map.begin(); iter != drive_letter_map.end(); ++iter) { - if (iter->second.count(drive_num) > 0) { - letters.push_back(iter->first); + std::map letters_volnames; + for (std::map::const_iterator iter = drive_letter_map.begin(); iter != drive_letter_map.end(); ++iter) { + if (iter->second.physical_drives.count(drive_num) > 0) { + letters_volnames[iter->first] = iter->second.volume_name; } } - drive->set_drive_letters(letters); - debug_out_dump("app", "Drive letters for: " << drive->get_device() << ": " << drive->format_drive_letters() << ".\n"); + drive->set_drive_letters(letters_volnames); + debug_out_dump("app", "Drive letters for: " << drive->get_device() << ": " << drive->format_drive_letters(true) << ".\n"); // Sometimes, a single physical drive may be accessible from both "/.//PhysicalDriveN" // and "/.//Scsi2" (e.g. pd0 and csmi2,1). Prefer the port-having ones (which is from --scan-open), diff --git a/gsmartcontrol/src/applib/storage_device.cpp b/gsmartcontrol/src/applib/storage_device.cpp index f883b74..0a2b86a 100644 --- a/gsmartcontrol/src/applib/storage_device.cpp +++ b/gsmartcontrol/src/applib/storage_device.cpp @@ -651,25 +651,28 @@ std::string StorageDevice::get_extra_arguments() const -void StorageDevice::set_drive_letters(const std::vector< char >& letters) +void StorageDevice::set_drive_letters(const std::map& letters) { drive_letters_ = letters; } -const std::vector< char >& StorageDevice::get_drive_letters() const +const std::map& StorageDevice::get_drive_letters() const { return drive_letters_; } -std::string StorageDevice::format_drive_letters() const +std::string StorageDevice::format_drive_letters(bool with_volnames) const { std::vector drive_letters_decorated; - for (std::size_t i = 0; i < drive_letters_.size(); ++i) { - drive_letters_decorated.push_back(std::string() + (char)std::toupper(drive_letters_[i]) + ":"); + for (std::map::const_iterator iter = drive_letters_.cbegin(); iter != drive_letters_.cend(); ++iter) { + drive_letters_decorated.push_back(std::string() + (char)std::toupper(iter->first) + ":"); + if (with_volnames && !iter->second.empty()) { + drive_letters_decorated.back() += std::string(" (") + iter->second + ")"; + } } return hz::string_join(drive_letters_decorated, ", "); } diff --git a/gsmartcontrol/src/applib/storage_device.h b/gsmartcontrol/src/applib/storage_device.h index 8bd142f..f3c6587 100644 --- a/gsmartcontrol/src/applib/storage_device.h +++ b/gsmartcontrol/src/applib/storage_device.h @@ -13,6 +13,7 @@ #define STORAGE_DEVICE_H #include +#include #include #include "hz/optional_value.h" @@ -166,13 +167,13 @@ class StorageDevice : public hz::intrusive_ptr_referenced { /// Set windows drive letters for this drive - void set_drive_letters(const std::vector& letters); + void set_drive_letters(const std::map& letters_volnames); /// Get windows drive letters for this drive - const std::vector& get_drive_letters() const; + const std::map& get_drive_letters() const; /// Get comma-separated win32 drive letters (if present) - std::string format_drive_letters() const; + std::string format_drive_letters(bool with_volnames) const; /// Get "virtual" status @@ -275,7 +276,7 @@ class StorageDevice : public hz::intrusive_ptr_referenced { std::string type_arg_; ///< Device type (for -d smartctl parameter), as specified when adding the device. std::string extra_args_; ///< Extra parameters for smartctl, as specified when adding the device. - std::vector drive_letters_; ///< Windows drive letters (if detected) + std::map drive_letters_; ///< Windows drive letters (if detected), with volume names bool is_virtual_; ///< If true, then this is not a real device - merely a loaded description of it. std::string virtual_file_; ///< A file (smartctl data) the virtual device was loaded from diff --git a/gsmartcontrol/src/gsc_info_window.cpp b/gsmartcontrol/src/gsc_info_window.cpp index 47b7a8f..4d79ae8 100644 --- a/gsmartcontrol/src/gsc_info_window.cpp +++ b/gsmartcontrol/src/gsc_info_window.cpp @@ -464,7 +464,7 @@ void GscInfoWindow::fill_ui_with_info(bool scan, bool clear_ui, bool clear_tests { std::string device = Glib::Markup::escape_text(drive->get_device_with_type()); std::string model = Glib::Markup::escape_text(drive->get_model_name().empty() ? "Unknown model" : drive->get_model_name()); - std::string drive_letters = Glib::Markup::escape_text(drive->format_drive_letters()); + std::string drive_letters = Glib::Markup::escape_text(drive->format_drive_letters(false)); this->set_title("Device Information - " + device + ": " + model + " - GSmartControl"); diff --git a/gsmartcontrol/src/gsc_main_window.cpp b/gsmartcontrol/src/gsc_main_window.cpp index 5df280b..d6423fa 100644 --- a/gsmartcontrol/src/gsc_main_window.cpp +++ b/gsmartcontrol/src/gsc_main_window.cpp @@ -946,7 +946,7 @@ void GscMainWindow::update_status_widgets() std::string model = Glib::Markup::escape_text(drive->get_model_name().empty() ? std::string("Unknown model") : drive->get_model_name()); std::string family = Glib::Markup::escape_text(drive->get_family_name().empty() ? "Unknown" : drive->get_family_name()); std::string family_fallback = Glib::Markup::escape_text(drive->get_family_name().empty() ? model : drive->get_family_name()); - std::string drive_letters_str = Glib::Markup::escape_text(drive->format_drive_letters()); + std::string drive_letters_str = Glib::Markup::escape_text(drive->format_drive_letters(false)); std::string info_str = device + (drive_letters_str.empty() ? "" : (" (" + drive_letters_str + ")")) diff --git a/gsmartcontrol/src/gsc_main_window_iconview.h b/gsmartcontrol/src/gsc_main_window_iconview.h index ecd472e..81e2857 100644 --- a/gsmartcontrol/src/gsc_main_window_iconview.h +++ b/gsmartcontrol/src/gsc_main_window_iconview.h @@ -282,10 +282,14 @@ class GscMainWindowIconView : public Gtk::IconView { // it needs this space to be symmetric (why?); std::string name; // = "" + drive->get_device_with_type() + " \n"; - Glib::ustring drive_letters = Glib::Markup::escape_text(drive->format_drive_letters()); + Glib::ustring drive_letters = Glib::Markup::escape_text(drive->format_drive_letters(false)); if (drive_letters.empty()) { drive_letters = "not mounted"; } + Glib::ustring drive_letters_with_volname = Glib::Markup::escape_text(drive->format_drive_letters(true)); + if (drive_letters_with_volname.empty()) { + drive_letters_with_volname = "not mounted"; + } // note: if this wraps, it becomes left-aligned in gtk <= 2.10. name += (drive->get_model_name().empty() ? Glib::ustring("Unknown model") : Glib::Markup::escape_text(drive->get_model_name())); @@ -323,7 +327,7 @@ class GscMainWindowIconView : public Gtk::IconView { } #ifdef _WIN32 - tooltip_strs.push_back("Drive letters: " + drive_letters + ""); + tooltip_strs.push_back("Drive letters: " + drive_letters_with_volname + ""); #endif if (!drive->get_serial_number().empty()) {