Files
SimpleRemoter/server/2015Remote/PluginSettingsDlg.cpp
T
yuanyuanxianganddeepseek-v4-pro 6220335f63 Fix: Decode GBK dialog/toolbar text on non-Chinese systems
MBCS dialog templates are decoded with the system ANSI code page, so on
non-Chinese systems the GBK template strings turn into "?" before
TranslateDialog can read them. Set those strings explicitly in OnInitDialog
(PluginSettings save/close, the three Advanced dialogs, the file-manager
search buttons/checkboxes, and Trigger Settings) so they are re-decoded
with the thread locale. Also fix the language-selection dialog and the
toolbar "Lang/语言" button: the language dialog's template is built as
WCHAR strings but created through the ANSI path, so its title, label, and
buttons are set explicitly in OnInitDialog (AppendString stays on CP_ACP),
with the title looked up via _TR("切换语言") and set through SetWindowTextW
after an explicit GBK conversion; new en_US ("Switch Language") and zh_TW
("切換語言") translations accompany it. The toolbar button is set through
the Unicode TB_SETBUTTONINFOW message after an explicit GBK conversion. Add
en_US/zh_TW translations for the experimental-features context menu items.

Co-Authored-By: deepseek-v4-pro
2026-10-08 21:53:53 +02:00

