mirror of
https://github.com/BeneficialCode/WinArk
synced 2026-08-09 12:00:31 +00:00
301 lines
10 KiB
C++
301 lines
10 KiB
C++
#include "stdafx.h"
|
|
#include "DeviceManagerView.h"
|
|
#include "resource.h"
|
|
#include "ImageHelper.h"
|
|
#include "SortHelper.h"
|
|
|
|
using namespace WinSys;
|
|
|
|
bool CDeviceManagerView::IsSortable(HWND,int col) const {
|
|
return col == 0;
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&) {
|
|
RECT rect;
|
|
HWND hWnd = GetParent().m_hWnd;
|
|
::GetClientRect(hWnd, &rect);
|
|
rect.bottom -= 50;
|
|
|
|
m_Splitter.Create(m_hWnd, rect, nullptr, WS_CHILD|WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0);
|
|
|
|
m_List.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE |
|
|
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_OWNERDATA | LVS_SINGLESEL);
|
|
m_Tree.Create(m_Splitter, rcDefault, nullptr, WS_CHILD | WS_VISIBLE |
|
|
WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_HASLINES | TVS_SHOWSELALWAYS);
|
|
|
|
m_List.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_LABELTIP);
|
|
m_List.InsertColumn(0, L"Property", LVCFMT_LEFT, 170);
|
|
m_List.InsertColumn(1, L"Value", LVCFMT_LEFT, 350);
|
|
m_List.InsertColumn(2, L"Details", LVCFMT_LEFT, 500);
|
|
|
|
m_Splitter.SetSplitterExtendedStyle(SPLIT_FLATBAR | SPLIT_PROPORTIONAL);
|
|
m_Splitter.SetSplitterPanes(m_Tree, m_List);
|
|
m_Splitter.SetSplitterPosPct(25);
|
|
|
|
m_DevMgr = DeviceManager::Create();
|
|
if (m_DevMgr == nullptr) {
|
|
AtlMessageBox(nullptr, L"Failed to create device manager", IDS_TITLE, MB_ICONERROR);
|
|
return -1;
|
|
}
|
|
|
|
Refresh();
|
|
return 0;
|
|
}
|
|
|
|
void CDeviceManagerView::Refresh() {
|
|
m_Tree.LockWindowUpdate(TRUE);
|
|
m_Tree.DeleteAllItems();
|
|
|
|
CImageList images = DeviceManager::GetClassImageList();
|
|
m_ComputerIcon = images.AddIcon(ImageHelper::GetSystemIcon(SIID_DESKTOPPC));
|
|
auto old = m_Tree.SetImageList(images, TVSIL_NORMAL);
|
|
if (old)
|
|
old.Destroy();
|
|
|
|
m_Devices = m_DevMgr->EnumDevices();
|
|
std::unordered_map<GUID, HTREEITEM> devClasses;
|
|
devClasses.reserve(32);
|
|
m_DeviceClasses.clear();
|
|
m_DeviceClasses.reserve(32);
|
|
|
|
auto root = m_Tree.InsertItem(L"This PC", m_ComputerIcon, m_ComputerIcon, TVI_ROOT, TVI_LAST);
|
|
|
|
for (auto& di : m_Devices) {
|
|
auto& guid = di.Data.ClassGuid;
|
|
if (guid == GUID_NULL)
|
|
continue;
|
|
auto it = devClasses.find(guid);
|
|
if (it == devClasses.end()) {
|
|
// add new device class
|
|
auto name = DeviceManager::GetDeviceClassDescription(&guid);
|
|
int image = DeviceManager::GetClassImageIndex(&guid);
|
|
auto hClass = m_Tree.InsertItem(name.c_str(), image, image, root, TVI_SORT);
|
|
m_DeviceClasses.insert({ hClass,guid });
|
|
devClasses.insert({ guid,hClass });
|
|
}
|
|
auto hClass = devClasses[guid];
|
|
int image;
|
|
auto hIcon = m_DevMgr->GetDeviceIcon(di);
|
|
if (hIcon)
|
|
image = m_Tree.GetImageList().AddIcon(hIcon);
|
|
else
|
|
m_Tree.GetImageList().AddIcon(hIcon);
|
|
auto hItem = m_Tree.InsertItem(di.Description.c_str(), image, image, hClass, TVI_SORT);
|
|
m_Tree.SetItemData(hItem, (DWORD_PTR)&di);
|
|
}
|
|
|
|
root.Expand(TVE_EXPAND);
|
|
|
|
m_Tree.LockWindowUpdate(FALSE);
|
|
}
|
|
|
|
void CDeviceManagerView::UpdateList() {
|
|
auto hSelected = m_Tree.GetSelectedItem();
|
|
m_List.SetItemCount(0);
|
|
|
|
if (hSelected == nullptr)
|
|
return;
|
|
|
|
// is it a class node
|
|
auto it = m_DeviceClasses.find(hSelected);
|
|
auto data = m_Tree.GetItemData(hSelected);
|
|
if (it == m_DeviceClasses.end()) {
|
|
if (data == 0)
|
|
return;
|
|
|
|
if (m_Items.empty()) {
|
|
std::vector<ItemData> items{
|
|
{L"Class",ItemType::String,DeviceRegistryPropertyType::Class},
|
|
{L"Class GUID",ItemType::String,DeviceRegistryPropertyType::ClassGuid},
|
|
{L"Description",ItemType::String,DeviceRegistryPropertyType::Description},
|
|
{L"Friendly Name",ItemType::String,DeviceRegistryPropertyType::FriendlyName},
|
|
{L"Hardware IDs",ItemType::MultiString,DeviceRegistryPropertyType::HardwareId},
|
|
{L"Compatible IDs",ItemType::MultiString,DeviceRegistryPropertyType::CompatibleIds},
|
|
{L"Capabilities",ItemType::Dword,DeviceRegistryPropertyType::Capabilities},
|
|
{L"Manufacturer",ItemType::String,DeviceRegistryPropertyType::Mfg},
|
|
{L"Service",ItemType::String,DeviceRegistryPropertyType::Service},
|
|
{L"Driver",ItemType::String,DeviceRegistryPropertyType::Driver},
|
|
{L"Enumerator",ItemType::String,DeviceRegistryPropertyType::Enumerator},
|
|
{L"Location",ItemType::String,DeviceRegistryPropertyType::Location},
|
|
{L"Characteristics",ItemType::Dword,DeviceRegistryPropertyType::Characteristics},
|
|
{L"Device Type",ItemType::Dword,DeviceRegistryPropertyType::DeviceType},
|
|
{L"Exclusive",ItemType::Boolean,DeviceRegistryPropertyType::Exclusive},
|
|
{L"Device Name",ItemType::String,DeviceRegistryPropertyType::PdoName},
|
|
{L"Location Paths",ItemType::MultiString,DeviceRegistryPropertyType::LocationPaths},
|
|
{L"Lower Filters",ItemType::MultiString,DeviceRegistryPropertyType::LowerFilters},
|
|
{L"Upper Filters",ItemType::MultiString,DeviceRegistryPropertyType::UpperFilters},
|
|
{L"Removal Policy",ItemType::Dword,DeviceRegistryPropertyType::RemovalPolicy},
|
|
{L"Removal Policy (Default)",ItemType::Dword,DeviceRegistryPropertyType::RemovalPolicyHwDefault},
|
|
{L"Removal Policy (Override)",ItemType::Dword,DeviceRegistryPropertyType::RemovalPolicyOverride},
|
|
{L"Security Descriptor",ItemType::String,DeviceRegistryPropertyType::SecurityDescriptorString},
|
|
{L"UI Number",ItemType::Dword,DeviceRegistryPropertyType::UINumber},
|
|
{L"Install State",ItemType::Dword,DeviceRegistryPropertyType::InstallState},
|
|
{L"Legacy Bus Type",ItemType::Dword,DeviceRegistryPropertyType::LegacyBusType},
|
|
};
|
|
m_Items.swap(items);// 去除m_Items中的多余容量
|
|
}
|
|
m_SelectedClass = nullptr;
|
|
m_SelectedDevice = (DeviceInfo*)data;
|
|
for (int i = 0; i < m_Items.size(); i++) {
|
|
m_Items[i].Value = GetDeviceProperty(*m_SelectedDevice, i);
|
|
}
|
|
|
|
m_List.SetItemCount(static_cast<int>(m_Items.size()));
|
|
}
|
|
else {
|
|
if (m_ClassItems.empty()) {
|
|
std::vector<ClassItemData> items{
|
|
{ L"Class GUID", ItemType::Guid },
|
|
{ L"Lower Filters", ItemType::MultiString, DeviceClassRegistryPropertyType::LowerFilters },
|
|
{ L"Upper Filters", ItemType::MultiString, DeviceClassRegistryPropertyType::UpperFilters },
|
|
{ L"Exclusive", ItemType::Boolean, DeviceClassRegistryPropertyType::Exclusive },
|
|
{ L"Characteristics", ItemType::Dword, DeviceClassRegistryPropertyType::Characteristics },
|
|
{ L"Security Descriptor", ItemType::String, DeviceClassRegistryPropertyType::SecurityDescriptionString },
|
|
};
|
|
m_ClassItems.swap(items);
|
|
}
|
|
|
|
m_SelectedClass = &it->second;
|
|
m_SelectedDevice = nullptr;
|
|
for (int i = 0; i < m_ClassItems.size(); i++) {
|
|
m_ClassItems[i].Value = GetDeviceClassProperty(m_SelectedClass, i);
|
|
}
|
|
m_List.SetItemCount(static_cast<int>(m_ClassItems.size()));
|
|
}
|
|
|
|
auto si = GetSortInfo(m_List);
|
|
if (si)
|
|
DoSort(si);
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::OnTreeSelectionChanged(int, LPNMHDR, BOOL&) {
|
|
UpdateList();
|
|
return 0;
|
|
}
|
|
|
|
CString CDeviceManagerView::GetDeviceProperty(DeviceInfo& di, int index) const {
|
|
CString result;
|
|
auto& prop = m_Items[index];
|
|
switch (prop.Type) {
|
|
case ItemType::String:
|
|
result = m_DevMgr->GetDeviceRegistryPropertyString(di, prop.PropertyType).c_str();
|
|
break;
|
|
|
|
case ItemType::MultiString:
|
|
for (auto& str : m_DevMgr->GetDeviceRegistryPropertyMultiString(di, prop.PropertyType))
|
|
result += str.c_str() + CString(L", ");
|
|
if (!result.IsEmpty())
|
|
result = result.Left(result.GetLength() - 2);
|
|
break;
|
|
|
|
case ItemType::Dword:
|
|
result.Format(L"%08X", m_DevMgr->GetDeviceRegistryProperty<DWORD>(di, prop.PropertyType));
|
|
break;
|
|
|
|
case ItemType::Boolean:
|
|
result = m_DevMgr->GetDeviceRegistryProperty<DWORD>(di, prop.PropertyType) ? L"Yes" : L"No";
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool CDeviceManagerView::CompareItems(const CString& i1, const CString& i2, bool asc) {
|
|
return SortHelper::SortStrings(i1, i2, asc);
|
|
}
|
|
|
|
void CDeviceManagerView::DoSort(const SortInfo* si) {
|
|
ATLASSERT(si->SortColumn == 0);
|
|
|
|
if (m_SelectedDevice) {
|
|
std::sort(m_Items.begin(), m_Items.end(), [&](const auto& i1, const auto& i2) {
|
|
return CompareItems(i1.Name, i2.Name, si->SortAscending);
|
|
});
|
|
}
|
|
else {
|
|
std::sort(m_ClassItems.begin(), m_ClassItems.end(), [&](const auto& i1, const auto& i2) {
|
|
return CompareItems(i1.Name, i2.Name, si->SortAscending);
|
|
});
|
|
}
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::OnListGetDispInfo(int, LPNMHDR hdr, BOOL&) {
|
|
auto lv = (NMLVDISPINFO*)hdr;
|
|
auto& item = lv->item;
|
|
if (m_SelectedClass)
|
|
return GetDeviceClassInfo(item);
|
|
return GetDeviceInfo(item);
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::GetDeviceClassInfo(LVITEM& item) const {
|
|
if (item.mask & LVIF_TEXT) {
|
|
auto index = item.iItem;
|
|
switch (item.iSubItem) {
|
|
case 0:
|
|
item.pszText = (PWSTR)m_ClassItems[index].Name;
|
|
break;
|
|
|
|
case 1:
|
|
::StringCchCopy(item.pszText, item.cchTextMax, GetDeviceClassProperty(m_SelectedClass, index));
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::GetDeviceInfo(LVITEM& item) const {
|
|
ATLASSERT(m_SelectedDevice);
|
|
if (item.mask & LVIF_TEXT) { // The pszText member or the lpszItem parameter is the address of a null-terminated string
|
|
auto index = item.iItem;
|
|
switch (item.iSubItem) { // 子项的索引值(可以视为列号)从0开始
|
|
case 0:
|
|
item.pszText = (PWSTR)m_Items[index].Name;
|
|
break;
|
|
|
|
case 1:
|
|
::StringCchCopy(item.pszText, item.cchTextMax, m_Items[index].Value);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
CString CDeviceManagerView::GetDeviceClassProperty(const GUID* guid, int index) const {
|
|
ATLASSERT(m_SelectedClass);
|
|
|
|
CString result;
|
|
auto& prop = m_ClassItems[index];
|
|
switch (prop.Type) {
|
|
case ItemType::Guid: // GUID
|
|
::StringFromGUID2(*guid, result.GetBufferSetLength(64), 64);
|
|
break;
|
|
|
|
case ItemType::MultiString:
|
|
for (auto& str : DeviceManager::GetDeviceClassRegistryPropertyMultiString(guid, prop.PropertyType))
|
|
result += str.c_str() + CString(L", ");
|
|
if (!result.IsEmpty())
|
|
result = result.Left(result.GetLength() - 2);
|
|
break;
|
|
|
|
case ItemType::Dword:
|
|
result.Format(L"0x%08X", DeviceManager::GetDeviceClassRegistryProperty<DWORD>(guid, prop.PropertyType));
|
|
break;
|
|
|
|
case ItemType::Boolean:
|
|
result = DeviceManager::GetDeviceClassRegistryProperty<DWORD>(guid, prop.PropertyType) ? L"Yes" : L"No";
|
|
break;
|
|
|
|
case ItemType::String:
|
|
result = DeviceManager::GetDeviceClassRegistryPropertyString(guid, prop.PropertyType).c_str();
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
LRESULT CDeviceManagerView::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) {
|
|
int cx = GET_X_LPARAM(lParam), cy = GET_Y_LPARAM(lParam);
|
|
m_Splitter.MoveWindow(0, 0, cx, cy);
|
|
return 0;
|
|
} |