3 Commits
Author SHA1 Message Date
yuanyuanxianganddeepseek-v4-pro d0bad75284 Feature: Remember host list sort preference in main dialog
Persist the sort column and direction chosen via the online host list
header (list\OnlineListSort registry key) so the next launch defaults to
the same sort. Re-apply the sort when hosts come online/offline so newly
connected hosts land in their sorted position instead of appending at the
end.

Co-Authored-By: deepseek-v4-pro
2026-08-13 13:12:29 +02:00
yuanyuanxianganddeepseek-v4-pro 9d2e9ec8ca Feature: Remember process/window list sort preference
Persist the sort column and direction chosen via the list header so the
next time the process or window management dialog opens it defaults to
the same sort. Process and window lists are remembered separately
(list\ProcessListSort and list\WindowListSort registry keys) since their
columns have different meanings.

Co-Authored-By: deepseek-v4-pro
2026-08-13 12:59:29 +02:00
yuanyuanxianganddeepseek-v4-pro 2d7f224a22 Fix: process list architecture column sorting was a no-op
The process list stored the architecture string only in ItemData::Arch,
leaving Data[3] (the architecture column) empty. Sorting by the
architecture column therefore compared empty strings and did nothing.
Populate Data[3] with the architecture value so the sort works.

Co-Authored-By: deepseek-v4-pro
2026-08-13 12:44:14 +02:00
4 changed files with 107 additions and 13 deletions

No files matched your search

