// test.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "VTM_IL.h" #include #include #include #include #include #include #include // for std::tolower #include using namespace std; #define MAX_LOADSTRING 100 #define ERROR_TITILE "可视柜台终端应用程序" const int HOTKEY_ID = 1; double horizontalScale; double verticalScale; HWND taskbar; RECT position; // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); MSG msg; HACCEL hAccelTable; // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TEST, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); Sleep(200); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_TEST); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } BOOL ExistsFileA(LPCSTR lpFilePath) { DWORD dwRet = GetFileAttributesA(lpFilePath); return (dwRet != INVALID_FILE_ATTRIBUTES) && !(dwRet & FILE_ATTRIBUTE_DIRECTORY); } BOOL ExistsDirA(LPCSTR lpDirPath) { DWORD dwRet = GetFileAttributesA(lpDirPath); return (dwRet != INVALID_FILE_ATTRIBUTES) && (dwRet & FILE_ATTRIBUTE_DIRECTORY); } UINT GetErrorMessage(CString& retMessage, LPCTSTR lpDefault, DWORD error = GetLastError()) { if (error == 0) { retMessage = lpDefault; return strlen(lpDefault); } LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); if (lpMsgBuf == NULL) { retMessage = lpDefault; return strlen(lpDefault); } CString strTemp; strTemp.Format("错误描述:%s", (LPCTSTR)lpMsgBuf); retMessage = strTemp; LocalFree((LPVOID)lpMsgBuf); return retMessage.GetLength(); } int GetVersion(char** pVersion) { char szFileName[MAX_PATH] = {0}; char szFilePath[MAX_PATH] = {0}; GetModuleFileNameA(NULL, szFileName, sizeof(szFileName)); string strFileName = szFileName; int nPos = strFileName.find_last_of("\\"); string strDir = strFileName.substr(0, nPos); sprintf_s(szFilePath, MAX_PATH,"%s\\active.txt", strDir.c_str()); if (!ExistsFileA(szFilePath)) { CString strText; strText.Format("[RTA0031] 版本文件不存在,请重新安装程序版本!"); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); return 0; } ifstream infile(szFilePath); if(infile.is_open()) { std::string line; if(std::getline(infile, line)){ CString strVersionTxt(line.c_str()); memcpy_s(*pVersion, MAX_PATH, strVersionTxt.GetString(), MAX_PATH); infile.close(); return 1; } else { CString strText; strText.Format("[RTA0032] 版本文件内容为空,请重新安装程序版本!"); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); infile.close(); return 0; } } else { const DWORD dwError = GetLastError(); CString strText; CString strError; char szDefault[128]; sprintf_s(szDefault, "错误描述:%u", dwError); GetErrorMessage(strError, szDefault, dwError); strText.Format("[RTA0033] 版本文件打开失败,请联系分行IT或厂商排查!\r\n\r\n%s", strError.GetBuffer()); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); return 0; } infile.close(); return 0; } BOOL GetSpShellPath(char** pPath) { char* pVer = new char[MAX_PATH]; memset(pVer, 0, MAX_PATH); char szFileName[MAX_PATH] = {0}; char szFilePath[MAX_PATH] = {0}; GetModuleFileNameA(NULL, szFileName, sizeof(szFileName)); string strFileName = szFileName; int nPos = strFileName.find_last_of("\\"); string strDir = strFileName.substr(0, nPos); if(!GetVersion(&pVer)) { if (NULL != pVer) { delete [] pVer; pVer = NULL; } return FALSE; } memset(szFileName, 0, sizeof(szFileName)); sprintf_s(szFileName, MAX_PATH, "%s\\%s", strDir.c_str(), pVer); if (!ExistsDirA(szFileName)) { CString strText; strText.Format("[RTA0034] 版本文件夹 [%s] 不存在,请重新安装程序版本!",pVer); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); if (NULL != pVer) { delete[] pVer; pVer = NULL; } return FALSE; } sprintf_s(szFilePath, MAX_PATH, "%s\\%s\\bin\\SpShell.exe", strDir.c_str(), pVer); memcpy_s(*pPath, MAX_PATH, szFilePath, MAX_PATH); if (NULL != pVer) { delete[] pVer; pVer = NULL; } if (!ExistsFileA(*pPath)) { CString strText; strText.Format("[RTA0035] 程序执行文件不存在,请重新安装程序版本!(文件路径:%s)", *pPath); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); return FALSE; } return TRUE; } BOOL Execute(const char* cExeName) { SHELLEXECUTEINFOA sei = {sizeof(SHELLEXECUTEINFOA)}; sei.lpVerb = "runas"; sei.lpFile = cExeName; sei.nShow = SW_SHOWNORMAL; if (!ShellExecuteExA(&sei)) { const DWORD dwError = GetLastError(); CString strText; CString strError; char szDefault[128]; sprintf_s(szDefault, "错误描述:%u", dwError); GetErrorMessage(strError, szDefault, dwError); strText.Format("[RTA0036] 执行应用程序文件失败,请联系分行IT或厂商排查!\r\n\r\n%s", strError.GetBuffer()); MessageBoxA(NULL, strText, ERROR_TITILE, MB_OK | MB_ICONERROR); return FALSE; } return TRUE; } BOOL RunSpshell() { BOOL ret = FALSE; char* pSpPath = new char[MAX_PATH]; memset(pSpPath, 0, MAX_PATH); do { if (!GetSpShellPath(&pSpPath)) { break; } if (!Execute(pSpPath)) { break; } ret = TRUE; } while (false); if (NULL != pSpPath) { delete[] pSpPath; pSpPath = NULL; } return ret; } //校正 int checkActiveTxtAttr() { char vtmexePath[MAX_PATH] = {0}; GetModuleFileNameA(NULL, vtmexePath, sizeof(vtmexePath)); string strRunVtmPath = vtmexePath; string strCheck = vtmexePath; std::transform(strCheck.begin(), strCheck.end(), strCheck.begin(), ::tolower); const auto nPosVtm = strCheck.find("\\version\\vtm.exe"); if(nPosVtm == -1) { MessageBoxA(NULL,"[RTA0030] 可视柜台应用程序不在规定路径下执行,请重新安装程序版本!", ERROR_TITILE, MB_OK | MB_ICONERROR); return -1; } const int nPos = strRunVtmPath.find_last_of("\\"); string strVersionDir = strRunVtmPath.substr(0, nPos); CString strActiveTxtPath=strVersionDir.c_str();//+"active.txt"; strActiveTxtPath +="\\"; strActiveTxtPath +="active.txt"; if (ExistsFileA(strActiveTxtPath)) { CFileStatus rStatus; CFile::GetStatus(strActiveTxtPath, rStatus);//获得文件的属性设置 //如果文件为只读的,将只读属性去掉 if (rStatus.m_attribute & CFile::readOnly) { rStatus.m_attribute = rStatus.m_attribute & 0x3E; CFile::SetStatus(strActiveTxtPath, rStatus);//更改文件的属性设置 } } return 0; } void RegistHotkey() { RegisterHotKey( NULL, // this thread will process the hotkey HOTKEY_ID, MOD_WIN, // win VK_OEM_3 // ~ ); } void UnRegistHotkey() { UnregisterHotKey(NULL, HOTKEY_ID); } void FormatPosition() { if (position.left < 0) { // taskbar is on the left, move right position.right -= position.left; position.left = 0; } if (position.bottom < 0) { // taskbar is on the bottom, move up position.top -= position.bottom; position.bottom = 0; } } void HideTaskbarEx() { auto empty = CreateRectRgn(0, 0, 0, 0); SetWindowRgn(taskbar, empty, true); DeleteObject(empty); } void ShowTaskbarEx() { auto region = CreateRectRgn(position.left, position.top, position.right * horizontalScale, position.bottom * verticalScale); SetWindowRgn(taskbar, region, true); DeleteObject(region); } VOID HideTaskBar(BOOL bHide) { int nCmdShow; HWND hWnd; LPARAM lParam; hWnd = FindWindow(_T("Shell_TrayWnd"), NULL); if (bHide == TRUE) { nCmdShow = SW_HIDE; lParam = ABS_AUTOHIDE | ABS_ALWAYSONTOP; } else { nCmdShow = SW_SHOW; lParam = ABS_ALWAYSONTOP; } if (hWnd != NULL) { taskbar = hWnd; //ShowWindow(hWnd, nCmdShow); //GetWindowRect(hWnd, &position); //FormatPosition(); //HideTaskbarEx(); #if defined(DEVOPS_ON_PRD) || defined(DEVOPS_ON_UAT) APPBARDATA apBar; memset(&apBar, 0, sizeof(apBar)); apBar.cbSize = sizeof(apBar); apBar.hWnd = hWnd; if (apBar.hWnd != NULL) { apBar.lParam = lParam; SHAppBarMessage(ABM_SETSTATE, &apBar); } #endif // DEVOPS_ON_PRD } } // Ref: https://stackoverflow.com/questions/54912038/querying-windows-display-scaling void GetDisplayScale() { auto activeWindow = GetActiveWindow(); HMONITOR monitor = MonitorFromWindow(activeWindow, MONITOR_DEFAULTTONEAREST); // Get the logical width and height of the monitor MONITORINFOEX monitorInfoEx; monitorInfoEx.cbSize = sizeof(monitorInfoEx); GetMonitorInfo(monitor, &monitorInfoEx); auto cxLogical = monitorInfoEx.rcMonitor.right - monitorInfoEx.rcMonitor.left; auto cyLogical = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top; // Get the physical width and height of the monitor DEVMODE devMode; devMode.dmSize = sizeof(devMode); devMode.dmDriverExtra = 0; EnumDisplaySettings(monitorInfoEx.szDevice, ENUM_CURRENT_SETTINGS, &devMode); auto cxPhysical = devMode.dmPelsWidth; auto cyPhysical = devMode.dmPelsHeight; // Calculate the scaling factor horizontalScale = ((double)cxPhysical / (double)cxLogical); verticalScale = ((double)cyPhysical / (double)cyLogical); #ifdef _DEBUG printf("horizontalScale: %f\n", horizontalScale); printf("verticalScale: %f\n", verticalScale); #endif } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { // 校正active.txt的属性 if (0 == checkActiveTxtAttr() && RunSpshell()) { HideTaskBar(TRUE); } hInst = hInstance; // 将实例句柄存储在全局变量中 //HWND hWnd = CreateWindowA(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, //CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); //if (!hWnd) //{ //return FALSE; //} //ShowWindow(hWnd, nCmdShow); //UpdateWindow(hWnd); return FALSE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // “关于”框的消息处理程序。 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; }