VTM_IL.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. // test.cpp : 定义应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include "VTM_IL.h"
  5. #include<string>
  6. #include<regex>
  7. #include <windows.h>
  8. #include <shellapi.h>
  9. #include <fstream>
  10. #include <ShlObj.h>
  11. using namespace std;
  12. #define MAX_LOADSTRING 100
  13. #define ERROR_TITILE "可视柜台终端应用程序"
  14. const int HOTKEY_ID = 1;
  15. double horizontalScale;
  16. double verticalScale;
  17. HWND taskbar;
  18. RECT position;
  19. // 全局变量:
  20. HINSTANCE hInst; // 当前实例
  21. TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
  22. TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
  23. // 此代码模块中包含的函数的前向声明:
  24. ATOM MyRegisterClass(HINSTANCE hInstance);
  25. BOOL InitInstance(HINSTANCE, int);
  26. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  27. INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
  28. int APIENTRY _tWinMain(HINSTANCE hInstance,
  29. HINSTANCE hPrevInstance,
  30. LPTSTR lpCmdLine,
  31. int nCmdShow)
  32. {
  33. UNREFERENCED_PARAMETER(hPrevInstance);
  34. UNREFERENCED_PARAMETER(lpCmdLine);
  35. MSG msg;
  36. HACCEL hAccelTable;
  37. // 初始化全局字符串
  38. LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  39. LoadString(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING);
  40. MyRegisterClass(hInstance);
  41. Sleep(200);
  42. // 执行应用程序初始化:
  43. if (!InitInstance (hInstance, nCmdShow))
  44. {
  45. return FALSE;
  46. }
  47. hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST));
  48. // 主消息循环:
  49. while (GetMessage(&msg, NULL, 0, 0))
  50. {
  51. if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  52. {
  53. TranslateMessage(&msg);
  54. DispatchMessage(&msg);
  55. }
  56. }
  57. return (int) msg.wParam;
  58. }
  59. //
  60. // 函数: MyRegisterClass()
  61. //
  62. // 目的: 注册窗口类。
  63. //
  64. // 注释:
  65. //
  66. // 仅当希望
  67. // 此代码与添加到 Windows 95 中的“RegisterClassEx”
  68. // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
  69. // 这样应用程序就可以获得关联的
  70. // “格式正确的”小图标。
  71. //
  72. ATOM MyRegisterClass(HINSTANCE hInstance)
  73. {
  74. WNDCLASSEX wcex;
  75. wcex.cbSize = sizeof(WNDCLASSEX);
  76. wcex.style = CS_HREDRAW | CS_VREDRAW;
  77. wcex.lpfnWndProc = WndProc;
  78. wcex.cbClsExtra = 0;
  79. wcex.cbWndExtra = 0;
  80. wcex.hInstance = hInstance;
  81. wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST));
  82. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  83. wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  84. wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TEST);
  85. wcex.lpszClassName = szWindowClass;
  86. wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
  87. return RegisterClassEx(&wcex);
  88. }
  89. BOOL ExistsFileA(LPCSTR lpFilePath)
  90. {
  91. DWORD dwRet = GetFileAttributesA(lpFilePath);
  92. return (dwRet != INVALID_FILE_ATTRIBUTES) && !(dwRet & FILE_ATTRIBUTE_DIRECTORY);
  93. }
  94. BOOL ExistsDirA(LPCSTR lpDirPath)
  95. {
  96. DWORD dwRet = GetFileAttributesA(lpDirPath);
  97. return (dwRet != INVALID_FILE_ATTRIBUTES) && (dwRet & FILE_ATTRIBUTE_DIRECTORY);
  98. }
  99. UINT GetErrorMessage(CString& retMessage, LPCTSTR lpDefault, DWORD error = GetLastError())
  100. {
  101. if (error == 0) {
  102. retMessage = lpDefault;
  103. return strlen(lpDefault);
  104. }
  105. LPVOID lpMsgBuf;
  106. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  107. | FORMAT_MESSAGE_FROM_SYSTEM
  108. | FORMAT_MESSAGE_IGNORE_INSERTS,
  109. NULL,
  110. error,
  111. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  112. (LPTSTR)&lpMsgBuf,
  113. 0,
  114. NULL);
  115. if (lpMsgBuf == NULL) {
  116. retMessage = lpDefault;
  117. return strlen(lpDefault);
  118. }
  119. CString strTemp;
  120. strTemp.Format("错误描述:%s", (LPCTSTR)lpMsgBuf);
  121. retMessage = strTemp;
  122. LocalFree((LPVOID)lpMsgBuf);
  123. return retMessage.GetLength();
  124. }
  125. int GetVersion(char** pVersion)
  126. {
  127. char szFileName[MAX_PATH] = {0};
  128. char szFilePath[MAX_PATH] = {0};
  129. GetModuleFileNameA(NULL, szFileName, sizeof(szFileName));
  130. string strFileName = szFileName;
  131. int nPos = strFileName.find_last_of("\\");
  132. string strDir = strFileName.substr(0, nPos);
  133. sprintf_s(szFilePath, MAX_PATH,"%s\\active.txt", strDir.c_str());
  134. if (!ExistsFileA(szFilePath)) {
  135. CString strText;
  136. strText.Format("[RTA0031] 版本文件 active.txt 不存在,请重新安装程序版本!(文件路径:%s)", szFilePath);
  137. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  138. return 0;
  139. }
  140. char cVer[MAX_PATH] = {0};
  141. ifstream infile(szFilePath);
  142. if(infile) // 有该文件
  143. {
  144. if(infile.getline(cVer, MAX_PATH))
  145. {
  146. CString strVersionTxt(cVer);
  147. strVersionTxt.Trim();
  148. if (strVersionTxt.IsEmpty()) {
  149. CString strText;
  150. strText.Format("[RTA0032] 版本文件 active.txt 内容为空,请重新安装程序版本!(文件路径:%s)", szFilePath);
  151. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  152. infile.close();
  153. return 0;
  154. }
  155. std::regex reg("^\\d+\\.\\d+\\.\\d+\\.\\d+$");
  156. std::string strVerion(strVersionTxt.GetString());
  157. /** 要不要加正则表达式校验待定,目前没有加 [Gifur@2025516]*/
  158. if (TRUE || std::regex_match(strVerion, reg))
  159. {
  160. memcpy_s(*pVersion, MAX_PATH, strVersionTxt.GetString(), MAX_PATH);
  161. infile.close();
  162. return 1;
  163. }
  164. else
  165. {
  166. CString strText;
  167. strText.Format("[RTAXXXX] 版本文件 active.txt 内容不符合 X.Y.Z.W 格式,请检查应用程序的完整性!\r\n版本文件路径:%s\r\n当前内容为:%s"
  168. , szFilePath, cVer);
  169. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  170. infile.close();
  171. return 0;
  172. }
  173. }
  174. else
  175. {
  176. CString strText;
  177. strText.Format("[RTA0032] 版本文件 active.txt 内容为空,请重新安装程序版本!(文件路径:%s)", szFilePath);
  178. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  179. infile.close();
  180. return 0;
  181. }
  182. }
  183. else {
  184. CString strText;
  185. strText.Format("[RTA0033] 版本文件 active.txt 打开失败,请联系分行IT或厂商排查!(文件路径:%s)", szFilePath);
  186. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  187. return 0;
  188. }
  189. infile.close();
  190. return 0;
  191. }
  192. BOOL GetSpShellPath(char** pPath)
  193. {
  194. char* pVer = new char[MAX_PATH];
  195. memset(pVer, 0, MAX_PATH);
  196. char szFileName[MAX_PATH] = {0};
  197. char szFilePath[MAX_PATH] = {0};
  198. GetModuleFileNameA(NULL, szFileName, sizeof(szFileName));
  199. string strFileName = szFileName;
  200. int nPos = strFileName.find_last_of("\\");
  201. string strDir = strFileName.substr(0, nPos);
  202. if(!GetVersion(&pVer))
  203. {
  204. if (NULL != pVer)
  205. {
  206. free(pVer);
  207. pVer = NULL;
  208. }
  209. return FALSE;
  210. }
  211. memset(szFileName, 0, sizeof(szFileName));
  212. sprintf_s(szFileName, MAX_PATH, "%s\\%s", strDir.c_str(), pVer);
  213. if (!ExistsDirA(szFileName)) {
  214. CString strText;
  215. strText.Format("[RTA0034] 版本文件夹 [%s] 不存在,请重新安装程序版本!(文件夹路径:%s)",pVer, szFileName);
  216. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  217. if (NULL != pVer)
  218. {
  219. free(pVer);
  220. pVer = NULL;
  221. }
  222. return FALSE;
  223. }
  224. sprintf_s(szFilePath, MAX_PATH, "%s\\%s\\bin\\SpShell.exe", strDir.c_str(), pVer);
  225. memcpy_s(*pPath, MAX_PATH, szFilePath, MAX_PATH);
  226. if (NULL != pVer)
  227. {
  228. free(pVer);
  229. pVer = NULL;
  230. }
  231. if (!ExistsFileA(*pPath)) {
  232. CString strText;
  233. strText.Format("[RTA0035] 程序执行文件 SpShell.exe 不存在,请重新安装程序版本!(文件路径:%s)", *pPath);
  234. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  235. return FALSE;
  236. }
  237. return TRUE;
  238. }
  239. BOOL Execute(const char* cExeName)
  240. {
  241. SHELLEXECUTEINFOA sei = {sizeof(SHELLEXECUTEINFOA)};
  242. sei.lpVerb = "runas";
  243. sei.lpFile = cExeName;
  244. sei.nShow = SW_SHOWNORMAL;
  245. if (!ShellExecuteExA(&sei))
  246. {
  247. const DWORD dwError = GetLastError();
  248. CString strText;
  249. CString strError;
  250. char szDefault[128];
  251. sprintf_s(szDefault, "错误描述:%u", dwError);
  252. GetErrorMessage(strError, szDefault, dwError);
  253. strText.Format("[RTA0036] 执行应用程序文件 SpShell.exe 失败,请联系分行IT或厂商排查!(文件路径:%s)\r\n\r\n%s", cExeName, strError.GetBuffer());
  254. MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR);
  255. return FALSE;
  256. }
  257. return TRUE;
  258. }
  259. BOOL RunSpshell()
  260. {
  261. BOOL ret = FALSE;
  262. char* pSpPath = new char[MAX_PATH];
  263. memset(pSpPath, 0, MAX_PATH);
  264. do
  265. {
  266. if (!GetSpShellPath(&pSpPath))
  267. {
  268. break;
  269. }
  270. if (!Execute(pSpPath))
  271. {
  272. break;
  273. }
  274. ret = TRUE;
  275. } while (false);
  276. if (NULL != pSpPath)
  277. {
  278. delete[] pSpPath;
  279. pSpPath = NULL;
  280. }
  281. return ret;
  282. }
  283. //校正
  284. int checkActiveTxtAttr()
  285. {
  286. char vtmexePath[MAX_PATH] = {0};
  287. GetModuleFileNameA(NULL, vtmexePath, sizeof(vtmexePath));
  288. string strRunVtmPath = vtmexePath;
  289. const auto nPosVtm = strRunVtmPath.find("\\version\\VTM.exe");
  290. if(nPosVtm == -1)
  291. {
  292. MessageBoxA(NULL,"[RTA0030] VTM.exe 不在规定路径下运行,请重新安装程序版本!", ERROR_TITILE, MB_OK | MB_ICONERROR);
  293. return -1;
  294. }
  295. const int nPos = strRunVtmPath.find_last_of("\\");
  296. string strVersionDir = strRunVtmPath.substr(0, nPos);
  297. CString strActiveTxtPath=strVersionDir.c_str();//+"active.txt";
  298. strActiveTxtPath +="\\";
  299. strActiveTxtPath +="active.txt";
  300. if (ExistsFileA(strActiveTxtPath)) {
  301. CFileStatus rStatus;
  302. CFile::GetStatus(strActiveTxtPath, rStatus);//获得文件的属性设置
  303. //如果文件为只读的,将只读属性去掉
  304. if (rStatus.m_attribute & CFile::readOnly) {
  305. rStatus.m_attribute = rStatus.m_attribute & 0x3E;
  306. CFile::SetStatus(strActiveTxtPath, rStatus);//更改文件的属性设置
  307. }
  308. }
  309. return 0;
  310. }
  311. void RegistHotkey()
  312. {
  313. RegisterHotKey(
  314. NULL, // this thread will process the hotkey
  315. HOTKEY_ID,
  316. MOD_WIN, // win
  317. VK_OEM_3 // ~
  318. );
  319. }
  320. void UnRegistHotkey()
  321. {
  322. UnregisterHotKey(NULL, HOTKEY_ID);
  323. }
  324. void FormatPosition()
  325. {
  326. if (position.left < 0) {
  327. // taskbar is on the left, move right
  328. position.right -= position.left;
  329. position.left = 0;
  330. }
  331. if (position.bottom < 0) {
  332. // taskbar is on the bottom, move up
  333. position.top -= position.bottom;
  334. position.bottom = 0;
  335. }
  336. }
  337. void HideTaskbarEx()
  338. {
  339. auto empty = CreateRectRgn(0, 0, 0, 0);
  340. SetWindowRgn(taskbar, empty, true);
  341. DeleteObject(empty);
  342. }
  343. void ShowTaskbarEx()
  344. {
  345. auto region = CreateRectRgn(position.left, position.top, position.right * horizontalScale, position.bottom * verticalScale);
  346. SetWindowRgn(taskbar, region, true);
  347. DeleteObject(region);
  348. }
  349. VOID HideTaskBar(BOOL bHide)
  350. {
  351. int nCmdShow;
  352. HWND hWnd;
  353. LPARAM lParam;
  354. hWnd = FindWindow(_T("Shell_TrayWnd"), NULL);
  355. if (bHide == TRUE) {
  356. nCmdShow = SW_HIDE;
  357. lParam = ABS_AUTOHIDE | ABS_ALWAYSONTOP;
  358. }
  359. else {
  360. nCmdShow = SW_SHOW;
  361. lParam = ABS_ALWAYSONTOP;
  362. }
  363. if (hWnd != NULL) {
  364. taskbar = hWnd;
  365. //ShowWindow(hWnd, nCmdShow);
  366. //GetWindowRect(hWnd, &position);
  367. //FormatPosition();
  368. //HideTaskbarEx();
  369. #if defined(DEVOPS_ON_PRD) || defined(DEVOPS_ON_UAT)
  370. APPBARDATA apBar;
  371. memset(&apBar, 0, sizeof(apBar));
  372. apBar.cbSize = sizeof(apBar);
  373. apBar.hWnd = hWnd;
  374. if (apBar.hWnd != NULL)
  375. {
  376. apBar.lParam = lParam;
  377. SHAppBarMessage(ABM_SETSTATE, &apBar);
  378. }
  379. #endif // DEVOPS_ON_PRD
  380. }
  381. }
  382. // Ref: https://stackoverflow.com/questions/54912038/querying-windows-display-scaling
  383. void GetDisplayScale()
  384. {
  385. auto activeWindow = GetActiveWindow();
  386. HMONITOR monitor = MonitorFromWindow(activeWindow, MONITOR_DEFAULTTONEAREST);
  387. // Get the logical width and height of the monitor
  388. MONITORINFOEX monitorInfoEx;
  389. monitorInfoEx.cbSize = sizeof(monitorInfoEx);
  390. GetMonitorInfo(monitor, &monitorInfoEx);
  391. auto cxLogical = monitorInfoEx.rcMonitor.right - monitorInfoEx.rcMonitor.left;
  392. auto cyLogical = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top;
  393. // Get the physical width and height of the monitor
  394. DEVMODE devMode;
  395. devMode.dmSize = sizeof(devMode);
  396. devMode.dmDriverExtra = 0;
  397. EnumDisplaySettings(monitorInfoEx.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
  398. auto cxPhysical = devMode.dmPelsWidth;
  399. auto cyPhysical = devMode.dmPelsHeight;
  400. // Calculate the scaling factor
  401. horizontalScale = ((double)cxPhysical / (double)cxLogical);
  402. verticalScale = ((double)cyPhysical / (double)cyLogical);
  403. #ifdef _DEBUG
  404. printf("horizontalScale: %f\n", horizontalScale);
  405. printf("verticalScale: %f\n", verticalScale);
  406. #endif
  407. }
  408. //
  409. // 函数: InitInstance(HINSTANCE, int)
  410. //
  411. // 目的: 保存实例句柄并创建主窗口
  412. //
  413. // 注释:
  414. //
  415. // 在此函数中,我们在全局变量中保存实例句柄并
  416. // 创建和显示主程序窗口。
  417. //
  418. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
  419. {
  420. // 校正active.txt的属性
  421. if (0 == checkActiveTxtAttr() && RunSpshell()) {
  422. HideTaskBar(TRUE);
  423. }
  424. hInst = hInstance; // 将实例句柄存储在全局变量中
  425. //HWND hWnd = CreateWindowA(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
  426. //CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
  427. //if (!hWnd)
  428. //{
  429. //return FALSE;
  430. //}
  431. //ShowWindow(hWnd, nCmdShow);
  432. //UpdateWindow(hWnd);
  433. return FALSE;
  434. }
  435. //
  436. // 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
  437. //
  438. // 目的: 处理主窗口的消息。
  439. //
  440. // WM_COMMAND - 处理应用程序菜单
  441. // WM_PAINT - 绘制主窗口
  442. // WM_DESTROY - 发送退出消息并返回
  443. //
  444. //
  445. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  446. {
  447. int wmId, wmEvent;
  448. PAINTSTRUCT ps;
  449. HDC hdc;
  450. switch (message)
  451. {
  452. case WM_COMMAND:
  453. wmId = LOWORD(wParam);
  454. wmEvent = HIWORD(wParam);
  455. // 分析菜单选择:
  456. switch (wmId)
  457. {
  458. case IDM_ABOUT:
  459. DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
  460. break;
  461. case IDM_EXIT:
  462. DestroyWindow(hWnd);
  463. break;
  464. default:
  465. return DefWindowProc(hWnd, message, wParam, lParam);
  466. }
  467. break;
  468. case WM_PAINT:
  469. hdc = BeginPaint(hWnd, &ps);
  470. // TODO: 在此添加任意绘图代码...
  471. EndPaint(hWnd, &ps);
  472. break;
  473. case WM_DESTROY:
  474. PostQuitMessage(0);
  475. break;
  476. default:
  477. return DefWindowProc(hWnd, message, wParam, lParam);
  478. }
  479. return 0;
  480. }
  481. // “关于”框的消息处理程序。
  482. INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  483. {
  484. UNREFERENCED_PARAMETER(lParam);
  485. switch (message)
  486. {
  487. case WM_INITDIALOG:
  488. return (INT_PTR)TRUE;
  489. case WM_COMMAND:
  490. if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  491. {
  492. EndDialog(hDlg, LOWORD(wParam));
  493. return (INT_PTR)TRUE;
  494. }
  495. break;
  496. }
  497. return (INT_PTR)FALSE;
  498. }