261 lines
8.8 KiB
C++
261 lines
8.8 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 <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);
|
|
}
|
|
#pragma once |