Files
eUi/include/simpleTools/windowsCtrl.hpp
T
RCiRoot 97462c8aab On main: V20260416-2.5.1
增加halconGuard类,用于防止halcon算法的输入输出和程序不一致而引起的报错,并且会检查算法文件是否存在,如不存在则会弹窗提示。
增加handleAiGpuThreadGuard类,用于防止因重复调用同一个模型而引起的报错,并且支持不停机更新模型,支持初始化时检测模型文件是否存在。
增加内存占用显示控件。
用户管理增加root权限,默认密码为dseuiroot,模型热更新时需要此权限。
支持缓存界面上的检测数据。
相机模块新增在回调后的指定时间没有取图时则清空容器的功能。
增加等待结果汇总功能,在启用时同一个SN的图片会等待总结果后再进行存图。
存图线程修改为多线程编码,单线程储存,提高IO效率。并且增加根据内存占用的百分比更新存图逻辑的功能,默认占用超过70%不储存OK原图,超过80%不储存原图,超过90%时不储存所有图片。
2026-04-26 12:25:13 +08:00

383 lines
13 KiB
C++

#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#include <tchar.h>
#include <stdio.h>
#include <string.h> // for strstr
#include <devguid.h>
#include <shellapi.h>
#include <ShlObj.h>
#include <string>
#include <vector>
#include <QPixmap>
#include <QFileIconProvider>
#include <QFileInfo>
#pragma comment(lib, "setupapi.lib")
// 禁用控制台选择(快速编辑与鼠标输入)
static bool disableConsoleSelection() {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE || hStdin == NULL) return false;
DWORD mode = 0;
if (!GetConsoleMode(hStdin, &mode)) return false;
// 必须先设置 ENABLE_EXTENDED_FLAGS,再清除 ENABLE_QUICK_EDIT_MODE
DWORD newMode = mode | ENABLE_EXTENDED_FLAGS;
newMode &= ~(ENABLE_QUICK_EDIT_MODE | ENABLE_MOUSE_INPUT);
if (newMode == mode) return true; // 已经是期望模式
return SetConsoleMode(hStdin, newMode) != 0;
}
// 恢复控制台选择(快速编辑与鼠标输入)
static bool enableConsoleSelection() {
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE || hStdin == NULL) return false;
DWORD mode = 0;
if (!GetConsoleMode(hStdin, &mode)) return false;
DWORD newMode = mode | ENABLE_EXTENDED_FLAGS | ENABLE_QUICK_EDIT_MODE | ENABLE_MOUSE_INPUT;
if (newMode == mode) return true;
return SetConsoleMode(hStdin, newMode) != 0;
}
// 是否运行在 Windows Terminal 主机(PowerShell/命令行在 Windows Terminal 中)
static bool isWindowsTerminalHost() {
// Windows Terminal 会设置 WT_SESSION 环境变量
return GetEnvironmentVariableW(L"WT_SESSION", nullptr, 0) > 0;
}
// 绑定 CRT 与标准句柄到当前控制台
static void bindCrtToConsoleIO() {
FILE* fp = nullptr;
freopen_s(&fp, "CONIN$", "r", stdin);
freopen_s(&fp, "CONOUT$", "w", stdout);
freopen_s(&fp, "CONOUT$", "w", stderr);
// 同步 C++ iostream 与 C stdio
std::ios::sync_with_stdio();
}
// 确保获得一个“不可选择”的控制台。
// 如果检测到 Windows Terminal/PowerShell 环境,则脱离父控制台并新建独立控制台,避免被宿主选择影响。
static bool ensureNoSelectionConsole(bool detachWhenWT = true) {
bool createdNew = false;
if (detachWhenWT && isWindowsTerminalHost()) {
FreeConsole(); // 脱离 PowerShell/WT 的控制台
if (AllocConsole()) {
bindCrtToConsoleIO();
createdNew = true;
}
} else if (GetConsoleWindow() == NULL) {
// GUI 子系统或当前无控制台时创建一个
if (AllocConsole()) {
bindCrtToConsoleIO();
createdNew = true;
}
} else {
// 已有控制台,仍然尝试绑定,避免句柄无效
bindCrtToConsoleIO();
}
// 禁用选择(对当前控制台生效)
bool ok = disableConsoleSelection();
// 保险:确保控制台窗口可见
if (HWND hWnd = GetConsoleWindow()) {
ShowWindow(hWnd, SW_SHOW);
}
return createdNew ? ok : ok;
}
static void DisableComPort(const char* portName) {
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Get the device information set for all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) {
printf("SetupDiGetClassDevs 失败: %ld\n", GetLastError());
return;
}
// Enumerate through all devices in the set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
DWORD DataT;
char buffer[4096];
DWORD buffersize = sizeof(buffer);
// Get the friendly name of the device.
if (SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buffer, buffersize, &buffersize)) {
if (strstr(buffer, portName) != NULL) {
printf("Found COM port: %s\n", buffer);
// Disable the device.
DEVINST devInst = DeviceInfoData.DevInst;
CONFIGRET status = CM_Disable_DevNode(devInst, 0);
if (status != CR_SUCCESS) {
printf("CM_Disable_DevNode failed: %d\n", status);
}
else {
printf("Device disabled successfully.\n");
}
break;
}
}
} if (GetLastError() != NO_ERROR && GetLastError() != ERROR_NO_MORE_ITEMS) {
printf("SetupDiEnumDeviceInfo failed: %ld\n", GetLastError());
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
static void EnableComPort(const char* portName) {
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Get the device information set for all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) {
printf("SetupDiGetClassDevs 失败: %ld\n", GetLastError());
return;
}
// Enumerate through all devices in the set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData); i++) {
DWORD DataT;
char buffer[4096];
DWORD buffersize = sizeof(buffer);
// Get the friendly name of the device.
if (SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buffer, buffersize, &buffersize)) {
if (strstr(buffer, portName) != NULL) {
printf("Found COM port: %s\n", buffer);
// Disable the device.
DEVINST devInst = DeviceInfoData.DevInst;
CONFIGRET status = CM_Enable_DevNode(devInst, 0);
if (status != CR_SUCCESS) {
printf("CM_Enable_DevNode failed: %d\n", status);
}
else {
printf("Device Enable successfully.\n");
}
break;
}
}
}
if (GetLastError() != NO_ERROR && GetLastError() != ERROR_NO_MORE_ITEMS) {
printf("SetupDiEnumDeviceInfo failed: %ld\n", GetLastError());
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
}
static bool isRunAsAdmin() {
BOOL fIsRunAsAdmin = FALSE;
PSID pAdministratorsGroup = NULL;
// Allocate and initialize a SID of the administrators group.
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &pAdministratorsGroup))
{
return false;
}
// Determine whether the SID of administrators group is enabled in the primary access token of the process.
if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin))
{
fIsRunAsAdmin = FALSE;
}
// Free the allocated SID.
if (pAdministratorsGroup)
{
FreeSid(pAdministratorsGroup);
}
return fIsRunAsAdmin;
}
static void restartAsAdmin() {
TCHAR szPath[MAX_PATH];
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath))) {
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.lpVerb = TEXT("runas");
sei.lpFile = szPath;
sei.hwnd = NULL;
sei.nShow = SW_NORMAL;
if (!ShellExecuteEx(&sei)) {
DWORD dwError = GetLastError();
if (dwError == ERROR_CANCELLED) {
//std::cout << "The user refused to allow privileges elevation.\n";
}
}
}
}
// 解析 .lnk 文件,获取目标路径
static QString getShortcutTarget(const QString& shortcutPath) {
HRESULT hres;
CoInitialize(NULL);
IShellLink* psl;
QString targetPath;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres)) {
IPersistFile* ppf;
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres)) {
WCHAR wsz[MAX_PATH];
shortcutPath.toWCharArray(wsz);
wsz[shortcutPath.length()] = 0;
hres = ppf->Load(wsz, STGM_READ);
if (SUCCEEDED(hres)) {
char szTarget[MAX_PATH];
WIN32_FIND_DATA wfd;
if (SUCCEEDED(psl->GetPath(szTarget, MAX_PATH, &wfd, SLGP_UNCPRIORITY))) {
targetPath = QString::fromLocal8Bit(szTarget);
}
}
ppf->Release();
}
psl->Release();
}
CoUninitialize();
return targetPath;
}
// 获取目标文件图标
static QIcon getFileIcon(const QString& filePath, const QSize& size) {
QFileIconProvider iconProvider;
QFileInfo fileInfo(filePath);
QIcon icon = iconProvider.icon(fileInfo);
QPixmap pixmap = icon.pixmap(size);
return QIcon(pixmap);
}
static bool restartProgram(bool asAdmin = false, bool exitCurrent = true, int delayMs = 0) {
wchar_t exePath[MAX_PATH];
if (GetModuleFileNameW(nullptr, exePath, MAX_PATH) == 0) {
return false;
}
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
std::wstring params;
if (argv && argc > 1) {
for (int i = 1; i < argc; ++i) {
const wchar_t* arg = argv[i];
bool needQuote = wcspbrk(arg, L" \t\"'") != nullptr;
if (i > 1) params.push_back(L' ');
if (needQuote) {
params.push_back(L'"');
for (const wchar_t* p = arg; *p; ++p) {
if (*p == L'"') params.push_back(L'\\'), params.push_back(L'"');
else params.push_back(*p);
}
params.push_back(L'"');
} else {
params.append(arg);
}
}
}
if (argv) LocalFree(argv);
if (delayMs <= 0) {
SHELLEXECUTEINFOW sei{};
sei.cbSize = sizeof(sei);
sei.lpVerb = asAdmin ? L"runas" : L"open";
sei.lpFile = exePath;
sei.lpParameters = params.empty() ? nullptr : params.c_str();
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteExW(&sei)) return false;
if (exitCurrent) ExitProcess(0);
return true;
} else {
std::wstring exeEsc;
for (const wchar_t* p = exePath; *p; ++p) {
if (*p == L'\'') exeEsc.push_back(L'\''); // duplicate single quote for PS literal
exeEsc.push_back(*p);
}
std::wstring argsEsc;
if (!params.empty()) {
for (const wchar_t* p = params.c_str(); *p; ++p) {
if (*p == L'\'') argsEsc.push_back(L'\'');
argsEsc.push_back(*p);
}
}
std::wstring psParam = L"-NoProfile -WindowStyle Hidden -Command \"Wait-Process -Id ";
psParam += std::to_wstring(GetCurrentProcessId());
psParam += L"; Start-Sleep -Milliseconds ";
psParam += std::to_wstring(delayMs);
psParam += L"; Start-Process -FilePath '";
psParam += exeEsc;
psParam += L"'";
if (!argsEsc.empty()) {
psParam += L" -ArgumentList '";
psParam += argsEsc;
psParam += L"'";
}
psParam += L"\"";
SHELLEXECUTEINFOW sei{};
sei.cbSize = sizeof(sei);
sei.lpVerb = asAdmin ? L"runas" : L"open";
sei.lpFile = L"powershell.exe";
sei.lpParameters = psParam.c_str();
sei.nShow = SW_HIDE;
if (!ShellExecuteExW(&sei)) return false;
if (exitCurrent) ExitProcess(0);
return true;
}
}
struct memUsage {
DWORDLONG totalPhys;//总物理内存大小
DWORDLONG availPhys;//可用物理内存大小
DWORDLONG usedPhys;//已使用物理内存大小
DWORDLONG totalVir;//总虚拟内存大小
DWORDLONG availVir;//可用虚拟内存大小
DWORDLONG usedVir;//已使用虚拟内存大小
DWORDLONG totalMem;//总物理+虚拟内存大小
DWORDLONG availMem;//可用物理+虚拟内存大小
DWORDLONG usedMem;//已使用物理+虚拟内存大小
double usedPhysPercent;//已使用物理内存大小的百分比
double usedMemPercent;//已使用物理+虚拟内存大小的百分比
};
static memUsage getMemUsage() {
memUsage result;
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(memInfo);
if (GlobalMemoryStatusEx(&memInfo))
{
result.totalPhys = memInfo.ullTotalPhys;
result.availPhys = memInfo.ullAvailPhys;
result.usedPhys = result.totalPhys - result.availPhys;
result.totalVir = memInfo.ullTotalPageFile - memInfo.ullTotalPhys;
result.availVir = memInfo.ullAvailPageFile - memInfo.ullAvailPhys;
result.usedPhys = result.totalVir - result.availVir;
result.totalMem = memInfo.ullTotalPageFile;
result.availMem = memInfo.ullAvailPageFile;
result.usedMem = result.totalMem - result.availMem;
result.usedPhysPercent = (double)result.usedPhys / (double)result.totalPhys;
result.usedMemPercent = (double)result.usedMem / (double)result.totalMem;
}
return result;
}
#pragma once