+45 -9
View File
@@ -1419,6 +1419,7 @@ VOID CMy2015RemoteDlg::InitControl()
g_Column_Online_Width+=g_Column_Data_Online[i].nWidth;
}
m_CList_Online.InitColumns();
LoadSortPreference(); // 加载上次记忆的排序偏好
// 隐藏空标题列(内部数据槽,不允许用户拖拽显示)
for (int i = 0; i < g_Column_Count_Online; ++i) {
if (g_Column_Data_Online[i].szTitle[0] == '\0') {
@@ -3486,6 +3487,7 @@ void CMy2015RemoteDlg::OnTimer(UINT_PTR nIDEvent)
// 虚拟列表:重建过滤索引并更新项目计数
if (hasListChange) {
ApplySort(); // 有排序偏好时重排,让新上线主机落到排序位置
RebuildFilteredIndices();
m_CList_Online.SetItemCountExV((int)m_FilteredIndices.size(), LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL);
}
@@ -3880,8 +3882,6 @@ void CMy2015RemoteDlg::SortByColumn(int nColumn)
// 缩略图列点击表头不参与排序 —— 没有可比较的数据维度,避免误触发
if (ColumnToDataSlot(nColumn) < 0) return;
static int m_nSortColumn = 0;
static bool m_bSortAscending = false;
if (nColumn == m_nSortColumn) {
// 如果点击的是同一列,切换排序顺序
m_bSortAscending = !m_bSortAscending;
@@ -3891,8 +3891,25 @@ void CMy2015RemoteDlg::SortByColumn(int nColumn)
m_bSortAscending = true;
}
// 虚拟列表:对数据源进行排序(列号映射到底层数据槽)
EnterCriticalSection(&m_cs);
ApplySort();
RebuildFilteredIndices();
LeaveCriticalSection(&m_cs);
// 刷新列表
m_CList_Online.Invalidate();
SaveSortPreference();
}
void CMy2015RemoteDlg::ApplySort()
{
// 无有效排序偏好或列不合法(缩略图/越界)时保持列表原始顺序
if (m_nSortColumn <= COL_THUMBNAIL || m_nSortColumn >= g_Column_Count_Online) {
return;
}
// 虚拟列表:对数据源进行排序(列号映射到底层数据槽),调用方需持有 m_cs
int slot = ColumnToDataSlot(m_nSortColumn);
bool asc = m_bSortAscending;
std::sort(m_HostList.begin(), m_HostList.end(),
@@ -3903,19 +3920,38 @@ void CMy2015RemoteDlg::SortByColumn(int nColumn)
return asc ? (result < 0) : (result > 0);
});
// 重建索引映射
// 排序后 clientID -> 索引映射已改变,需重建
m_ClientIndex.clear();
for (size_t i = 0; i < m_HostList.size(); ++i) {
if (m_HostList[i]) {
m_ClientIndex[m_HostList[i]->GetClientID()] = i;
}
}
// 重建过滤索引
RebuildFilteredIndices();
LeaveCriticalSection(&m_cs);
}
// 刷新列表
m_CList_Online.Invalidate();
void CMy2015RemoteDlg::LoadSortPreference()
{
std::string val = THIS_CFG.GetStr("list", "OnlineListSort", "");
if (val.empty()) {
m_nSortColumn = -1; // 无偏好:保持列表原始顺序
m_bSortAscending = true;
return;
}
auto arr = StringToVector(val, ',');
if (arr.size() >= 2) {
m_nSortColumn = atoi(arr[0].c_str());
m_bSortAscending = (atoi(arr[1].c_str()) != 0);
} else {
m_nSortColumn = -1;
m_bSortAscending = true;
}
}
void CMy2015RemoteDlg::SaveSortPreference()
{
std::string val = std::to_string(m_nSortColumn) + "," + (m_bSortAscending ? "1" : "0");
THIS_CFG.SetStr("list", "OnlineListSort", val);
}
void CMy2015RemoteDlg::OnHdnItemclickList(NMHDR* pNMHDR, LRESULT* pResult)
+5
View File
@@ -173,6 +173,9 @@ protected:
DECLARE_MESSAGE_MAP()
public:
void SortByColumn(int nColumn);
void ApplySort(); // 按偏好重排 m_HostList(调用方需持有 m_cs)
void LoadSortPreference();
void SaveSortPreference();
afx_msg VOID OnHdnItemclickList(NMHDR* pNMHDR, LRESULT* pResult);
static int CALLBACK CompareFunction(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
template<class T, int id, int Show = SW_SHOW> LRESULT OpenDialog(WPARAM wParam, LPARAM lParam)
@@ -342,6 +345,8 @@ public:
std::vector<context*> m_HostList; // 虚拟列表数据源(全部客户端)
std::unordered_map<uint64_t, size_t> m_ClientIndex; // clientID -> m_HostList 索引映射
std::vector<size_t> m_FilteredIndices; // 当前分组过滤后的索引列表
int m_nSortColumn = -1; // 当前排序列,-1 表示未排序
bool m_bSortAscending = true; // 排序方向(true=升序)
std::set<std::string> m_GroupList;
std::string m_selectedGroup;
std::string m_v2KeyPath; // V2 密钥文件路径
+52 -4
View File
@@ -80,6 +80,7 @@ BOOL CSystemDlg::OnInitDialog()
SetWindowText(str);//设置对话框标题
m_ControlList.SetExtendedStyle(LVS_EX_FLATSB | LVS_EX_FULLROWSELECT);
LoadSortPreference(); // 加载上次记忆的排序偏好
if (m_bHow==TOKEN_PSLIST) { //进程管理初始化列表
m_ControlList.InsertColumnL(0, "映像名称", LVCFMT_LEFT, 180);
m_ControlList.InsertColumnL(1, "PID", LVCFMT_LEFT, 70);
@@ -227,6 +228,8 @@ void CSystemDlg::ShowWindowsList(void)
lvc.pszText = str.GetBuffer(0);
lvc.cchTextMax = str.GetLength();
m_ControlList.SetColumn(1, &lvc);
ApplySort(); // 应用记忆的排序偏好
}
void CSystemDlg::ShowProcessList(void)
@@ -260,8 +263,8 @@ void CSystemDlg::ShowProcessList(void)
m_ControlList.SetItemText(i, 1, str);
m_ControlList.SetItemText(i, 2, szProcessFullPath);
m_ControlList.SetItemText(i, 3, arr[1].empty() ? "N/A" : arr[1].c_str());
// ItemData 为进程ID
auto data = new ItemData{ *PID, {arr[0].c_str(), str, szProcessFullPath}, arr[1].c_str() };
// ItemData 为进程ID;Data[3] 需与第 4 列"架构"一致,否则按架构排序拿到空串而无意义
auto data = new ItemData{ *PID, {arr[0].c_str(), str, szProcessFullPath, arr[1].empty() ? "N/A" : arr[1].c_str()}, arr[1].c_str() };
m_ControlList.SetItemData(i, DWORD_PTR(data));
dwOffset += sizeof(DWORD) + lstrlen(szExeFile) + lstrlen(szProcessFullPath) + 2; //跳过这个数据结构 进入下一个循环
@@ -273,6 +276,8 @@ void CSystemDlg::ShowProcessList(void)
lvc.pszText = str.GetBuffer(0);
lvc.cchTextMax = str.GetLength();
m_ControlList.SetColumn(2, &lvc); //在列表中显示有多少个进程
ApplySort(); // 应用记忆的排序偏好
}
@@ -319,8 +324,6 @@ int CALLBACK CSystemDlg::CompareFunction(LPARAM lParam1, LPARAM lParam2, LPARAM
void CSystemDlg::SortByColumn(int nColumn)
{
static int m_nSortColumn = 0;
static bool m_bSortAscending = false;
if (nColumn == m_nSortColumn) {
// 如果点击的是同一列,切换排序顺序
m_bSortAscending = !m_bSortAscending;
@@ -330,11 +333,56 @@ void CSystemDlg::SortByColumn(int nColumn)
m_bSortAscending = true;
}
ApplySort();
SaveSortPreference();
}
void CSystemDlg::ApplySort()
{
// 无有效排序偏好时保持列表原始顺序
if (m_nSortColumn < 0) {
return;
}
// 防御:配置被手动修改导致列索引越界时跳过排序
CHeaderCtrl* pHeader = m_ControlList.GetHeaderCtrl();
if (pHeader && m_nSortColumn >= pHeader->GetItemCount()) {
return;
}
// 创建排序信息
std::pair<int, bool> sortInfo(m_nSortColumn, m_bSortAscending);
m_ControlList.SortItems(CompareFunction, reinterpret_cast<LPARAM>(&sortInfo));
}
void CSystemDlg::LoadSortPreference()
{
// 进程管理 / 窗口管理 分别记忆各自的排序偏好
const char* key = (m_bHow == TOKEN_PSLIST) ? "ProcessListSort" : "WindowListSort";
std::string val = THIS_CFG.GetStr("list", key, "");
if (val.empty()) {
m_nSortColumn = -1; // 无偏好:保持列表原始顺序
m_bSortAscending = true;
return;
}
auto arr = StringToVector(val, ',');
if (arr.size() >= 2) {
m_nSortColumn = atoi(arr[0].c_str());
m_bSortAscending = (atoi(arr[1].c_str()) != 0);
} else {
m_nSortColumn = -1;
m_bSortAscending = true;
}
}
void CSystemDlg::SaveSortPreference()
{
const char* key = (m_bHow == TOKEN_PSLIST) ? "ProcessListSort" : "WindowListSort";
std::string val = std::to_string(m_nSortColumn) + "," + (m_bSortAscending ? "1" : "0");
THIS_CFG.SetStr("list", key, val);
}
void CSystemDlg::OnHdnItemclickList(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMHEADER pNMHeader = reinterpret_cast<LPNMHEADER>(pNMHDR);
+5
View File
@@ -19,6 +19,8 @@ public:
void OnReceiveComplete(void);
CWnd* m_pParent;
BOOL m_bHow;
int m_nSortColumn = -1; // 当前排序列,-1 表示未排序
bool m_bSortAscending = true; // 排序方向(true=升序)
// 对话框数据
enum { IDD = IDD_DIALOG_SYSTEM };
@@ -32,6 +34,9 @@ public:
void DeleteAllItems();
void SortByColumn(int nColumn);
void ApplySort();
void LoadSortPreference();
void SaveSortPreference();
afx_msg VOID OnHdnItemclickList(NMHDR* pNMHDR, LRESULT* pResult);
static int CALLBACK CompareFunction(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);