diff --git a/client/LoginServer.cpp b/client/LoginServer.cpp index 548f441..94204b8 100644 --- a/client/LoginServer.cpp +++ b/client/LoginServer.cpp @@ -11,138 +11,89 @@ #include #include "ScreenCapture.h" -// by ChatGPT -bool IsWindows11() -{ - typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW); - RTL_OSVERSIONINFOW rovi = { 0 }; - rovi.dwOSVersionInfoSize = sizeof(rovi); - - HMODULE hMod = GetModuleHandleW(L"ntdll.dll"); - if (hMod) { - RtlGetVersionPtr rtlGetVersion = (RtlGetVersionPtr)GetProcAddress(hMod, "RtlGetVersion"); - if (rtlGetVersion) { - rtlGetVersion(&rovi); - return (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion == 0 && rovi.dwBuildNumber >= 22000); - } - } - return false; -} - -/************************************************************************ ---------------------- -作者:IT1995 -来源:CSDN -原文:https://blog.csdn.net/qq78442761/article/details/64440535 -版权声明:本文为博主原创文章,转载请附上博文链接! -修改说明:2019.3.29由袁沅祥修改 -************************************************************************/ std::string getSystemName() { - std::string vname("未知操作系统"); - //先判断是否为win8.1或win10 - typedef void(__stdcall*NTPROC)(DWORD*, DWORD*, DWORD*); - HINSTANCE hinst = LoadLibrary("ntdll.dll"); - if (hinst == NULL) { - return vname; - } - if (IsWindows11()) { - vname = "Windows 11"; - Mprintf("此电脑的版本为:%s\n", vname.c_str()); - return vname; - } - DWORD dwMajor, dwMinor, dwBuildNumber; - NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers"); - if (proc==NULL) { - return vname; - } - proc(&dwMajor, &dwMinor, &dwBuildNumber); - if (dwMajor == 6 && dwMinor == 3) { //win 8.1 - vname = "Windows 8.1"; - Mprintf("此电脑的版本为:%s\n", vname.c_str()); - return vname; - } - if (dwMajor == 10 && dwMinor == 0) { //win 10 - vname = "Windows 10"; - Mprintf("此电脑的版本为:%s\n", vname.c_str()); - return vname; - } - //下面不能判断Win Server,因为本人还未有这种系统的机子,暂时不给出 + typedef void(__stdcall* NTPROC)(DWORD*, DWORD*, DWORD*); - //判断win8.1以下的版本 - SYSTEM_INFO info; //用SYSTEM_INFO结构判断64位AMD处理器 - GetSystemInfo(&info); //调用GetSystemInfo函数填充结构 - OSVERSIONINFOEX os; - os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (GetVersionEx((OSVERSIONINFO *)&os)) { - //下面根据版本信息判断操作系统名称 - switch (os.dwMajorVersion) { - //判断主版本号 - case 4: - switch (os.dwMinorVersion) { - //判断次版本号 - case 0: - if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) - vname ="Windows NT 4.0"; //1996年7月发布 - else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) - vname = "Windows 95"; - break; - case 10: - vname ="Windows 98"; - break; - case 90: - vname = "Windows Me"; - break; - } - break; - case 5: - switch (os.dwMinorVersion) { - //再比较dwMinorVersion的值 - case 0: - vname = "Windows 2000"; //1999年12月发布 - break; - case 1: - vname = "Windows XP"; //2001年8月发布 - break; - case 2: - if (os.wProductType == VER_NT_WORKSTATION && - info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) - vname = "Windows XP Professional x64 Edition"; - else if (GetSystemMetrics(SM_SERVERR2) == 0) - vname = "Windows Server 2003"; //2003年3月发布 - else if (GetSystemMetrics(SM_SERVERR2) != 0) - vname = "Windows Server 2003 R2"; - break; - } - break; - case 6: - switch (os.dwMinorVersion) { - case 0: - if (os.wProductType == VER_NT_WORKSTATION) - vname = "Windows Vista"; - else - vname = "Windows Server 2008"; //服务器版本 - break; - case 1: - if (os.wProductType == VER_NT_WORKSTATION) - vname = "Windows 7"; - else - vname = "Windows Server 2008 R2"; - break; - case 2: - if (os.wProductType == VER_NT_WORKSTATION) - vname = "Windows 8"; - else - vname = "Windows Server 2012"; - break; - } - break; - default: - vname = "未知操作系统"; + HINSTANCE hinst = LoadLibrary("ntdll.dll"); + if (!hinst) { + return "未知操作系统"; + } + + NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers"); + if (!proc) { + FreeLibrary(hinst); + return "未知操作系统"; + } + + DWORD dwMajor, dwMinor, dwBuildNumber; + proc(&dwMajor, &dwMinor, &dwBuildNumber); + dwBuildNumber &= 0xFFFF; // 高位是标志位,只取低16位 + + FreeLibrary(hinst); + + // 判断是否为 Server 版本 + OSVERSIONINFOEX osvi = { sizeof(osvi) }; + GetVersionEx((OSVERSIONINFO*)&osvi); + bool isServer = (osvi.wProductType != VER_NT_WORKSTATION); + + std::string vname; + + if (dwMajor == 10 && dwMinor == 0) { + if (isServer) { + // Windows Server + if (dwBuildNumber >= 20348) + vname = "Windows Server 2022"; + else if (dwBuildNumber >= 17763) + vname = "Windows Server 2019"; + else + vname = "Windows Server 2016"; } - Mprintf("此电脑的版本为:%s\n", vname.c_str()); - } else - Mprintf("版本获取失败\n"); + else { + // Windows 桌面版 + if (dwBuildNumber >= 22000) + vname = "Windows 11"; + else + vname = "Windows 10"; + } + } + else if (dwMajor == 6) { + switch (dwMinor) { + case 3: + vname = isServer ? "Windows Server 2012 R2" : "Windows 8.1"; + break; + case 2: + vname = isServer ? "Windows Server 2012" : "Windows 8"; + break; + case 1: + vname = isServer ? "Windows Server 2008 R2" : "Windows 7"; + break; + case 0: + vname = isServer ? "Windows Server 2008" : "Windows Vista"; + break; + } + } + else if (dwMajor == 5) { + switch (dwMinor) { + case 2: + vname = "Windows Server 2003"; + break; + case 1: + vname = "Windows XP"; + break; + case 0: + vname = "Windows 2000"; + break; + } + } + + if (vname.empty()) { + char buf[64]; + sprintf(buf, "Windows (Build %d)", dwBuildNumber); + vname = buf; + } + + Mprintf("此电脑的版本为:%s (Build %d)\n", vname.c_str(), dwBuildNumber); return vname; } diff --git a/client/SCLoader.vcxproj b/client/SCLoader.vcxproj index f103377..f535f40 100644 --- a/client/SCLoader.vcxproj +++ b/client/SCLoader.vcxproj @@ -106,12 +106,18 @@ Level3 true - true + false true - WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ECB=0;CTR=0;%(PreprocessorDefinitions) true MultiThreaded 4018;4244;4267;4819;4838 + MinSpace + Size + false + false + false + Fast Windows @@ -142,12 +148,17 @@ Level3 true - true true - NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ECB=0;CTR=0;%(PreprocessorDefinitions) true MultiThreaded 4018;4244;4267;4819;4838 + MinSpace + Size + false + false + false + Fast Windows diff --git a/common/aes.c b/common/aes.c index 8f5ea28..6b26ead 100644 --- a/common/aes.c +++ b/common/aes.c @@ -37,6 +37,8 @@ NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) #include // CBC mode, for memset #include "aes.h" +#pragma intrinsic(memcpy) + /*****************************************************************************/ /* Defines: */ /*****************************************************************************/ diff --git a/lib/FileUpload_Lib.lib b/lib/FileUpload_Lib.lib index 83360fe..e44dc1a 100644 Binary files a/lib/FileUpload_Lib.lib and b/lib/FileUpload_Lib.lib differ diff --git a/lib/FileUpload_Libd.lib b/lib/FileUpload_Libd.lib index 75bd3fe..6eac904 100644 Binary files a/lib/FileUpload_Libd.lib and b/lib/FileUpload_Libd.lib differ diff --git a/lib/FileUpload_Libx64.lib b/lib/FileUpload_Libx64.lib index e257ea7..1137d6c 100644 Binary files a/lib/FileUpload_Libx64.lib and b/lib/FileUpload_Libx64.lib differ diff --git a/lib/FileUpload_Libx64d.lib b/lib/FileUpload_Libx64d.lib index f967fc7..807e60f 100644 Binary files a/lib/FileUpload_Libx64d.lib and b/lib/FileUpload_Libx64d.lib differ diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc index f7f5337..c91dc47 100644 Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index dbb61e8..f38a687 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -47,6 +47,7 @@ #include "SplashDlg.h" #include #include "CDlgFileSend.h" +#include "CClientListDlg.h" #ifdef _DEBUG #define new DEBUG_NEW @@ -115,49 +116,6 @@ std::string PluginPath() return path; } - -////////////////////////////////////////////////////////////////////////// - -// 保存 unordered_map 到文件 -void SaveToFile(const ComputerNoteMap& data, const std::string& filename) -{ - std::ofstream outFile(filename, std::ios::binary); // 打开文件(以二进制模式) - if (outFile.is_open()) { - for (const auto& pair : data) { - outFile.write(reinterpret_cast(&pair.first), sizeof(ClientKey)); // 保存 key - int valueSize = pair.second.GetLength(); - outFile.write(reinterpret_cast(&valueSize), sizeof(int)); // 保存 value 的大小 - outFile.write((char*)&pair.second, valueSize); // 保存 value 字符串 - } - outFile.close(); - } else { - Mprintf("Unable to open file '%s' for writing!\n", filename.c_str()); - } -} - -// 从文件读取 unordered_map 数据 -void LoadFromFile(ComputerNoteMap& data, const std::string& filename) -{ - std::ifstream inFile(filename, std::ios::binary); // 打开文件(以二进制模式) - if (inFile.is_open()) { - while (inFile.peek() != EOF) { - ClientKey key; - inFile.read(reinterpret_cast(&key), sizeof(ClientKey)); // 读取 key - - int valueSize; - inFile.read(reinterpret_cast(&valueSize), sizeof(int)); // 读取 value 的大小 - - ClientValue value; - inFile.read((char*)&value, valueSize); // 读取 value 字符串 - - data[key] = value; // 插入到 map 中 - } - inFile.close(); - } else { - Mprintf("Unable to open file '%s' for reading!\n", filename.c_str()); - } -} - ////////////////////////////////////////////////////////////////////////// class CAboutDlg : public CDialogEx @@ -417,6 +375,7 @@ std::string CMy2015RemoteDlg::GetHardwareID(int v) CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogEx(CMy2015RemoteDlg::IDD, pParent) { + m_ClientMap = NewClientList(); g_StartTick = GetTickCount(); auto s = GetMasterHash(); char buf[17] = { 0 }; @@ -469,6 +428,7 @@ CMy2015RemoteDlg::CMy2015RemoteDlg(CWnd* pParent): CDialogEx(CMy2015RemoteDlg::I CMy2015RemoteDlg::~CMy2015RemoteDlg() { + SAFE_DELETE(m_ClientMap); DeleteCriticalSection(&m_cs); for (int i = 0; i < PAYLOAD_MAXTYPE; i++) { SAFE_DELETE(m_ServerDLL[i]); @@ -612,7 +572,8 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_PROXY_PORT, &CMy2015RemoteDlg::OnProxyPort) ON_COMMAND(ID_HOOK_WIN, &CMy2015RemoteDlg::OnHookWin) ON_COMMAND(ID_RUNAS_SERVICE, &CMy2015RemoteDlg::OnRunasService) -END_MESSAGE_MAP() + ON_COMMAND(ID_HISTORY_CLIENTS, &CMy2015RemoteDlg::OnHistoryClients) + END_MESSAGE_MAP() // CMy2015RemoteDlg 消息处理程序 @@ -651,7 +612,7 @@ VOID CMy2015RemoteDlg::CreateSolidMenu() if (GetPwdHash() != masterHash) { SubMenu->DeleteMenu(ID_TOOL_GEN_MASTER, MF_BYCOMMAND); } - SubMenu = m_MainMenu.GetSubMenu(3); + SubMenu = m_MainMenu.GetSubMenu(4); if (!THIS_CFG.GetStr("settings", "Password").empty()) { SubMenu->ModifyMenuA(ID_TOOL_REQUEST_AUTH, MF_STRING, ID_TOOL_REQUEST_AUTH, _T("序列号")); } @@ -802,17 +763,13 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName id, v[RES_CLIENT_ID].c_str(), strIP.GetString(), path.GetString()); } bool modify = false; - CString loc = GetClientMapData(id, MAP_LOCATION); + CString loc = m_ClientMap->GetClientMapData(id, MAP_LOCATION); if (loc.IsEmpty()) { loc = v[RES_CLIENT_LOC].c_str(); if (loc.IsEmpty()) { IPConverter cvt; loc = cvt.GetGeoLocation(data[ONLINELIST_IP].GetString()).c_str(); } - if (!loc.IsEmpty()) { - modify = true; - SetClientMapData(id, MAP_LOCATION, loc); - } } bool flag = strIP == "127.0.0.1" && !v[RES_CLIENT_PUBIP].empty(); data[ONLINELIST_IP] = flag ? v[RES_CLIENT_PUBIP].c_str() : strIP; @@ -820,6 +777,7 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName ContextObject->SetClientInfo(data, v); ContextObject->SetID(id); ContextObject->SetGroup(groupName); + m_ClientMap->SaveClientMapData(ContextObject); EnterCriticalSection(&m_cs); @@ -843,14 +801,14 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName } if (modify) - SaveToFile(m_ClientMap, GetDbPath()); - auto& m = m_ClientMap[ContextObject->ID]; + m_ClientMap->SaveToFile(GetDbPath()); m_HostList.insert(ContextObject); if (groupName == m_selectedGroup || (groupName.empty() && m_selectedGroup == "default")) { int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(), data[ONLINELIST_IP]); for (int n = ONLINELIST_ADDR; n <= ONLINELIST_CLIENTTYPE; n++) { + auto note = m_ClientMap->GetClientMapData(ContextObject->GetClientID(), MAP_NOTE); n == ONLINELIST_COMPUTER_NAME ? - m_CList_Online.SetItemText(i, n, m.GetNote()[0] ? m.GetNote() : data[n]) : + m_CList_Online.SetItemText(i, n, !note.IsEmpty() ? note : data[n]) : m_CList_Online.SetItemText(i, n, data[n].IsEmpty() ? "?" : data[n]); } m_CList_Online.SetItemData(i, (DWORD_PTR)ContextObject); @@ -1195,7 +1153,7 @@ BOOL CMy2015RemoteDlg::OnInitDialog() UPDATE_SPLASH(35, "正在加载客户端数据库..."); // 将"关于..."菜单项添加到系统菜单中。 SetWindowText(_T("Yama")); - LoadFromFile(m_ClientMap, GetDbPath()); + m_ClientMap->LoadFromFile(GetDbPath()); // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); @@ -1662,6 +1620,15 @@ void CMy2015RemoteDlg::Release() ContextObject->Destroy(); } LeaveCriticalSection(&m_cs); + m_ClientMap->SaveToFile(GetDbPath()); + if (m_pClientListDlg != nullptr && ::IsWindow(m_pClientListDlg->GetSafeHwnd())) { + // 关键:调用 DestroyWindow,它会触发窗口的关闭和销毁流程 + m_pClientListDlg->DestroyWindow(); + + // 注意:如果你在对话框的 PostNcDestroy 里写了 delete this; + // 那么此时不要再 delete m_pClientListDlg,只需将指针置 NULL 即可 + m_pClientListDlg = nullptr; + } Sleep(500); while (m_hFRPThread) Sleep(20); @@ -2837,6 +2804,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) BOOL authorized = AuthorizeClient(hb.SN, hb.Passcode, hb.PwdHmac); if (authorized) { Mprintf("%s HMAC 校验成功: %lld\n", hb.Passcode, hb.PwdHmac); + m_ClientMap->SetClientMapInteger(host->GetClientID(), MAP_AUTH, TRUE); std::string tip = std::string(hb.Passcode) + " 授权成功: "; tip += std::to_string(hb.PwdHmac) + "[" + std::string(ctx->GetClientData(ONLINELIST_IP)) + "]"; CharMsg* msg = new CharMsg(tip.c_str()); @@ -3177,19 +3145,13 @@ void CMy2015RemoteDlg::OnOnlineHostnote() while (Pos) { int iItem = m_CList_Online.GetNextSelectedItem(Pos); context* ContextObject = (context*)m_CList_Online.GetItemData(iItem); - auto f = m_ClientMap.find(ContextObject->GetClientID()); - if (f == m_ClientMap.end()) - m_ClientMap[ContextObject->GetClientID()] = ClientValue("", dlg.m_str); - else - m_ClientMap[ContextObject->GetClientID()].UpdateNote(dlg.m_str); + m_ClientMap->SetClientMapData(ContextObject->GetClientID(), MAP_NOTE, dlg.m_str); m_CList_Online.SetItemText(iItem, ONLINELIST_COMPUTER_NAME, dlg.m_str); modified = TRUE; } LeaveCriticalSection(&m_cs); if (modified) { - EnterCriticalSection(&m_cs); - SaveToFile(m_ClientMap, GetDbPath()); - LeaveCriticalSection(&m_cs); + m_ClientMap->SaveToFile(GetDbPath()); } } @@ -3992,11 +3954,10 @@ void CMy2015RemoteDlg::OnOnlineAddWatch() while (Pos) { int iItem = m_CList_Online.GetNextSelectedItem(Pos); context* ctx = (context*)m_CList_Online.GetItemData(iItem); - auto f = m_ClientMap.find(ctx->GetClientID()); - int r = f != m_ClientMap.end() ? f->second.GetLevel() : 0; - m_ClientMap[ctx->GetClientID()].UpdateLevel(++r >= 4 ? 0 : r); + int r = m_ClientMap->GetClientMapInteger(ctx->GetClientID(), MAP_LEVEL); + m_ClientMap->SetClientMapInteger(ctx->GetClientID(), MAP_LEVEL, ++r >= 4 ? 0 : r); } - SaveToFile(m_ClientMap, GetDbPath()); + m_ClientMap->SaveToFile(GetDbPath()); LeaveCriticalSection(&m_cs); } @@ -4015,9 +3976,8 @@ void CMy2015RemoteDlg::OnNMCustomdrawOnline(NMHDR* pNMHDR, LRESULT* pResult) int nRow = static_cast(pLVCD->nmcd.dwItemSpec); EnterCriticalSection(&m_cs); context* ctx = (context*)m_CList_Online.GetItemData(nRow); - auto f = m_ClientMap.find(ctx->GetClientID()); - int r = f != m_ClientMap.end() ? f->second.GetLevel() : 0; LeaveCriticalSection(&m_cs); + int r = m_ClientMap->GetClientMapInteger(ctx->GetClientID(), MAP_LEVEL); if (r >= 1) pLVCD->clrText = RGB(0, 0, 255); // 字体蓝 if (r >= 2) pLVCD->clrText = RGB(255, 0, 0); // 字体红 if (r >= 3) pLVCD->clrTextBk = RGB(255, 160, 160); // 背景红 @@ -4113,14 +4073,14 @@ void CMy2015RemoteDlg::LoadListData(const std::string& group) auto g = ctx->GetGroupName(); if ((group == _T("default") && g.empty()) || g == group) { CString strIP=ctx->GetClientData(ONLINELIST_IP); - auto& m = m_ClientMap[ctx->GetClientID()]; auto pubIP = ctx->GetAdditionalData(RES_CLIENT_PUBIP); bool flag = strIP == "127.0.0.1" && !pubIP.IsEmpty(); int i = m_CList_Online.InsertItem(m_CList_Online.GetItemCount(), flag ? pubIP : strIP); for (int n = ONLINELIST_ADDR; n <= ONLINELIST_CLIENTTYPE; n++) { auto data = ctx->GetClientData(n); + auto note = m_ClientMap->GetClientMapData(ctx->GetClientID(), MAP_NOTE); n == ONLINELIST_COMPUTER_NAME ? - m_CList_Online.SetItemText(i, n, m.GetNote()[0] ? m.GetNote() : data) : + m_CList_Online.SetItemText(i, n, !note.IsEmpty() ? note : data) : m_CList_Online.SetItemText(i, n, data.IsEmpty() ? "?" : data); } m_CList_Online.SetItemData(i, (DWORD_PTR)ctx); @@ -4805,3 +4765,22 @@ void CMy2015RemoteDlg::OnRunasService() SubMenu->CheckMenuItem(ID_RUNAS_SERVICE, !m_runNormal ? MF_CHECKED : MF_UNCHECKED); BOOL r = m_runNormal ? ServerService_Uninstall() : ServerService_Install(); } + +void CMy2015RemoteDlg::OnHistoryClients() +{ + // 1. 如果窗口已经存在,直接带到前台,不要重复创建 + if (m_pClientListDlg != nullptr && ::IsWindow(m_pClientListDlg->GetSafeHwnd())) { + m_pClientListDlg->ShowWindow(SW_SHOW); + m_pClientListDlg->SetForegroundWindow(); + return; + } + + // 2. 创建对话框实例 + // 注意:如果是非模态,传进去的 m_ClientMap 引用要确保在对话框存在期间一直有效 + m_pClientListDlg = new CClientListDlg(m_ClientMap, this); + + // IDD_CLIENT_LIST 是你对话框的 ID + if (m_pClientListDlg->Create(IDD_DIALOG_CLIENTLIST, GetDesktopWindow())) { + m_pClientListDlg->ShowWindow(SW_SHOW); + } +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index d6856f0..25e9fa6 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -47,75 +47,8 @@ typedef struct FileTransformCmd { } FileTransformCmd; #define ID_DYNAMIC_MENU_BASE 36500 - -////////////////////////////////////////////////////////////////////////// -#include -#include +#include "HostInfo.h" #include "CGridDialog.h" -#include - -enum { - MAP_NOTE, - MAP_LOCATION, - MAP_LEVEL, -}; - -struct _ClientValue { - char Note[64]; - char Location[64]; - char Level; - char Reserved[127]; // 预留 - _ClientValue() - { - memset(this, 0, sizeof(_ClientValue)); - } - _ClientValue(const CString& loc, const CString& s) - { - memset(this, 0, sizeof(_ClientValue)); - strcpy_s(Note, s.GetString()); - strcpy_s(Location, loc.GetString()); - } - void UpdateNote(const CString& s) - { - strcpy_s(Note, s.GetString()); - } - void UpdateLocation(const CString& loc) - { - strcpy_s(Location, loc.GetString()); - } - void UpdateLevel(int level) - { - Level = level; - } - const char* GetNote() const - { - return Note; - } - const char* GetLocation() const - { - return Location; - } - int GetLevel() const - { - return Level; - } - int GetLength() const - { - return sizeof(_ClientValue); - } -}; - -typedef uint64_t ClientKey; - -typedef _ClientValue ClientValue; - -typedef std::unordered_map ComputerNoteMap; - -// 保存 unordered_map 到文件 -void SaveToFile(const ComputerNoteMap& data, const std::string& filename); - -// 从文件读取 unordered_map 数据 -void LoadFromFile(ComputerNoteMap& data, const std::string& filename); ////////////////////////////////////////////////////////////////////////// @@ -126,6 +59,7 @@ enum { }; class CSplashDlg; // 前向声明 +class CClientListDlg; #include "pwd_gen.h" @@ -134,43 +68,9 @@ class CMy2015RemoteDlg : public CDialogEx { public: static std::string GetHardwareID(int v=-1); -protected: - ComputerNoteMap m_ClientMap; - CString GetClientMapData(ClientKey key, int typ) - { - EnterCriticalSection(&m_cs); - auto f = m_ClientMap.find(key); - CString r; - if (f != m_ClientMap.end()) { - switch (typ) { - case MAP_NOTE: - r = f->second.GetNote(); - break; - case MAP_LOCATION: - r = f->second.GetLocation(); - break; - default: - break; - } - } - LeaveCriticalSection(&m_cs); - return r; - } - void SetClientMapData(ClientKey key, int typ, const char* value) - { - EnterCriticalSection(&m_cs); - switch (typ) { - case MAP_NOTE: - m_ClientMap[key].UpdateNote(value); - break; - case MAP_LOCATION: - m_ClientMap[key].UpdateLocation(value); - break; - default: - break; - } - LeaveCriticalSection(&m_cs); - } + _ClientList *m_ClientMap = nullptr; + CClientListDlg* m_pClientListDlg = nullptr; + // 构造 public: CMy2015RemoteDlg(CWnd* pParent = NULL); // 标准构造函数 @@ -412,4 +312,5 @@ public: afx_msg void OnProxyPort(); afx_msg void OnHookWin(); afx_msg void OnRunasService(); + afx_msg void OnHistoryClients(); }; diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj index 4350a3e..24a5b2d 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj +++ b/server/2015Remote/2015Remote_vs2015.vcxproj @@ -282,10 +282,12 @@ + + @@ -299,6 +301,7 @@ + @@ -373,6 +376,7 @@ + diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters index 47411cb..33acc92 100644 --- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters +++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters @@ -64,6 +64,7 @@ + @@ -140,6 +141,9 @@ + + + diff --git a/server/2015Remote/BuildDlg.cpp b/server/2015Remote/BuildDlg.cpp index 472e4c2..9ca1aa8 100644 --- a/server/2015Remote/BuildDlg.cpp +++ b/server/2015Remote/BuildDlg.cpp @@ -496,6 +496,7 @@ void CBuildDlg::OnBnClickedOk() BOOL checked = m_BtnFileServer.GetCheck() == BST_CHECKED; if (checked){ strcpy(sc->downloadUrl, m_sDownloadUrl.IsEmpty() ? BuildPayloadUrl(m_strIP, sc->file) : m_sDownloadUrl); + if (m_sDownloadUrl.IsEmpty()) MessageBox(CString("文件下载地址: \r\n") + sc->downloadUrl, "提示"); } tip = payload.IsEmpty() ? "\r\n警告: 没有生成载荷!" : checked ? "\r\n提示: 载荷文件必须拷贝至\"Payloads\"目录。" : "\r\n提示: 载荷文件必须拷贝至程序目录。"; diff --git a/server/2015Remote/CClientListDlg.cpp b/server/2015Remote/CClientListDlg.cpp new file mode 100644 index 0000000..31ff09a --- /dev/null +++ b/server/2015Remote/CClientListDlg.cpp @@ -0,0 +1,248 @@ +// CClientListDlg.cpp: 实现文件 +// + +#include "stdafx.h" +#include "afxdialogex.h" +#include "CClientListDlg.h" + + +// CClientListDlg 对话框 + +IMPLEMENT_DYNAMIC(CClientListDlg, CDialogEx) + +CClientListDlg::CClientListDlg(_ClientList* clients, CMy2015RemoteDlg* pParent) + : g_ClientList(clients), g_pParent(pParent), CDialogEx(IDD_DIALOG_CLIENTLIST, pParent) + , m_nSortColumn(-1) + , m_bSortAscending(TRUE) +{ +} + +CClientListDlg::~CClientListDlg() +{ +} + +void CClientListDlg::DoDataExchange(CDataExchange* pDX) +{ + CDialogEx::DoDataExchange(pDX); + DDX_Control(pDX, IDC_CLIENT_LIST, m_ClientList); +} + + +BEGIN_MESSAGE_MAP(CClientListDlg, CDialogEx) + ON_WM_SIZE() + ON_NOTIFY(LVN_COLUMNCLICK, IDC_CLIENT_LIST, &CClientListDlg::OnColumnClick) +END_MESSAGE_MAP() + + +// CClientListDlg 消息处理程序 + +BOOL CClientListDlg::OnInitDialog() +{ + CDialogEx::OnInitDialog(); + + HICON hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_MACHINE)); + SetIcon(hIcon, FALSE); + + // 设置扩展样式 + m_ClientList.SetExtendedStyle( + LVS_EX_FULLROWSELECT | // 整行选中 + LVS_EX_GRIDLINES // 显示网格线 + ); + + // 添加列 + m_ClientList.InsertColumn(0, _T("序号"), LVCFMT_LEFT, 50); + m_ClientList.InsertColumn(1, _T("ID"), LVCFMT_LEFT, 120); + m_ClientList.InsertColumn(2, _T("备注"), LVCFMT_LEFT, 80); + m_ClientList.InsertColumn(3, _T("位置"), LVCFMT_LEFT, 100); + m_ClientList.InsertColumn(4, _T("IP"), LVCFMT_LEFT, 120); + m_ClientList.InsertColumn(5, _T("系统"), LVCFMT_LEFT, 120); + m_ClientList.InsertColumn(6, _T("安装时间"), LVCFMT_LEFT, 130); + m_ClientList.InsertColumn(7, _T("最后登录"), LVCFMT_LEFT, 130); + m_ClientList.InsertColumn(8, _T("关注级别"), LVCFMT_LEFT, 70); + m_ClientList.InsertColumn(9, _T("已授权"), LVCFMT_LEFT, 60); + + // 首次加载数据 + AdjustColumnWidths(); + RefreshClientList(); + + return TRUE; +} + +void CClientListDlg::RefreshClientList() +{ + m_clients = g_ClientList->GetAll(); // 保存到成员变量 + + // 如果之前有排序,保持排序 + if (m_nSortColumn >= 0) { + SortByColumn(m_nSortColumn, m_bSortAscending); + } + else { + m_ClientList.SetRedraw(FALSE); + DisplayClients(); + m_ClientList.SetRedraw(TRUE); + m_ClientList.Invalidate(); + } +} + +void CClientListDlg::DisplayClients() +{ + m_ClientList.DeleteAllItems(); + + int i = 0; + for (const auto& pair : m_clients) { + const ClientKey& key = pair.first; + const ClientValue& val = pair.second; + + CString strNo; + strNo.Format(_T("%d"), i + 1); // 序号从1开始 + + CString strID; + strID.Format(_T("%llu"), key); + + CString strLevel; + strLevel.Format(_T("%d"), val.Level); + + CString strAuth = val.Authorized ? _T("Y") : _T("N"); + + int nItem = m_ClientList.InsertItem(i, strNo); // 第一列是序号 + m_ClientList.SetItemText(nItem, 1, strID); + m_ClientList.SetItemText(nItem, 2, val.Note); + m_ClientList.SetItemText(nItem, 3, val.Location); + m_ClientList.SetItemText(nItem, 4, val.IP); + m_ClientList.SetItemText(nItem, 5, val.OsName); + m_ClientList.SetItemText(nItem, 6, val.InstallTime); + m_ClientList.SetItemText(nItem, 7, val.LastLoginTime); + m_ClientList.SetItemText(nItem, 8, strLevel); + m_ClientList.SetItemText(nItem, 9, strAuth); + m_ClientList.SetItemData(nItem, (DWORD_PTR)key); + i++; + } +} + +void CClientListDlg::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); + int nColumn = pNMLV->iSubItem; + + // 序号列不排序 + if (nColumn == 0) { + *pResult = 0; + return; + } + + // 点击同一列切换排序方向 + if (nColumn == m_nSortColumn) { + m_bSortAscending = !m_bSortAscending; + } + else { + m_nSortColumn = nColumn; + m_bSortAscending = TRUE; + } + + SortByColumn(nColumn, m_bSortAscending); + + *pResult = 0; +} + +void CClientListDlg::SortByColumn(int nColumn, BOOL bAscending) +{ + std::sort(m_clients.begin(), m_clients.end(), + [nColumn, bAscending](const std::pair& a, + const std::pair& b) { + int result = 0; + + switch (nColumn) { + case 1: // ID + result = (a.first < b.first) ? -1 : ((a.first > b.first) ? 1 : 0); + break; + case 2: // 备注 + result = strcmp(a.second.Note, b.second.Note); + break; + case 3: // 位置 + result = strcmp(a.second.Location, b.second.Location); + break; + case 4: // IP + result = strcmp(a.second.IP, b.second.IP); + break; + case 5: // 系统 + result = strcmp(a.second.OsName, b.second.OsName); + break; + case 6: // 安装时间 + result = strcmp(a.second.InstallTime, b.second.InstallTime); + break; + case 7: // 最后登录 + result = strcmp(a.second.LastLoginTime, b.second.LastLoginTime); + break; + case 8: // 关注级别 + result = a.second.Level - b.second.Level; + break; + case 9: // 已授权 + result = a.second.Authorized - b.second.Authorized; + break; + default: + return false; + } + + return bAscending ? (result < 0) : (result > 0); + }); + + m_ClientList.SetRedraw(FALSE); + DisplayClients(); + m_ClientList.SetRedraw(TRUE); + m_ClientList.Invalidate(); +} + +void CClientListDlg::AdjustColumnWidths() +{ + CRect rect; + m_ClientList.GetClientRect(&rect); + int totalWidth = rect.Width() - 20; + + m_ClientList.SetColumnWidth(0, totalWidth * 5 / 100); // 序号 + m_ClientList.SetColumnWidth(1, totalWidth * 12 / 100); // ID + m_ClientList.SetColumnWidth(2, totalWidth * 10 / 100); // 备注 + m_ClientList.SetColumnWidth(3, totalWidth * 11 / 100); // 位置 + m_ClientList.SetColumnWidth(4, totalWidth * 11 / 100); // IP + m_ClientList.SetColumnWidth(5, totalWidth * 11 / 100); // 系统 + m_ClientList.SetColumnWidth(6, totalWidth * 13 / 100); // 安装时间 + m_ClientList.SetColumnWidth(7, totalWidth * 13 / 100); // 最后登录 + m_ClientList.SetColumnWidth(8, totalWidth * 7 / 100); // 关注级别 + m_ClientList.SetColumnWidth(9, totalWidth * 7 / 100); // 已授权 +} + +void CClientListDlg::OnSize(UINT nType, int cx, int cy) +{ + CDialogEx::OnSize(nType, cx, cy); + + if (m_ClientList.GetSafeHwnd() == NULL) { + return; // 控件还没创建 + } + + // 留点边距 + int margin = 10; + + // 列表控件填满整个对话框(留边距) + m_ClientList.MoveWindow(margin, margin, cx - margin * 2, cy - margin * 2); + + AdjustColumnWidths(); +} + +void CClientListDlg::OnCancel() +{ + DestroyWindow(); +} + +void CClientListDlg::PostNcDestroy() +{ + if (g_pParent) { + g_pParent->m_pClientListDlg = nullptr; + } + + CDialogEx::PostNcDestroy(); + + delete this; +} + +void CClientListDlg::OnOK() +{ +} diff --git a/server/2015Remote/CClientListDlg.h b/server/2015Remote/CClientListDlg.h new file mode 100644 index 0000000..7ee4d28 --- /dev/null +++ b/server/2015Remote/CClientListDlg.h @@ -0,0 +1,46 @@ +#pragma once +#include "afxdialogex.h" +#include "HostInfo.h" +#include "Resource.h" +#include +#include +#include "2015RemoteDlg.h" + +// CClientListDlg 对话框 + +class CClientListDlg : public CDialogEx +{ + DECLARE_DYNAMIC(CClientListDlg) + +public: + CClientListDlg(_ClientList* clients, CMy2015RemoteDlg* pParent = nullptr); + virtual ~CClientListDlg(); + + // 对话框数据 +#ifdef AFX_DESIGN_TIME + enum { IDD = IDD_DIALOG_CLIENTLIST }; +#endif + +protected: + _ClientList* g_ClientList; + CMy2015RemoteDlg* g_pParent; + std::vector> m_clients; // 数据副本 + int m_nSortColumn; // 当前排序列 + BOOL m_bSortAscending; // 是否升序 + + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 + + DECLARE_MESSAGE_MAP() +public: + CListCtrl m_ClientList; + virtual BOOL OnInitDialog(); + void RefreshClientList(); + void DisplayClients(); + void AdjustColumnWidths(); + void SortByColumn(int nColumn, BOOL bAscending); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult); + virtual void OnCancel(); + virtual void PostNcDestroy(); + virtual void OnOK(); +}; diff --git a/server/2015Remote/HostInfo.h b/server/2015Remote/HostInfo.h new file mode 100644 index 0000000..b78a79b --- /dev/null +++ b/server/2015Remote/HostInfo.h @@ -0,0 +1,58 @@ +#pragma once + + +////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include "context.h" + +enum { + MAP_NOTE, + MAP_LOCATION, + MAP_LEVEL, + MAP_AUTH, +}; + +#pragma pack(push, 1) +class _ClientValue { +public: + char Note[64]; + char Location[64]; + char Level; + char IP[46]; + char InstallTime[20]; + char LastLoginTime[20]; + char OsName[32]; + char Authorized; + uint64_t ID; + char Reserved[768]; + + _ClientValue() + { + memset(this, 0, sizeof(_ClientValue)); + } +}; +#pragma pack(pop) + +typedef uint64_t ClientKey; + +typedef _ClientValue ClientValue; + +typedef std::unordered_map ClientMap; + +class _ClientList { +public: + virtual ~_ClientList() {} + virtual bool Exists(ClientKey key) = 0; + virtual CString GetClientMapData(ClientKey key, int typ) = 0; + virtual int GetClientMapInteger(ClientKey key, int typ) = 0; + virtual void SetClientMapInteger(ClientKey key, int typ, int value) = 0; + virtual void SetClientMapData(ClientKey key, int typ, const char* value) = 0; + virtual void SaveClientMapData(context* ctx) = 0; + virtual std::vector> GetAll() = 0; + virtual void SaveToFile(const std::string& filename) = 0; + virtual void LoadFromFile(const std::string& filename) = 0; +}; + +_ClientList* NewClientList(); diff --git a/server/2015Remote/IOCPKCPServer.h b/server/2015Remote/IOCPKCPServer.h index 9bbb13f..2a8b559 100644 --- a/server/2015Remote/IOCPKCPServer.h +++ b/server/2015Remote/IOCPKCPServer.h @@ -17,7 +17,7 @@ public: { return "KCP"; } - VOID InitMember(SOCKET s, Server* svr) override + VOID InitMember(SOCKET s, VOID* svr) override { CONTEXT_OBJECT::InitMember(s, svr); clientAddr = {}; diff --git a/server/2015Remote/Server.h b/server/2015Remote/Server.h index b7d0e42..f390e23 100644 --- a/server/2015Remote/Server.h +++ b/server/2015Remote/Server.h @@ -32,24 +32,6 @@ std::string GetRemoteIP(SOCKET sock); #define Muncompress(dest, destLen, source, sourceLen) m_Dctx ? ZSTD_decompressDCtx(m_Dctx, dest, *(destLen), source, sourceLen):\ ZSTD_decompress(dest, *(destLen), source, sourceLen) -enum { - ONLINELIST_IP = 0, // IP的列顺序 - ONLINELIST_ADDR, // 地址 - ONLINELIST_LOCATION, // 地理位置 - ONLINELIST_COMPUTER_NAME, // 计算机名/备注 - ONLINELIST_OS, // 操作系统 - ONLINELIST_CPU, // CPU - ONLINELIST_VIDEO, // 摄像头(有无) - ONLINELIST_PING, // PING(对方的网速) - ONLINELIST_VERSION, // 版本信息 - ONLINELIST_INSTALLTIME, // 安装时间 - ONLINELIST_LOGINTIME, // 活动窗口 - ONLINELIST_CLIENTTYPE, // 客户端类型 - ONLINELIST_PATH, // 文件路径 - ONLINELIST_PUBIP, - ONLINELIST_MAX, -}; - enum { PARSER_WINOS = -2, PARSER_FAILED = -1, // 解析失败 @@ -311,6 +293,7 @@ public: } }; +class CONTEXT_OBJECT; typedef BOOL (CALLBACK* pfnNotifyProc)(CONTEXT_OBJECT* ContextObject); typedef BOOL (CALLBACK* pfnOfflineProc)(CONTEXT_OBJECT* ContextObject); @@ -335,39 +318,10 @@ public: virtual void Disconnect(CONTEXT_OBJECT* ctx) {} }; -class context -{ -public: - // 纯虚函数 - virtual VOID InitMember(SOCKET s, Server* svr)=0; - virtual BOOL Send2Client(PBYTE szBuffer, ULONG ulOriginalLength) = 0; - virtual CString GetClientData(int index)const = 0; - virtual void GetAdditionalData(CString(&s)[RES_MAX]) const =0; - virtual CString GetAdditionalData(int index) const = 0; - virtual uint64_t GetClientID() const = 0; - virtual std::string GetPeerName() const = 0; - virtual int GetPort() const = 0; - virtual std::string GetProtocol() const = 0; - virtual int GetServerPort() const = 0; - virtual FlagType GetFlagType() const = 0; - virtual std::string GetGroupName() const = 0; - virtual uint64_t GetAliveTime()const = 0; -public: - virtual ~context() {} - virtual void Destroy() {} - virtual BOOL IsLogin() const - { - return TRUE; - } - virtual bool IsEqual(context *ctx) const - { - return this == ctx || this->GetPort() == ctx->GetPort(); - } -}; - // 预分配解压缩缓冲区大小 #define PREALLOC_DECOMPRESS_SIZE (4 * 1024) +#include "context.h" typedef class CONTEXT_OBJECT : public context { public: @@ -508,7 +462,7 @@ public: { return server->GetPort(); } - VOID InitMember(SOCKET s, Server *svr) + VOID InitMember(SOCKET s, VOID*svr) { memset(szBuffer, 0, sizeof(char) * PACKET_LENGTH); hDlg = NULL; @@ -527,7 +481,7 @@ public: Parser.Reset(); bLogin = FALSE; m_bProxyConnected = FALSE; - server = svr; + server = (Server*)svr; OnlineTime = time(0); } uint64_t GetAliveTime()const @@ -761,7 +715,7 @@ public: { return "UDP"; } - VOID InitMember(SOCKET s, Server* svr) override + VOID InitMember(SOCKET s, VOID* svr) override { CONTEXT_OBJECT::InitMember(s, svr); clientAddr = {}; diff --git a/server/2015Remote/context.h b/server/2015Remote/context.h new file mode 100644 index 0000000..7b9de0d --- /dev/null +++ b/server/2015Remote/context.h @@ -0,0 +1,53 @@ +#pragma once + +#include "common/header.h" +#include "common/commands.h" +#include + +enum { + ONLINELIST_IP = 0, // IP˳ + ONLINELIST_ADDR, // ַ + ONLINELIST_LOCATION, // λ + ONLINELIST_COMPUTER_NAME, // /ע + ONLINELIST_OS, // ϵͳ + ONLINELIST_CPU, // CPU + ONLINELIST_VIDEO, // ͷ() + ONLINELIST_PING, // PING(Է) + ONLINELIST_VERSION, // 汾Ϣ + ONLINELIST_INSTALLTIME, // װʱ + ONLINELIST_LOGINTIME, //  + ONLINELIST_CLIENTTYPE, // ͻ + ONLINELIST_PATH, // ļ· + ONLINELIST_PUBIP, + ONLINELIST_MAX, +}; + +class context +{ +public: + // 麯 + virtual VOID InitMember(SOCKET s, VOID* svr) = 0; + virtual BOOL Send2Client(PBYTE szBuffer, ULONG ulOriginalLength) = 0; + virtual CString GetClientData(int index)const = 0; + virtual void GetAdditionalData(CString(&s)[RES_MAX]) const = 0; + virtual CString GetAdditionalData(int index) const = 0; + virtual uint64_t GetClientID() const = 0; + virtual std::string GetPeerName() const = 0; + virtual int GetPort() const = 0; + virtual std::string GetProtocol() const = 0; + virtual int GetServerPort() const = 0; + virtual FlagType GetFlagType() const = 0; + virtual std::string GetGroupName() const = 0; + virtual uint64_t GetAliveTime()const = 0; +public: + virtual ~context() {} + virtual void Destroy() {} + virtual BOOL IsLogin() const + { + return TRUE; + } + virtual bool IsEqual(context* ctx) const + { + return this == ctx || this->GetPort() == ctx->GetPort(); + } +}; diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h index 0c9c917..f216dc3 100644 --- a/server/2015Remote/resource.h +++ b/server/2015Remote/resource.h @@ -197,6 +197,7 @@ #define IDD_DIALOG_FILESEND 320 #define IDR_SCLOADER_X86_OLD 322 #define IDR_SCLOADER_X64_OLD 323 +#define IDD_DIALOG_CLIENTLIST 324 #define IDC_MESSAGE 1000 #define IDC_ONLINE 1001 #define IDC_STATIC_TIPS 1002 @@ -445,6 +446,7 @@ #define IDC_STATIC_DOWNLOAD 2223 #define IDC_EDIT_DOWNLOAD_URL 2224 #define IDC_EDIT_FILESERVER_PORT 2225 +#define IDC_CLIENT_LIST 2227 #define ID_ONLINE_UPDATE 32772 #define ID_ONLINE_MESSAGE 32773 #define ID_ONLINE_DELETE 32775 @@ -625,15 +627,17 @@ #define ID_RANDOM_NAME 32994 #define ID_32995 32995 #define ID_DOWNLOAD_SERVERPORT 32996 +#define ID_32997 32997 +#define ID_HISTORY_CLIENTS 32998 #define ID_EXIT_FULLSCREEN 40001 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 324 -#define _APS_NEXT_COMMAND_VALUE 32997 -#define _APS_NEXT_CONTROL_VALUE 2226 +#define _APS_NEXT_RESOURCE_VALUE 326 +#define _APS_NEXT_COMMAND_VALUE 32999 +#define _APS_NEXT_CONTROL_VALUE 2228 #define _APS_NEXT_SYMED_VALUE 105 #endif #endif