#include "URIReg.h" #include #include #include #include #include URIReg URIReg::instance; URIReg::URIReg() { } URIReg::~URIReg() { } URIReg& URIReg::getInstance() { return instance; } bool URIReg::reg(const QString& protocolName) { #ifdef Q_OS_WIN // 获取当前工作目录 QString appPath = QCoreApplication::applicationFilePath(); #if 0 // 提升权限 if (!runAsAdmin()) return false; #endif #if 1 if (!isRunningAsAdmin()) return false; #endif // 创建注册表项 #if 0 // 因应用操作注册表的权限问题,改成HKEY_CURRENT_USER QSettings settings("HKEY_CLASSES_ROOT\\" + protocolName, QSettings::NativeFormat); #else QSettings settings("HKEY_CURRENT_USER\\Software\\Classes\\" + protocolName, QSettings::NativeFormat); #endif // 设置协议描述 settings.setValue("Default", QString("URL:%1 Protocol").arg(protocolName)); settings.sync(); if (QSettings::NoError != settings.status()) return false; // 标识这是一个URL协议 settings.setValue("URL Protocol", ""); settings.sync(); if (QSettings::NoError != settings.status()) return false; // 创建命令子项 settings.beginGroup("shell"); settings.beginGroup("open"); settings.beginGroup("command"); // 设置启动命令(注意转义 %1) QString command = QString("\"%1\" \"%2\"").arg(appPath).arg("%1"); settings.setValue("Default", command); settings.endGroup(); settings.endGroup(); settings.endGroup(); QSettings::Status s = settings.status(); // 验证写入结果 if (QSettings::NoError != settings.status()) return false; return true; #else // TODO:非Win平台下未实现 assert(0); return false; #endif } #ifdef Q_OS_WIN #include #include bool URIReg::runAsAdmin() { wchar_t path[MAX_PATH]; GetModuleFileNameW(nullptr, path, MAX_PATH); SHELLEXECUTEINFOW sei = { sizeof(sei) }; sei.lpVerb = L"runas"; sei.lpFile = path; sei.hwnd = nullptr; sei.nShow = SW_NORMAL; if (!ShellExecuteExW(&sei)) { qWarning() << QStringLiteral("提权失败:") << GetLastError(); return false; } return true; } // 检查是否以管理员权限运行 bool URIReg::isRunningAsAdmin() { HANDLE hToken; BOOL isElevated = FALSE; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { TOKEN_ELEVATION elevation; DWORD cbSize = sizeof(TOKEN_ELEVATION); GetTokenInformation(hToken, TokenElevation, &elevation, cbSize, &cbSize); CloseHandle(hToken); isElevated = elevation.TokenIsElevated; } return isElevated != FALSE; } #include #include void URIReg::fixRegistryPermissions(const QString& keyPath) { HKEY hKey; LONG result = RegOpenKeyExW( HKEY_CURRENT_USER, keyPath.toStdWString().c_str(), 0, // 选项,必须为0 KEY_READ | KEY_WRITE, // 读写权限, &hKey ); if (result == ERROR_SUCCESS) { // 重置为默认权限 PSECURITY_DESCRIPTOR sd; if (ConvertStringSecurityDescriptorToSecurityDescriptorW( L"D:(A;;KA;;;SY)(A;;KA;;;BA)(A;;KR;;;IU)", // 标准用户权限 SDDL_REVISION_1, &sd, nullptr)) { RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, sd); LocalFree(sd); } RegCloseKey(hKey); } } bool URIReg::writeUrlProtocol(const QString& protocol) { HKEY hKey; DWORD disp; QString fullPath = QString("Software\\Classes\\") + protocol; LONG res = RegCreateKeyExW( HKEY_CURRENT_USER, fullPath.toStdWString().c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, &disp ); if (res == ERROR_SUCCESS) { // 写入协议标识 DWORD zero = 0; RegSetValueExW(hKey, L"URL Protocol", 0, REG_SZ, (BYTE*)L"", 2); // 写入描述 std::wstring desc = L"URL:" + protocol.toStdWString() + L" Protocol"; RegSetValueExW(hKey, nullptr, 0, REG_SZ, (BYTE*)desc.c_str(), (desc.size() + 1) * sizeof(wchar_t)); RegCloseKey(hKey); return true; } return false; } #endif // Q_OS_WIN