369 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "PluginSettingsDlg.h"
#include "2015RemoteDlg.h"
#include "resource.h"
#include "jsoncpp/json.h"
#include <fstream>
#include <sstream>
#ifndef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "jsoncpp/jsoncppd.lib")
#else
#pragma comment(lib, "jsoncpp/jsoncpp.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "jsoncpp/jsoncpp_x64d.lib")
#else
#pragma comment(lib, "jsoncpp/jsoncpp_x64.lib")
#endif
#endif
BEGIN_MESSAGE_MAP(CPluginSettingsDlg, CDialogLangEx)
ON_BN_CLICKED(IDC_BTN_SAVE, &CPluginSettingsDlg::OnBnClickedBtnSave)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PLUGINS, &CPluginSettingsDlg::OnLvnItemchangedListPlugins)
END_MESSAGE_MAP()
CPluginSettingsDlg::CPluginSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent)
: CDialogLangEx(IDD_DIALOG_PLUGIN_SETTINGS, pParent)
, m_DllList(dllList)
, m_nSelectedIndex(-1)
{
}
CPluginSettingsDlg::~CPluginSettingsDlg()
{
}
void CPluginSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogLangEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST_PLUGINS, m_listPlugins);
DDX_Control(pDX, IDC_COMBO_RUNTYPE_P, m_comboRunType);
DDX_Control(pDX, IDC_COMBO_CALLTYPE, m_comboCallType);
DDX_Control(pDX, IDC_COMBO_MODE, m_comboMode);
DDX_Control(pDX, IDC_EDIT_INTERVAL, m_editInterval);
DDX_Control(pDX, IDC_EDIT_MAXCOUNT, m_editMaxCount);
}
BOOL CPluginSettingsDlg::OnInitDialog()
{
CDialogLangEx::OnInitDialog();
// 初始化列表控件
InitListCtrl();
// 初始化运行类型下拉框
m_comboRunType.InsertString(SHELLCODE, _TR("Shellcode"));
m_comboRunType.InsertString(MEMORYDLL, _TR("内存DLL"));
m_comboRunType.SetCurSel(MEMORYDLL);
// 初始化调用方式下拉框
m_comboCallType.InsertString(CALLTYPE_DEFAULT, _TR("自动检测"));
m_comboCallType.InsertString(CALLTYPE_IOCPTHREAD, _TR("IOCP线程"));
m_comboCallType.InsertString(CALLTYPE_FRPC_CALL, _TR("自定义FRPC[不可用]"));
m_comboCallType.InsertString(CALLTYPE_FRPC_STDCALL, _TR("标准FRPC[不可用]"));
m_comboCallType.SetCurSel(CALLTYPE_DEFAULT);
// 初始化调度模式下拉框
m_comboMode.InsertString(SCH_MODE_NONE, _TR("不自动执行"));
m_comboMode.InsertString(SCH_MODE_STARTUP, _TR("启动执行"));
m_comboMode.InsertString(SCH_MODE_DAILY, _TR("每日定时"));
m_comboMode.InsertString(SCH_MODE_WEEKLY, _TR("每周定时"));
m_comboMode.InsertString(SCH_MODE_MONTHLY, _TR("每月定时"));
m_comboMode.InsertString(SCH_MODE_YEARLY, _TR("每年定时"));
m_comboMode.InsertString(SCH_MODE_OFF, _TR("关闭执行"));
m_comboMode.SetCurSel(SCH_MODE_NONE);
// 加载配置
m_Configs = LoadPluginConfigs();
// 加载插件列表
LoadPluginsToList();
return TRUE;
}
void CPluginSettingsDlg::InitListCtrl()
{
m_listPlugins.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_listPlugins.InsertColumn(0, _TR("名称"), LVCFMT_LEFT, 120);
m_listPlugins.InsertColumn(1, _TR("大小"), LVCFMT_RIGHT, 80);
m_listPlugins.InsertColumn(2, _TR("运行类型"), LVCFMT_LEFT, 80);
m_listPlugins.InsertColumn(3, _TR("调度模式"), LVCFMT_LEFT, 120);
m_listPlugins.InsertColumn(4, _TR("MD5"), LVCFMT_LEFT, 220);
GetDlgItem(IDC_STATIC_PLUGIN_SETTINGS)->SetWindowText(_TR("插件参数配置"));
GetDlgItem(IDC_STATIC_PLUGIN_RUNTYPE)->SetWindowText(_TR("运行类型:"));
GetDlgItem(IDC_STATIC_PLUGIN_CALLTYPE)->SetWindowText(_TR("调用方式:"));
GetDlgItem(IDC_STATIC_PLUGIN_SCHEDULE)->SetWindowText(_TR("调度模式:"));
GetDlgItem(IDC_STATIC_PLUGIN_INTERVAL)->SetWindowText(_TR("间隔(秒):"));
GetDlgItem(IDC_STATIC_PLUGIN_COUNTER)->SetWindowText(_TR("最大次数:"));
SetWindowText(_TR("插件设置"));
// 按钮文字来自对话框模板,非中文系统上会被系统 ACP 转成 "??",须显式设置(参照 NotifySettingsDlg)
SetDlgItemText(IDC_BTN_SAVE, _TR("保存"));
SetDlgItemText(IDOK, _TR("关闭"));
}
void CPluginSettingsDlg::LoadPluginsToList()
{
m_listPlugins.DeleteAllItems();
const char* runTypeNames[] = { "Shellcode", "内存DLL", "Inject SC"};
const char* modeNames[] = { "不自动执行", "启动执行", "每日定时", "每周定时", "每月定时", "每年定时", "关闭执行", };
int index = 0;
for (const auto& dll : m_DllList) {
if (!dll || !dll->Data) continue;
// 获取 DllExecuteInfo
const char* buf = (char*)(dll->Data->Buf());
if (dll->Data->length() < 1 + sizeof(DllExecuteInfo)) continue;
const DllExecuteInfo* info = reinterpret_cast<const DllExecuteInfo*>(buf + 1);
// 查找或创建配置
PluginConfig* cfg = FindConfig(dll->Name);
m_listPlugins.InsertItem(index, CString(dll->Name.c_str()));
CString sizeStr;
sizeStr.Format(_T("%d KB"), info->Size / 1024);
m_listPlugins.SetItemText(index, 1, sizeStr);
int runType = cfg ? cfg->RunType : info->RunType;
int mode = cfg ? cfg->Mode : info->Schedule.Mode;
m_listPlugins.SetItemText(index, 2, _TR(runTypeNames[runType < RUNTYPE_MAX ? runType : MEMORYDLL]));
m_listPlugins.SetItemText(index, 3, _TR(modeNames[mode < SCH_MODE_MAX ? mode : SCH_MODE_NONE]));
m_listPlugins.SetItemText(index, 4, CString(info->Md5));
m_listPlugins.SetItemData(index, (DWORD_PTR)dll);
index++;
}
}
void CPluginSettingsDlg::OnLvnItemchangedListPlugins(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
*pResult = 0;
if (pNMLV->uNewState & LVIS_SELECTED) {
m_nSelectedIndex = pNMLV->iItem;
UpdateSelectedPluginInfo();
}
}
void CPluginSettingsDlg::UpdateSelectedPluginInfo()
{
if (m_nSelectedIndex < 0) return;
DllInfo* dll = reinterpret_cast<DllInfo*>(m_listPlugins.GetItemData(m_nSelectedIndex));
if (!dll || !dll->Data) return;
const char* buf = (char*)(dll->Data->Buf());
const DllExecuteInfo* info = reinterpret_cast<const DllExecuteInfo*>(buf + 1);
// 查找配置(如果有)
PluginConfig* cfg = FindConfig(dll->Name);
// 更新下拉框和编辑框
int runType = cfg ? cfg->RunType : info->RunType;
int callType = cfg ? cfg->CallType : info->CallType;
int mode = cfg ? cfg->Mode : info->Schedule.Mode;
unsigned int interval = cfg ? cfg->Interval : info->Schedule.Config.Startup.Interval;
unsigned char maxCount = cfg ? cfg->MaxCount : info->Schedule.MaxCount;
m_comboRunType.SetCurSel(runType < RUNTYPE_MAX ? runType : MEMORYDLL);
m_comboCallType.SetCurSel(callType < CALLTYPE_MAX ? callType : CALLTYPE_IOCPTHREAD);
m_comboMode.SetCurSel(mode < SCH_MODE_MAX ? mode : SCH_MODE_NONE);
CString str;
str.Format(_T("%u"), interval);
m_editInterval.SetWindowText(str);
str.Format(_T("%u"), maxCount);
m_editMaxCount.SetWindowText(str);
}
void CPluginSettingsDlg::OnBnClickedBtnSave()
{
if (m_nSelectedIndex < 0) {
MessageBoxL(_T("请先选择一个插件"), _T("提示"), MB_ICONINFORMATION);
return;
}
SaveCurrentPluginConfig();
SavePluginConfigs(m_Configs);
// 刷新列表显示
LoadPluginsToList();
// 重新选中
m_listPlugins.SetItemState(m_nSelectedIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
MessageBoxL(_T("配置已保存"), _T("提示"), MB_ICONINFORMATION);
}
void CPluginSettingsDlg::SaveCurrentPluginConfig()
{
if (m_nSelectedIndex < 0) return;
DllInfo* dll = reinterpret_cast<DllInfo*>(m_listPlugins.GetItemData(m_nSelectedIndex));
if (!dll || !dll->Data) return;
const char* buf = (char*)dll->Data->Buf();
const DllExecuteInfo* info = reinterpret_cast<const DllExecuteInfo*>(buf + 1);
// 查找或创建配置
PluginConfig* cfg = FindConfig(dll->Name);
if (!cfg) {
PluginConfig newCfg;
newCfg.Name = dll->Name;
m_Configs.push_back(newCfg);
cfg = &m_Configs.back();
}
cfg->Md5 = info->Md5;
cfg->RunType = m_comboRunType.GetCurSel();
cfg->CallType = m_comboCallType.GetCurSel();
cfg->Mode = (unsigned char)m_comboMode.GetCurSel();
CString str;
m_editInterval.GetWindowText(str);
cfg->Interval = _ttoi(str);
m_editMaxCount.GetWindowText(str);
cfg->MaxCount = (unsigned char)_ttoi(str);
// 更新 DllInfo 中的 Buffer(修改 DllExecuteInfo)
DllExecuteInfo* infoMut = const_cast<DllExecuteInfo*>(info);
infoMut->RunType = cfg->RunType;
infoMut->CallType = cfg->CallType;
infoMut->Schedule.Mode = cfg->Mode;
infoMut->Schedule.Config.Startup.Interval = cfg->Interval;
infoMut->Schedule.MaxCount = cfg->MaxCount;
}
PluginConfig* CPluginSettingsDlg::FindConfig(const std::string& name)
{
for (auto& cfg : m_Configs) {
if (cfg.Name == name) {
return &cfg;
}
}
return nullptr;
}
std::string CPluginSettingsDlg::GetPluginConfigPath()
{
std::string dbPath = GetDbPath();
// 获取目录部分
size_t pos = dbPath.find_last_of("\\/");
std::string dir = (pos != std::string::npos) ? dbPath.substr(0, pos + 1) : "";
return dir + "plugins.json";
}
std::vector<PluginConfig> CPluginSettingsDlg::LoadPluginConfigs()
{
std::vector<PluginConfig> configs;
std::string path = GetPluginConfigPath();
std::ifstream file(path);
if (!file.is_open()) {
return configs;
}
Json::Value root;
Json::CharReaderBuilder builder;
std::string errors;
if (!Json::parseFromStream(builder, file, &root, &errors)) {
return configs;
}
if (!root.isArray()) {
return configs;
}
for (const auto& item : root) {
PluginConfig cfg;
cfg.Name = item.get("name", "").asString();
cfg.Md5 = item.get("md5", "").asString();
cfg.RunType = item.get("runType", MEMORYDLL).asInt();
cfg.CallType = item.get("callType", CALLTYPE_IOCPTHREAD).asInt();
cfg.Mode = (unsigned char)item.get("mode", SCH_MODE_NONE).asInt();
cfg.Flags = (unsigned char)item.get("flags", 0).asInt();
cfg.Interval = item.get("interval", 0).asUInt();
cfg.MaxCount = (unsigned char)item.get("maxCount", 0).asInt();
if (!cfg.Name.empty()) {
configs.push_back(cfg);
}
}
return configs;
}
void CPluginSettingsDlg::SavePluginConfigs(const std::vector<PluginConfig>& configs)
{
std::string path = GetPluginConfigPath();
Json::Value root(Json::arrayValue);
for (const auto& cfg : configs) {
Json::Value item;
item["name"] = cfg.Name;
item["md5"] = cfg.Md5;
item["runType"] = cfg.RunType;
item["callType"] = cfg.CallType;
item["mode"] = cfg.Mode;
item["flags"] = cfg.Flags;
item["interval"] = cfg.Interval;
item["maxCount"] = cfg.MaxCount;
root.append(item);
}
std::ofstream file(path);
if (file.is_open()) {
Json::StreamWriterBuilder builder;
builder["indentation"] = " ";
std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
writer->write(root, &file);
}
}
void CPluginSettingsDlg::PatchDllList(std::vector<DllInfo*>& dllList)
{
std::vector<PluginConfig> configs = LoadPluginConfigs();
for (auto& dll : dllList) {
if (!dll || !dll->Data) continue;
// 查找对应的配置
PluginConfig* cfg = nullptr;
for (auto& c : configs) {
if (c.Name == dll->Name) {
cfg = &c;
break;
}
}
if (!cfg) continue;
// 更新 DllExecuteInfo
char* buf = (char*)dll->Data->Buf();
if (dll->Data->length() < 1 + sizeof(DllExecuteInfo)) continue;
DllExecuteInfo* info = reinterpret_cast<DllExecuteInfo*>(buf + 1);
info->RunType = cfg->RunType;
info->CallType = cfg->CallType;
info->Schedule.Mode = cfg->Mode;
info->Schedule.Flags = cfg->Flags;
info->Schedule.Config.Startup.Interval = cfg->Interval;
info->Schedule.MaxCount = cfg->MaxCount;
}
}